diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	Sun Nov 10 19:28:40 2002
+++ b/CREDITS	Sun Nov 10 19:28:40 2002
@@ -533,6 +533,10 @@
 S: Taiwan 251
 S: Republic of China
 
+N: Michael Elizabeth Chastain
+E: mec@shout.net
+D: Configure, Menuconfig, xconfig
+
 N: Raymond Chen
 E: raymondc@microsoft.com
 D: Author of Configure script
@@ -562,7 +566,7 @@
 N: Randolph Chung
 E: tausq@debian.org
 D: Linux/PA-RISC hacker
-S: Fremont, CA 94538
+S: Los Altos, CA 94022
 S: USA
 
 N: Juan Jose Ciarlante
@@ -753,6 +757,14 @@
 S: Round Rock, TX  78682
 S: USA
 
+N: John G Dorsey
+E: john+@cs.cmu.edu
+D: ARM Linux ports to Assabet/Neponset, Spot
+S: Department of Electrical and Computer Engineering
+S: Carnegie Mellon University
+S: Pittsburgh, PA  15213
+S: USA
+
 N: Eddie C. Dost
 E: ecd@skynet.be
 D: Linux/Sparc kernel hacker
@@ -1133,11 +1145,11 @@
 S: South Africa
 
 N: Grant Grundler
-E: grundler@puffin.external.hp.com
-W: http://www.grundler.net/
+E: grundler@parisc-linux.org
 W: http://obmouse.sourceforge.net/
+W: http://www.parisc-linux.org/
 D: obmouse - rewrote Olivier Florent's Omnibook 600 "pop-up" mouse driver
-D: PA-RISC - IO Interrupt/PCI HBA/IO MMU author and architect
+D: PA-RISC - Interrupt/PCI HBA/IOMMU author and architect
 S: Mountain View, California
 S: USA
 
@@ -1284,7 +1296,7 @@
 S: Germany
 
 N: David Hinds
-E: dhinds@zen.stanford.edu
+E: dahinds@users.sourceforge.net
 W: http://tao.stanford.edu/~dhinds
 D: PCMCIA and CardBus stuff, PCMCIA-HOWTO, PCMCIA client drivers
 S: 2019 W. Middlefield Rd #1
@@ -2218,6 +2230,15 @@
 S: Lafayette, Indiana 47905
 S: USA
 
+N: Scott Murray
+E: scottm@somanetworks.com
+E: scott@spiteful.org
+D: OPL3-SA2, OPL3-SA3 sound driver
+D: CompactPCI hotplug core
+D: Ziatech ZT5550 and generic CompactPCI hotplug drivers
+S: Toronto, Ontario
+S: Canada
+
 N: Trond Myklebust
 E: trond.myklebust@fys.uio.no
 D: current NFS client hacker.
@@ -2269,6 +2290,15 @@
 S: Potsdam, New York 13676
 S: USA
 
+N: Dave Neuer
+E: dneuer@innovation-charter.com
+E: mr_fred_smoothie@yahoo.com
+D: Helped implement support for Compaq's H31xx series iPAQs
+D: Other mostly minor tweaks & bugfixes
+S: 325 E. Main St., Suite 3
+S: Carnegie, PA 15105
+S: USA
+
 N: Michael Neuffer
 E: mike@i-Connect.Net
 E: neuffer@goofy.zdv.uni-mainz.de
@@ -2433,6 +2463,7 @@
 N: Nicolas Pitre
 E: nico@cam.org
 D: StrongARM SA1100 support integrator & hacker
+D: Xscale PXA architecture
 S: Montreal, Quebec, Canada
 
 N: Ken Pizzini
@@ -2703,6 +2734,12 @@
 S: Valurink. 4A11
 S: 03600 Karkkila
 S: Finland
+
+N: Deepak Saxena
+E: deepak@csociety.purdue.edu
+D: I2O kernel layer (config, block, core, pci, net). I2O disk support for LILO
+D: XScale(IOP310) porting
+S: Tempe, Arizona
 
 N: Eric Schenk
 E: Eric.Schenk@dna.lth.se
diff -Nru a/Documentation/Changes b/Documentation/Changes
--- a/Documentation/Changes	Sun Nov 10 19:28:41 2002
+++ b/Documentation/Changes	Sun Nov 10 19:28:41 2002
@@ -31,7 +31,7 @@
 Eine deutsche Version dieser Datei finden Sie unter
 <http://www.stefan-winter.de/Changes-2.4.0.txt>.
 
-Last updated: October 1st, 2002
+Last updated: October 29th, 2002
 
 Chris Ricker (kaboom@gatech.edu or chris.ricker@genetics.utah.edu).
 
@@ -313,7 +313,7 @@
 
 E2fsprogs
 ---------
-o  <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.25.tar.gz>
+o  <http://prdownloads.sourceforge.net/e2fsprogs/e2fsprogs-1.29.tar.gz>
 
 JFSutils
 --------
diff -Nru a/Documentation/DocBook/journal-api.tmpl b/Documentation/DocBook/journal-api.tmpl
--- a/Documentation/DocBook/journal-api.tmpl	Sun Nov 10 19:28:36 2002
+++ b/Documentation/DocBook/journal-api.tmpl	Sun Nov 10 19:28:36 2002
@@ -207,9 +207,9 @@
 The opportunities for abuse and DOS attacks with this should be obvious,
 if you allow unprivileged userspace to trigger codepaths containing these
 calls.
-
-<para>
+</para>
 </sect1>
+
 <sect1>
 <title>Summary</title>
 <para>
@@ -244,6 +244,8 @@
    }
    journal_destroy(my_jrnl);
 </programlisting>
+</para>
+</sect1>
 
 </chapter>
 
diff -Nru a/Documentation/DocBook/kernel-hacking.tmpl b/Documentation/DocBook/kernel-hacking.tmpl
--- a/Documentation/DocBook/kernel-hacking.tmpl	Sun Nov 10 19:28:40 2002
+++ b/Documentation/DocBook/kernel-hacking.tmpl	Sun Nov 10 19:28:40 2002
@@ -1133,11 +1133,6 @@
     </listitem>
     <listitem>
      <para>
-      Labeled elements
-     </para>
-    </listitem>
-    <listitem>
-     <para>
       typeof
      </para>
     </listitem>
@@ -1247,7 +1242,7 @@
      bash, even though it looks like bash; the safe way is to use only
      the constructs that you already see in
      <filename>Config.in</filename> files (see
-     <filename>Documentation/kbuild/config-language.txt</filename>).
+     <filename>Documentation/kbuild/kconfig-language.txt</filename>).
      It's good to run "make xconfig" at least once to test (because
      it's the only one with a static parser).
     </para>
diff -Nru a/Documentation/crypto/api-intro.txt b/Documentation/crypto/api-intro.txt
--- a/Documentation/crypto/api-intro.txt	Sun Nov 10 19:28:40 2002
+++ b/Documentation/crypto/api-intro.txt	Sun Nov 10 19:28:40 2002
@@ -101,6 +101,14 @@
 on a recognized standard and/or have been subjected to appropriate
 peer review.
 
+Also check for any RFCs which may relate to the use of specific algorithms,
+as well as general application notes such as RFC2451 ("The ESP CBC-Mode
+Cipher Algorithms").
+
+It's a good idea to avoid using lots of macros and use inlined functions
+instead, as gcc does a good job with inlining, while excessive use of
+macros can cause compilation problems on some platforms.
+
 
 BUGS
 
@@ -163,7 +171,8 @@
   Dana L. How (DES)
   Andrew Tridgell and Steve French (MD4)
   Colin Plumb (MD5)
-  Steve Raid (SHA1)
+  Steve Reid (SHA1)
+  Jean-Luc Cooke (SHA256)
   Kazunori Miyazawa / USAGI (HMAC)
 
 The DES code was subsequently redeveloped by:
@@ -171,6 +180,11 @@
   Raimar Falke
   Gisle Sælensminde
   Niels Möller
+
+The Blowfish code was subsequently redeveloped by:
+  Herbert Valerio Riedel
+  Kyle McMartin
+
 
 Please send any credits updates or corrections to:
 James Morris <jmorris@intercode.com.au>
diff -Nru a/Documentation/filesystems/devfs/ChangeLog b/Documentation/filesystems/devfs/ChangeLog
--- a/Documentation/filesystems/devfs/ChangeLog	Sun Nov 10 19:28:37 2002
+++ b/Documentation/filesystems/devfs/ChangeLog	Sun Nov 10 19:28:37 2002
@@ -1965,3 +1965,13 @@
 - Updated README from master HTML file
 
 - Fixed module unload race in <devfs_open>
+===============================================================================
+Changes for patch v218
+
+- Removed DEVFS_FL_AUTO_OWNER flag
+
+- Switched lingering structure field initialiser to ISO C
+
+- Added locking when setting/clearing flags
+
+- Documentation fix in fs/devfs/util.c
diff -Nru a/Documentation/kbuild/00-INDEX b/Documentation/kbuild/00-INDEX
--- a/Documentation/kbuild/00-INDEX	Sun Nov 10 19:28:37 2002
+++ b/Documentation/kbuild/00-INDEX	Sun Nov 10 19:28:37 2002
@@ -4,7 +4,7 @@
 	- known bugs in kbuild programs
 commands.txt
 	- overview of kbuild commands
-config-language.txt
-	- specification of Config Language, the language in Config.in files
+kconfig-language.txt
+	- specification of Config Language, the language in Kconfig files
 makefiles.txt
 	- developer information for linux kernel makefiles
diff -Nru a/Documentation/kbuild/config-language.txt b/Documentation/kbuild/config-language.txt
--- a/Documentation/kbuild/config-language.txt	Sun Nov 10 19:28:39 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,710 +0,0 @@
-Config Language Specification
-18 October 1999
-Michael Elizabeth Chastain, <mailto:mec@shout.net>
-
-
-
-=== Introduction
-
-Config Language is not 'bash'.
-
-This document describes Config Language, the Linux Kernel Configuration
-Language.  config.in and Config.in files are written in this language.
-
-Although it looks, and usually acts, like a subset of the 'sh' language,
-Config Language has a restricted syntax and different semantics.
-
-Here is a basic guideline for Config Language programming: use only the
-programming idioms that you see in existing Config.in files.  People often
-draw on their shell programming experience to invent idioms that look
-reasonable to shell programmers, but silently fail in Config Language.
-
-Config Language is not 'bash'.
-
-
-
-=== Interpreters
-
-Four different configuration programs read Config Language:
-
-    scripts/Configure   make config, make oldconfig
-    scripts/Menuconfig  make menuconfig
-    scripts/tkparse     make xconfig
-    mconfig             ftp.kernel.org/pub/linux/kernel/people/hch/mconfig/
-
-'Configure' is a bash script which interprets Config.in files by sourcing
-them.  Some of the Config Language commands are native bash commands;
-simple bash functions implement the rest of the commands.
-
-'Menuconfig' is another bash script.  It scans the input files with a
-small awk script, builds a shell function for each menu, sources the
-shell functions that it builds, and then executes the shell functions
-in a user-driven order.  Menuconfig uses 'lxdialog', a back-end utility
-program, to perform actual screen output.  'lxdialog' is a C program
-which uses curses.
-
-'scripts/tkparse' is a C program with an ad hoc parser which translates
-a Config Language script to a huge TCL/TK program.  'make xconfig'
-then hands this TCL/TK program to 'wish', which executes it.
-
-'mconfig' is the next generation of Config Language interpreters.  It is a
-C program with a bison parser which translates a Config Language script
-into an internal syntax tree and then hands the syntax tree to one of
-several user-interface front ends.
-
-
-
-=== Statements
-
-A Config Language script is a list of statements.  There are 21 simple
-statements; an 'if' statement; menu blocks; and a 'source' statement.
-
-A '\' at the end of a line marks a line continuation.
-
-'#' usually introduces a comment, which continues to the end of the line.
-Lines of the form '# ... is not set', however, are not comments.  They
-are semantically meaningful, and all four config interpreters implement
-this meaning.
-
-Newlines are significant.  You may not substitute semicolons for newlines.
-The 'if' statement does accept a semicolon in one position; you may use
-a newline in that position instead.
-
-Here are the basic grammar elements.
-
-    A /prompt/ is a single-quoted string or a double-quoted string.
-    If the word is double-quoted, it may not have any $ substitutions.
-
-    A /word/ is a single unquoted word, a single-quoted string, or a
-    double-quoted string.  If the word is unquoted or double quoted,
-    then $-substitution will be performed on the word.
-
-    A /symbol/ is a single unquoted word.  A symbol must have a name of
-    the form CONFIG_*.  scripts/mkdep.c relies on this convention in order
-    to generate dependencies on individual CONFIG_* symbols instead of
-    making one massive dependency on include/linux/autoconf.h.
-
-    A /dep/ is a dependency.  Syntactically, it is a /word/.  At run
-    time, a /dep/ must evaluate to "y", "m", "n", or "".
-
-    An /expr/ is a bash-like expression using the operators
-    '=', '!=', '-a', '-o', and '!'.
-
-Here are all the statements:
-
-    Text statements:
-
-        mainmenu_name   /prompt/
-        comment         /prompt/
-        text            /prompt/
-
-    Ask statements:
-
-        bool            /prompt/ /symbol/
-        hex             /prompt/ /symbol/ /word/
-        int             /prompt/ /symbol/ /word/
-        string          /prompt/ /symbol/ /word/
-        tristate        /prompt/ /symbol/
-
-    Define statements:
-
-        define_bool     /symbol/ /word/
-        define_hex      /symbol/ /word/
-        define_int      /symbol/ /word/
-        define_string   /symbol/ /word/
-        define_tristate /symbol/ /word/
-
-    Dependent statements:
-
-        dep_bool        /prompt/ /symbol/ /dep/ ...
-        dep_mbool       /prompt/ /symbol/ /dep/ ...
-        dep_hex         /prompt/ /symbol/ /word/ /dep/ ...
-        dep_int         /prompt/ /symbol/ /word/ /dep/ ...
-        dep_string      /prompt/ /symbol/ /word/ /dep/ ...
-        dep_tristate    /prompt/ /symbol/ /dep/ ...
-
-    Unset statement:
-
-        unset /symbol/ ...
-
-    Choice statements:
-
-        choice          /prompt/ /word/ /word/
-        nchoice         /prompt/ /symbol/ /prompt/ /symbol/ ...
-
-    If statements:
-
-        if [ /expr/ ] ; then
-	  /statement/
-	  ...
-        fi
-
-        if [ /expr/ ] ; then
-	  /statement/
-	  ...
-        else
-	  /statement/
-	  ...
-        fi
-
-    Menu block:
-
-        mainmenu_option next_comment
-        comment /prompt/
-          /statement/
-	  ...
-        endmenu
-
-    Source statement:
-
-        source /word/
-
-
-
-=== mainmenu_name /prompt/
-
-This verb is a lot less important than it looks.  It specifies the top-level
-name of this Config Language file.
-
-Configure:  ignores this line
-Menuconfig: ignores this line
-Xconfig:    uses /prompt/ for the label window.
-mconfig:    ignores this line (mconfig does a better job without it).
-
-Example:
-
-    # arch/sparc/config.in
-    mainmenu_name "Linux/SPARC Kernel Configuration"
-
-
-
-=== comment /prompt/
-
-This verb displays its prompt to the user during the configuration process
-and also echoes it to the output files during output.  Note that the
-prompt, like all prompts, is a quoted string with no dollar substitution.
-
-The 'comment' verb is not a Config Language comment.  It causes the
-user interface to display text, and it causes output to appear in the
-output files.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # drivers/net/Config.in
-    comment 'CCP compressors for PPP are only built as modules.'
-
-
-
-=== text /prompt/
-
-This verb displays the prompt to the user with no adornment whatsoever.
-It does not echo the prompt to the output file.  mconfig uses this verb
-internally for its help facility.
-
-Configure:  not implemented
-Menuconfig: not implemented
-Xconfig:    not implemented
-mconfig:    implemented
-
-Example:
-
-    # mconfig internal help text
-    text 'Here are all the mconfig command line options.'
-
-
-
-=== bool /prompt/ /symbol/
-
-This verb displays /prompt/ to the user, accepts a value from the user,
-and assigns that value to /symbol/.  The legal input values are "n" and
-"y".
-
-Note that the bool verb does not have a default value.  People keep
-trying to write Config Language scripts with a default value for bool,
-but *all* of the existing language interpreters discard additional values.
-Feel free to submit a multi-interpreter patch to linux-kbuild if you
-want to implement this as an enhancement.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # arch/i386/config.in
-    bool 'Symmetric multi-processing support' CONFIG_SMP
-
-
-
-=== hex /prompt/ /symbol/ /word/
-
-This verb displays /prompt/ to the user, accepts a value from the user,
-and assigns that value to /symbol/.  Any hexadecimal number is a legal
-input value.  /word/ is the default value.
-
-The hex verb does not accept range parameters.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # drivers/sound/Config.in
-    hex 'I/O base for SB Check from manual of the card' CONFIG_SB_BASE 220
-
-
-
-=== int /prompt/ /symbol/ /word/
-
-This verb displays /prompt/ to the user, accepts a value from the user,
-and assigns that value to /symbol/.  /word/ is the default value.
-Any decimal number is a legal input value.
-
-The int verb does not accept range parameters.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # drivers/char/Config.in
-    int 'Maximum number of Unix98 PTYs in use (0-2048)' \
-        CONFIG_UNIX98_PTY_COUNT 256
-
-
-
-=== string /prompt/ /symbol/ /word/
-
-This verb displays /prompt/ to the user, accepts a value from the user,
-and assigns that value to /symbol/.  /word/ is the default value.  Legal
-input values are any ASCII string, except for the characters '"' and '\\'.
-Configure will trap an input string of "?" to display help.
-
-The default value is mandatory.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # drivers/sound/Config.in
-    string '  Full pathname of DSPxxx.LD firmware file' \
-        CONFIG_PSS_BOOT_FILE /etc/sound/dsp001.ld
-
-
-
-=== tristate /prompt/ /symbol/
-
-This verb displays /prompt/ to the user, accepts a value from the user,
-and assigns that value to /symbol/.  Legal values are "n", "m", or "y".
-
-The value "m" stands for "module"; it indicates that /symbol/ should
-be built as a kernel module.  The value "m" is legal only if the symbol
-CONFIG_MODULES currently has the value "y".
-
-The tristate verb does not have a default value.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # fs/Config.in
-    tristate 'NFS filesystem support' CONFIG_NFS_FS
-
-
-
-=== define_bool /symbol/ /word/
-
-This verb the value of /word/ to /symbol/.  Legal values are "n" or "y".
-
-For compatibility reasons, the value of "m" is also legal, because it
-will be a while before define_tristate is implemented everywhere.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # arch/alpha/config.in
-    if [ "$CONFIG_ALPHA_GENERIC" = "y" ]
-    then
-            define_bool CONFIG_PCI y
-            define_bool CONFIG_ALPHA_NEED_ROUNDING_EMULATION y
-    fi
-
-
-
-=== define_hex /symbol/ /word/
-
-This verb assigns the value of /word/ to /symbol/.  Any hexadecimal
-number is a legal value.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # Not from the corpus
-    bool 'Specify custom serial port' CONFIG_SERIAL_PORT_CUSTOM
-    if [ "$CONFIG_SERIAL_PORT_CUSTOM" = "y" ]; then
-	hex 'Serial port number' CONFIG_SERIAL_PORT
-    else
-	define_hex CONFIG_SERIAL_PORT 0x3F8
-    fi
-
-
-
-=== define_int /symbol/ /word/
-
-This verb assigns /symbol/ the value /word/.  Any decimal number is a
-legal value.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # drivers/char/ftape/Config.in
-    define_int CONFIG_FT_ALPHA_CLOCK 0
-
-
-
-=== define_string /symbol/ /word/
-
-This verb assigns the value of /word/ to /symbol/.  Legal input values
-are any ASCII string, except for the characters '"' and '\\'.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-Example
-
-    # Not from the corpus
-    define_string CONFIG_VERSION "2.2.0"
-
-
-
-=== define_tristate /symbol/ /word/
-
-This verb assigns the value of /word/ to /symbol/.  Legal input values
-are "n", "m", and "y".
-
-As soon as this verb is implemented in all interpreters, please use it
-instead of define_bool to define tristate values.  This aids in static
-type checking.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # drivers/video/Config.in
-    if [ "$CONFIG_FB_AMIGA" = "y" ]; then
-       define_tristate CONFIG_FBCON_AFB y
-       define_tristate CONFIG_FBCON_ILBM y
-    else
-       if [ "$CONFIG_FB_AMIGA" = "m" ]; then
-          define_tristate CONFIG_FBCON_AFB m
-          define_tristate CONFIG_FBCON_ILBM m
-       fi
-    fi
-
-
-
-=== dep_bool /prompt/ /symbol/ /dep/ ...
-
-This verb evaluates all of the dependencies in the dependency list.
-Any dependency which has a value of "y" does not restrict the input
-range.  Any dependency which has an empty value is ignored.
-Any dependency which has a value of "n", or which has some other value,
-(like "m") restricts the input range to "n".  Quoting dependencies is not
-allowed. Using dependencies with an empty value possible is not
-recommended.  See also dep_mbool below.
-
-If the input range is restricted to the single choice "n", dep_bool
-silently assigns "n" to /symbol/.  If the input range has more than
-one choice, dep_bool displays /prompt/ to the user, accepts a value
-from the user, and assigns that value to /symbol/.
-
-Configure:  implemented
-Menuconfig: implemented
-XConfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # drivers/net/Config.in
-    dep_bool 'Aironet 4500/4800 PCI support 'CONFIG_AIRONET4500_PCI $CONFIG_PCI
-
-Known bugs:
-- Xconfig does not write "# foo is not set" to .config (as well as
-  "#undef foo" to autoconf.h) if command is disabled by its dependencies.
-
-
-=== dep_mbool /prompt/ /symbol/ /dep/ ...
-
-This verb evaluates all of the dependencies in the dependency list.
-Any dependency which has a value of "y" or "m" does not restrict the
-input range.  Any dependency which has an empty value is ignored.
-Any dependency which has a value of "n", or which has some other value,
-restricts the input range to "n".  Quoting dependencies is not allowed.
-Using dependencies with an empty value possible is not recommended.
-
-If the input range is restricted to the single choice "n", dep_bool
-silently assigns "n" to /symbol/.  If the input range has more than
-one choice, dep_bool displays /prompt/ to the user, accepts a value
-from the user, and assigns that value to /symbol/.
-
-Notice that the only difference between dep_bool and dep_mbool
-is in the way of treating the "m" value as a dependency.
-
-Configure:  implemented
-Menuconfig: implemented
-XConfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # Not from the corpus
-    dep_mbool 'Packet socket: mmapped IO' CONFIG_PACKET_MMAP $CONFIG_PACKET
-
-Known bugs:
-- Xconfig does not write "# foo is not set" to .config (as well as
-  "#undef foo" to autoconf.h) if command is disabled by its dependencies.
-
-
-=== dep_hex /prompt/ /symbol/ /word/ /dep/ ...
-=== dep_int /prompt/ /symbol/ /word/ /dep/ ...
-=== dep_string /prompt/ /symbol/ /word/ /dep/ ...
-
-I am still thinking about the semantics of these verbs.
-
-Configure:  not implemented
-Menuconfig: not implemented
-XConfig:    not implemented
-mconfig:    not implemented
-
-
-
-=== dep_tristate /prompt/ /symbol/ /dep/ ...
-
-This verb evaluates all of the dependencies in the dependency list.
-Any dependency which has a value of "y" does not restrict the input range.
-Any dependency which has a value of "m" restricts the input range to
-"m" or "n".  Any dependency which has an empty value is ignored.
-Any dependency which has a value of "n", or which has some other value,
-restricts the input range to "n".  Quoting dependencies is not allowed.
-Using dependencies with an empty value possible is not recommended.
-
-If the input range is restricted to the single choice "n", dep_tristate
-silently assigns "n" to /symbol/.  If the input range has more than
-one choice, dep_tristate displays /prompt/ to the user, accepts a value
-from the user, and assigns that value to /symbol/.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # drivers/char/Config.in
-    dep_tristate 'Parallel printer support' CONFIG_PRINTER $CONFIG_PARPORT
-
-Known bugs:
-- Xconfig does not write "# foo is not set" to .config (as well as
-  "#undef foo" to autoconf.h) if command is disabled by its dependencies.
-
-
-=== unset /symbol/ ...
-
-This verb assigns the value "" to /symbol/, but does not cause /symbol/
-to appear in the output.  The existence of this verb is a hack; it covers
-up deeper problems with variable semantics in a random-execution language.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented (with bugs)
-mconfig:    implemented
-
-Example:
-
-    # arch/mips/config.in
-    unset CONFIG_PCI
-    unset CONFIG_MIPS_JAZZ
-    unset CONFIG_VIDEO_G364
-
-
-
-=== choice /prompt/ /word/ /word/
-
-This verb implements a choice list or "radio button list" selection.
-It displays /prompt/ to the user, as well as a group of sub-prompts
-which have corresponding symbols.
-
-When the user selects a value, the choice verb sets the corresponding
-symbol to "y" and sets all the other symbols in the choice list to "n".
-
-The second argument is a single-quoted or double-quoted word that
-describes a series of sub-prompts and symbol names.  The interpreter
-breaks up the word at white space boundaries into a list of sub-words.
-The first sub-word is the first prompt; the second sub-word is the
-first symbol.  The third sub-word is the second prompt; the fourth
-sub-word is the second symbol.  And so on, for all the sub-words.
-
-The third word is a literal word.  Its value must be a unique abbreviation
-for exactly one of the prompts.  The symbol corresponding to this prompt
-is the default enabled symbol.
-
-Note that because of the syntax of the choice verb, the sub-prompts
-may not have spaces in them.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-Example:
-
-    # arch/i386/config.in
-    choice '  PCI access mode' \
-        "BIOS           CONFIG_PCI_GOBIOS       \
-         Direct         CONFIG_PCI_GODIRECT     \
-         Any            CONFIG_PCI_GOANY"       Any
-
-
-
-=== nchoice /prompt/ /symbol/ /prompt/ /symbol/ ...
-
-This verb has the same semantics as the choice verb, but with a sensible
-syntax.
-
-The first /prompt/ is the master prompt for the entire choice list.
-
-The first /symbol/ is the default symbol to enable (notice that this
-is a symbol, not a unique prompt abbreviation).
-
-The subsequent /prompt/ and /symbol/ pairs are the prompts and symbols
-for the choice list.
-
-Configure:  not implemented
-Menuconfig: not implemented
-XConfig:    not implemented
-mconfig:    implemented
-
-
-
-=== if [ /expr/ ] ; then
-
-This is a conditional statement, with an optional 'else' clause.  You may
-substitute a newline for the semicolon if you choose.
-
-/expr/ may contain the following atoms and operators.  Note that, unlike
-shell, you must use double quotes around every atom.
-
-    /atom/:
-	"..."			a literal
-	"$..."			a variable
-
-    /expr/:
-	/atom/  = /atom/	true if atoms have identical value
-	/atom/ != /atom/	true if atoms have different value
-
-    /expr/:
-	/expr/ -o /expr/	true if either expression is true
-	/expr/ -a /expr/	true if both expressions are true
-	! /expr/		true if expression is not true
-
-Note that a naked /atom/ is not a valid /expr/.  If you try to use it
-as such:
-
-    # Do not do this.
-    if [ "$CONFIG_EXPERIMENTAL" ]; then
-	bool 'Bogus experimental feature' CONFIG_BOGUS
-    fi
-
-... then you will be surprised, because CONFIG_EXPERIMENTAL never has a
-value of the empty string!  It is always "y" or "n", and both of these
-are treated as true (non-empty) by the bash-based interpreters Configure
-and Menuconfig.
-
-Configure:  implemented
-Menuconfig: implemented
-XConfig:    implemented, with bugs
-mconfig:    implemented
-
-Xconfig has some known bugs, and probably some unknown bugs too:
-
-- literals with an empty "" value are not properly handled.
-
-
-
-=== mainmenu_option next_comment
-
-This verb introduces a new menu.  The next statement must have a comment
-verb.  The /prompt/ of that comment verb becomes the title of the menu.
-(I have no idea why the original designer didn't create a 'menu ...' verb).
-
-Statements outside the scope of any menu are in the implicit top menu.
-The title of the top menu comes from a variety of sources, depending on
-the interpreter.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-
-
-=== endmenu
-
-This verb closes the scope of a menu.
-
-Configure:  implemented
-Menuconfig: implemented
-Xconfig:    implemented
-mconfig:    implemented
-
-
-
-=== source /word/
-
-This verb interprets the literal /word/ as a filename, and interpolates
-the contents of that file.  The word must be a single unquoted literal
-word.
-
-Some interpreters interpret this verb at run time; some interpreters
-interpret it at parse time.
-
-Inclusion is textual inclusion, like the C preprocessor #include facility.
-The source verb does not imply a submenu or any kind of block nesting.
-
-Configure:  implemented (run time)
-Menuconfig: implemented (parse time)
-Xconfig:    implemented (parse time)
-mconfig:    implemented (parse time)
diff -Nru a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/kbuild/kconfig-language.txt	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,255 @@
+Introduction
+------------
+
+The configuration database is collection of configuration options
+organized in a tree structure:
+
+	+- Code maturity level options
+	|  +- Prompt for development and/or incomplete code/drivers
+	+- General setup
+	|  +- Networking support
+	|  +- System V IPC
+	|  +- BSD Process Accounting
+	|  +- Sysctl support
+	+- Loadable module support
+	|  +- Enable loadable module support
+	|     +- Set version information on all module symbols
+	|     +- Kernel module loader
+	+- ...
+
+Every entry has its own dependencies. These dependencies are used
+to determine the visible of an entry. Any child entry is only
+visible if its parent entry is also visible.
+
+Menu entries
+------------
+
+Most entries define a config option, all other entries help to organize
+them. A single configuration option is defined like this:
+
+config MODVERSIONS
+	bool "Set version information on all module symbols"
+	depends MODULES
+	help
+	  Usually, modules have to be recompiled whenever you switch to a new
+	  kernel.  ...
+
+Every line starts with a key word and can be followed by multiple
+arguments.  "config" starts a new config entry. The following lines
+define attributes for this config option. Attributes can be the type of
+the config option, input prompt, dependencies, help text and default
+values. A config option can be defined multiple times with the same
+name, but every definition can have only a single input prompt and the
+type must not conflict.
+
+Menu attributes
+---------------
+
+A menu entry can have a number of attributes. Not all of them are
+applicable everywhere (see syntax).
+
+- type definition: "bool"/"tristate"/"string"/"hex"/"integer"
+  Every config option must have a type. There are only two basic types:
+  tristate and string, the other types base on these two. The type
+  definition optionally accepts an input prompt, so these two examples
+  are equivalent:
+
+	bool "Networking support"
+  and
+	bool
+	prompt "Networking support"
+
+- input prompt: "prompt" <prompt> ["if" <expr>]
+  Every menu entry can have at most one prompt, which is used to display
+  to the user. Optionally dependencies only for this prompt can be added
+  with "if".
+
+- default value: "default" <symbol> ["if" <expr>]
+  A config option can have any number of default values. If multiple
+  default values are visible, only the first defined one is active.
+  Default values are not limited to the menu entry, where they are
+  defined, this means the default can be defined somewhere else or be
+  overriden by an earlier definition.
+  The default value is only assigned to the config symbol if no other
+  value was set by the user (via the input prompt above). If an input
+  prompt is visible the default value is presented to the user and can
+  be overridden by him.
+  Optionally dependencies only for this default value can be added with
+  "if".
+
+- dependencies: "depends on"/"requires" <expr>
+  This defines a dependency for this menu entry. If multiple
+  dependencies are defined they are connected with '&&'. Dependencies
+  are applied to all other options within this menu entry (which also
+  accept "if" expression), so these two examples are equivalent:
+
+	bool "foo" if BAR
+	default y if BAR
+  and
+	depends on BAR
+	bool "foo"
+	default y
+
+- help text: "help"
+  This defines a help text. The end of the help text is determined by
+  the level indentation, this means it ends at the first line which has
+  a smaller indentation than the first line of the help text.
+
+
+Menu dependencies
+-----------------
+
+Dependencies define the visibility of a menu entry and can also reduce
+the input range of tristate symbols. The tristate logic used in the
+expressions uses one more state than normal boolean logic to express the
+module state. Dependency expressions have the following syntax:
+
+<expr> ::= <symbol>                             (1)
+           <symbol> '=' <symbol>                (2)
+           <symbol> '!=' <symbol>               (3)
+           '(' <expr> ')'                       (4)
+           '!' <expr>                           (5)
+           <expr> '||' <expr>                   (6)
+           <expr> '&&' <expr>                   (7)
+
+Expressions are listed in decreasing order of precedence. 
+
+(1) Convert the symbol into an expression. Boolean and tristate symbols
+    are simply converted into the respective expression values. All
+    other symbol types result in 'n'.
+(2) If the values of both symbols are equal, it returns 'y',
+    otherwise 'n'.
+(3) If the values of both symbols are equal, it returns 'n',
+    otherwise 'y'.
+(4) Returns the value of the expression. Used to override precedence.
+(5) Returns the result of (2-/expr/).
+(6) Returns the result of min(/expr/, /expr/).
+(7) Returns the result of max(/expr/, /expr/).
+
+An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2
+respectively for calculations). A menu entry becomes visible when it's
+expression evaluates to 'm' or 'y'.
+
+There are two type of symbols: constant and nonconstant symbols.
+Nonconstant symbols are the most common ones and are defined with the
+'config' statement. Nonconstant symbols consist entirely of alphanumeric
+characters or underscores.
+Constant symbols are only part of expressions. Constant symbols are
+always surrounded by single or double quotes. Within the quote any
+other character is allowed and the quotes can be escaped using '\'.
+
+Menu structure
+--------------
+
+The position of a menu entry in the tree is determined in two ways. First
+it can be specified explicitely:
+
+menu "Network device support"
+	depends NET
+
+config NETDEVICES
+	...
+
+endmenu
+
+All entries within the "menu" ... "endmenu" block become a submenu of
+"Network device support". All subentries inherit the dependencies from
+the menu entry, e.g. this means the dependency "NET" is added to the
+dependency list of the config option NETDEVICES.
+
+The other way to generate the menu structure is done by analyzing the
+dependencies. If a menu entry somehow depends on the previous entry, it
+can be made a submenu of it. First the the previous (parent) symbol must
+be part of the dependency list and then one of these two condititions
+must be true:
+- the child entry must become invisible, if the parent is set to 'n'
+- the child entry must only be visible, if the parent is visible
+
+config MODULES
+	bool "Enable loadable module support"
+
+config MODVERSIONS
+	bool "Set version information on all module symbols"
+	depends MODULES
+
+comment "module support disabled"
+	depends !MODULES
+
+MODVERSIONS directly depends on MODULES, this means it's only visible if
+MODULES is different from 'n'. The comment on the other hand is always
+visible when MODULES it's visible (the (empty) dependency of MODULES is
+also part of the comment dependencies).
+
+
+Kconfig syntax
+--------------
+
+The configuration file describes a series of menu entries, where every
+line starts with a keyword (except help texts). The following keywords
+end a menu entry:
+- config
+- choice/endchoice
+- comment
+- menu/endmenu
+- if/endif
+- source
+The first four also start the definition of a menu entry.
+
+config:
+
+	"config" <symbol>
+	<config options>
+
+This defines a config symbol <symbol> and accepts any of above
+attributes as options.
+
+choices:
+
+	"choice"
+	<choice options>
+	<choice block>
+	"endchoice"
+
+This defines a choice group and accepts any of above attributes as
+options. A choice can only be of type bool or tristate, while a boolean
+choice only allows a single config entry to be selected, a tristate
+choice also allows any number of config entries to be set to 'm'. This
+can be used if multiple drivers for a single hardware exists and only a
+single driver can be compiled/loaded into the kernel, but all drivers
+can be compiled as modules.
+A choice accepts another option "optional", which allows to set the
+choice to 'n' and no entry needs to be selected.
+
+comment:
+
+	"comment" <prompt>
+	<comment options>
+
+This defines a comment which is displayed to the user during the
+configuration process and is also echoed to the output files. The only
+possible options are dependencies.
+
+menu:
+
+	"menu" <prompt>
+	<menu options>
+	<menu block>
+	"endmenu"
+
+This defines a menu block, see "Menu structure" above for more
+information. The only possible options are dependencies.
+
+if:
+
+	"if" <expr>
+	<if block>
+	"endif"
+
+This defines an if block. The dependency expression <expr> is appended
+to all enclosed menu entries.
+
+source:
+
+	"source" <prompt>
+
+This reads the specified configuration file. This file is always parsed.
diff -Nru a/Documentation/networking/pktgen.txt b/Documentation/networking/pktgen.txt
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/Documentation/networking/pktgen.txt	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,77 @@
+How to use the Linux packet generator module.
+
+1. Enable CONFIG_NET_PKTGEN to compile and build pktgen.o, install it
+   in the place where insmod may find it.
+2. Cut script "ipg" (see below).
+3. Edit script to set preferred device and destination IP address.
+3a.  Create more scripts for different interfaces.  Up to thirty-two
+     pktgen processes can be configured and run at once by using the
+     32 /proc/net/pktgen/pg* files.
+4. Run in shell: ". ipg"
+5. After this two commands are defined:
+   A. "pg" to start generator and to get results.
+   B. "pgset" to change generator parameters. F.e.
+      pgset "clone_skb 100"   sets the number of coppies of the same packet 
+                              will be sent before a new packet is allocated
+      pgset "clone_skb 0"     use multiple SKBs for packet generation
+      pgset "pkt_size 9014"   sets packet size to 9014
+      pgset "frags 5"         packet will consist of 5 fragments
+      pgset "count 200000"    sets number of packets to send, set to zero
+                              for continious sends untill explicitly
+                              stopped.
+      pgset "ipg 5000"        sets artificial gap inserted between packets
+                              to 5000 nanoseconds
+      pgset "dst 10.0.0.1"    sets IP destination address
+                              (BEWARE! This generator is very aggressive!)
+      pgset "dst_min 10.0.0.1"            Same as dst
+      pgset "dst_max 10.0.0.254"          Set the maximum destination IP.
+      pgset "src_min 10.0.0.1"            Set the minimum (or only) source IP.
+      pgset "src_max 10.0.0.254"          Set the maximum source IP.
+      pgset "dstmac 00:00:00:00:00:00"    sets MAC destination address
+      pgset "srcmac 00:00:00:00:00:00"    sets MAC source address
+      pgset "src_mac_count 1" Sets the number of MACs we'll range through.  The
+                              'minimum' MAC is what you set with srcmac.
+      pgset "dst_mac_count 1" Sets the number of MACs we'll range through.  The
+                              'minimum' MAC is what you set with dstmac.
+      pgset "flag [name]"     Set a flag to determine behaviour.  Current flags
+                              are: IPSRC_RND #IP Source is random (between min/max),
+                                   IPDST_RND, UDPSRC_RND,
+                                   UDPDST_RND, MACSRC_RND, MACDST_RND 
+      pgset "udp_src_min 9"   set UDP source port min, If < udp_src_max, then
+                              cycle through the port range.
+      pgset "udp_src_max 9"   set UDP source port max.
+      pgset "udp_dst_min 9"   set UDP destination port min, If < udp_dst_max, then
+                              cycle through the port range.
+      pgset "udp_dst_max 9"   set UDP destination port max.
+      pgset stop    	      aborts injection
+      
+  Also, ^C aborts generator.
+
+---- cut here
+
+#! /bin/sh
+
+modprobe pktgen
+
+PGDEV=/proc/net/pktgen/pg0
+
+function pgset() {
+    local result
+
+    echo $1 > $PGDEV
+
+    result=`cat $PGDEV | fgrep "Result: OK:"`
+    if [ "$result" = "" ]; then
+         cat $PGDEV | fgrep Result:
+    fi
+}
+
+function pg() {
+    echo inject > $PGDEV
+    cat $PGDEV
+}
+
+pgset "odev eth0"
+pgset "dst 0.0.0.0"
+
+---- cut here
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Sun Nov 10 19:28:40 2002
+++ b/MAINTAINERS	Sun Nov 10 19:28:40 2002
@@ -222,6 +222,13 @@
 M:	linux@treblig.org
 S:	Maintained
 
+ARM/PT DIGITAL BOARD PORT
+P:	Stefan Eletzhofer
+M:	stefan.eletzhofer@eletztrick.de
+L:	linux-arm-kernel@lists.arm.linux.org.uk
+W:	http://www.arm.linux.org.uk/
+S:	Maintained
+
 ARM/SHARK MACHINE SUPPORT
 P:	Alexander Schulz
 M:	alex@shark-linux.de
@@ -317,6 +324,27 @@
 W:	http://www.coda.cs.cmu.edu/
 S:	Maintained
 
+COMPACTPCI HOTPLUG CORE
+P:	Scott Murray
+M:	scottm@somanetworks.com
+M:	scott@spiteful.org
+L:	pcihpd-discuss@lists.sourceforge.net
+S:	Supported
+
+COMPACTPCI HOTPLUG ZIATECH ZT5550 DRIVER
+P:	Scott Murray
+M:	scottm@somanetworks.com
+M:	scott@spiteful.org
+L:	pcihpd-discuss@lists.sourceforge.net
+S:	Supported
+
+COMPACTPCI HOTPLUG GENERIC DRIVER
+P:	Scott Murray
+M:	scottm@somanetworks.com
+M:	scott@spiteful.org
+L:	pcihpd-discuss@lists.sourceforge.net
+S:	Supported
+
 COMPAQ FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA
 P:	Amy Vanzant-Hodge 
 M:	Amy Vanzant-Hodge (fibrechannel@compaq.com)
@@ -351,13 +379,6 @@
 M:	Gergely Madarasz <gorgo@itc.hu>
 S:	Supported
 
-CONFIGURE, MENUCONFIG, XCONFIG
-P:	Michael Elizabeth Chastain
-M:	mec@shout.net
-L:	kbuild-devel@lists.sourceforge.net
-W:	http://kbuild.sourceforge.net
-S:	Maintained
-
 COSA/SRP SYNC SERIAL DRIVER
 P:	Jan "Yenya" Kasprzak
 M:	kas@fi.muni.cz
@@ -914,6 +935,12 @@
 W:	http://www.suse.cz/development/joystick/
 S:	Maintained
 
+KCONFIG
+P:	Roman Zippel
+M:	zippel@linux-m68k.org
+L:	kbuild-devel@lists.sourceforge.net
+S:	Maintained
+
 KERNEL AUTOMOUNTER (AUTOFS)
 P:	H. Peter Anvin
 M:	hpa@zytor.com
@@ -1255,6 +1282,15 @@
 W:	http://www.torque.net/linux-pp.html
 S:	Maintained
 
+PARISC ARCHITECTURE
+P:	Matthew Wilcox
+M:	matthew@wil.cx
+P:	Grant Grundler
+M:	grundler@parisc-linux.org
+L:	parisc-linux@parisc-linux.org
+W:	http://www.parisc-linux.org/
+S:	Maintained
+
 PERSONALITY HANDLING
 P:	Christoph Hellwig
 M:	hch@infradead.org
@@ -1294,7 +1330,7 @@
 
 PCMCIA SUBSYSTEM
 P:	David Hinds
-M:	dhinds@zen.stanford.edu
+M:	dahinds@users.sourceforge.net
 L:	linux-kernel@vger.kernel.org
 W:	http://pcmcia-cs.sourceforge.net
 S:	Maintained
@@ -1407,7 +1443,7 @@
 SA1100 SUPPORT
 P:	Nicolas Pitre
 M:	nico@cam.org
-L:	sa1100-linux@pa.dec.com
+L:	linux-arm@lists.arm.linux.org.uk
 S:	Maintained
 
 SBPCD CDROM DRIVER
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Sun Nov 10 19:28:37 2002
+++ b/Makefile	Sun Nov 10 19:28:37 2002
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 5
-SUBLEVEL = 46
+SUBLEVEL = 47
 EXTRAVERSION =
 
 # *DOCUMENTATION*
@@ -175,7 +175,7 @@
 export	VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \
 	CONFIG_SHELL TOPDIR HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
 	CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE \
-	HOSTCXX HOSTCXXFLAGS
+	HOSTCXX HOSTCXXFLAGS LDFLAGS_BLOB
 
 export CPPFLAGS NOSTDINC_FLAGS OBJCOPYFLAGS LDFLAGS
 export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE 
@@ -252,7 +252,7 @@
 
 #	In this section, we need .config
 
--include ..config.cmd
+-include .config.cmd
 
 ifdef CONFIG_MODULES
 export EXPORT_FLAGS := -DEXPORT_SYMTAB
diff -Nru a/arch/alpha/Kconfig b/arch/alpha/Kconfig
--- a/arch/alpha/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/arch/alpha/Kconfig	Sun Nov 10 19:28:40 2002
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 config ALPHA
 	bool
diff -Nru a/arch/alpha/Makefile b/arch/alpha/Makefile
--- a/arch/alpha/Makefile	Sun Nov 10 19:28:40 2002
+++ b/arch/alpha/Makefile	Sun Nov 10 19:28:40 2002
@@ -12,7 +12,7 @@
 
 LDFLAGS_vmlinux = -static -N #-relax
 CFLAGS := $(CFLAGS) -pipe -mno-fp-regs -ffixed-8
-ARCHBLOBLFLAGS := -I binary -O elf64-alpha -B alpha
+LDFLAGS_BLOB := --format binary --oformat elf64-alpha
 
 # Determine if we can use the BWX instructions with GAS.
 old_gas := $(shell if $(AS) --version 2>&1 | grep 'version 2.7' > /dev/null; then echo y; else echo n; fi)
diff -Nru a/arch/alpha/kernel/alpha_ksyms.c b/arch/alpha/kernel/alpha_ksyms.c
--- a/arch/alpha/kernel/alpha_ksyms.c	Sun Nov 10 19:28:37 2002
+++ b/arch/alpha/kernel/alpha_ksyms.c	Sun Nov 10 19:28:37 2002
@@ -144,7 +144,6 @@
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(hwrpb);
-EXPORT_SYMBOL(wrusp);
 EXPORT_SYMBOL(start_thread);
 EXPORT_SYMBOL(alpha_read_fp_reg);
 EXPORT_SYMBOL(alpha_read_fp_reg_s);
diff -Nru a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c
--- a/arch/alpha/kernel/asm-offsets.c	Sun Nov 10 19:28:41 2002
+++ b/arch/alpha/kernel/asm-offsets.c	Sun Nov 10 19:28:41 2002
@@ -20,11 +20,22 @@
 	DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
 	DEFINE(TI_CPU, offsetof(struct thread_info, cpu));
 	BLANK();
+
+        DEFINE(TASK_BLOCKED, offsetof(struct task_struct, blocked));
+        DEFINE(TASK_UID, offsetof(struct task_struct, uid));
+        DEFINE(TASK_EUID, offsetof(struct task_struct, euid));
+        DEFINE(TASK_GID, offsetof(struct task_struct, gid));
+        DEFINE(TASK_EGID, offsetof(struct task_struct, egid));
+        DEFINE(TASK_REAL_PARENT, offsetof(struct task_struct, real_parent));
+        DEFINE(TASK_TGID, offsetof(struct task_struct, tgid));
+        BLANK();
+
 	DEFINE(PT_PTRACED, PT_PTRACED);
 	DEFINE(CLONE_VM, CLONE_VM);
 	DEFINE(CLONE_UNTRACED, CLONE_UNTRACED);
 	DEFINE(SIGCHLD, SIGCHLD);
 	BLANK();
+
 	DEFINE(HAE_CACHE, offsetof(struct alpha_machine_vector, hae_cache));
 	DEFINE(HAE_REG, offsetof(struct alpha_machine_vector, hae_register));
 }
diff -Nru a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
--- a/arch/alpha/kernel/entry.S	Sun Nov 10 19:28:36 2002
+++ b/arch/alpha/kernel/entry.S	Sun Nov 10 19:28:36 2002
@@ -1,19 +1,20 @@
 /*
- * alpha/entry.S
+ * arch/alpha/kernel/entry.S
  *
- * kernel entry-points
+ * Kernel entry-points.
  */
 
 #include <linux/config.h>
-#include <asm/system.h>
-#include <asm/cache.h>
 #include <asm/asm_offsets.h>
 #include <asm/thread_info.h>
+#include <asm/pal.h>
+#include <asm/errno.h>
 #include <asm/unistd.h>
 
-/*
- * stack offsets
- */
+	.text
+	.set noat
+
+/* Stack offsets.  */
 #define SP_OFF			184
 #define SWITCH_STACK_SIZE	320
 
@@ -28,145 +29,578 @@
  */
 
 #define SAVE_ALL			\
-	subq	$30,SP_OFF,$30;		\
-	stq	$0,0($30);		\
-	stq	$1,8($30);		\
-	stq	$2,16($30);		\
-	stq	$3,24($30);		\
-	stq	$4,32($30);		\
-	stq	$28,144($30);		\
-	lda	$2,alpha_mv;		\
-	stq	$5,40($30);		\
-	stq	$6,48($30);		\
-	stq	$7,56($30);		\
-	stq	$8,64($30);		\
-	stq	$19,72($30);		\
-	stq	$20,80($30);		\
-	stq	$21,88($30);		\
-	ldq	$2,HAE_CACHE($2);	\
-	stq	$22,96($30);		\
-	stq	$23,104($30);		\
-	stq	$24,112($30);		\
-	stq	$25,120($30);		\
-	stq	$26,128($30);		\
-	stq	$27,136($30);		\
-	stq	$2,152($30);		\
-	stq	$16,160($30);		\
-	stq	$17,168($30);		\
-	stq	$18,176($30)
+	subq	$sp, SP_OFF, $sp;	\
+	stq	$0, 0($sp);		\
+	stq	$1, 8($sp);		\
+	stq	$2, 16($sp);		\
+	stq	$3, 24($sp);		\
+	stq	$4, 32($sp);		\
+	stq	$28, 144($sp);		\
+	lda	$2, alpha_mv;		\
+	stq	$5, 40($sp);		\
+	stq	$6, 48($sp);		\
+	stq	$7, 56($sp);		\
+	stq	$8, 64($sp);		\
+	stq	$19, 72($sp);		\
+	stq	$20, 80($sp);		\
+	stq	$21, 88($sp);		\
+	ldq	$2, HAE_CACHE($2);	\
+	stq	$22, 96($sp);		\
+	stq	$23, 104($sp);		\
+	stq	$24, 112($sp);		\
+	stq	$25, 120($sp);		\
+	stq	$26, 128($sp);		\
+	stq	$27, 136($sp);		\
+	stq	$2, 152($sp);		\
+	stq	$16, 160($sp);		\
+	stq	$17, 168($sp);		\
+	stq	$18, 176($sp)
 
 #define RESTORE_ALL			\
-	lda	$19,alpha_mv;		\
-	ldq	$0,0($30);		\
-	ldq	$1,8($30);		\
-	ldq	$2,16($30);		\
-	ldq	$3,24($30);		\
-	ldq	$21,152($30);		\
-	ldq	$20,HAE_CACHE($19);	\
-	ldq	$4,32($30);		\
-	ldq	$5,40($30);		\
-	ldq	$6,48($30);		\
-	ldq	$7,56($30);		\
-	subq	$20,$21,$20;		\
-	ldq	$8,64($30);		\
-	beq	$20,99f;		\
-	ldq	$20,HAE_REG($19);	\
-	stq	$21,HAE_CACHE($19);	\
-	stq	$21,0($20);		\
-	ldq	$0,0($30);		\
-	ldq	$1,8($30);		\
+	lda	$19, alpha_mv;		\
+	ldq	$0, 0($sp);		\
+	ldq	$1, 8($sp);		\
+	ldq	$2, 16($sp);		\
+	ldq	$3, 24($sp);		\
+	ldq	$21, 152($sp);		\
+	ldq	$20, HAE_CACHE($19);	\
+	ldq	$4, 32($sp);		\
+	ldq	$5, 40($sp);		\
+	ldq	$6, 48($sp);		\
+	ldq	$7, 56($sp);		\
+	subq	$20, $21, $20;		\
+	ldq	$8, 64($sp);		\
+	beq	$20, 99f;		\
+	ldq	$20, HAE_REG($19);	\
+	stq	$21, HAE_CACHE($19);	\
+	stq	$21, 0($20);		\
+	ldq	$0, 0($sp);		\
+	ldq	$1, 8($sp);		\
 99:;					\
-	ldq	$19,72($30);		\
-	ldq	$20,80($30);		\
-	ldq	$21,88($30);		\
-	ldq	$22,96($30);		\
-	ldq	$23,104($30);		\
-	ldq	$24,112($30);		\
-	ldq	$25,120($30);		\
-	ldq	$26,128($30);		\
-	ldq	$27,136($30);		\
-	ldq	$28,144($30);		\
-	addq	$30,SP_OFF,$30
-
-.text
-.set noat
-
-.align 3
-.globl	entInt
-.ent	entInt
+	ldq	$19, 72($sp);		\
+	ldq	$20, 80($sp);		\
+	ldq	$21, 88($sp);		\
+	ldq	$22, 96($sp);		\
+	ldq	$23, 104($sp);		\
+	ldq	$24, 112($sp);		\
+	ldq	$25, 120($sp);		\
+	ldq	$26, 128($sp);		\
+	ldq	$27, 136($sp);		\
+	ldq	$28, 144($sp);		\
+	addq	$sp, SP_OFF, $sp
+
+/*
+ * Non-syscall kernel entry points.
+ */
+
+	.align	4
+	.globl	entInt
+	.ent	entInt
 entInt:
 	SAVE_ALL
-	lda	$8,0x3fff
-	lda	$26,ret_from_sys_call
-	bic	$30,$8,$8
-	jsr	$31,do_entInt
+	lda	$8, 0x3fff
+	lda	$26, ret_from_sys_call
+	bic	$sp, $8, $8
+	mov	$sp, $19
+	jsr	$31, do_entInt
 .end entInt
 
-.align 3
-.globl	entMM
-.ent	entMM
+	.align	4
+	.globl	entArith
+	.ent	entArith
+entArith:
+	SAVE_ALL
+	lda	$8, 0x3fff
+	lda	$26, ret_from_sys_call
+	bic	$sp, $8, $8
+	mov	$sp, $18
+	jsr	$31, do_entArith
+.end entArith
+
+	.align	4
+	.globl	entMM
+	.ent	entMM
 entMM:
 	SAVE_ALL
 /* save $9 - $15 so the inline exception code can manipulate them.  */
-	subq	$30,56,$30
-	stq	$9,0($30)
-	stq	$10,8($30)
-	stq	$11,16($30)
-	stq	$12,24($30)
-	stq	$13,32($30)
-	stq	$14,40($30)
-	stq	$15,48($30)
-	addq	$30,56,$19
+	subq	$sp, 56, $sp
+	stq	$9, 0($sp)
+	stq	$10, 8($sp)
+	stq	$11, 16($sp)
+	stq	$12, 24($sp)
+	stq	$13, 32($sp)
+	stq	$14, 40($sp)
+	stq	$15, 48($sp)
+	addq	$sp, 56, $19
 /* handle the fault */
-	lda	$8,0x3fff
-	bic	$30,$8,$8
-	jsr	$26,do_page_fault
+	lda	$8, 0x3fff
+	bic	$sp, $8, $8
+	jsr	$26, do_page_fault
 /* reload the registers after the exception code played.  */
-	ldq	$9,0($30)
-	ldq	$10,8($30)
-	ldq	$11,16($30)
-	ldq	$12,24($30)
-	ldq	$13,32($30)
-	ldq	$14,40($30)
-	ldq	$15,48($30)
-	addq	$30,56,$30
+	ldq	$9, 0($sp)
+	ldq	$10, 8($sp)
+	ldq	$11, 16($sp)
+	ldq	$12, 24($sp)
+	ldq	$13, 32($sp)
+	ldq	$14, 40($sp)
+	ldq	$15, 48($sp)
+	addq	$sp, 56, $sp
 /* finish up the syscall as normal.  */
 	br	ret_from_sys_call
 .end entMM
 
-.align 3
-.globl	entArith
-.ent	entArith
-entArith:
-	SAVE_ALL
-	lda	$8,0x3fff
-	lda	$26,ret_from_sys_call
-	bic	$30,$8,$8
-	jsr	$31,do_entArith
-.end entArith
-
-.align 3
-.globl	entIF
-.ent	entIF
+	.align	4
+	.globl	entIF
+	.ent	entIF
 entIF:
 	SAVE_ALL
-	lda	$8,0x3fff
-	lda	$26,ret_from_sys_call
-	bic	$30,$8,$8
-	jsr	$31,do_entIF
+	lda	$8, 0x3fff
+	lda	$26, ret_from_sys_call
+	bic	$sp, $8, $8
+	mov	$sp, $17
+	jsr	$31, do_entIF
 .end entIF
 
-.align 3
-.globl	entDbg
-.ent	entDbg
+	.align	4
+	.globl	entUna
+	.ent	entUna
+entUna:
+	lda	$sp, -256($sp)
+	stq	$0, 0($sp)
+	ldq	$0, 256($sp)	/* get PS */
+	stq	$1, 8($sp)
+	stq	$2, 16($sp)
+	stq	$3, 24($sp)
+	and	$0, 8, $0		/* user mode? */
+	stq	$4, 32($sp)
+	bne	$0, entUnaUser	/* yup -> do user-level unaligned fault */
+	stq	$5, 40($sp)
+	stq	$6, 48($sp)
+	stq	$7, 56($sp)
+	stq	$8, 64($sp)
+	stq	$9, 72($sp)
+	stq	$10, 80($sp)
+	stq	$11, 88($sp)
+	stq	$12, 96($sp)
+	stq	$13, 104($sp)
+	stq	$14, 112($sp)
+	stq	$15, 120($sp)
+	/* 16-18 PAL-saved */
+	stq	$19, 152($sp)
+	stq	$20, 160($sp)
+	stq	$21, 168($sp)
+	stq	$22, 176($sp)
+	stq	$23, 184($sp)
+	stq	$24, 192($sp)
+	stq	$25, 200($sp)
+	stq	$26, 208($sp)
+	stq	$27, 216($sp)
+	stq	$28, 224($sp)
+	stq	$gp, 232($sp)
+	lda	$8, 0x3fff
+	stq	$31, 248($sp)
+	bic	$sp, $8, $8
+	jsr	$26, do_entUna
+	ldq	$0, 0($sp)
+	ldq	$1, 8($sp)
+	ldq	$2, 16($sp)
+	ldq	$3, 24($sp)
+	ldq	$4, 32($sp)
+	ldq	$5, 40($sp)
+	ldq	$6, 48($sp)
+	ldq	$7, 56($sp)
+	ldq	$8, 64($sp)
+	ldq	$9, 72($sp)
+	ldq	$10, 80($sp)
+	ldq	$11, 88($sp)
+	ldq	$12, 96($sp)
+	ldq	$13, 104($sp)
+	ldq	$14, 112($sp)
+	ldq	$15, 120($sp)
+	/* 16-18 PAL-saved */
+	ldq	$19, 152($sp)
+	ldq	$20, 160($sp)
+	ldq	$21, 168($sp)
+	ldq	$22, 176($sp)
+	ldq	$23, 184($sp)
+	ldq	$24, 192($sp)
+	ldq	$25, 200($sp)
+	ldq	$26, 208($sp)
+	ldq	$27, 216($sp)
+	ldq	$28, 224($sp)
+	ldq	$gp, 232($sp)
+	lda	$sp, 256($sp)
+	call_pal PAL_rti
+.end entUna
+
+	.align	4
+	.ent	entUnaUser
+entUnaUser:
+	ldq	$0, 0($sp)	/* restore original $0 */
+	lda	$sp, 256($sp)	/* pop entUna's stack frame */
+	SAVE_ALL		/* setup normal kernel stack */
+	lda	$sp, -56($sp)
+	stq	$9, 0($sp)
+	stq	$10, 8($sp)
+	stq	$11, 16($sp)
+	stq	$12, 24($sp)
+	stq	$13, 32($sp)
+	stq	$14, 40($sp)
+	stq	$15, 48($sp)
+	lda	$8, 0x3fff
+	addq	$sp, 56, $19
+	bic	$sp, $8, $8
+	jsr	$26, do_entUnaUser
+	ldq	$9, 0($sp)
+	ldq	$10, 8($sp)
+	ldq	$11, 16($sp)
+	ldq	$12, 24($sp)
+	ldq	$13, 32($sp)
+	ldq	$14, 40($sp)
+	ldq	$15, 48($sp)
+	lda	$sp, 56($sp)
+	br	ret_from_sys_call
+.end entUnaUser
+
+	.align	4
+	.globl	entDbg
+	.ent	entDbg
 entDbg:
 	SAVE_ALL
-	lda	$8,0x3fff
-	lda	$26,ret_from_sys_call
-	bic	$30,$8,$8
-	jsr	$31,do_entDbg
+	lda	$8, 0x3fff
+	lda	$26, ret_from_sys_call
+	bic	$sp, $8, $8
+	mov	$sp, $16
+	jsr	$31, do_entDbg
 .end entDbg
+
+/*
+ * The system call entry point is special.  Most importantly, it looks
+ * like a function call to userspace as far as clobbered registers.  We
+ * do preserve the argument registers (for syscall restarts) and $26
+ * (for leaf syscall functions).
+ *
+ * So much for theory.  We don't take advantage of this yet.
+ *
+ * Note that a0-a2 are not saved by PALcode as with the other entry points.
+ */
+
+	.align	4
+	.globl	entSys
+	.globl	ret_from_sys_call
+	.ent	entSys
+entSys:
+	SAVE_ALL
+	lda	$8, 0x3fff
+	bic	$sp, $8, $8
+	lda	$4, NR_SYSCALLS($31)
+	stq	$16, SP_OFF+24($sp)
+	lda	$5, sys_call_table
+	lda	$27, sys_ni_syscall
+	cmpult	$0, $4, $4
+	ldl	$3, TI_FLAGS($8)
+	stq	$17, SP_OFF+32($sp)
+	s8addq	$0, $5, $5
+	stq	$18, SP_OFF+40($sp)
+	blbs	$3, strace
+	beq	$4, 1f
+	ldq	$27, 0($5)
+1:	jsr	$26, ($27), alpha_ni_syscall
+	ldgp	$gp, 0($26)
+	blt	$0, $syscall_error	/* the call failed */
+	stq	$0, 0($sp)
+	stq	$31, 72($sp)		/* a3=0 => no error */
+
+	.align	4
+ret_from_sys_call:
+	cmovne	$26, 0, $19		/* $19 = 0 => non-restartable */
+	ldq	$0, SP_OFF($sp)
+	and	$0, 8, $0
+	beq	$0, restore_all
+ret_from_reschedule:
+	/* Make sure need_resched and sigpending don't change between
+		sampling and the rti.  */
+	lda	$16, 7
+	call_pal PAL_swpipl
+	ldl	$5, TI_FLAGS($8)
+	and	$5, _TIF_WORK_MASK, $2
+	bne	$5, work_pending
+restore_all:
+	RESTORE_ALL
+	call_pal PAL_rti
+
+	.align 3
+$syscall_error:
+	/*
+	 * Some system calls (e.g., ptrace) can return arbitrary
+	 * values which might normally be mistaken as error numbers.
+	 * Those functions must zero $0 (v0) directly in the stack
+	 * frame to indicate that a negative return value wasn't an
+	 * error number..
+	 */
+	ldq	$19, 0($sp)	/* old syscall nr (zero if success) */
+	beq	$19, $ret_success
 
+	ldq	$20, 72($sp)	/* .. and this a3 */
+	subq	$31, $0, $0	/* with error in v0 */
+	addq	$31, 1, $1	/* set a3 for errno return */
+	stq	$0, 0($sp)
+	mov	$31, $26	/* tell "ret_from_sys_call" we can restart */
+	stq	$1, 72($sp)	/* a3 for return */
+	br	ret_from_sys_call
+
+$ret_success:
+	stq	$0, 0($sp)
+	stq	$31, 72($sp)	/* a3=0 => no error */
+	br	ret_from_sys_call
+.end entSys
+
+/*
+ * Do all cleanup when returning from all interrupts and system calls.
+ *
+ * Arguments:
+ *       $5: TI_FLAGS.
+ *       $8: current.
+ *      $19: The old syscall number, or zero if this is not a return
+ *           from a syscall that errored and is possibly restartable.
+ *      $20: Error indication.
+ */
+
+	.align	4
+	.ent	work_pending
+work_pending:
+	and	$5, _TIF_NEED_RESCHED, $2
+	beq	$2, $work_notifysig
+
+$work_resched:
+	subq	$sp, 16, $sp
+	stq	$19, 0($sp)              /* save syscall nr */
+	stq	$20, 8($sp)              /* and error indication (a3) */
+	jsr	$26, schedule
+	ldq	$19, 0($sp)
+	ldq	$20, 8($sp)
+	addq	$sp, 16, $sp
+	/* Make sure need_resched and sigpending don't change between
+		sampling and the rti.  */
+	lda	$16, 7
+	call_pal PAL_swpipl
+	ldl	$5, TI_FLAGS($8)
+	and	$5, _TIF_WORK_MASK, $2
+	beq	$2, restore_all
+	and	$5, _TIF_NEED_RESCHED, $2
+	bne	$2, $work_resched
+
+$work_notifysig:
+	mov	$sp, $17
+	br	$1, do_switch_stack
+	mov	$5, $21
+	mov	$sp, $18
+	mov	$31, $16
+	jsr	$26, do_notify_resume
+	bsr	$1, undo_switch_stack
+	br	restore_all
+.end work_pending
+
+/*
+ * PTRACE syscall handler
+ */
+
+	.align	4
+	.ent	strace
+strace:
+	/* set up signal stack, call syscall_trace */
+	bsr	$1, do_switch_stack
+	jsr	$26, syscall_trace
+	bsr	$1, undo_switch_stack
+
+	/* get the system call number and the arguments back.. */
+	ldq	$0, 0($sp)
+	ldq	$16, SP_OFF+24($sp)
+	ldq	$17, SP_OFF+32($sp)
+	ldq	$18, SP_OFF+40($sp)
+	ldq	$19, 72($sp)
+	ldq	$20, 80($sp)
+	ldq	$21, 88($sp)
+
+	/* get the system call pointer.. */
+	lda	$1, NR_SYSCALLS($31)
+	lda	$2, sys_call_table
+	lda	$27, alpha_ni_syscall
+	cmpult	$0, $1, $1
+	s8addq	$0, $2, $2
+	beq	$1, 1f
+	ldq	$27, 0($2)
+1:	jsr	$26, ($27), sys_gettimeofday
+	ldgp	$gp, 0($26)
+
+	/* check return.. */
+	blt	$0, $strace_error	/* the call failed */
+	stq	$31, 72($sp)		/* a3=0 => no error */
+$strace_success:
+	stq	$0, 0($sp)		/* save return value */
+
+	bsr	$1, do_switch_stack
+	jsr	$26, syscall_trace
+	bsr	$1, undo_switch_stack
+	br	$31, ret_from_sys_call
+
+	.align	3
+$strace_error:
+	ldq	$19, 0($sp)	/* old syscall nr (zero if success) */
+	beq	$19, $strace_success
+	ldq	$20, 72($sp)	/* .. and this a3 */
+
+	subq	$31, $0, $0	/* with error in v0 */
+	addq	$31, 1, $1	/* set a3 for errno return */
+	stq	$0, 0($sp)
+	stq	$1, 72($sp)	/* a3 for return */
+
+	bsr	$1, do_switch_stack
+	mov	$19, $9		/* save old syscall number */
+	mov	$20, $10	/* save old a3 */
+	jsr	$26, syscall_trace
+	mov	$9, $19
+	mov	$10, $20
+	bsr	$1, undo_switch_stack
+
+	mov	$31, $26	/* tell "ret_from_sys_call" we can restart */
+	br	ret_from_sys_call
+.end strace
+
+/*
+ * Save and restore the switch stack -- aka the balance of the user context.
+ */
+
+	.align	4
+	.ent	do_switch_stack
+do_switch_stack:
+	lda	$sp, -SWITCH_STACK_SIZE($sp)
+	stq	$9, 0($sp)
+	stq	$10, 8($sp)
+	stq	$11, 16($sp)
+	stq	$12, 24($sp)
+	stq	$13, 32($sp)
+	stq	$14, 40($sp)
+	stq	$15, 48($sp)
+	stq	$26, 56($sp)
+	stt	$f0, 64($sp)
+	stt	$f1, 72($sp)
+	stt	$f2, 80($sp)
+	stt	$f3, 88($sp)
+	stt	$f4, 96($sp)
+	stt	$f5, 104($sp)
+	stt	$f6, 112($sp)
+	stt	$f7, 120($sp)
+	stt	$f8, 128($sp)
+	stt	$f9, 136($sp)
+	stt	$f10, 144($sp)
+	stt	$f11, 152($sp)
+	stt	$f12, 160($sp)
+	stt	$f13, 168($sp)
+	stt	$f14, 176($sp)
+	stt	$f15, 184($sp)
+	stt	$f16, 192($sp)
+	stt	$f17, 200($sp)
+	stt	$f18, 208($sp)
+	stt	$f19, 216($sp)
+	stt	$f20, 224($sp)
+	stt	$f21, 232($sp)
+	stt	$f22, 240($sp)
+	stt	$f23, 248($sp)
+	stt	$f24, 256($sp)
+	stt	$f25, 264($sp)
+	stt	$f26, 272($sp)
+	stt	$f27, 280($sp)
+	mf_fpcr	$f0		# get fpcr
+	stt	$f28, 288($sp)
+	stt	$f29, 296($sp)
+	stt	$f30, 304($sp)
+	stt	$f0, 312($sp)	# save fpcr in slot of $f31
+	ldt	$f0, 64($sp)	# dont let "do_switch_stack" change fp state.
+	ret	$31, ($1), 1
+.end do_switch_stack
+
+	.align	4
+	.ent	undo_switch_stack
+undo_switch_stack:
+	ldq	$9, 0($sp)
+	ldq	$10, 8($sp)
+	ldq	$11, 16($sp)
+	ldq	$12, 24($sp)
+	ldq	$13, 32($sp)
+	ldq	$14, 40($sp)
+	ldq	$15, 48($sp)
+	ldq	$26, 56($sp)
+	ldt	$f30, 312($sp)	# get saved fpcr
+	ldt	$f0, 64($sp)
+	ldt	$f1, 72($sp)
+	ldt	$f2, 80($sp)
+	ldt	$f3, 88($sp)
+	mt_fpcr	$f30		# install saved fpcr
+	ldt	$f4, 96($sp)
+	ldt	$f5, 104($sp)
+	ldt	$f6, 112($sp)
+	ldt	$f7, 120($sp)
+	ldt	$f8, 128($sp)
+	ldt	$f9, 136($sp)
+	ldt	$f10, 144($sp)
+	ldt	$f11, 152($sp)
+	ldt	$f12, 160($sp)
+	ldt	$f13, 168($sp)
+	ldt	$f14, 176($sp)
+	ldt	$f15, 184($sp)
+	ldt	$f16, 192($sp)
+	ldt	$f17, 200($sp)
+	ldt	$f18, 208($sp)
+	ldt	$f19, 216($sp)
+	ldt	$f20, 224($sp)
+	ldt	$f21, 232($sp)
+	ldt	$f22, 240($sp)
+	ldt	$f23, 248($sp)
+	ldt	$f24, 256($sp)
+	ldt	$f25, 264($sp)
+	ldt	$f26, 272($sp)
+	ldt	$f27, 280($sp)
+	ldt	$f28, 288($sp)
+	ldt	$f29, 296($sp)
+	ldt	$f30, 304($sp)
+	lda	$sp, SWITCH_STACK_SIZE($sp)
+	ret	$31, ($1), 1
+.end undo_switch_stack
+
+/*
+ * The meat of the context switch code.
+ */
+
+	.align	4
+	.globl	alpha_switch_to
+	.ent	alpha_switch_to
+alpha_switch_to:
+	.prologue 0
+	bsr	$1, do_switch_stack
+	call_pal PAL_swpctx
+	lda	$8, 0x3fff
+	bsr	$1, undo_switch_stack
+	bic	$sp, $8, $8
+	ret
+.end alpha_switch_to
+
+/*
+ * New processes begin life here.
+ */
+
+	.globl	ret_from_fork
+#if CONFIG_SMP || CONFIG_PREEMPT
+	.align	4
+	.ent	ret_from_fork
+ret_from_fork:
+	lda	$26, ret_from_sys_call
+	mov	$17, $16
+	jmp	$31, schedule_tail
+.end ret_from_fork
+#else
+ret_from_fork = ret_from_sys_call
+#endif
 
 /*
  * kernel_thread(fn, arg, clone_flags)
@@ -175,9 +609,9 @@
 	.globl	kernel_thread
 	.ent	kernel_thread
 kernel_thread:
-	ldgp	$29,0($27)	/* we can be called from a module */
+	ldgp	$gp, 0($27)	/* we can be called from a module */
 	.prologue 1
-	subq	$30,SP_OFF+6*8,$30
+	subq	$sp, SP_OFF+6*8, $sp
 	br	$1, 2f		/* load start address */
 
 	/* We've now "returned" from a fake system call.  */
@@ -186,9 +620,9 @@
 	ldi	$1, 0x3fff
 	beq	$20, 1f		/* parent or child?  */
 
-	bic	$30, $1, $8	/* in child.  */
+	bic	$sp, $1, $8	/* in child.  */
 	jsr	$26, ($27)
-	ldgp	$29, 0($26)
+	ldgp	$gp, 0($26)
 	mov	$0, $16
 	mov	$31, $26
 	jmp	$31, sys_exit
@@ -197,19 +631,19 @@
 
 	.align 4
 2:	/* Fake a system call stack frame, as we can't do system calls
-	   from kernel space.  Note that we store FN and ARG as they 
+	   from kernel space.  Note that we store FN and ARG as they
 	   need to be set up in the child for the call.  Also store $8
 	   and $26 for use in the parent.  */
-	stq	$31, SP_OFF($30)	/* ps */
-	stq	$1, SP_OFF+8($30)	/* pc */
-	stq	$29, SP_OFF+16($30)	/* gp */
-	stq	$16, 136($30)		/* $27; FN for child */
-	stq	$17, SP_OFF+24($30)	/* $16; ARG for child */
-	stq	$8, 64($30)		/* $8 */
-	stq	$26, 128($30)		/* $26 */
+	stq	$31, SP_OFF($sp)	/* ps */
+	stq	$1, SP_OFF+8($sp)	/* pc */
+	stq	$gp, SP_OFF+16($sp)	/* gp */
+	stq	$16, 136($sp)		/* $27; FN for child */
+	stq	$17, SP_OFF+24($sp)	/* $16; ARG for child */
+	stq	$8, 64($sp)		/* $8 */
+	stq	$26, 128($sp)		/* $26 */
 	/* Avoid the HAE being gratuitously wrong, to avoid restoring it.  */
 	ldq	$2, alpha_mv+HAE_CACHE
-	stq	$2, 152($30)		/* HAE */
+	stq	$2, 152($sp)		/* HAE */
 
 	/* Shuffle FLAGS to the front; add CLONE_VM.  */
 	ldi	$1, CLONE_VM|CLONE_UNTRACED
@@ -218,515 +652,269 @@
 
 	/* We don't actually care for a3 success widgetry in the kernel.
 	   Not for positive errno values.  */
-	stq	$0, 0($30)		/* $0 */
+	stq	$0, 0($sp)		/* $0 */
 	br	restore_all
-.end	kernel_thread
+.end kernel_thread
 
 /*
  * __kernel_execve(path, argv, envp, regs)
  */
-.align 3
-.globl	__kernel_execve
-.ent	__kernel_execve
+	.align	4
+	.globl	__kernel_execve
+	.ent	__kernel_execve
 __kernel_execve:
-	ldgp	$29,0($27)	/* we can be called from modules.  */
-	subq	$30,16,$30
-	.frame	$30,16,$26,0
-	stq	$26,0($30)
-	stq	$19,8($30)
+	ldgp	$gp, 0($27)	/* we can be called from modules.  */
+	subq	$sp, 16, $sp
+	.frame	$sp, 16, $26, 0
+	stq	$26, 0($sp)
+	stq	$19, 8($sp)
 	.prologue 1
-	jsr	$26,do_execve
-	bne	$0,1f		/* error! */
-	ldq	$30,8($30)
-	br	$31,ret_from_sys_call
-1:	ldq	$26,0($30)
-	addq	$30,16,$30
+	jsr	$26, do_execve
+	bne	$0, 1f		/* error! */
+	ldq	$sp, 8($sp)
+	br	$31, ret_from_sys_call
+1:	ldq	$26, 0($sp)
+	addq	$sp, 16, $sp
 	ret
-.end	__kernel_execve
-
-.align 3
-.ent	do_switch_stack
-do_switch_stack:
-	lda	$30,-SWITCH_STACK_SIZE($30)
-	stq	$9,0($30)
-	stq	$10,8($30)
-	stq	$11,16($30)
-	stq	$12,24($30)
-	stq	$13,32($30)
-	stq	$14,40($30)
-	stq	$15,48($30)
-	stq	$26,56($30)
-	stt	$f0,64($30)
-	stt	$f1,72($30)
-	stt	$f2,80($30)
-	stt	$f3,88($30)
-	stt	$f4,96($30)
-	stt	$f5,104($30)
-	stt	$f6,112($30)
-	stt	$f7,120($30)
-	stt	$f8,128($30)
-	stt	$f9,136($30)
-	stt	$f10,144($30)
-	stt	$f11,152($30)
-	stt	$f12,160($30)
-	stt	$f13,168($30)
-	stt	$f14,176($30)
-	stt	$f15,184($30)
-	stt	$f16,192($30)
-	stt	$f17,200($30)
-	stt	$f18,208($30)
-	stt	$f19,216($30)
-	stt	$f20,224($30)
-	stt	$f21,232($30)
-	stt	$f22,240($30)
-	stt	$f23,248($30)
-	stt	$f24,256($30)
-	stt	$f25,264($30)
-	stt	$f26,272($30)
-	stt	$f27,280($30)
-	mf_fpcr	$f0		# get fpcr
-	stt	$f28,288($30)
-	stt	$f29,296($30)
-	stt	$f30,304($30)
-	stt	$f0,312($30)	# save fpcr in slot of $f31
-	ldt	$f0,64($30)	# dont let "do_switch_stack" change fp state.
-	ret	$31,($1),1
-.end do_switch_stack
-
-.align 3
-.ent	undo_switch_stack
-undo_switch_stack:
-	ldq	$9,0($30)
-	ldq	$10,8($30)
-	ldq	$11,16($30)
-	ldq	$12,24($30)
-	ldq	$13,32($30)
-	ldq	$14,40($30)
-	ldq	$15,48($30)
-	ldq	$26,56($30)
-	ldt	$f30,312($30)	# get saved fpcr
-	ldt	$f0,64($30)
-	ldt	$f1,72($30)
-	ldt	$f2,80($30)
-	ldt	$f3,88($30)
-	mt_fpcr	$f30		# install saved fpcr
-	ldt	$f4,96($30)
-	ldt	$f5,104($30)
-	ldt	$f6,112($30)
-	ldt	$f7,120($30)
-	ldt	$f8,128($30)
-	ldt	$f9,136($30)
-	ldt	$f10,144($30)
-	ldt	$f11,152($30)
-	ldt	$f12,160($30)
-	ldt	$f13,168($30)
-	ldt	$f14,176($30)
-	ldt	$f15,184($30)
-	ldt	$f16,192($30)
-	ldt	$f17,200($30)
-	ldt	$f18,208($30)
-	ldt	$f19,216($30)
-	ldt	$f20,224($30)
-	ldt	$f21,232($30)
-	ldt	$f22,240($30)
-	ldt	$f23,248($30)
-	ldt	$f24,256($30)
-	ldt	$f25,264($30)
-	ldt	$f26,272($30)
-	ldt	$f27,280($30)
-	ldt	$f28,288($30)
-	ldt	$f29,296($30)
-	ldt	$f30,304($30)
-	lda	$30,SWITCH_STACK_SIZE($30)
-	ret	$31,($1),1
-.end undo_switch_stack
-
-.align 3
-.globl	entUna
-.ent	entUna
-entUna:
-	lda	$30,-256($30)
-	stq	$0,0($30)
-	ldq	$0,256($30)	/* get PS */
-	stq	$1,8($30)
-	stq	$2,16($30)
-	stq	$3,24($30)
-	and	$0,8,$0		/* user mode? */
-	stq	$4,32($30)
-	bne	$0,entUnaUser	/* yup -> do user-level unaligned fault */
-	stq	$5,40($30)
-	stq	$6,48($30)
-	stq	$7,56($30)
-	stq	$8,64($30)
-	stq	$9,72($30)
-	stq	$10,80($30)
-	stq	$11,88($30)
-	stq	$12,96($30)
-	stq	$13,104($30)
-	stq	$14,112($30)
-	stq	$15,120($30)
-	/* 16-18 PAL-saved */
-	stq	$19,152($30)
-	stq	$20,160($30)
-	stq	$21,168($30)
-	stq	$22,176($30)
-	stq	$23,184($30)
-	stq	$24,192($30)
-	stq	$25,200($30)
-	stq	$26,208($30)
-	stq	$27,216($30)
-	stq	$28,224($30)
-	stq	$29,232($30)
-	lda	$8,0x3fff
-	stq	$31,248($30)
-	bic	$30,$8,$8
-	jsr	$26,do_entUna
-	ldq	$0,0($30)
-	ldq	$1,8($30)
-	ldq	$2,16($30)
-	ldq	$3,24($30)
-	ldq	$4,32($30)
-	ldq	$5,40($30)
-	ldq	$6,48($30)
-	ldq	$7,56($30)
-	ldq	$8,64($30)
-	ldq	$9,72($30)
-	ldq	$10,80($30)
-	ldq	$11,88($30)
-	ldq	$12,96($30)
-	ldq	$13,104($30)
-	ldq	$14,112($30)
-	ldq	$15,120($30)
-	/* 16-18 PAL-saved */
-	ldq	$19,152($30)
-	ldq	$20,160($30)
-	ldq	$21,168($30)
-	ldq	$22,176($30)
-	ldq	$23,184($30)
-	ldq	$24,192($30)
-	ldq	$25,200($30)
-	ldq	$26,208($30)
-	ldq	$27,216($30)
-	ldq	$28,224($30)
-	ldq	$29,232($30)
-	lda	$30,256($30)
-	call_pal PAL_rti
-.end entUna
-
-.align 3
-.ent	entUnaUser
-entUnaUser:
-	ldq	$0,0($30)	/* restore original $0 */
-	lda	$30,256($30)	/* pop entUna's stack frame */
-	SAVE_ALL		/* setup normal kernel stack */
-	lda	$30,-56($30)
-	stq	$9,0($30)
-	stq	$10,8($30)
-	stq	$11,16($30)
-	stq	$12,24($30)
-	stq	$13,32($30)
-	stq	$14,40($30)
-	stq	$15,48($30)
-	lda	$8,0x3fff
-	addq	$30,56,$19
-	bic	$30,$8,$8
-	jsr	$26,do_entUnaUser
-	ldq	$9,0($30)
-	ldq	$10,8($30)
-	ldq	$11,16($30)
-	ldq	$12,24($30)
-	ldq	$13,32($30)
-	ldq	$14,40($30)
-	ldq	$15,48($30)
-	lda	$30,56($30)
-	br	ret_from_sys_call
-.end	entUnaUser
+.end __kernel_execve
 
+
 /*
- * A fork is the same as clone(SIGCHLD, 0);
+ * Special system calls.  Most of these are special in that they either
+ * have to play switch_stack games or in some way use the pt_regs struct.
  */
-.align 3
-.globl	sys_fork
-.ent	sys_fork
+	.align	4
+	.globl	sys_fork
+	.ent	sys_fork
 sys_fork:
-	bsr	$1,do_switch_stack
-	bis	$31,SIGCHLD,$16
-	mov	$31,$17
-	mov	$31,$18
-	mov	$30,$19
-	jsr	$26,alpha_clone
-	bsr	$1,undo_switch_stack
-	ret	$31,($26),1
-.end	sys_fork
-
-.align 3
-.globl	sys_clone
-.ent	sys_clone
+	.prologue 0
+	mov	$sp, $19
+	bsr	$1, do_switch_stack
+	/* A fork is the same as clone(SIGCHLD, 0);  */
+	bis	$31, SIGCHLD, $16
+	mov	$31, $17
+	mov	$31, $18
+	jsr	$26, alpha_clone
+	bsr	$1, undo_switch_stack
+	ret
+.end sys_fork
+
+	.align	4
+	.globl	sys_clone
+	.ent	sys_clone
 sys_clone:
-	bsr	$1,do_switch_stack
+	.prologue 0
+	mov	$sp, $19
+	bsr	$1, do_switch_stack
 	/* $16, $17, $18, $19 come from the user; $19 is used later
 	   via pt_regs->r19.  */
-	mov	$30,$19
-	jsr	$26,alpha_clone
-	bsr	$1,undo_switch_stack
-	ret	$31,($26),1
-.end	sys_clone
-
-.align 3
-.globl	sys_vfork
-.ent	sys_vfork
+	jsr	$26, alpha_clone
+	bsr	$1, undo_switch_stack
+	ret
+.end sys_clone
+
+	.align	4
+	.globl	sys_vfork
+	.ent	sys_vfork
 sys_vfork:
-	bsr	$1,do_switch_stack
-	mov	$30,$16
-	jsr	$26,alpha_vfork
-	bsr	$1,undo_switch_stack
-	ret	$31,($26),1
-.end	sys_vfork
-
-.align 3
-.globl  alpha_switch_to
-.ent    alpha_switch_to
-alpha_switch_to:
 	.prologue 0
-	bsr	$1,do_switch_stack
-	call_pal PAL_swpctx
-	lda	$8,0x3fff
-	bsr	$1,undo_switch_stack
-	bic	$30,$8,$8
-	ret	$31,($26),1
-.end alpha_switch_to
+	bsr	$1, do_switch_stack
+	mov	$sp, $16
+	jsr	$26, alpha_vfork
+	bsr	$1, undo_switch_stack
+	ret
+.end sys_vfork
 
-#if CONFIG_SMP || CONFIG_PREEMPT
-.globl  ret_from_fork
-.align 3
-.ent ret_from_fork
-ret_from_fork:
-	lda	$26,ret_from_sys_call
-	mov	$17,$16
-	jmp	$31,schedule_tail
-.end ret_from_fork
-#endif
+	.align	4
+	.globl	sys_sigreturn
+	.ent	sys_sigreturn
+sys_sigreturn:
+	.prologue 0
+	mov	$sp, $17
+	lda	$18, -SWITCH_STACK_SIZE($sp)
+	lda	$sp, -SWITCH_STACK_SIZE($sp)
+	jsr	$26, do_sigreturn
+	br	$1, undo_switch_stack
+	br	ret_from_sys_call
+.end sys_sigreturn
 
-/*
- * Oh, well.. Disassembling OSF/1 binaries to find out how the
- * system calls work isn't much fun.
- *
- * entSys is special in that the PAL-code doesn't save a0-a2, so
- * we start off by doing that by hand.
- */
-.align 3
-.globl	entSys
-.globl	ret_from_sys_call
-.ent	entSys
-entSys:
-	SAVE_ALL
-	lda	$8,0x3fff
-	bic	$30,$8,$8
-	lda	$4,NR_SYSCALLS($31)
-	stq	$16,SP_OFF+24($30)
-	lda	$5,sys_call_table
-	lda	$27,sys_ni_syscall
-	cmpult	$0,$4,$4
-	ldl	$3,TI_FLAGS($8)
-	stq	$17,SP_OFF+32($30)
-	s8addq	$0,$5,$5
-	stq	$18,SP_OFF+40($30)
-	blbs	$3,strace
-	beq	$4,1f
-	ldq	$27,0($5)
-1:	jsr	$26,($27),alpha_ni_syscall
-	ldgp	$29,0($26)
-	blt	$0,syscall_error	/* the call failed */
-	stq	$0,0($30)
-	stq	$31,72($30)		/* a3=0 => no error */
+	.align	4
+	.globl	sys_rt_sigreturn
+	.ent	sys_rt_sigreturn
+sys_rt_sigreturn:
+	.prologue 0
+	mov	$sp, $17
+	lda	$18, -SWITCH_STACK_SIZE($sp)
+	lda	$sp, -SWITCH_STACK_SIZE($sp)
+	jsr	$26, do_rt_sigreturn
+	br	$1, undo_switch_stack
+	br	ret_from_sys_call
+.end sys_rt_sigreturn
 
-.align 3
-ret_from_sys_call:
-	cmovne	$26,0,$19		/* $19 = 0 => non-restartable */
-	ldq	$0,SP_OFF($30)
-	and	$0,8,$0
-	beq	$0,restore_all
-ret_from_reschedule:
-	/* Make sure need_resched and sigpending don't change between
-		sampling and the rti.  */
-	lda	$16,7
-	call_pal PAL_swpipl
-	ldl	$5,TI_FLAGS($8)
-	and	$5,_TIF_WORK_MASK,$2
-	bne	$5,work_pending
-restore_all:
-	RESTORE_ALL
-	call_pal PAL_rti
+	.align	4
+	.globl	sys_sigsuspend
+	.ent	sys_sigsuspend
+sys_sigsuspend:
+	.prologue 0
+	mov	$sp, $17
+	br	$1, do_switch_stack
+	mov	$sp, $18
+	subq	$sp, 16, $sp
+	stq	$26, 0($sp)
+	jsr	$26, do_sigsuspend
+	ldq	$26, 0($sp)
+	lda	$sp, SWITCH_STACK_SIZE+16($sp)
+	ret
+.end sys_sigsuspend
 
-work_pending:
-	and	$5,_TIF_NEED_RESCHED,$2
-	beq	$2,work_notifysig
+	.align	4
+	.globl	sys_rt_sigsuspend
+	.ent	sys_rt_sigsuspend
+sys_rt_sigsuspend:
+	.prologue 0
+	mov	$sp, $18
+	br	$1, do_switch_stack
+	mov	$sp, $19
+	subq	$sp, 16, $sp
+	stq	$26, 0($sp)
+	jsr	$26, do_rt_sigsuspend
+	ldq	$26, 0($sp)
+	lda	$sp, SWITCH_STACK_SIZE+16($sp)
+	ret
+.end sys_rt_sigsuspend
 
-work_resched:
-	subq	$30,16,$30
-	stq	$19,0($30)              /* save syscall nr */
-	stq	$20,8($30)              /* and error indication (a3) */
-	jsr	$26,schedule
-	ldq	$19,0($30)
-	ldq	$20,8($30)
-	addq	$30,16,$30
-	/* Make sure need_resched and sigpending don't change between
-		sampling and the rti.  */
-	lda	$16,7
-	call_pal PAL_swpipl
-	ldl	$5,TI_FLAGS($8)
-	and	$5,_TIF_WORK_MASK,$2
-	beq	$2,restore_all
-	and	$5,_TIF_NEED_RESCHED,$2
-	bne	$2,work_resched
-
-work_notifysig:
-	mov	$30,$17
-	br	$1,do_switch_stack
-	mov	$5,$21
-	mov	$30,$18
-	mov	$31,$16
-	jsr	$26,do_notify_resume
-	bsr	$1,undo_switch_stack
-	br	restore_all
+	.align	4
+	.globl	sys_sethae
+	.ent	sys_sethae
+sys_sethae:
+	.prologue 0
+	stq	$16, 152($sp)
+	ret
+.end sys_sethae
 
-/* PTRACE syscall handler */
-.align 3
-strace:
-	/* set up signal stack, call syscall_trace */
-	bsr	$1,do_switch_stack
-	jsr	$26,syscall_trace
-	bsr	$1,undo_switch_stack
+	.align	4
+	.globl	osf_getpriority
+	.ent	osf_getpriority
+osf_getpriority:
+	lda	$sp, -16($sp)
+	stq	$26, 0($sp)
+	.prologue 0
 
-	/* get the system call number and the arguments back.. */
-	ldq	$0,0($30)
-	ldq	$16,SP_OFF+24($30)
-	ldq	$17,SP_OFF+32($30)
-	ldq	$18,SP_OFF+40($30)
-	ldq	$19,72($30)
-	ldq	$20,80($30)
-	ldq	$21,88($30)
+	jsr	$26, sys_getpriority
 
-	/* get the system call pointer.. */
-	lda	$1,NR_SYSCALLS($31)
-	lda	$2,sys_call_table
-	lda	$27,alpha_ni_syscall
-	cmpult	$0,$1,$1
-	s8addq	$0,$2,$2
-	beq	$1,1f
-	ldq	$27,0($2)
-1:	jsr	$26,($27),sys_gettimeofday
-	ldgp	$29,0($26)
+	ldq	$26, 0($sp)
+	blt	$0, 1f
 
-	/* check return.. */
-	blt	$0,strace_error	/* the call failed */
-	stq	$31,72($30)		/* a3=0 => no error */
-strace_success:
-	stq	$0,0($30)		/* save return value */
-
-	bsr	$1,do_switch_stack
-	jsr	$26,syscall_trace
-	bsr	$1,undo_switch_stack
-	br	$31,ret_from_sys_call
+	/* Return value is the unbiased priority, i.e. 20 - prio.
+	   This does result in negative return values, so signal
+	   no error by writing into the R0 slot.  */
+	lda	$1, 20
+	stq	$31, 16($sp)
+	subl	$1, $0, $0
+	unop
 
-	.align	3
-strace_error:
-	ldq	$19,0($30)	/* old syscall nr (zero if success) */
-	beq	$19,strace_success
-	ldq	$20,72($30)	/* .. and this a3 */
-
-	subq	$31,$0,$0	/* with error in v0 */
-	addq	$31,1,$1	/* set a3 for errno return */
-	stq	$0,0($30)
-	stq	$1,72($30)	/* a3 for return */
-
-	bsr	$1,do_switch_stack
-	mov	$19,$9		/* save old syscall number */
-	mov	$20,$10		/* save old a3 */
-	jsr	$26,syscall_trace
-	mov	$9,$19
-	mov	$10,$20
-	bsr	$1,undo_switch_stack
+1:	lda	$sp, 16($sp)
+	ret
+.end osf_getpriority
 
-	mov	$31,$26		/* tell "ret_from_sys_call" we can restart */
-	br	ret_from_sys_call
+	.align	4
+	.globl	sys_getxuid
+	.ent	sys_getxuid
+sys_getxuid:
+	.prologue 0
+	ldq	$2, TI_TASK($8)
+	ldl	$0, TASK_UID($2)
+	ldl	$1, TASK_EUID($2)
+	stq	$1, 80($sp)
+	ret
+.end sys_getxuid
 
-	.align 3
-syscall_error:
-	/*
-	 * Some system calls (e.g., ptrace) can return arbitrary
-	 * values which might normally be mistaken as error numbers.
-	 * Those functions must zero $0 (v0) directly in the stack
-	 * frame to indicate that a negative return value wasn't an
-	 * error number..
-	 */
-	ldq	$19,0($30)	/* old syscall nr (zero if success) */
-	beq	$19,ret_success
+	.align	4
+	.globl	sys_getxgid
+	.ent	sys_getxgid
+sys_getxgid:
+	.prologue 0
+	ldq	$2, TI_TASK($8)
+	ldl	$0, TASK_GID($2)
+	ldl	$1, TASK_EGID($2)
+	stq	$1, 80($sp)
+	ret
+.end sys_getxgid
 
-	ldq	$20,72($30)	/* .. and this a3 */
-	subq	$31,$0,$0	/* with error in v0 */
-	addq	$31,1,$1	/* set a3 for errno return */
-	stq	$0,0($30)
-	mov	$31,$26		/* tell "ret_from_sys_call" we can restart */
-	stq	$1,72($30)	/* a3 for return */
-	br	ret_from_sys_call
+	.align	4
+	.globl	sys_getxpid
+	.ent	sys_getxpid
+sys_getxpid:
+	.prologue 0
+	ldq	$2, TI_TASK($8)
 
-ret_success:
-	stq	$0,0($30)
-	stq	$31,72($30)	/* a3=0 => no error */
-	br	ret_from_sys_call
-.end entSys
+	/* See linux/kernel/timer.c sys_getppid for discussion
+	   about this loop.  */
+	ldq	$3, TASK_REAL_PARENT($2)
+1:	ldl	$1, TASK_TGID($3)
+#if CONFIG_SMP
+	mov	$3, $4
+	mb
+	ldq	$3, TASK_REAL_PARENT($2)
+	cmpeq	$3, $4, $4
+	beq	$4, 1b
+#endif
+	stq	$1, 80($sp)
+	ldl	$0, TASK_TGID($2)
+	ret
+.end sys_getxpid
 
-.align 3
-.globl sys_sigreturn
-.ent sys_sigreturn
-sys_sigreturn:
-	mov	$30,$17
-	lda	$18,-SWITCH_STACK_SIZE($30)
-	lda	$30,-SWITCH_STACK_SIZE($30)
-	jsr	$26,do_sigreturn
-	br	$1,undo_switch_stack
-	br	ret_from_sys_call
-.end sys_sigreturn
+	.align	4
+	.globl	sys_pipe
+	.ent	sys_pipe
+sys_pipe:
+	lda	$sp, -16($sp)
+	stq	$26, 0($sp)
+	.prologue 0
 
-.align 3
-.globl sys_rt_sigreturn
-.ent sys_rt_sigreturn
-sys_rt_sigreturn:
-	mov	$30,$17
-	lda	$18,-SWITCH_STACK_SIZE($30)
-	lda	$30,-SWITCH_STACK_SIZE($30)
-	jsr	$26,do_rt_sigreturn
-	br	$1,undo_switch_stack
-	br	ret_from_sys_call
-.end sys_rt_sigreturn
+	lda	$16, 8($sp)
+	jsr	$26, do_pipe
 
-.align 3
-.globl sys_sigsuspend
-.ent sys_sigsuspend
-sys_sigsuspend:
-	mov	$30,$17
-	br	$1,do_switch_stack
-	mov	$30,$18
-	subq	$30,16,$30
-	stq	$26,0($30)
-	jsr	$26,do_sigsuspend
-	ldq	$26,0($30)
-	lda	$30,SWITCH_STACK_SIZE+16($30)
-	ret	$31,($26),1
-.end sys_sigsuspend
+	ldq	$26, 0($sp)
+	bne	$0, 1f
 
-.align 3
-.globl sys_rt_sigsuspend
-.ent sys_rt_sigsuspend
-sys_rt_sigsuspend:
-	mov	$30,$18
-	br	$1,do_switch_stack
-	mov	$30,$19
-	subq	$30,16,$30
-	stq	$26,0($30)
-	jsr	$26,do_rt_sigsuspend
-	ldq	$26,0($30)
-	lda	$30,SWITCH_STACK_SIZE+16($30)
-	ret	$31,($26),1
-.end sys_rt_sigsuspend
+	/* The return values are in $0 and $20.  */
+	ldl	$1, 12($sp)
+	ldl	$0, 8($sp)
+
+	stq	$1, 80+16($sp)
+1:	lda	$sp, 16($sp)
+	ret
+.end sys_pipe
+
+	.align	4
+	.globl	alpha_create_module
+	.ent	alpha_create_module
+alpha_create_module:
+	.prologue 0
+	mov	$sp, $18
+	jmp	$31, do_alpha_create_module
+.end alpha_create_module
+
+	.align	4
+	.globl	sys_ptrace
+	.ent	sys_ptrace
+sys_ptrace:
+	.prologue 0
+	mov	$sp, $20
+	jmp	$31, do_sys_ptrace
+.end sys_ptrace
+
+	.align	4
+	.globl	alpha_ni_syscall
+	.ent	alpha_ni_syscall
+alpha_ni_syscall:
+	.prologue 0
+	/* Special because it also implements overflow handling via
+	   syscall number 0.  And if you recall, zero is a special
+	   trigger for "not an error".  Store large non-zero there.  */
+	lda	$0, -ENOSYS
+	unop
+	stq	$0, 0($sp)
+	ret
+.end alpha_ni_syscall
diff -Nru a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
--- a/arch/alpha/kernel/irq_alpha.c	Sun Nov 10 19:28:38 2002
+++ b/arch/alpha/kernel/irq_alpha.c	Sun Nov 10 19:28:38 2002
@@ -37,14 +37,13 @@
  */
 
 asmlinkage void 
-do_entInt(unsigned long type, unsigned long vector, unsigned long la_ptr,
-	  unsigned long a3, unsigned long a4, unsigned long a5,
-	  struct pt_regs regs)
+do_entInt(unsigned long type, unsigned long vector,
+	  unsigned long la_ptr, struct pt_regs *regs)
 {
 	switch (type) {
 	case 0:
 #ifdef CONFIG_SMP
-		handle_ipi(&regs);
+		handle_ipi(regs);
 		return;
 #else
 		irq_err_count++;
@@ -56,32 +55,32 @@
 #ifdef CONFIG_SMP
 	  {
 		long cpu;
-		smp_percpu_timer_interrupt(&regs);
+		smp_percpu_timer_interrupt(regs);
 		cpu = smp_processor_id();
 		if (cpu != boot_cpuid) {
 		        kstat_cpu(cpu).irqs[RTC_IRQ]++;
 		} else {
-			handle_irq(RTC_IRQ, &regs);
+			handle_irq(RTC_IRQ, regs);
 		}
 	  }
 #else
-		handle_irq(RTC_IRQ, &regs);
+		handle_irq(RTC_IRQ, regs);
 #endif
 		return;
 	case 2:
-		alpha_mv.machine_check(vector, la_ptr, &regs);
+		alpha_mv.machine_check(vector, la_ptr, regs);
 		return;
 	case 3:
-		alpha_mv.device_interrupt(vector, &regs);
+		alpha_mv.device_interrupt(vector, regs);
 		return;
 	case 4:
-		perf_irq(vector, &regs);
+		perf_irq(vector, regs);
 		return;
 	default:
 		printk(KERN_CRIT "Hardware intr %ld %lx? Huh?\n",
 		       type, vector);
 	}
-	printk("PC = %016lx PS=%04lx\n", regs.pc, regs.ps);
+	printk(KERN_CRIT "PC = %016lx PS=%04lx\n", regs->pc, regs->ps);
 }
 
 void __init
@@ -96,10 +95,8 @@
 void __init
 init_IRQ(void)
 {
-	/* Uh, this really MUST come first, just in case
-	 * the platform init_irq() causes interrupts/mchecks
-	 * (as is the case with RAWHIDE, at least).
-	 */
+	/* Just in case the platform init_irq() causes interrupts/mchecks
+	   (as is the case with RAWHIDE, at least).  */
 	wrent(entInt, 0);
 
 	alpha_mv.init_irq();
diff -Nru a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
--- a/arch/alpha/kernel/osf_sys.c	Sun Nov 10 19:28:36 2002
+++ b/arch/alpha/kernel/osf_sys.c	Sun Nov 10 19:28:36 2002
@@ -45,7 +45,6 @@
 
 extern int do_pipe(int *);
 extern asmlinkage unsigned long sys_brk(unsigned long);
-extern int sys_getpriority(int, int);
 extern asmlinkage unsigned long sys_create_module(char *, unsigned long);
 
 /*
@@ -172,68 +171,9 @@
 #undef ROUND_UP
 #undef NAME_OFFSET
 
-/*
- * Alpha syscall convention has no problem returning negative
- * values:
- */
-asmlinkage int
-osf_getpriority(int which, int who,
-		int a2, int a3, int a4, int a5, struct pt_regs regs)
-{
-	extern int sys_getpriority(int, int);
-	int prio;
-
-	/*
-	 * We don't need to acquire the kernel lock here, because
-	 * all of these operations are local. sys_getpriority
-	 * will get the lock as required..
-	 */
-	prio = sys_getpriority(which, who);
-	if (prio >= 0) {
-		regs.r0 = 0;		/* special return: no errors */
-		prio = 20 - prio;
-	}
-	return prio;
-}
-
-/*
- * No need to acquire the kernel lock, we're local..
- */
-asmlinkage unsigned long
-sys_getxuid(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs)
-{
-	struct task_struct * tsk = current;
-	(&regs)->r20 = tsk->euid;
-	return tsk->uid;
-}
-
-asmlinkage unsigned long
-sys_getxgid(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs)
-{
-	struct task_struct * tsk = current;
-	(&regs)->r20 = tsk->egid;
-	return tsk->gid;
-}
-
-asmlinkage unsigned long
-sys_getxpid(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs)
-{
-	struct task_struct *tsk = current;
-
-	/* 
-	 * This isn't strictly "local" any more and we should actually
-	 * acquire the kernel lock. The "p_opptr" pointer might change
-	 * if the parent goes away (or due to ptrace). But any race
-	 * isn't actually going to matter, as if the parent happens
-	 * to change we can happily return either of the pids.
-	 */
-	(&regs)->r20 = tsk->real_parent->tgid;
-	return tsk->tgid;
-}
-
 asmlinkage unsigned long
 osf_mmap(unsigned long addr, unsigned long len, unsigned long prot,
-         unsigned long flags, unsigned long fd, unsigned long off)
+	 unsigned long flags, unsigned long fd, unsigned long off)
 {
 	struct file *file = NULL;
 	unsigned long ret = -EBADF;
@@ -502,19 +442,6 @@
 	return NR_OPEN;
 }
 
-asmlinkage int
-sys_pipe(int a0, int a1, int a2, int a3, int a4, int a5, struct pt_regs regs)
-{
-	int fd[2], error;
-
-	error = do_pipe(fd);
-	if (!error) {
-		regs.r20 = fd[1];
-		error = fd[0];
-	}
-	return error;
-}
-
 /*
  * For compatibility with OSF/1 only.  Use utsname(2) instead.
  */
@@ -723,8 +650,8 @@
  */
 
 asmlinkage unsigned long
-alpha_create_module(char *module_name, unsigned long size,
-		    int a3, int a4, int a5, int a6, struct pt_regs regs)
+do_alpha_create_module(char *module_name, unsigned long size,
+		       struct pt_regs *regs)
 {
 	long retval;
 
@@ -735,7 +662,7 @@
 	   the error number is a small negative number, while the address
 	   is always negative but much larger.  */
 	if (retval + 1000 < 0)
-		regs.r0 = 0;
+		regs->r0 = 0;
 
         unlock_kernel();
 	return retval;
diff -Nru a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c
--- a/arch/alpha/kernel/pci.c	Sun Nov 10 19:28:37 2002
+++ b/arch/alpha/kernel/pci.c	Sun Nov 10 19:28:37 2002
@@ -340,7 +340,7 @@
 	return PCI_SLOT(dev->devfn);
 }
 
-void __init
+void __devinit
 pcibios_fixup_pbus_ranges(struct pci_bus * bus,
 			  struct pbus_set_ranges_data * ranges)
 {
diff -Nru a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
--- a/arch/alpha/kernel/process.c	Sun Nov 10 19:28:41 2002
+++ b/arch/alpha/kernel/process.c	Sun Nov 10 19:28:41 2002
@@ -42,18 +42,6 @@
 #include "proto.h"
 #include "pci_impl.h"
 
-/*
- * No need to acquire the kernel lock, we're entirely local..
- */
-asmlinkage int
-sys_sethae(unsigned long hae, unsigned long a1, unsigned long a2,
-	   unsigned long a3, unsigned long a4, unsigned long a5,
-	   struct pt_regs regs)
-{
-	(&regs)->hae = hae;
-	return 0;
-}
-
 void default_idle(void)
 {
 	barrier();
@@ -227,6 +215,9 @@
 	   with respect to the FPU.  This is all exceptions disabled.  */
 	current_thread_info()->ieee_state = 0;
 	wrfpcr(FPCR_DYN_NORMAL | ieee_swcr_to_fpcr(0));
+
+	/* Clean slate for TLS.  */
+	current_thread_info()->pcb.unique = 0;
 }
 
 void
@@ -244,16 +235,15 @@
  * with parameters (SIGCHLD, 0).
  */
 int
-alpha_clone(unsigned long clone_flags, unsigned long usp,
-	    int *user_tid, struct switch_stack * swstack)
+alpha_clone(unsigned long clone_flags, unsigned long usp, int *user_tid,
+	    struct pt_regs *regs)
 {
 	struct task_struct *p;
-	struct pt_regs *u_regs = (struct pt_regs *) (swstack+1);
 
 	if (!usp)
 		usp = rdusp();
 
-	p = do_fork(clone_flags & ~CLONE_IDLETASK, usp, u_regs, 0, user_tid);
+	p = do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0, user_tid);
 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
@@ -282,7 +272,6 @@
 	    unsigned long unused,
 	    struct task_struct * p, struct pt_regs * regs)
 {
-	extern void ret_from_sys_call(void);
 	extern void ret_from_fork(void);
 
 	struct thread_info *childti = p->thread_info;
@@ -304,11 +293,7 @@
 	stack = ((struct switch_stack *) regs) - 1;
 	childstack = ((struct switch_stack *) childregs) - 1;
 	*childstack = *stack;
-#ifdef CONFIG_SMP
 	childstack->r26 = (unsigned long) ret_from_fork;
-#else
-	childstack->r26 = (unsigned long) ret_from_sys_call;
-#endif
 	childti->pcb.usp = usp;
 	childti->pcb.ksp = (unsigned long) childstack;
 	childti->pcb.flags = 1;	/* set FEN, clear everything else */
diff -Nru a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
--- a/arch/alpha/kernel/ptrace.c	Sun Nov 10 19:28:41 2002
+++ b/arch/alpha/kernel/ptrace.c	Sun Nov 10 19:28:41 2002
@@ -249,8 +249,8 @@
 }
 
 asmlinkage long
-sys_ptrace(long request, long pid, long addr, long data,
-	   int a4, int a5, struct pt_regs regs)
+do_sys_ptrace(long request, long pid, long addr, long data,
+	      struct pt_regs *regs)
 {
 	struct task_struct *child;
 	long ret;
@@ -307,14 +307,14 @@
 		if (copied != sizeof(tmp))
 			goto out;
 		
-		regs.r0 = 0;	/* special return: no errors */
+		regs->r0 = 0;	/* special return: no errors */
 		ret = tmp;
 		goto out;
 	}
 
 	/* Read register number ADDR. */
 	case PTRACE_PEEKUSR:
-		regs.r0 = 0;	/* special return: no errors */
+		regs->r0 = 0;	/* special return: no errors */
 		ret = get_reg(child, addr);
 		DBG(DBG_MEM, ("peek $%ld->%#lx\n", addr, ret));
 		goto out;
diff -Nru a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
--- a/arch/alpha/kernel/traps.c	Sun Nov 10 19:28:41 2002
+++ b/arch/alpha/kernel/traps.c	Sun Nov 10 19:28:41 2002
@@ -210,8 +210,7 @@
 
 asmlinkage void
 do_entArith(unsigned long summary, unsigned long write_mask,
-	    unsigned long a2, unsigned long a3, unsigned long a4,
-	    unsigned long a5, struct pt_regs regs)
+	    struct pt_regs *regs)
 {
 	long si_code = FPE_FLTINV;
 	siginfo_t info;
@@ -221,23 +220,23 @@
 		   emulate the instruction.  If the processor supports
 		   precise exceptions, we don't have to search.  */
 		if (!amask(AMASK_PRECISE_TRAP))
-			si_code = alpha_fp_emul(regs.pc - 4);
+			si_code = alpha_fp_emul(regs->pc - 4);
 		else
-			si_code = alpha_fp_emul_imprecise(&regs, write_mask);
+			si_code = alpha_fp_emul_imprecise(regs, write_mask);
+		if (si_code == 0)
+			return;
 	}
-	die_if_kernel("Arithmetic fault", &regs, 0, 0);
+	die_if_kernel("Arithmetic fault", regs, 0, 0);
 
 	info.si_signo = SIGFPE;
 	info.si_errno = 0;
 	info.si_code = si_code;
-	info.si_addr = (void *) regs.pc;
+	info.si_addr = (void *) regs->pc;
 	send_sig_info(SIGFPE, &info, current);
 }
 
 asmlinkage void
-do_entIF(unsigned long type, unsigned long a1,
-	 unsigned long a2, unsigned long a3, unsigned long a4,
-	 unsigned long a5, struct pt_regs regs)
+do_entIF(unsigned long type, struct pt_regs *regs)
 {
 	siginfo_t info;
 	int signo, code;
@@ -245,13 +244,13 @@
 	if (!opDEC_testing || type != 4) {
 		if (type == 1) {
 			const unsigned int *data
-			  = (const unsigned int *) regs.pc;
+			  = (const unsigned int *) regs->pc;
 			printk("Kernel bug at %s:%d\n",
 			       (const char *)(data[1] | (long)data[2] << 32), 
 			       data[0]);
 		}
 		die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"),
-		      &regs, type, 0);
+			      regs, type, 0);
 	}
 
 	switch (type) {
@@ -260,10 +259,10 @@
 		info.si_errno = 0;
 		info.si_code = TRAP_BRKPT;
 		info.si_trapno = 0;
-		info.si_addr = (void *) regs.pc;
+		info.si_addr = (void *) regs->pc;
 
 		if (ptrace_cancel_bpt(current)) {
-			regs.pc -= 4;	/* make pc point to former bpt */
+			regs->pc -= 4;	/* make pc point to former bpt */
 		}
 
 		send_sig_info(SIGTRAP, &info, current);
@@ -273,15 +272,15 @@
 		info.si_signo = SIGTRAP;
 		info.si_errno = 0;
 		info.si_code = __SI_FAULT;
-		info.si_addr = (void *) regs.pc;
+		info.si_addr = (void *) regs->pc;
 		info.si_trapno = 0;
 		send_sig_info(SIGTRAP, &info, current);
 		return;
 		
 	      case 2: /* gentrap */
-		info.si_addr = (void *) regs.pc;
-		info.si_trapno = regs.r16;
-		switch ((long) regs.r16) {
+		info.si_addr = (void *) regs->pc;
+		info.si_trapno = regs->r16;
+		switch ((long) regs->r16) {
 		case GEN_INTOVF:
 			signo = SIGFPE;
 			code = FPE_INTOVF;
@@ -341,7 +340,7 @@
 		info.si_signo = signo;
 		info.si_errno = 0;
 		info.si_code = code;
-		info.si_addr = (void *) regs.pc;
+		info.si_addr = (void *) regs->pc;
 		send_sig_info(signo, &info, current);
 		return;
 
@@ -358,26 +357,26 @@
 			   we get the correct PC.  If not, we set a flag
 			   to correct it every time through.  */
 			if (opDEC_testing) {
-				if (regs.pc == opDEC_test_pc) {
+				if (regs->pc == opDEC_test_pc) {
 					opDEC_fix = 4;
-					regs.pc += 4;
+					regs->pc += 4;
 					printk("opDEC fixup enabled.\n");
 				}
 				return;
 			}
-			regs.pc += opDEC_fix; 
+			regs->pc += opDEC_fix; 
 			
 			/* EV4 does not implement anything except normal
 			   rounding.  Everything else will come here as
 			   an illegal instruction.  Emulate them.  */
-			si_code = alpha_fp_emul(regs.pc - 4);
+			si_code = alpha_fp_emul(regs->pc - 4);
 			if (si_code == 0)
 				return;
 			if (si_code > 0) {
 				info.si_signo = SIGFPE;
 				info.si_errno = 0;
 				info.si_code = si_code;
-				info.si_addr = (void *) regs.pc;
+				info.si_addr = (void *) regs->pc;
 				send_sig_info(SIGFPE, &info, current);
 				return;
 			}
@@ -406,7 +405,7 @@
 	info.si_signo = SIGILL;
 	info.si_errno = 0;
 	info.si_code = ILL_ILLOPC;
-	info.si_addr = regs.pc;
+	info.si_addr = (void *) regs->pc;
 	send_sig_info(SIGILL, &info, current);
 }
 
@@ -418,18 +417,16 @@
    and if we don't put something on the entry point we'll oops.  */
 
 asmlinkage void
-do_entDbg(unsigned long type, unsigned long a1,
-	  unsigned long a2, unsigned long a3, unsigned long a4,
-	  unsigned long a5, struct pt_regs regs)
+do_entDbg(struct pt_regs *regs)
 {
 	siginfo_t info;
 
-	die_if_kernel("Instruction fault", &regs, type, 0);
+	die_if_kernel("Instruction fault", regs, 0, 0);
 
 	info.si_signo = SIGILL;
 	info.si_errno = 0;
 	info.si_code = ILL_ILLOPC;
-	info.si_addr = regs.pc;
+	info.si_addr = (void *) regs->pc;
 	force_sig_info(SIGILL, &info, current);
 }
 
@@ -1083,22 +1080,6 @@
 	return;
 }
 
-/*
- * Unimplemented system calls.
- */
-asmlinkage long
-alpha_ni_syscall(unsigned long a0, unsigned long a1, unsigned long a2,
-		 unsigned long a3, unsigned long a4, unsigned long a5,
-		 struct pt_regs regs)
-{
-	/* We only get here for OSF system calls, minus #112;
-	   the rest go to sys_ni_syscall.  */
-#if 0
-	printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
-#endif
-	return -ENOSYS;
-}
-
 void
 trap_init(void)
 {
@@ -1114,9 +1095,7 @@
 	wrent(entDbg, 6);
 
 	/* Hack for Multia (UDB) and JENSEN: some of their SRMs have
-	 * a bug in the handling of the opDEC fault.  Fix it up if so.
-	 */
-	if (implver() == IMPLVER_EV4) {
+	   a bug in the handling of the opDEC fault.  Fix it up if so.  */
+	if (implver() == IMPLVER_EV4)
 		opDEC_check();
-	}
 }
diff -Nru a/arch/alpha/math-emu/math.c b/arch/alpha/math-emu/math.c
--- a/arch/alpha/math-emu/math.c	Sun Nov 10 19:28:41 2002
+++ b/arch/alpha/math-emu/math.c	Sun Nov 10 19:28:41 2002
@@ -223,12 +223,12 @@
 				FP_CONV(S,D,1,1,SR,DB);
 				goto pack_s;
 			} else {
-				/* CVTST need do nothing else but copy the
-				   bits and repack.  */
+				vb = alpha_read_fp_reg_s(fb);
+				FP_UNPACK_SP(SB, &vb);
 				DR_c = DB_c;
 				DR_s = DB_s;
 				DR_e = DB_e;
-				DR_f = DB_f;
+				DR_f = SB_f << (52 - 23);
 				goto pack_d;
 			}
 
diff -Nru a/arch/alpha/vmlinux.lds.S b/arch/alpha/vmlinux.lds.S
--- a/arch/alpha/vmlinux.lds.S	Sun Nov 10 19:28:40 2002
+++ b/arch/alpha/vmlinux.lds.S	Sun Nov 10 19:28:40 2002
@@ -69,7 +69,7 @@
 
   .init.ramfs ALIGN(8192): {
 	__initramfs_start = .;
-	*(.init.initramfs)
+	*(.init.ramfs)
 	__initramfs_end = .;
   }
 
diff -Nru a/arch/arm/Kconfig b/arch/arm/Kconfig
--- a/arch/arm/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/arch/arm/Kconfig	Sun Nov 10 19:28:40 2002
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 
 mainmenu "Linux Kernel Configuration"
diff -Nru a/arch/arm/Makefile b/arch/arm/Makefile
--- a/arch/arm/Makefile	Sun Nov 10 19:28:39 2002
+++ b/arch/arm/Makefile	Sun Nov 10 19:28:39 2002
@@ -8,6 +8,7 @@
 # Copyright (C) 1995-2001 by Russell King
 
 LDFLAGS_vmlinux	:=-p -X
+LDFLAGS_BLOB	:=--format binary
 AFLAGS_vmlinux.lds.o = -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR)
 OBJCOPYFLAGS	:=-O binary -R .note -R .comment -S
 GZFLAGS		:=-9
@@ -60,6 +61,7 @@
 ifeq ($(CONFIG_CPU_26),y)
 PROCESSOR	:= armo
 HEAD		:= arch/arm/mach-arc/head.o arch/arm/kernel/init_task.o
+LDFLAGS_BLOB	+= --oformat elf26-littlearm
   ifeq ($(CONFIG_ROM_KERNEL),y)
     DATAADDR	 = 0x02080000
     TEXTADDR	 = 0x03800000
@@ -72,6 +74,7 @@
 PROCESSOR	 = armv
 HEAD		:= arch/arm/kernel/head.o arch/arm/kernel/init_task.o
 TEXTADDR	 = 0xC0008000
+LDFLAGS_BLOB	+= --oformat elf32-littlearm
 endif
 
 ifeq ($(CONFIG_ARCH_ARCA5K),y)
diff -Nru a/arch/arm/def-configs/neponset b/arch/arm/def-configs/neponset
--- a/arch/arm/def-configs/neponset	Sun Nov 10 19:28:38 2002
+++ b/arch/arm/def-configs/neponset	Sun Nov 10 19:28:38 2002
@@ -2,14 +2,10 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
+CONFIG_SWAP=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
-# CONFIG_GENERIC_BUST_SPINLOCK is not set
-# CONFIG_GENERIC_ISA_DMA is not set
 
 #
 # Code maturity level options
@@ -40,6 +36,7 @@
 # CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
@@ -57,17 +54,30 @@
 #
 # Archimedes/A5000 Implementations (select only ONE)
 #
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+
+#
+# Epxa10db
+#
 
 #
 # Footbridge Implementations
 #
-# CONFIG_ARCH_CATS is not set
-# CONFIG_ARCH_PERSONAL_SERVER is not set
-# CONFIG_ARCH_EBSA285_ADDIN is not set
-# CONFIG_ARCH_EBSA285_HOST is not set
-# CONFIG_ARCH_NETWINDER is not set
+
+#
+# IOP310 Implementation Options
+#
+
+#
+# IOP310 Chipset Features
+#
+
+#
+# Intel PXA250/210 Implementations
+#
 
 #
 # SA11x0 Implementations
@@ -80,7 +90,6 @@
 # CONFIG_SA1100_H3100 is not set
 # CONFIG_SA1100_H3600 is not set
 # CONFIG_SA1100_H3800 is not set
-# CONFIG_SA1100_H3XXX is not set
 # CONFIG_SA1100_EXTENEX1 is not set
 # CONFIG_SA1100_FLEXANET is not set
 # CONFIG_SA1100_FREEBIRD is not set
@@ -104,61 +113,18 @@
 # CONFIG_SA1100_XP860 is not set
 # CONFIG_SA1100_YOPY is not set
 # CONFIG_SA1100_STORK is not set
+CONFIG_SA1100_USB=m
+CONFIG_SA1100_USB_NETLINK=m
+CONFIG_SA1100_USB_CHAR=m
 CONFIG_SA1111=y
 CONFIG_FORCE_MAX_ZONEORDER=9
-# CONFIG_SA1100_USB is not set
-# CONFIG_SA1100_USB_NETLINK is not set
-# CONFIG_SA1100_USB_CHAR is not set
-# CONFIG_H3600_SLEEVE is not set
-
-#
-# CLPS711X/EP721X Implementations
-#
-# CONFIG_ARCH_AUTCPU12 is not set
-# CONFIG_ARCH_CDB89712 is not set
-# CONFIG_ARCH_CLEP7312 is not set
-# CONFIG_ARCH_EDB7211 is not set
-# CONFIG_ARCH_P720T is not set
-# CONFIG_ARCH_FORTUNET is not set
-# CONFIG_ARCH_EP7211 is not set
-# CONFIG_ARCH_EP7212 is not set
-
-#
-# IOP310 Implementation Options
-#
-# CONFIG_ARCH_IQ80310 is not set
-
-#
-# IOP310 Chipset Features
-#
-# CONFIG_IOP310_AAU is not set
-# CONFIG_IOP310_DMA is not set
-# CONFIG_IOP310_MU is not set
-# CONFIG_IOP310_PMON is not set
-# CONFIG_ARCH_ACORN is not set
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
-CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
 
 #
 # Processor Type
 #
-# CONFIG_CPU_32v3 is not set
-CONFIG_CPU_32v4=y
-# CONFIG_CPU_32v5 is not set
-# CONFIG_CPU_ARM610 is not set
-# CONFIG_CPU_ARM710 is not set
-# CONFIG_CPU_ARM720T is not set
-# CONFIG_CPU_ARM920T is not set
-# CONFIG_CPU_ARM922T is not set
-# CONFIG_CPU_ARM926T is not set
-# CONFIG_CPU_ARM1020 is not set
-# CONFIG_CPU_SA110 is not set
+CONFIG_CPU_32=y
 CONFIG_CPU_SA1100=y
-# CONFIG_CPU_XSCALE is not set
-# CONFIG_XSCALE_PMU is not set
+CONFIG_CPU_32v4=y
 
 #
 # Processor Features
@@ -168,26 +134,23 @@
 # General setup
 #
 CONFIG_DISCONTIGMEM=y
-# CONFIG_PCI is not set
 CONFIG_ISA=y
-# CONFIG_ISA_DMA is not set
-# CONFIG_FIQ is not set
-# CONFIG_ZBOOT_ROM is not set
-CONFIG_ZBOOT_ROM_TEXT=0
-CONFIG_ZBOOT_ROM_BSS=0
+CONFIG_ZBOOT_ROM=y
+CONFIG_ZBOOT_ROM_TEXT=0x80000
+CONFIG_ZBOOT_ROM_BSS=0xc1000000
 CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_24_API=y
+CONFIG_CPU_FREQ_26_API=y
 CONFIG_HOTPLUG=y
 
 #
 # PCMCIA/CardBus support
 #
 CONFIG_PCMCIA=y
-CONFIG_PCMCIA_PROBE=y
-# CONFIG_I82092 is not set
 # CONFIG_I82365 is not set
 # CONFIG_TCIC is not set
-# CONFIG_PCMCIA_CLPS6700 is not set
 CONFIG_PCMCIA_SA1100=y
+CONFIG_PCMCIA_SA1111=y
 
 #
 # At least one math emulation must be selected
@@ -203,7 +166,7 @@
 # CONFIG_PREEMPT is not set
 CONFIG_APM=y
 # CONFIG_ARTHUR is not set
-CONFIG_CMDLINE="console=ttySA0,38400n8 console=tty1 cpufreq=221200 rw root=/dev/mtdblock3 load_ramdisk=1 prompt_ramdisk=0 mem=32M noinitrd initrd=0xc0800000,3M profile=2"
+CONFIG_CMDLINE="console=ttySA0,38400n8 cpufreq=221200 rw root=/dev/mtdblock2 mtdparts=sa1100:512K(boot),1M(kernel),2560K(initrd),4M(root) load_ramdisk=1 prompt_ramdisk=0 mem=32M noinitrd initrd=0xc0800000,3M"
 CONFIG_LEDS=y
 CONFIG_LEDS_TIMER=y
 CONFIG_LEDS_CPU=y
@@ -222,7 +185,7 @@
 CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CONCAT=y
 CONFIG_MTD_REDBOOT_PARTS=y
-# CONFIG_MTD_BOOTLDR_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
 # CONFIG_MTD_AFS_PARTS is not set
 
 #
@@ -246,13 +209,10 @@
 # CONFIG_MTD_CFI_GEOMETRY is not set
 CONFIG_MTD_CFI_INTELEXT=y
 # CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_RAM is not set
+CONFIG_MTD_RAM=y
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
 # CONFIG_MTD_OBSOLETE_CHIPS is not set
-# CONFIG_MTD_AMDSTD is not set
-# CONFIG_MTD_SHARP is not set
-# CONFIG_MTD_JEDEC is not set
 
 #
 # Mapping drivers for chip access
@@ -260,19 +220,14 @@
 # CONFIG_MTD_PHYSMAP is not set
 # CONFIG_MTD_NORA is not set
 # CONFIG_MTD_ARM_INTEGRATOR is not set
-# CONFIG_MTD_CDB89712 is not set
 CONFIG_MTD_SA1100=y
-# CONFIG_MTD_2PARTS_IPAQ is not set
-# CONFIG_MTD_DC21285 is not set
-# CONFIG_MTD_IQ80310 is not set
-# CONFIG_MTD_EPXA10DB is not set
-# CONFIG_MTD_FORTUNET is not set
-# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_EDB7312 is not set
+CONFIG_MTD_PCMCIA=y
+# CONFIG_MTD_UCLINUX is not set
 
 #
 # Self-contained MTD device drivers
 #
-# CONFIG_MTD_PMC551 is not set
 # CONFIG_MTD_SLRAM is not set
 # CONFIG_MTD_MTDRAM is not set
 # CONFIG_MTD_BLKMTD is not set
@@ -283,7 +238,6 @@
 # CONFIG_MTD_DOC1000 is not set
 # CONFIG_MTD_DOC2000 is not set
 # CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOCPROBE is not set
 
 #
 # NAND Flash Device Drivers
@@ -294,20 +248,12 @@
 # Plug and Play configuration
 #
 # CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
 
 #
 # Block devices
 #
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_CISS_SCSI_TAPE is not set
-# CONFIG_BLK_DEV_DAC960 is not set
-# CONFIG_BLK_DEV_UMEM is not set
 # CONFIG_BLK_DEV_LOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -318,18 +264,11 @@
 # Multi-device support (RAID and LVM)
 #
 # CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
 
 #
 # Networking options
 #
-CONFIG_PACKET=m
+CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 # CONFIG_NETLINK_DEV is not set
 # CONFIG_NETFILTER is not set
@@ -345,25 +284,19 @@
 # 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
 
 #
-#  
+# SCTP Configuration (EXPERIMENTAL)
 #
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-
-#
-# Appletalk devices
-#
-# CONFIG_DEV_APPLETALK is not set
+CONFIG_IPV6_SCTP__=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -394,18 +327,11 @@
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
-# CONFIG_ARM_AM79C961A is not set
-# CONFIG_SUNLANCE is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
-# CONFIG_SUNGEM is not set
 # CONFIG_NET_VENDOR_3COM is not set
 # CONFIG_LANCE is not set
 CONFIG_NET_VENDOR_SMC=y
 # CONFIG_WD80x3 is not set
-# CONFIG_ULTRAMCA is not set
 # CONFIG_ULTRA is not set
-# CONFIG_ULTRA32 is not set
 CONFIG_SMC9194=y
 # CONFIG_NET_VENDOR_RACAL is not set
 # CONFIG_AT1700 is not set
@@ -418,18 +344,8 @@
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_ACENIC is not set
-# CONFIG_DL2K is not set
-# CONFIG_E1000 is not set
-# CONFIG_MYRI_SBUS is not set
-# CONFIG_NS83820 is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
-# CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 
@@ -443,7 +359,6 @@
 #
 # CONFIG_TR is not set
 # CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
 
 #
@@ -452,11 +367,6 @@
 # CONFIG_WAN is not set
 
 #
-# Tulip family network device support
-#
-# CONFIG_NET_TULIP is not set
-
-#
 # PCMCIA network device support
 #
 CONFIG_NET_PCMCIA=y
@@ -468,25 +378,22 @@
 # CONFIG_PCMCIA_SMC91C92 is not set
 # CONFIG_PCMCIA_XIRC2PS is not set
 # CONFIG_PCMCIA_AXNET is not set
-# CONFIG_ARCNET_COM20020_CS is not set
-# CONFIG_PCMCIA_IBMTR is not set
 # CONFIG_NET_PCMCIA_RADIO is not set
 
 #
-# Amateur Radio support
+# IrDA (infrared) support
 #
-# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
 
 #
-# IrDA (infrared) support
+# Amateur Radio support
 #
-# CONFIG_IRDA is not set
+# CONFIG_HAMRADIO is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# ATA/ATAPI/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
 
 #
 # SCSI support
@@ -497,10 +404,6 @@
 # I2O device support
 #
 # CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
 
 #
 # ISDN subsystem
@@ -515,11 +418,11 @@
 #
 # Userland interfaces
 #
-CONFIG_INPUT_KEYBDEV=y
 # CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 # CONFIG_INPUT_JOYDEV is not set
-# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_TSDEV=y
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
 CONFIG_INPUT_TSLIBDEV=y
 # CONFIG_INPUT_EVDEV is not set
 # CONFIG_INPUT_EVBUG is not set
@@ -529,17 +432,10 @@
 #
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
-# CONFIG_GAMEPORT_NS558 is not set
-# CONFIG_GAMEPORT_L4 is not set
-# CONFIG_INPUT_EMU10K1 is not set
-# CONFIG_GAMEPORT_VORTEX is not set
-# CONFIG_GAMEPORT_FM801 is not set
-# CONFIG_GAMEPORT_CS461x is not set
 CONFIG_SERIO=y
 # CONFIG_SERIO_I8042 is not set
-# CONFIG_SERIO_SERPORT is not set
+CONFIG_SERIO_SERPORT=m
 # CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
 CONFIG_SERIO_SA1111=y
 
 #
@@ -548,44 +444,20 @@
 CONFIG_INPUT_KEYBOARD=y
 CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_SUNKBD is not set
-# CONFIG_KEYBOARD_PS2SERKBD is not set
 # CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_INPUT_MOUSE is not set
-# CONFIG_MOUSE_PS2 is not set
-# CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_INPORT is not set
-# CONFIG_MOUSE_LOGIBM is not set
-# CONFIG_MOUSE_PC110PAD is not set
 # CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_JOYSTICK_ANALOG is not set
-# CONFIG_JOYSTICK_A3D is not set
-# CONFIG_JOYSTICK_ADI is not set
-# CONFIG_JOYSTICK_COBRA is not set
-# CONFIG_JOYSTICK_GF2K is not set
-# CONFIG_JOYSTICK_GRIP is not set
-# CONFIG_JOYSTICK_GUILLEMOT is not set
-# CONFIG_JOYSTICK_INTERACT is not set
-# CONFIG_JOYSTICK_SIDEWINDER is not set
-# CONFIG_JOYSTICK_TMDC is not set
-# CONFIG_JOYSTICK_IFORCE_USB is not set
-# CONFIG_JOYSTICK_IFORCE_232 is not set
-# CONFIG_JOYSTICK_WARRIOR is not set
-# CONFIG_JOYSTICK_MAGELLAN is not set
-# CONFIG_JOYSTICK_SPACEORB is not set
-# CONFIG_JOYSTICK_SPACEBALL is not set
-# CONFIG_JOYSTICK_STINGER is not set
-# CONFIG_JOYSTICK_TWIDDLER is not set
-# CONFIG_JOYSTICK_DB9 is not set
-# CONFIG_JOYSTICK_GAMECON is not set
-# CONFIG_JOYSTICK_TURBOGRAFX is not set
 CONFIG_INPUT_TOUCHSCREEN=y
 # CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Character devices
 #
 CONFIG_VT=y
-# CONFIG_VT_CONSOLE is not set
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
 CONFIG_SERIAL_NONSTANDARD=y
 # CONFIG_COMPUTONE is not set
 # CONFIG_ROCKETPORT is not set
@@ -612,29 +484,10 @@
 # CONFIG_SERIAL_8250_CONSOLE is not set
 CONFIG_SERIAL_8250_CS=y
 # CONFIG_SERIAL_8250_EXTENDED is not set
-# CONFIG_SERIAL_8250_MANY_PORTS is not set
-# CONFIG_SERIAL_8250_SHARE_IRQ is not set
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_RSA is not set
 
 #
 # Non-8250 serial port support
 #
-# CONFIG_ATOMWIDE_SERIAL is not set
-# CONFIG_DUALSP_SERIAL is not set
-# CONFIG_SERIAL_ANAKIN is not set
-# CONFIG_SERIAL_ANAKIN_CONSOLE is not set
-# CONFIG_SERIAL_AMBA is not set
-# CONFIG_SERIAL_AMBA_CONSOLE is not set
-# CONFIG_SERIAL_CLPS711X is not set
-# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
-# CONFIG_SERIAL_CLPS711X_OLD_NAME is not set
-# CONFIG_SERIAL_21285 is not set
-# CONFIG_SERIAL_21285_OLD is not set
-# CONFIG_SERIAL_21285_CONSOLE is not set
-# CONFIG_SERIAL_UART00 is not set
-# CONFIG_SERIAL_UART00_CONSOLE is not set
 CONFIG_SERIAL_SA1100=y
 CONFIG_SERIAL_SA1100_CONSOLE=y
 CONFIG_SERIAL_CORE=y
@@ -647,9 +500,9 @@
 #
 CONFIG_I2C=y
 CONFIG_I2C_ALGOBIT=y
-# CONFIG_I2C_PHILIPSPAR is not set
 # CONFIG_I2C_ELV is not set
 # CONFIG_I2C_VELLEMAN is not set
+# CONFIG_SCx200_ACB is not set
 CONFIG_I2C_BIT_SA1100_GPIO=y
 # CONFIG_I2C_ALGOPCF is not set
 CONFIG_I2C_CHARDEV=y
@@ -661,18 +514,12 @@
 CONFIG_L3=y
 CONFIG_L3_ALGOBIT=y
 CONFIG_L3_BIT_SA1100_GPIO=y
-
-#
-# Other L3 adapters
-#
-CONFIG_L3_SA1111=y
 CONFIG_BIT_SA1100_GPIO=y
 
 #
 # Mice
 #
 # CONFIG_BUSMOUSE is not set
-# CONFIG_MOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 
 #
@@ -686,19 +533,18 @@
 # CONFIG_PCWATCHDOG is not set
 # CONFIG_ACQUIRE_WDT is not set
 # CONFIG_ADVANTECH_WDT is not set
-# CONFIG_21285_WATCHDOG is not set
-# CONFIG_977_WATCHDOG is not set
 CONFIG_SA1100_WATCHDOG=m
 # CONFIG_EUROTECH_WDT is not set
 # CONFIG_IB700_WDT is not set
 # CONFIG_I810_TCO is not set
 # CONFIG_MIXCOMWD is not set
+# CONFIG_SCx200_WDT is not set
 # CONFIG_60XX_WDT is not set
 # CONFIG_W83877F_WDT is not set
 # CONFIG_MACHZ_WDT is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
 CONFIG_SA1100_RTC=y
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
@@ -715,6 +561,7 @@
 # PCMCIA character devices
 #
 # CONFIG_SYNCLINK_CS is not set
+# CONFIG_RAW_DRIVER is not set
 
 #
 # Multimedia devices
@@ -725,24 +572,18 @@
 # File systems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_QFMT_V1 is not set
-# CONFIG_QFMT_V2 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_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EXT3_FS is not set
 # CONFIG_JBD is not set
-# CONFIG_JBD_DEBUG is not set
 CONFIG_FAT_FS=m
 CONFIG_MSDOS_FS=m
-# CONFIG_UMSDOS_FS is not set
 CONFIG_VFAT_FS=m
 # CONFIG_EFS_FS is not set
 # CONFIG_JFFS_FS is not set
@@ -753,31 +594,22 @@
 # CONFIG_TMPFS is not set
 CONFIG_RAMFS=y
 # CONFIG_ISO9660_FS is not set
-# CONFIG_JOLIET is not set
-# CONFIG_ZISOFS is not set
 # CONFIG_JFS_FS is not set
-# CONFIG_JFS_DEBUG is not set
-# CONFIG_JFS_STATISTICS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
 
 #
 # Network File Systems
@@ -786,24 +618,15 @@
 # CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
-# CONFIG_ROOT_NFS is not set
+# CONFIG_NFS_V4 is not set
 # CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
-# CONFIG_NFSD_TCP is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
 # CONFIG_EXPORTFS is not set
+# CONFIG_CIFS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
-# CONFIG_ZISOFS_FS is not set
+# CONFIG_AFS_FS is not set
 
 #
 # Partition Types
@@ -820,7 +643,6 @@
 # CONFIG_ULTRIX_PARTITION is not set
 # CONFIG_SUN_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
-# CONFIG_SMB_NLS is not set
 CONFIG_NLS=y
 
 #
@@ -868,7 +690,6 @@
 #
 # Console drivers
 #
-CONFIG_PC_KEYMAP=y
 # CONFIG_VGA_CONSOLE is not set
 
 #
@@ -876,11 +697,7 @@
 #
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
-# CONFIG_FB_ACORN is not set
-# CONFIG_FB_ANAKIN is not set
-# CONFIG_FB_CLPS711X is not set
 CONFIG_FB_SA1100=y
-# CONFIG_FB_CYBER2000 is not set
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FBCON_ADVANCED is not set
 CONFIG_FBCON_CFB2=y
@@ -888,12 +705,13 @@
 CONFIG_FBCON_CFB8=y
 CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_FONTWIDTH8_ONLY=y
+# CONFIG_FONT_SUN8x16 is not set
 CONFIG_FBCON_FONTS=y
 # CONFIG_FONT_8x8 is not set
 # CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_SUN8x16 is not set
 # CONFIG_FONT_PEARL_8x8 is not set
 CONFIG_FONT_ACORN_8x8=y
+# CONFIG_FONT_MINI_4x6 is not set
 
 #
 # Sound
@@ -905,35 +723,20 @@
 #
 CONFIG_SOUND_PRIME=y
 # CONFIG_SOUND_BT878 is not set
-# CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_EMU10K1 is not set
-# CONFIG_MIDI_EMU10K1 is not set
 # CONFIG_SOUND_FUSION is not set
 # CONFIG_SOUND_CS4281 is not set
-# CONFIG_SOUND_ES1370 is not set
-# CONFIG_SOUND_ES1371 is not set
 # CONFIG_SOUND_ESSSOLO1 is not set
 # CONFIG_SOUND_MAESTRO is not set
-# CONFIG_SOUND_MAESTRO3 is not set
-# CONFIG_SOUND_ICH is not set
-# CONFIG_SOUND_RME96XX is not set
 # CONFIG_SOUND_SONICVIBES is not set
 # CONFIG_SOUND_TRIDENT is not set
 # CONFIG_SOUND_MSNDCLAS is not set
 # CONFIG_SOUND_MSNDPIN is not set
-# CONFIG_SOUND_VIA82CXXX is not set
-# CONFIG_MIDI_VIA82CXXX is not set
 CONFIG_SOUND_SA1100=y
 CONFIG_SOUND_UDA1341=y
 CONFIG_SOUND_ASSABET_UDA1341=y
-# CONFIG_SOUND_H3600_UDA1341 is not set
-# CONFIG_SOUND_PANGOLIN_UDA1341 is not set
 CONFIG_SOUND_SA1111_UDA1341=y
-# CONFIG_SOUND_STORK_UDA1341 is not set
 # CONFIG_SOUND_SA1100SSP is not set
-# CONFIG_SOUND_STORK_AC97 is not set
 # CONFIG_SOUND_OSS is not set
-# CONFIG_SOUND_WAVEARTIST is not set
 # CONFIG_SOUND_TVMIXER is not set
 
 #
@@ -942,6 +745,10 @@
 # CONFIG_SND is not set
 
 #
+# Misc devices
+#
+
+#
 # Multimedia Capabilities Port drivers
 #
 CONFIG_MCP=y
@@ -973,9 +780,8 @@
 # USB Host Controller Drivers
 #
 # CONFIG_USB_EHCI_HCD is not set
-# CONFIG_USB_OHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=m
 # CONFIG_USB_UHCI_HCD_ALT is not set
-CONFIG_USB_OHCI_SA1111=m
 # CONFIG_USB_SL811HS is not set
 
 #
@@ -988,37 +794,29 @@
 # CONFIG_USB_PRINTER is not set
 
 #
-#   SCSI support is needed for USB Storage
+# SCSI support is needed for USB Storage
 #
-# 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_SDDR55 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
 
 #
 # USB Human Interface Devices (HID)
 #
 # CONFIG_USB_HID is not set
-# CONFIG_USB_HIDINPUT is not set
-# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
+#
 # CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
+CONFIG_USB_MOUSE=m
 # CONFIG_USB_AIPTEK is not set
 # CONFIG_USB_WACOM is not set
+# CONFIG_USB_POWERMATE is not set
+# CONFIG_USB_XPAD is not set
 
 #
 # USB Imaging devices
 #
 # 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
@@ -1026,16 +824,8 @@
 # CONFIG_USB_DABUSB is not set
 
 #
-#   Video4Linux support is needed for USB Multimedia device support
+# Video4Linux support is needed for USB Multimedia device support
 #
-# CONFIG_USB_VICAM is not set
-# CONFIG_USB_DSBR is not set
-# CONFIG_USB_IBMCAM is not set
-# CONFIG_USB_KONICAWC is not set
-# CONFIG_USB_OV511 is not set
-# CONFIG_USB_PWC is not set
-# CONFIG_USB_SE401 is not set
-# CONFIG_USB_STV680 is not set
 
 #
 # USB Network adaptors
@@ -1050,51 +840,21 @@
 #
 # 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_USA19QW is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_KLSI is not set
-# CONFIG_USB_SERIAL_MCT_U232 is not set
-# CONFIG_USB_SERIAL_PL2303 is not set
-# CONFIG_USB_SERIAL_SAFE is not set
-# CONFIG_USB_SERIAL_SAFE_PADDED 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_EMI26 is not set
 # CONFIG_USB_TIGL is not set
 # CONFIG_USB_AUERSWALD is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_BRLVGER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_TEST is not set
 
 #
 # Bluetooth support
@@ -1114,9 +874,18 @@
 # CONFIG_DEBUG_WAITQ is not set
 CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_ERRORS=y
+# CONFIG_KALLSYMS is not set
 CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_DC21285_PORT is not set
-# CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Security options
+#
+CONFIG_SECURITY_CAPABILITIES=y
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
 
 #
 # Library routines
diff -Nru a/arch/arm/def-configs/rpc b/arch/arm/def-configs/rpc
--- a/arch/arm/def-configs/rpc	Sun Nov 10 19:28:36 2002
+++ b/arch/arm/def-configs/rpc	Sun Nov 10 19:28:36 2002
@@ -2,18 +2,23 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_ARM=y
-# CONFIG_EISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
+CONFIG_MMU=y
+CONFIG_SWAP=y
 CONFIG_UID16=y
 CONFIG_RWSEM_GENERIC_SPINLOCK=y
-# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
 
 #
 # Code maturity level options
 #
 CONFIG_EXPERIMENTAL=y
-# CONFIG_OBSOLETE is not set
+
+#
+# General setup
+#
+CONFIG_NET=y
+CONFIG_SYSVIPC=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
 
 #
 # Loadable module support
@@ -25,17 +30,22 @@
 #
 # System Type
 #
+# CONFIG_ARCH_ADIFCC is not set
+# CONFIG_ARCH_ANAKIN is not set
 # CONFIG_ARCH_ARCA5K is not set
 # CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_PXA is not set
 # CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_CAMELOT is not set
 # CONFIG_ARCH_FOOTBRIDGE is not set
 # CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP310 is not set
+# CONFIG_ARCH_L7200 is not set
 CONFIG_ARCH_RPC=y
 # CONFIG_ARCH_SA1100 is not set
-# CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_ANAKIN is not set
+# CONFIG_ARCH_SHARK is not set
 
 #
 # Archimedes/A5000 Implementations
@@ -44,89 +54,71 @@
 #
 # Archimedes/A5000 Implementations (select only ONE)
 #
-# CONFIG_ARCH_ARC is not set
-# CONFIG_ARCH_A5K is not set
+
+#
+# CLPS711X/EP721X Implementations
+#
+
+#
+# Epxa10db
+#
 
 #
 # Footbridge Implementations
 #
-# CONFIG_ARCH_CATS is not set
-# CONFIG_ARCH_PERSONAL_SERVER is not set
-# CONFIG_ARCH_EBSA285_ADDIN is not set
-# CONFIG_ARCH_EBSA285_HOST is not set
-# CONFIG_ARCH_NETWINDER is not set
 
 #
-# SA11x0 Implementations
+# IOP310 Implementation Options
 #
-# CONFIG_SA1100_ASSABET is not set
-# CONFIG_ASSABET_NEPONSET is not set
-# CONFIG_SA1100_BRUTUS is not set
-# CONFIG_SA1100_CERF is not set
-# CONFIG_SA1100_BITSY is not set
-# CONFIG_SA1100_EXTENEX1 is not set
-# CONFIG_SA1100_FREEBIRD is not set
-# CONFIG_SA1100_GRAPHICSCLIENT is not set
-# CONFIG_SA1100_JORNADA720 is not set
-# CONFIG_SA1100_HUW_WEBPANEL is not set
-# CONFIG_SA1100_ITSY is not set
-# CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_NANOENGINE is not set
-# CONFIG_SA1100_OMNIMETER is not set
-# CONFIG_SA1100_PANGOLIN is not set
-# CONFIG_SA1100_PLEB is not set
-# CONFIG_SA1100_SHERMAN is not set
-# CONFIG_SA1100_PFS168 is not set
-# CONFIG_SA1100_VICTOR is not set
-# CONFIG_SA1100_XP860 is not set
-# CONFIG_SA1100_YOPY is not set
 
 #
-# CLPS711X/EP721X Implementations
+# IOP310 Chipset Features
+#
+
+#
+# Intel PXA250/210 Implementations
+#
+
+#
+# SA11x0 Implementations
 #
-# CONFIG_ARCH_P720T is not set
 CONFIG_ARCH_ACORN=y
-# CONFIG_FOOTBRIDGE is not set
-# CONFIG_FOOTBRIDGE_HOST is not set
-# CONFIG_FOOTBRIDGE_ADDIN is not set
-CONFIG_CPU_32=y
-# CONFIG_CPU_26 is not set
 
 #
 # Processor Type
 #
-CONFIG_CPU_32v3=y
-# CONFIG_CPU_32v4 is not set
+CONFIG_CPU_32=y
 CONFIG_CPU_ARM610=y
 CONFIG_CPU_ARM710=y
-# CONFIG_CPU_ARM720T is not set
-# CONFIG_CPU_ARM920T is not set
-# CONFIG_CPU_ARM1020 is not set
 CONFIG_CPU_SA110=y
-# CONFIG_CPU_SA1100 is not set
-# CONFIG_DISCONTIGMEM is not set
+CONFIG_CPU_32v3=y
+
+#
+# Processor Features
+#
 
 #
 # General setup
 #
-# CONFIG_PCI is not set
-# CONFIG_ISA is not set
-# CONFIG_ISA_DMA is not set
+CONFIG_FIQ=y
+# CONFIG_ZBOOT_ROM is not set
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
 # CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-CONFIG_NET=y
-CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
-CONFIG_SYSCTL=y
+
+#
+# At least one math emulation must be selected
+#
 CONFIG_FPE_NWFPE=y
-CONFIG_FPE_FASTFPE=y
 CONFIG_KCORE_ELF=y
 # CONFIG_KCORE_AOUT is not set
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
 # CONFIG_BINFMT_MISC is not set
 # CONFIG_PM is not set
+# CONFIG_PREEMPT is not set
 # CONFIG_ARTHUR is not set
+CONFIG_CMDLINE=""
 CONFIG_ALIGNMENT_TRAP=y
 
 #
@@ -134,13 +126,11 @@
 #
 CONFIG_PARPORT=y
 CONFIG_PARPORT_PC=y
+CONFIG_PARPORT_PC_CML1=y
+# CONFIG_PARPORT_SERIAL is not set
 CONFIG_PARPORT_PC_FIFO=y
 # CONFIG_PARPORT_PC_SUPERIO is not set
 # CONFIG_PARPORT_ARC is not set
-# CONFIG_PARPORT_AMIGA is not set
-# CONFIG_PARPORT_MFC3 is not set
-# CONFIG_PARPORT_ATARI is not set
-# CONFIG_PARPORT_SUNBPP is not set
 # CONFIG_PARPORT_OTHER is not set
 # CONFIG_PARPORT_1284 is not set
 
@@ -150,78 +140,15 @@
 # CONFIG_MTD is not set
 
 #
-# RAM/ROM/Flash chip drivers
-#
-# CONFIG_MTD_CFI is not set
-# CONFIG_MTD_CFI_INTELEXT is not set
-# CONFIG_MTD_CFI_AMDSTD is not set
-# CONFIG_MTD_AMDSTD is not set
-# CONFIG_MTD_SHARP is not set
-# CONFIG_MTD_RAM is not set
-# CONFIG_MTD_ROM is not set
-# CONFIG_MTD_JEDEC is not set
-
-#
-# Mapping drivers for chip access
-#
-# CONFIG_MTD_PHYSMAP is not set
-# CONFIG_MTD_SUN_UFLASH is not set
-# CONFIG_MTD_NORA is not set
-# CONFIG_MTD_PNC2000 is not set
-# CONFIG_MTD_RPXLITE is not set
-# CONFIG_MTD_SC520CDP is not set
-# CONFIG_MTD_NETSC520 is not set
-# CONFIG_MTD_SBC_GXX is not set
-# CONFIG_MTD_ELAN_104NC is not set
-# CONFIG_MTD_SA1100 is not set
-# CONFIG_MTD_SA1100_REDBOOT_PARTITIONS is not set
-# CONFIG_MTD_SA1100_BOOTLDR_PARTITIONS is not set
-# CONFIG_MTD_DC21285 is not set
-# CONFIG_MTD_IQ80310 is not set
-# CONFIG_MTD_DBOX2 is not set
-# CONFIG_MTD_CSTM_MIPS_IXX is not set
-# CONFIG_MTD_CFI_FLAGADM is not set
-# CONFIG_MTD_MIXMEM is not set
-# CONFIG_MTD_OCTAGON is not set
-# CONFIG_MTD_VMAX is not set
-# CONFIG_MTD_ARMFLASH is not set
-
-#
-# Self-contained MTD device drivers
-#
-# CONFIG_MTD_PMC551 is not set
-# CONFIG_MTD_SLRAM is not set
-# CONFIG_MTD_MTDRAM is not set
-
-#
-# Disk-On-Chip Device Drivers
-#
-# CONFIG_MTD_DOC1000 is not set
-# CONFIG_MTD_DOC2000 is not set
-# CONFIG_MTD_DOC2001 is not set
-# CONFIG_MTD_DOCPROBE is not set
-
-#
-# NAND Flash Device Drivers
-#
-# CONFIG_MTD_NAND is not set
-# CONFIG_MTD_NAND_SPIA is not set
-
-#
 # Plug and Play configuration
 #
 # CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
 
 #
 # Block devices
 #
 CONFIG_BLK_DEV_FD=y
-# CONFIG_BLK_DEV_XD is not set
 # CONFIG_PARIDE is not set
-# CONFIG_BLK_CPQ_DA is not set
-# CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_BLK_DEV_DAC960 is not set
 CONFIG_BLK_DEV_LOOP=m
 # CONFIG_BLK_DEV_NBD is not set
 CONFIG_BLK_DEV_RAM=y
@@ -232,12 +159,6 @@
 # Multi-device support (RAID and LVM)
 #
 # CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_BLK_DEV_LVM is not set
 
 #
 # Acorn-specific block devices
@@ -247,7 +168,7 @@
 # Networking options
 #
 # CONFIG_PACKET is not set
-# CONFIG_NETLINK is not set
+CONFIG_NETLINK_DEV=y
 # CONFIG_NETFILTER is not set
 # CONFIG_FILTER is not set
 CONFIG_UNIX=y
@@ -258,22 +179,23 @@
 # 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
 
 #
-#  
+# SCTP Configuration (EXPERIMENTAL)
 #
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
+CONFIG_IPV6_SCTP__=y
+# CONFIG_IP_SCTP is not set
+# CONFIG_ATM is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_LLC is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
-# CONFIG_LLC is not set
 # CONFIG_NET_DIVERT is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
@@ -298,7 +220,7 @@
 # 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)
@@ -308,28 +230,18 @@
 CONFIG_ARM_ETHER3=y
 CONFIG_ARM_ETHERH=y
 # CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_AT1700 is not set
-# CONFIG_DEPCA is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
 # CONFIG_NET_POCKET is not set
 
 #
 # Ethernet (1000 Mbit)
 #
-# CONFIG_ACENIC is not set
-# CONFIG_HAMACHI is not set
-# CONFIG_YELLOWFIN is not set
-# CONFIG_SK98LIN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
 # CONFIG_PLIP is not set
 CONFIG_PPP=m
 # CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_FILTER is not set
 # CONFIG_PPP_ASYNC is not set
 # CONFIG_PPP_SYNC_TTY is not set
 # CONFIG_PPP_DEFLATE is not set
@@ -345,9 +257,7 @@
 #
 # Token Ring devices
 #
-# CONFIG_TR is not set
 # CONFIG_NET_FC is not set
-# CONFIG_RCPCI is not set
 # CONFIG_SHAPER is not set
 
 #
@@ -356,17 +266,17 @@
 # CONFIG_WAN is not set
 
 #
-# Amateur Radio support
+# IrDA (infrared) support
 #
-# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
 
 #
-# IrDA (infrared) support
+# Amateur Radio support
 #
-# CONFIG_IRDA is not set
+# CONFIG_HAMRADIO is not set
 
 #
-# ATA/IDE/MFM/RLL support
+# ATA/ATAPI/MFM/RLL support
 #
 CONFIG_IDE=y
 
@@ -378,31 +288,25 @@
 #
 # Please see Documentation/ide.txt for help/info on IDE drives
 #
-# CONFIG_BLK_DEV_HD_IDE is not set
 # CONFIG_BLK_DEV_HD is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_IDEDISK_MULTI_MODE=y
-# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_IDEDISK_STROKE is not set
 CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
 # CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL 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_IDEDMA=y
 CONFIG_BLK_DEV_IDE_ICSIDE=y
 CONFIG_BLK_DEV_IDEDMA_ICS=y
 CONFIG_IDEDMA_ICS_AUTO=y
-CONFIG_BLK_DEV_IDEDMA=y
 CONFIG_BLK_DEV_IDE_RAPIDE=y
-# CONFIG_IDE_CHIPSETS is not set
 CONFIG_IDEDMA_AUTO=y
 # CONFIG_IDEDMA_IVB is not set
-# CONFIG_BLK_DEV_IDE_MODES is not set
 
 #
 # SCSI support
@@ -413,7 +317,6 @@
 # SCSI support type (disk, tape, CD-ROM)
 #
 CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=8
 CONFIG_CHR_DEV_ST=m
 # CONFIG_CHR_DEV_OSST is not set
 CONFIG_BLK_DEV_SR=y
@@ -424,51 +327,37 @@
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
-CONFIG_SCSI_DEBUG_QUEUES=y
 # CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_REPORT_LUNS is not set
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
 
 #
 # SCSI low-level drivers
 #
-# CONFIG_SCSI_7000FASST is not set
 # CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
 # CONFIG_SCSI_AIC7XXX is not set
 # CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_DPT_I2O is not set
 # CONFIG_SCSI_ADVANSYS is not set
 # CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
 # CONFIG_SCSI_MEGARAID is not set
 # CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DMX3191D is not set
-# CONFIG_SCSI_DTC3280 is not set
 # CONFIG_SCSI_EATA is not set
 # CONFIG_SCSI_EATA_DMA is not set
 # CONFIG_SCSI_EATA_PIO is not set
 # CONFIG_SCSI_FUTURE_DOMAIN is not set
 # CONFIG_SCSI_GDTH is not set
 # CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
 CONFIG_SCSI_PPA=m
 CONFIG_SCSI_IMM=m
 # CONFIG_SCSI_IZIP_EPP16 is not set
 # CONFIG_SCSI_IZIP_SLOW_CTR is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_PAS16 is not set
 # CONFIG_SCSI_PCI2000 is not set
 # CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_SIM710 is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_T128 is not set
 # CONFIG_SCSI_U14_34F is not set
+# CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 CONFIG_SCSI_ACORNSCSI_3=m
 CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE=y
@@ -488,51 +377,85 @@
 # I2O device support
 #
 # CONFIG_I2O is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
 
 #
 # ISDN subsystem
 #
-# CONFIG_ISDN is not set
+# CONFIG_ISDN_BOOL is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
 
 #
-# Input core support
+# Userland interfaces
 #
-# CONFIG_INPUT is not set
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+# CONFIG_INPUT_TSLIBDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input I/O drivers
+#
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_CT82C710 is not set
+# CONFIG_SERIO_PARKBD is not set
+CONFIG_SERIO_RPCKBD=y
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+CONFIG_MOUSE_RISCPC=y
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Character devices
 #
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
-CONFIG_SERIAL=y
-CONFIG_SERIAL_CONSOLE=y
-CONFIG_ATOMWIDE_SERIAL=y
-CONFIG_DUALSP_SERIAL=y
-CONFIG_SERIAL_EXTENDED=y
-# CONFIG_SERIAL_MANY_PORTS is not set
-CONFIG_SERIAL_SHARE_IRQ=y
-# CONFIG_SERIAL_DETECT_IRQ is not set
-# CONFIG_SERIAL_MULTIPORT is not set
-# CONFIG_HUB6 is not set
+CONFIG_HW_CONSOLE=y
 # CONFIG_SERIAL_NONSTANDARD is not set
-# CONFIG_SERIAL_21285 is not set
-# CONFIG_SERIAL_21285_OLD is not set
-# CONFIG_SERIAL_21285_CONSOLE is not set
-# CONFIG_SERIAL_SA1100 is not set
-# CONFIG_SERIAL_SA1100_CONSOLE is not set
-# CONFIG_SERIAL_AMBA is not set
-# CONFIG_SERIAL_AMBA_CONSOLE is not set
-# CONFIG_SERIAL_CLPS711X is not set
-# CONFIG_SERIAL_CLPS711X_CONSOLE is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_8250_ACORN=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
 CONFIG_PRINTER=m
 # CONFIG_LP_CONSOLE is not set
 # CONFIG_PPDEV is not set
+# CONFIG_TIPAR is not set
 
 #
 # I2C support
@@ -542,38 +465,29 @@
 # CONFIG_I2C_PHILIPSPAR is not set
 # CONFIG_I2C_ELV is not set
 # CONFIG_I2C_VELLEMAN is not set
+# CONFIG_SCx200_ACB is not set
 # CONFIG_I2C_ALGOPCF is not set
 CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_PROC is not set
 
 #
-# Mice
+# L3 serial bus support
 #
-CONFIG_BUSMOUSE=y
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_LOGIBUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
-CONFIG_MOUSE=y
-# CONFIG_PSMOUSE is not set
-# CONFIG_82C710_MOUSE is not set
-# CONFIG_PC110_PAD is not set
+# CONFIG_L3 is not set
 
 #
-# Joysticks
-#
-# CONFIG_JOYSTICK is not set
-
-#
-# Input core support is needed for joysticks
+# Mice
 #
+# CONFIG_BUSMOUSE is not set
 # CONFIG_QIC02_TAPE is not set
 
 #
 # Watchdog Cards
 #
 # CONFIG_WATCHDOG is not set
-# CONFIG_INTEL_RNG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
+# CONFIG_GEN_RTC is not set
 # CONFIG_DTLK is not set
 # CONFIG_R3964 is not set
 # CONFIG_APPLICOM is not set
@@ -584,7 +498,7 @@
 # CONFIG_FTAPE is not set
 # CONFIG_AGP is not set
 # CONFIG_DRM is not set
-CONFIG_RPCMOUSE=y
+# CONFIG_RAW_DRIVER is not set
 
 #
 # Multimedia devices
@@ -598,73 +512,67 @@
 # CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=m
 # CONFIG_REISERFS_FS is not set
-# CONFIG_REISERFS_CHECK is not set
 CONFIG_ADFS_FS=y
 # CONFIG_ADFS_FS_RW is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
+# CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+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_RAMFS=y
 CONFIG_ISO9660_FS=y
 CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_JFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
 # 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
-# CONFIG_UFS_FS_WRITE is not set
+# CONFIG_XFS_FS is not set
 
 #
 # Network File Systems
 #
 # CONFIG_CODA_FS is not set
+# CONFIG_INTERMEZZO_FS is not set
 CONFIG_NFS_FS=y
 # CONFIG_NFS_V3 is not set
-# CONFIG_ROOT_NFS is not set
+# CONFIG_NFS_V4 is not set
 # CONFIG_NFSD is not set
-# CONFIG_NFSD_V3 is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
+# CONFIG_EXPORTFS is not set
+# CONFIG_CIFS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
+# CONFIG_AFS_FS is not set
+CONFIG_FS_MBCACHE=y
 
 #
 # Partition Types
 #
 CONFIG_PARTITION_ADVANCED=y
 CONFIG_ACORN_PARTITION=y
+# CONFIG_ACORN_PARTITION_CUMANA is not set
+# CONFIG_ACORN_PARTITION_EESOX is not set
 CONFIG_ACORN_PARTITION_ICS=y
 CONFIG_ACORN_PARTITION_ADFS=y
 CONFIG_ACORN_PARTITION_POWERTEC=y
@@ -678,10 +586,11 @@
 # CONFIG_MINIX_SUBPARTITION is not set
 CONFIG_SOLARIS_X86_PARTITION=y
 # CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
 CONFIG_SGI_PARTITION=y
 # CONFIG_ULTRIX_PARTITION is not set
 CONFIG_SUN_PARTITION=y
-# CONFIG_SMB_NLS is not set
+# CONFIG_EFI_PARTITION is not set
 CONFIG_NLS=y
 
 #
@@ -709,6 +618,7 @@
 # CONFIG_NLS_CODEPAGE_949 is not set
 CONFIG_NLS_CODEPAGE_874=m
 CONFIG_NLS_ISO8859_8=m
+# CONFIG_NLS_CODEPAGE_1250 is not set
 # CONFIG_NLS_CODEPAGE_1251 is not set
 CONFIG_NLS_ISO8859_1=m
 CONFIG_NLS_ISO8859_2=m
@@ -728,7 +638,6 @@
 #
 # Console drivers
 #
-CONFIG_FB=y
 
 #
 # Frame-buffer support
@@ -736,11 +645,6 @@
 CONFIG_FB=y
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FB_ACORN=y
-# CONFIG_FB_CLPS711X is not set
-# CONFIG_FB_CYBER2000 is not set
-# CONFIG_FB_SA1100 is not set
-# CONFIG_FB_ANAKIN is not set
-# CONFIG_FB_E1355 is not set
 # CONFIG_FB_VIRTUAL is not set
 CONFIG_FBCON_ADVANCED=y
 CONFIG_FBCON_MFB=y
@@ -750,44 +654,43 @@
 CONFIG_FBCON_CFB16=y
 CONFIG_FBCON_CFB24=y
 CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_ACCEL is not set
 # CONFIG_FBCON_AFB is not set
 # CONFIG_FBCON_ILBM is not set
 # CONFIG_FBCON_IPLAN2P2 is not set
 # CONFIG_FBCON_IPLAN2P4 is not set
 # CONFIG_FBCON_IPLAN2P8 is not set
-# CONFIG_FBCON_MAC is not set
 # CONFIG_FBCON_VGA_PLANES is not set
-# CONFIG_FBCON_VGA is not set
 # CONFIG_FBCON_HGA is not set
 # CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
 CONFIG_FBCON_FONTS=y
 # CONFIG_FONT_8x8 is not set
 # CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
 # CONFIG_FONT_6x11 is not set
 # CONFIG_FONT_PEARL_8x8 is not set
 CONFIG_FONT_ACORN_8x8=y
+# CONFIG_FONT_MINI_4x6 is not set
 
 #
 # Sound
 #
 CONFIG_SOUND=m
-# CONFIG_SOUND_CMPCI is not set
-# CONFIG_SOUND_EMU10K1 is not set
+
+#
+# Open Sound System
+#
+CONFIG_SOUND_PRIME=m
+# CONFIG_SOUND_BT878 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_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_SOUND_OSS=m
 # CONFIG_SOUND_TRACEINIT is not set
 # CONFIG_SOUND_DMAP is not set
@@ -805,7 +708,6 @@
 # CONFIG_SOUND_NM256 is not set
 # CONFIG_SOUND_MAD16 is not set
 # CONFIG_SOUND_PAS is not set
-# CONFIG_PAS_JOYSTICK is not set
 # CONFIG_SOUND_PSS is not set
 # CONFIG_SOUND_SB is not set
 # CONFIG_SOUND_AWE32_SYNTH is not set
@@ -814,28 +716,66 @@
 # CONFIG_SOUND_YM3812 is not set
 # CONFIG_SOUND_OPL3SA1 is not set
 # CONFIG_SOUND_OPL3SA2 is not set
-# CONFIG_SOUND_YMFPCI is not set
-# CONFIG_SOUND_YMFPCI_LEGACY is not set
 # CONFIG_SOUND_UART6850 is not set
 # CONFIG_SOUND_AEDSP16 is not set
 CONFIG_SOUND_VIDC=m
-# CONFIG_SOUND_WAVEARTIST is not set
 # CONFIG_SOUND_TVMIXER is not set
 
 #
+# Advanced Linux Sound Architecture
+#
+# CONFIG_SND is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+# CONFIG_MCP is not set
+
+#
+# Console Switches
+#
+# CONFIG_SWITCHES is not set
+
+#
 # USB support
 #
-# CONFIG_USB is not set
+
+#
+# Bluetooth support
+#
+# CONFIG_BT is not set
 
 #
 # Kernel hacking
 #
 CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_ERRORS=y
 CONFIG_DEBUG_USER=y
 # CONFIG_DEBUG_INFO is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SLAB is not set
 CONFIG_MAGIC_SYSRQ=y
-# CONFIG_NO_PGT_CACHE is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_KALLSYMS is not set
 CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_DC21285_PORT is not set
-# CONFIG_DEBUG_CLPS711X_UART2 is not set
+
+#
+# Security options
+#
+CONFIG_SECURITY_CAPABILITIES=y
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC32 is not set
diff -Nru a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
--- a/arch/arm/kernel/process.c	Sun Nov 10 19:28:41 2002
+++ b/arch/arm/kernel/process.c	Sun Nov 10 19:28:41 2002
@@ -391,12 +391,12 @@
  */
 pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 {
-	pid_t __ret;
+	register unsigned int r0 asm("r0") = flags | CLONE_VM | CLONE_UNTRACED;
+	register unsigned int r1 asm("r1") = 0;
+	register pid_t __ret asm("r0");
 
 	__asm__ __volatile__(
-	"orr	r0, %1, %2	@ kernel_thread sys_clone	\n\
-	mov	r1, #0						\n\
-	"__syscall(clone)"					\n\
+	__syscall(clone)"	@ kernel_thread sys_clone	\n\
 	movs	%0, r0		@ if we are the child		\n\
 	bne	1f						\n\
 	mov	fp, #0		@ ensure that fp is zero	\n\
@@ -406,8 +406,8 @@
 	b	sys_exit					\n\
 1:	"
         : "=r" (__ret)
-        : "Ir" (flags), "r" (CLONE_VM | CLONE_UNTRACED), "r" (fn), "r" (arg)
-	: "r0", "r1", "lr");
+        : "0" (r0), "r" (r1), "r" (fn), "r" (arg)
+	: "lr");
 	return __ret;
 }
 
diff -Nru a/arch/arm/mm/Makefile b/arch/arm/mm/Makefile
--- a/arch/arm/mm/Makefile	Sun Nov 10 19:28:41 2002
+++ b/arch/arm/mm/Makefile	Sun Nov 10 19:28:41 2002
@@ -34,7 +34,7 @@
 p-$(CONFIG_CPU_SA1100)	+= proc-sa110.o   tlb-v4wb.o copypage-v4mc.o abort-ev4.o   minicache.o
 
 # ARMv5
-p-$(CONFIG_CPU_ARM926T)	+= proc-arm926.o  tlb-v4wb.o copypage-v4wb.o abort-ev5ej.o
+p-$(CONFIG_CPU_ARM926T)	+= proc-arm926.o  tlb-v4wb.o copypage-v4wb.o abort-ev5tej.o
 p-$(CONFIG_CPU_XSCALE)	+= proc-xscale.o  tlb-v4wb.o copypage-xscale.o abort-xscale.o minicache.o
 
 obj-y		+= $(sort $(p-y))
diff -Nru a/arch/arm/vmlinux-armv.lds.in b/arch/arm/vmlinux-armv.lds.in
--- a/arch/arm/vmlinux-armv.lds.in	Sun Nov 10 19:28:38 2002
+++ b/arch/arm/vmlinux-armv.lds.in	Sun Nov 10 19:28:38 2002
@@ -37,7 +37,7 @@
 		__initcall_end = .;
 		. = ALIGN(32);
 		__initramfs_start = .;
-			*(.init.initramfs)
+			usr/built-in.o(.init.ramfs)
 		__initramfs_end = .;
 		. = ALIGN(4096);
 		__init_end = .;
diff -Nru a/arch/cris/drivers/ethernet.c b/arch/cris/drivers/ethernet.c
--- a/arch/cris/drivers/ethernet.c	Sun Nov 10 19:28:39 2002
+++ b/arch/cris/drivers/ethernet.c	Sun Nov 10 19:28:39 2002
@@ -234,8 +234,8 @@
 static unsigned int network_rec_config_shadow = 0;
 
 /* Network speed indication. */
-static struct timer_list speed_timer;
-static struct timer_list clear_led_timer;
+static struct timer_list speed_timer = TIMER_INITIALIZER(NULL, 0, 0);
+static struct timer_list clear_led_timer = TIMER_INITIALIZER(NULL, 0, 0);
 static int current_speed; /* Speed read from tranceiver */
 static int current_speed_selection; /* Speed selected by user */
 static int led_next_time;
diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig
--- a/arch/i386/Kconfig	Sun Nov 10 19:28:37 2002
+++ b/arch/i386/Kconfig	Sun Nov 10 19:28:37 2002
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 
 mainmenu "Linux Kernel Configuration"
@@ -337,7 +337,6 @@
 
 config X86_UP_APIC
 	bool "Local APIC support on uniprocessors" if !SMP
-	default y if SMP
 	---help---
 	  A local APIC (Advanced Programmable Interrupt Controller) is an
 	  integrated interrupt controller in the CPU. If you have a single-CPU
@@ -447,7 +446,7 @@
 	  the 386 and 486, so nearly everyone can say Y here.
 
 config X86_MCE_NONFATAL
-	bool "Check for non-fatal errors on Athlon/Duron"
+	bool "Check for non-fatal errors on AMD Athlon/Duron / Intel Pentium 4"
 	depends on X86_MCE
 	help
 	  Enabling this feature starts a timer that triggers every 5 seconds which
@@ -456,12 +455,12 @@
 	  Disable this if you don't want to see these messages.
 	  Seeing the messages this option prints out may be indicative of dying hardware,
 	  or out-of-spec (ie, overclocked) hardware.
-	  This option only does something on hardware with Intel P6 style MCE.
-	  (Pentium Pro and above, AMD Athlon/Duron)
+	  This option only does something on certain CPUs.
+	  (AMD Athlon/Duron and Intel Pentium 4)
 
 config X86_MCE_P4THERMAL
 	bool "check for P4 thermal throttling interrupt."
-	depends on X86_MCE && X86_UP_APIC
+	depends on X86_MCE && (X86_UP_APIC || SMP)
 	help
 	  Enabling this feature will cause a message to be printed when the P4
 	  enters thermal throttling.
diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile
--- a/arch/i386/Makefile	Sun Nov 10 19:28:39 2002
+++ b/arch/i386/Makefile	Sun Nov 10 19:28:39 2002
@@ -18,8 +18,8 @@
 
 LDFLAGS		:= -m elf_i386
 OBJCOPYFLAGS	:= -O binary -R .note -R .comment -S
-ARCHBLOBLFLAGS	:= -I binary -O elf32-i386 -B i386
 LDFLAGS_vmlinux := -e stext
+LDFLAGS_BLOB	:= --format binary --oformat elf32-i386
 
 CFLAGS += -pipe
 
@@ -42,7 +42,7 @@
 cflags-$(CONFIG_MWINCHIPC6)	+= $(call check_gcc,-march=winchip-c6,-march=i586)
 cflags-$(CONFIG_MWINCHIP2)	+= $(call check_gcc,-march=winchip2,-march=i586)
 cflags-$(CONFIG_MWINCHIP3D)	+= -march=i586
-cflags-$(CONFIG_MCYRIXIII)	+= $(call check_gcc,-march=c3,-march=i586)
+cflags-$(CONFIG_MCYRIXIII)	+= $(call check_gcc,-march=c3,-march=i486) -malign-functions=0 -malign-jumps=0 -malign-loops=0
 
 CFLAGS += $(cflags-y)
 
diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
--- a/arch/i386/kernel/Makefile	Sun Nov 10 19:28:37 2002
+++ b/arch/i386/kernel/Makefile	Sun Nov 10 19:28:37 2002
@@ -8,8 +8,7 @@
 
 obj-y	:= process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
 		ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
-		pci-dma.o i386_ksyms.o i387.o bluesmoke.o dmi_scan.o \
-		bootflag.o
+		pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o
 
 obj-y				+= cpu/
 obj-y				+= timers/
diff -Nru a/arch/i386/kernel/bluesmoke.c b/arch/i386/kernel/bluesmoke.c
--- a/arch/i386/kernel/bluesmoke.c	Sun Nov 10 19:28:38 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,504 +0,0 @@
-/*
- * arch/i386/kernel/bluesmoke.c - x86 Machine Check Exception Reporting
- */
-
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/jiffies.h>
-#include <linux/smp.h>
-#include <linux/config.h>
-#include <linux/irq.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-
-#include <asm/processor.h> 
-#include <asm/system.h>
-#include <asm/msr.h>
-#include <asm/apic.h>
-#include <asm/pgtable.h>
-#include <asm/tlbflush.h>
-#include <asm/hardirq.h>
-
-#ifdef CONFIG_X86_MCE
-
-/* as supported by the P4/Xeon family */
-struct intel_mce_extended_msrs {
-	u32 eax;
-	u32 ebx;
-	u32 ecx;
-	u32 edx;
-	u32 esi;
-	u32 edi;
-	u32 ebp;
-	u32 esp;
-	u32 eflags;
-	u32 eip;
-	/* u32 *reserved[]; */
-};
-
-static int mce_disabled __initdata = 0;
-
-static int mce_num_extended_msrs = 0;
-static int banks;
-
-
-#ifdef CONFIG_X86_MCE_P4THERMAL
-/*
- *	P4/Xeon Thermal transition interrupt handler
- */
-
-static void intel_thermal_interrupt(struct pt_regs *regs)
-{
-	u32 l, h;
-	unsigned int cpu = smp_processor_id();
-
-	ack_APIC_irq();
-
-	rdmsr(MSR_IA32_THERM_STATUS, l, h);
-	if (l & 1) {
-		printk(KERN_EMERG "CPU#%d: Temperature above threshold\n", cpu);
-		printk(KERN_EMERG "CPU#%d: Running in modulated clock mode\n", cpu);
-	} else {
-		printk(KERN_INFO "CPU#%d: Temperature/speed normal\n", cpu);
-	}
-}
-
-static void unexpected_thermal_interrupt(struct pt_regs *regs)
-{	
-	printk(KERN_ERR "CPU#%d: Unexpected LVT TMR interrupt!\n", smp_processor_id());
-}
-
-/*
- *	Thermal interrupt handler for this CPU setup
- */
-
-static void (*vendor_thermal_interrupt)(struct pt_regs *regs) = unexpected_thermal_interrupt;
-
-asmlinkage void smp_thermal_interrupt(struct pt_regs regs)
-{
-	irq_enter();
-	vendor_thermal_interrupt(&regs);
-	irq_exit();
-}
-
-/* P4/Xeon Thermal regulation detect and init */
-
-static void __init intel_init_thermal(struct cpuinfo_x86 *c)
-{
-	u32 l, h;
-	unsigned int cpu = smp_processor_id();
-
-	/* Thermal monitoring */
-	if (!cpu_has(c, X86_FEATURE_ACPI))
-		return;	/* -ENODEV */
-
-	/* Clock modulation */
-	if (!cpu_has(c, X86_FEATURE_ACC))
-		return;	/* -ENODEV */
-
-	/* first check if its enabled already, in which case there might
-	 * be some SMM goo which handles it, so we can't even put a handler
-	 * since it might be delivered via SMI already -zwanem.
-	 */
-	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
-	h = apic_read(APIC_LVTTHMR);
-	if ((l & (1<<3)) && (h & APIC_DM_SMI)) {
-		printk(KERN_DEBUG "CPU#%d: Thermal monitoring handled by SMI\n", cpu);
-		return; /* -EBUSY */
-	}
-
-	/* check whether a vector already exists, temporarily masked? */	
-	if (h & APIC_VECTOR_MASK) {
-		printk(KERN_DEBUG "CPU#%d: Thermal LVT vector (%#x) already installed\n",
-			cpu, (h & APIC_VECTOR_MASK));
-		return; /* -EBUSY */
-	}
-
-	/* The temperature transition interrupt handler setup */
-	h = THERMAL_APIC_VECTOR;		/* our delivery vector */
-	h |= (APIC_DM_FIXED | APIC_LVT_MASKED);	/* we'll mask till we're ready */
-	apic_write_around(APIC_LVTTHMR, h);
-
-	rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
-	wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03 , h);
-
-	/* ok we're good to go... */
-	vendor_thermal_interrupt = intel_thermal_interrupt;
-	
-	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
-	wrmsr(MSR_IA32_MISC_ENABLE, l | (1<<3), h);
-	
-	l = apic_read(APIC_LVTTHMR);
-	apic_write_around(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
-	printk(KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu);
-	return;
-}
-#endif /* CONFIG_X86_MCE_P4THERMAL */
-
-
-/* P4/Xeon Extended MCE MSR retrieval, return 0 if unsupported */
-
-static int inline intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
-{
-	u32 h;
-
-	if (mce_num_extended_msrs == 0)
-		goto done;
-
-	rdmsr(MSR_IA32_MCG_EAX, r->eax, h);
-	rdmsr(MSR_IA32_MCG_EBX, r->ebx, h);
-	rdmsr(MSR_IA32_MCG_ECX, r->ecx, h);
-	rdmsr(MSR_IA32_MCG_EDX, r->edx, h);
-	rdmsr(MSR_IA32_MCG_ESI, r->esi, h);
-	rdmsr(MSR_IA32_MCG_EDI, r->edi, h);
-	rdmsr(MSR_IA32_MCG_EBP, r->ebp, h);
-	rdmsr(MSR_IA32_MCG_ESP, r->esp, h);
-	rdmsr(MSR_IA32_MCG_EFLAGS, r->eflags, h);
-	rdmsr(MSR_IA32_MCG_EIP, r->eip, h);
-
-	/* can we rely on kmalloc to do a dynamic
-	 * allocation for the reserved registers?
-	 */
-done:
-	return mce_num_extended_msrs;
-}
-
-/*
- *	Machine Check Handler For PII/PIII
- */
-
-static void intel_machine_check(struct pt_regs * regs, long error_code)
-{
-	int recover=1;
-	u32 alow, ahigh, high, low;
-	u32 mcgstl, mcgsth;
-	int i;
-	struct intel_mce_extended_msrs dbg;
-
-	rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
-	if(mcgstl&(1<<0))	/* Recoverable ? */
-		recover=0;
-
-	printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl);
-
-	if (intel_get_extended_msrs(&dbg)) {
-		printk(KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n",
-			smp_processor_id(), dbg.eip, dbg.eflags);
-		printk(KERN_DEBUG "\teax: %08x ebx: %08x ecx: %08x edx: %08x\n",
-			dbg.eax, dbg.ebx, dbg.ecx, dbg.edx);
-		printk(KERN_DEBUG "\tesi: %08x edi: %08x ebp: %08x esp: %08x\n",
-			dbg.esi, dbg.edi, dbg.ebp, dbg.esp);
-	}
-
-	for (i=0;i<banks;i++) {
-		rdmsr(MSR_IA32_MC0_STATUS+i*4,low, high);
-		if(high&(1<<31)) {
-			if(high&(1<<29))
-				recover|=1;
-			if(high&(1<<25))
-				recover|=2;
-			printk(KERN_EMERG "Bank %d: %08x%08x", i, high, low);
-			high&=~(1<<31);
-			if(high&(1<<27)) {
-				rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh);
-				printk("[%08x%08x]", ahigh, alow);
-			}
-			if(high&(1<<26)) {
-				rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
-				printk(" at %08x%08x", ahigh, alow);
-			}
-			printk("\n");
-			/* Clear it */
-			wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
-			/* Serialize */
-			wmb();
-		}
-	}
-
-	if(recover&2)
-		panic("CPU context corrupt");
-	if(recover&1)
-		panic("Unable to continue");
-	printk(KERN_EMERG "Attempting to continue.\n");
-	mcgstl&=~(1<<2);
-	wrmsr(MSR_IA32_MCG_STATUS,mcgstl, mcgsth);
-}
-
-/*
- *	Machine check handler for Pentium class Intel
- */
-
-static void pentium_machine_check(struct pt_regs * regs, long error_code)
-{
-	u32 loaddr, hi, lotype;
-	rdmsr(MSR_IA32_P5_MC_ADDR, loaddr, hi);
-	rdmsr(MSR_IA32_P5_MC_TYPE, lotype, hi);
-	printk(KERN_EMERG "CPU#%d: Machine Check Exception:  0x%8X (type 0x%8X).\n", smp_processor_id(), loaddr, lotype);
-	if(lotype&(1<<5))
-		printk(KERN_EMERG "CPU#%d: Possible thermal failure (CPU on fire ?).\n", smp_processor_id());
-}
-
-/*
- *	Machine check handler for WinChip C6
- */
-
-static void winchip_machine_check(struct pt_regs * regs, long error_code)
-{
-	printk(KERN_EMERG "CPU#%d: Machine Check Exception.\n", smp_processor_id());
-}
-
-/*
- *	Handle unconfigured int18 (should never happen)
- */
-
-static void unexpected_machine_check(struct pt_regs * regs, long error_code)
-{	
-	printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id());
-}
-
-/*
- *	Call the installed machine check handler for this CPU setup.
- */
-
-static void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
-
-asmlinkage void do_machine_check(struct pt_regs * regs, long error_code)
-{
-	machine_check_vector(regs, error_code);
-}
-
-
-#ifdef CONFIG_X86_MCE_NONFATAL
-static struct timer_list mce_timer;
-static int timerset = 0;
-
-#define MCE_RATE	15*HZ	/* timer rate is 15s */
-
-static void mce_checkregs (void *info)
-{
-	u32 low, high;
-	int i;
-
-	preempt_disable(); 
-	for (i=0; i<banks; i++) {
-		rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high);
-
-		if ((low | high) != 0) {
-			printk (KERN_EMERG "MCE: The hardware reports a non fatal, correctable incident occured on CPU %d.\n", smp_processor_id());
-			printk (KERN_EMERG "Bank %d: %08x%08x\n", i, high, low);
-
-			/* Scrub the error so we don't pick it up in MCE_RATE seconds time. */
-			wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
-
-			/* Serialize */
-			wmb();
-		}
-	}
-	preempt_enable();
-}
-
-static void do_mce_timer(void *data)
-{ 
-	smp_call_function (mce_checkregs, NULL, 1, 1);
-} 
-
-static DECLARE_WORK(mce_work, do_mce_timer, NULL);
-
-static void mce_timerfunc (unsigned long data)
-{
-#ifdef CONFIG_SMP
-	if (num_online_cpus() > 1) 
-		schedule_work(&mce_work); 
-#else
-	mce_checkregs(NULL);
-#endif
-	mce_timer.expires = jiffies + MCE_RATE;
-	add_timer (&mce_timer);
-}	
-#endif
-
-
-/*
- *	Set up machine check reporting for processors with Intel style MCE
- */
-
-static void __init intel_mcheck_init(struct cpuinfo_x86 *c)
-{
-	u32 l, h;
-	int i;
-	static int done;
-	
-	/*
-	 *	Check for MCE support
-	 */
-
-	if( !cpu_has(c, X86_FEATURE_MCE) )
-		return;	
-
-	/*
-	 *	Pentium machine check
-	 */
-
-	if(c->x86 == 5)
-	{
-		/* Default P5 to off as its often misconnected */
-		if(mce_disabled != -1)
-			return;
-		machine_check_vector = pentium_machine_check;
-		wmb();
-		/* Read registers before enabling */
-		rdmsr(MSR_IA32_P5_MC_ADDR, l, h);
-		rdmsr(MSR_IA32_P5_MC_TYPE, l, h);
-		if(done==0)
-			printk(KERN_INFO "Intel old style machine check architecture supported.\n");
- 		/* Enable MCE */
-		set_in_cr4(X86_CR4_MCE);
-		printk(KERN_INFO "Intel old style machine check reporting enabled on CPU#%d.\n", smp_processor_id());
-		return;
-	}
-
-
-	/*
-	 *	Check for PPro style MCA
-	 */
- 		
-	if( !cpu_has(c, X86_FEATURE_MCA) )
-		return;
-
-	/* Ok machine check is available */
-
-	machine_check_vector = intel_machine_check;
-	wmb();
-
-	if(done==0)
-		printk(KERN_INFO "Intel machine check architecture supported.\n");
-	rdmsr(MSR_IA32_MCG_CAP, l, h);
-	if(l&(1<<8))	/* Control register present ? */
-		wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
-	banks = l&0xff;
-
-	/* Don't enable bank 0 on intel P6 cores, it goes bang quickly. */
-	if (c->x86_vendor == X86_VENDOR_INTEL && c->x86 == 6) {
-		for(i=1; i<banks; i++)
-			wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
-	} else {
-		for(i=0; i<banks; i++)
-			wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
-	}
-
-	for(i=0; i<banks; i++)
-		wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
-
-	set_in_cr4(X86_CR4_MCE);
-	printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id());
-
-	/*
-	 *	Check for P4/Xeon specific MCE extensions
-	 */
-
-	if (c->x86_vendor == X86_VENDOR_INTEL && c->x86 == 15) {
-		/* Check for P4/Xeon extended MCE MSRs */
-		rdmsr(MSR_IA32_MCG_CAP, l, h);
-		if (l & (1<<9))	{/* MCG_EXT_P */
-			mce_num_extended_msrs = (l >> 16) & 0xff;
-			printk(KERN_INFO "CPU#%d: Intel P4/Xeon Extended MCE MSRs (%d) available\n",
-				smp_processor_id(), mce_num_extended_msrs);
-		}
-		
-#ifdef CONFIG_X86_MCE_P4THERMAL
-		/* Check for P4/Xeon Thermal monitor */
-		intel_init_thermal(c);
-#endif
-	}
-
-	done=1;
-}
-
-/*
- *	Set up machine check reporting on the Winchip C6 series
- */
-
-static void __init winchip_mcheck_init(struct cpuinfo_x86 *c)
-{
-	u32 lo, hi;
-	/* Not supported on C3 */
-	if(c->x86 != 5)
-		return;
-	/* Winchip C6 */
-	machine_check_vector = winchip_machine_check;
-	wmb();
-	rdmsr(MSR_IDT_FCR1, lo, hi);
-	lo|= (1<<2);	/* Enable EIERRINT (int 18 MCE) */
-	lo&= ~(1<<4);	/* Enable MCE */
-	wrmsr(MSR_IDT_FCR1, lo, hi);
-	set_in_cr4(X86_CR4_MCE);
-	printk(KERN_INFO "Winchip machine check reporting enabled on CPU#%d.\n", smp_processor_id());
-}
-
-
-/*
- *	This has to be run for each processor
- */
-
-void __init mcheck_init(struct cpuinfo_x86 *c)
-{
-
-	if(mce_disabled==1)
-		return;
-
-	switch(c->x86_vendor)
-	{
-		case X86_VENDOR_AMD:
-			/* AMD K7 machine check is Intel like */
-			if(c->x86 == 6 || c->x86 == 15) {
-				intel_mcheck_init(c);
-#ifdef CONFIG_X86_MCE_NONFATAL
-				if (timerset == 0) {
-					/* Set the timer to check for non-fatal
-					   errors every MCE_RATE seconds */
-					init_timer (&mce_timer);
-					mce_timer.expires = jiffies + MCE_RATE;
-					mce_timer.data = 0;
-					mce_timer.function = &mce_timerfunc;
-					add_timer (&mce_timer);
-					timerset = 1;
-					printk(KERN_INFO "Machine check exception polling timer started.\n");
-				}
-#endif
-			}
-			break;
-
-		case X86_VENDOR_INTEL:
-			intel_mcheck_init(c);
-			break;
-
-		case X86_VENDOR_CENTAUR:
-			winchip_mcheck_init(c);
-			break;
-
-		default:
-			break;
-	}
-}
-
-static int __init mcheck_disable(char *str)
-{
-	mce_disabled = 1;
-	return 0;
-}
-
-static int __init mcheck_enable(char *str)
-{
-	mce_disabled = -1;
-	return 0;
-}
-
-__setup("nomce", mcheck_disable);
-__setup("mce", mcheck_enable);
-
-#else
-asmlinkage void do_machine_check(struct pt_regs * regs, long error_code) {}
-asmlinkage void smp_thermal_interrupt(struct pt_regs regs) {}
-void __init mcheck_init(struct cpuinfo_x86 *c) {}
-#endif
diff -Nru a/arch/i386/kernel/cpu/Makefile b/arch/i386/kernel/cpu/Makefile
--- a/arch/i386/kernel/cpu/Makefile	Sun Nov 10 19:28:40 2002
+++ b/arch/i386/kernel/cpu/Makefile	Sun Nov 10 19:28:40 2002
@@ -13,7 +13,10 @@
 obj-y	+=	nexgen.o
 obj-y	+=	umc.o
 
+obj-$(CONFIG_X86_MCE)	+=	mcheck/
+
 obj-$(CONFIG_MTRR)	+= 	mtrr/
 obj-$(CONFIG_CPU_FREQ)	+=	cpufreq/
+
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/i386/kernel/cpu/centaur.c b/arch/i386/kernel/cpu/centaur.c
--- a/arch/i386/kernel/cpu/centaur.c	Sun Nov 10 19:28:40 2002
+++ b/arch/i386/kernel/cpu/centaur.c	Sun Nov 10 19:28:40 2002
@@ -3,6 +3,7 @@
 #include <linux/bitops.h>
 #include <asm/processor.h>
 #include <asm/msr.h>
+#include <asm/e820.h>
 #include "cpu.h"
 
 #ifdef CONFIG_X86_OOSTORE
diff -Nru a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
--- a/arch/i386/kernel/cpu/common.c	Sun Nov 10 19:28:36 2002
+++ b/arch/i386/kernel/cpu/common.c	Sun Nov 10 19:28:36 2002
@@ -358,7 +358,9 @@
 	       boot_cpu_data.x86_capability[3]);
 
 	/* Init Machine Check Exception if available. */
+#ifdef CONFIG_X86_MCE
 	mcheck_init(c);
+#endif
 }
 /*
  *	Perform early boot up checks for a valid TSC. See arch/i386/kernel/time.c
diff -Nru a/arch/i386/kernel/cpu/cpufreq/speedstep.c b/arch/i386/kernel/cpu/cpufreq/speedstep.c
--- a/arch/i386/kernel/cpu/cpufreq/speedstep.c	Sun Nov 10 19:28:36 2002
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep.c	Sun Nov 10 19:28:36 2002
@@ -1,5 +1,5 @@
 /*
- *  $Id: speedstep.c,v 1.53 2002/09/29 23:43:11 db Exp $
+ *  $Id: speedstep.c,v 1.57 2002/11/05 12:01:12 db Exp $
  *
  * (C) 2001  Dave Jones, Arjan van de ven.
  * (C) 2002  Dominik Brodowski <linux@brodo.de>
@@ -46,7 +46,8 @@
 
 /* speedstep_processor
  */
-static unsigned int                     speedstep_processor;
+static unsigned int                     speedstep_processor = 0;
+static int                              speedstep_coppermine = 0;
 
 #define SPEEDSTEP_PROCESSOR_PIII_C      0x00000001  /* Coppermine core */
 #define SPEEDSTEP_PROCESSOR_PIII_T      0x00000002  /* Tualatin core */
@@ -72,7 +73,7 @@
 #ifdef SPEEDSTEP_DEBUG
 #define dprintk(msg...) printk(msg)
 #else
-#define dprintk(msg...) do { } while(0);
+#define dprintk(msg...) do { } while(0)
 #endif
 
 
@@ -429,7 +430,7 @@
 /** 
  * speedstep_detect_processor - detect Intel SpeedStep-capable processors.
  *
- *   Returns the SPEEDSTEP_PROCESSOR_-number for the detected chipset, 
+ *   Returns the SPEEDSTEP_PROCESSOR_-number for the detected processor, 
  * or zero on failure.
  */
 static unsigned int speedstep_detect_processor (void)
@@ -474,8 +475,6 @@
 		return SPEEDSTEP_PROCESSOR_PIII_T;
 
 	case 0x08: /* Intel PIII [Coppermine] */
-		/* based on reverse-engineering information and
-		 * some guessing. HANDLE WITH CARE! */
  	        {
 			u32     msr_lo, msr_hi;
 
@@ -487,21 +486,13 @@
 			if (msr_lo != 0x0080000)
 				return 0;
 
-			/* platform ID seems to be 0x00140000 */
-			rdmsr(MSR_IA32_PLATFORM_ID, msr_lo, msr_hi);
-			dprintk(KERN_DEBUG "cpufreq: Coppermine: MSR_IA32_PLATFORM ID is 0x%x, 0x%x\n", msr_lo, msr_hi);
-			msr_hi = msr_lo & 0x001c0000;
-			if (msr_hi != 0x00140000)
-				return 0;
-
-			/* and these bits seem to be either 00_b, 01_b or
-			 * 10_b but never 11_b */
-			msr_lo &= 0x00030000;
-			if (msr_lo == 0x0030000)
-				return 0;
+			if (speedstep_coppermine)
+				return SPEEDSTEP_PROCESSOR_PIII_C;
 
-			/* let's hope this is correct... */
-			return SPEEDSTEP_PROCESSOR_PIII_C;
+			printk(KERN_INFO "cpufreq: in case this is a SpeedStep-capable Intel Pentium III Coppermine\n");
+			printk(KERN_INFO "cpufreq: processor, please pass the boot option or module parameter\n");
+			printk(KERN_INFO "cpufreq: `speedstep_coppermine=1` to the kernel. Thanks!\n");
+			return 0;
 		}
 
 	default:
@@ -622,6 +613,25 @@
 }
 
 
+#ifndef MODULE
+/**
+ * speedstep_setup  speedstep command line parameter parsing
+ *
+ * speedstep command line parameter.  Use:
+ *  speedstep_coppermine=1
+ * if the CPU in your notebook is a SpeedStep-capable Intel
+ * Pentium III Coppermine. These processors cannot be detected
+ * automatically, as Intel continues to consider the detection 
+ * alogrithm as proprietary material.
+ */
+static int __init speedstep_setup(char *str)
+{
+	speedstep_coppermine = simple_strtoul(str, &str, 0);
+	return 1;
+}
+__setup("speedstep_coppermine=", speedstep_setup);
+#endif
+
 /**
  * speedstep_init - initializes the SpeedStep CPUFreq driver
  *
@@ -637,18 +647,19 @@
 
 
 	/* detect chipset */
-	speedstep_chipset = speedstep_detect_chipset();
+	speedstep_chipset = speedstep_detect_chipset(); 
 
 	/* detect chipset */
 	if (speedstep_chipset)
 		speedstep_processor = speedstep_detect_processor();
 
 	if ((!speedstep_chipset) || (!speedstep_processor)) {
-		dprintk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) for this %s not (yet) available.\n", speedstep_processor ? "chipset" : "processor");
+		printk(KERN_INFO "a 0x%x b 0x%x\n", speedstep_processor, speedstep_chipset);
+		printk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) for this %s not (yet) available.\n", speedstep_chipset ? "processor" : "chipset");
 		return -ENODEV;
 	}
 
-	dprintk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) support $Revision: 1.53 $\n");
+	dprintk(KERN_INFO "cpufreq: Intel(R) SpeedStep(TM) support $Revision: 1.57 $\n");
 	dprintk(KERN_DEBUG "cpufreq: chipset 0x%x - processor 0x%x\n", 
 	       speedstep_chipset, speedstep_processor);
 
@@ -726,3 +737,5 @@
 MODULE_LICENSE ("GPL");
 module_init(speedstep_init);
 module_exit(speedstep_exit);
+
+MODULE_PARM (speedstep_coppermine, "i");
diff -Nru a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
--- a/arch/i386/kernel/cpu/cyrix.c	Sun Nov 10 19:28:37 2002
+++ b/arch/i386/kernel/cpu/cyrix.c	Sun Nov 10 19:28:37 2002
@@ -5,6 +5,7 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/processor.h>
+#include <asm/timer.h>
 
 #include "cpu.h"
 
@@ -170,7 +171,7 @@
 		c->coma_bug = 1;
 		break;
 
-	case 4: /* MediaGX/GXm */
+	case 4: /* MediaGX/GXm or Geode GXM/GXLV/GX1 */
 #ifdef CONFIG_PCI
 		/* It isn't really a PCI quirk directly, but the cure is the
 		   same. The MediaGX has deep magic SMM stuff that handles the
@@ -188,29 +189,26 @@
 		isa_dma_bridge_buggy = 2;
 #endif		
 		c->x86_cache_size=16;	/* Yep 16K integrated cache thats it */
+ 
+		/*
+		 *  The 5510/5520 companion chips have a funky PIT.
+		 */  
+		if (pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) ||
+		    pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL))
+			pit_latch_buggy = 1;
 
 		/* GXm supports extended cpuid levels 'ala' AMD */
 		if (c->cpuid_level == 2) {
-			/* Enable Natsemi MMX extensions */
-			setCx86(CX86_CCR7, getCx86(CX86_CCR7) | 1);
+			/* Enable cxMMX extensions (GX1 Datasheet 54) */
+			setCx86(CX86_CCR7, getCx86(CX86_CCR7)|1);
 
 			get_model_name(c);  /* get CPU marketing name */
-			/*
-			 *  The 5510/5520 companion chips have a funky PIT
-			 *  that breaks the TSC synchronizing, so turn it off
-			 */
-			if (pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5510, NULL) ||
-				pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5520, NULL))
-				clear_bit(X86_FEATURE_TSC, c->x86_capability);
 			return;
 		}
 		else {  /* MediaGX */
 			Cx86_cb[2] = (dir0_lsn & 1) ? '3' : '4';
 			p = Cx86_cb+2;
 			c->x86_model = (dir1 & 0x20) ? 1 : 2;
-#ifndef CONFIG_CS5520
-			clear_bit(X86_FEATURE_TSC, c->x86_capability);
-#endif
 		}
 		break;
 
diff -Nru a/arch/i386/kernel/cpu/mcheck/Makefile b/arch/i386/kernel/cpu/mcheck/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mcheck/Makefile	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,5 @@
+obj-y	=	mce.o k7.o p4.o p5.o p6.o winchip.o
+obj-$(CONFIG_X86_MCE_NONFATAL)	+=	non-fatal.o
+
+include $(TOPDIR)/Rules.make
+
diff -Nru a/arch/i386/kernel/cpu/mcheck/k7.c b/arch/i386/kernel/cpu/mcheck/k7.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mcheck/k7.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,96 @@
+/*
+ * Athlon specific Machine Check Exception Reporting
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+
+#include <asm/processor.h> 
+#include <asm/system.h>
+#include <asm/msr.h>
+
+#include "mce.h"
+
+/* Machine Check Handler For AMD Athlon/Duron */
+static void k7_machine_check(struct pt_regs * regs, long error_code)
+{
+	int recover=1;
+	u32 alow, ahigh, high, low;
+	u32 mcgstl, mcgsth;
+	int i;
+
+	rdmsr (MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
+	if (mcgstl & (1<<0))	/* Recoverable ? */
+		recover=0;
+
+	printk (KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n",
+		smp_processor_id(), mcgsth, mcgstl);
+
+	for (i=0; i<nr_mce_banks; i++) {
+		rdmsr (MSR_IA32_MC0_STATUS+i*4,low, high);
+		if (high&(1<<31)) {
+			if (high & (1<<29))
+				recover |= 1;
+			if (high & (1<<25))
+				recover |= 2;
+			printk (KERN_EMERG "Bank %d: %08x%08x", i, high, low);
+			high &= ~(1<<31);
+			if (high & (1<<27)) {
+				rdmsr (MSR_IA32_MC0_MISC+i*4, alow, ahigh);
+				printk ("[%08x%08x]", ahigh, alow);
+			}
+			if (high & (1<<26)) {
+				rdmsr (MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
+				printk (" at %08x%08x", ahigh, alow);
+			}
+			printk ("\n");
+			/* Clear it */
+			wrmsr (MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
+			/* Serialize */
+			wmb();
+		}
+	}
+
+	if (recover&2)
+		panic ("CPU context corrupt");
+	if (recover&1)
+		panic ("Unable to continue");
+	printk (KERN_EMERG "Attempting to continue.\n");
+	mcgstl &= ~(1<<2);
+	wrmsr (MSR_IA32_MCG_STATUS,mcgstl, mcgsth);
+}
+
+
+/* AMD K7 machine check is Intel like */
+void __init amd_mcheck_init(struct cpuinfo_x86 *c)
+{
+	u32 l, h;
+	int i;
+
+	machine_check_vector = k7_machine_check;
+	wmb();
+
+	printk (KERN_INFO "Intel machine check architecture supported.\n");
+	rdmsr (MSR_IA32_MCG_CAP, l, h);
+	if (l & (1<<8))	/* Control register present ? */
+		wrmsr (MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
+	nr_mce_banks = l & 0xff;
+
+	for (i=0; i<nr_mce_banks; i++) {
+		wrmsr (MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
+		wrmsr (MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
+	}
+
+	set_in_cr4 (X86_CR4_MCE);
+	printk (KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n",
+		smp_processor_id());
+
+#ifdef CONFIG_X86_MCE_NONFATAL
+	init_nonfatal_mce_checker();
+#endif
+}
diff -Nru a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mcheck/mce.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,77 @@
+/*
+ * mce.c - x86 Machine Check Exception Reporting
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/smp.h>
+#include <asm/processor.h> 
+#include <asm/system.h>
+#include <asm/thread_info.h>
+
+#include "mce.h"
+
+int mce_disabled __initdata = 0;
+int nr_mce_banks;
+
+/* Handle unconfigured int18 (should never happen) */
+static void unexpected_machine_check(struct pt_regs * regs, long error_code)
+{	
+	printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id());
+}
+
+/* Call the installed machine check handler for this CPU setup. */
+void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
+
+asmlinkage void do_machine_check(struct pt_regs * regs, long error_code)
+{
+	machine_check_vector(regs, error_code);
+}
+
+/* This has to be run for each processor */
+void __init mcheck_init(struct cpuinfo_x86 *c)
+{
+	if (mce_disabled==1)
+		return;
+
+	switch (c->x86_vendor) {
+		case X86_VENDOR_AMD:
+			if (c->x86==6 || c->x86==15)
+				amd_mcheck_init(c);
+			break;
+
+		case X86_VENDOR_INTEL:
+			if (c->x86==5)
+				intel_p5_mcheck_init(c);
+			if (c->x86==6)
+				intel_p6_mcheck_init(c);
+			if (c->x86==15)
+				intel_p4_mcheck_init(c);
+			break;
+
+		case X86_VENDOR_CENTAUR:
+			if (c->x86==5)
+				winchip_mcheck_init(c);
+			break;
+
+		default:
+			break;
+	}
+}
+
+static int __init mcheck_disable(char *str)
+{
+	mce_disabled = 1;
+	return 0;
+}
+
+static int __init mcheck_enable(char *str)
+{
+	mce_disabled = -1;
+	return 0;
+}
+
+__setup("nomce", mcheck_disable);
+__setup("mce", mcheck_enable);
diff -Nru a/arch/i386/kernel/cpu/mcheck/mce.h b/arch/i386/kernel/cpu/mcheck/mce.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mcheck/mce.h	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,16 @@
+#include <linux/init.h>
+
+void amd_mcheck_init(struct cpuinfo_x86 *c);
+void intel_p4_mcheck_init(struct cpuinfo_x86 *c);
+void intel_p5_mcheck_init(struct cpuinfo_x86 *c);
+void intel_p6_mcheck_init(struct cpuinfo_x86 *c);
+void winchip_mcheck_init(struct cpuinfo_x86 *c);
+
+void init_nonfatal_mce_checker(void);
+
+/* Call the installed machine check handler for this CPU setup. */
+extern void (*machine_check_vector)(struct pt_regs *, long error_code);
+
+extern int mce_disabled __initdata;
+extern int nr_mce_banks;
+
diff -Nru a/arch/i386/kernel/cpu/mcheck/non-fatal.c b/arch/i386/kernel/cpu/mcheck/non-fatal.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mcheck/non-fatal.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,83 @@
+/*
+ * P4 specific Machine Check Exception Reporting
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/config.h>
+#include <linux/irq.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+
+#include <asm/processor.h> 
+#include <asm/system.h>
+#include <asm/msr.h>
+
+#include "mce.h"
+
+static struct timer_list mce_timer;
+static int timerset;
+
+#define MCE_RATE	15*HZ	/* timer rate is 15s */
+
+static void mce_checkregs (void *info)
+{
+	u32 low, high;
+	int i;
+
+	preempt_disable(); 
+	for (i=0; i<nr_mce_banks; i++) {
+		rdmsr (MSR_IA32_MC0_STATUS+i*4, low, high);
+
+		if (high & (1<<31)) {
+			printk (KERN_EMERG "MCE: The hardware reports a non fatal, correctable incident occured on CPU %d.\n",
+				smp_processor_id());
+			printk (KERN_EMERG "Bank %d: %08x%08x\n", i, high, low);
+
+			/* Scrub the error so we don't pick it up in MCE_RATE seconds time. */
+			wrmsr (MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
+
+			/* Serialize */
+			wmb();
+		}
+	}
+	preempt_enable();
+}
+
+static void do_mce_timer(void *data)
+{ 
+	mce_checkregs (NULL);
+	smp_call_function (mce_checkregs, NULL, 1, 1);
+} 
+
+static DECLARE_WORK(mce_work, do_mce_timer, NULL);
+
+static void mce_timerfunc (unsigned long data)
+{
+#ifdef CONFIG_SMP
+	if (num_online_cpus() > 1) 
+		schedule_work (&mce_work); 
+#else
+	mce_checkregs (NULL);
+#endif
+	mce_timer.expires = jiffies + MCE_RATE;
+	add_timer (&mce_timer);
+}	
+
+void init_nonfatal_mce_checker()
+{
+	if (timerset == 0) {
+		/* Set the timer to check for non-fatal
+		   errors every MCE_RATE seconds */
+		init_timer (&mce_timer);
+		mce_timer.expires = jiffies + MCE_RATE;
+		mce_timer.data = 0;
+		mce_timer.function = &mce_timerfunc;
+		add_timer (&mce_timer);
+		timerset = 1;
+		printk(KERN_INFO "Machine check exception polling timer started.\n");
+	}
+}
diff -Nru a/arch/i386/kernel/cpu/mcheck/p4.c b/arch/i386/kernel/cpu/mcheck/p4.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mcheck/p4.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,261 @@
+/*
+ * P4 specific Machine Check Exception Reporting
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/config.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+
+#include <asm/processor.h> 
+#include <asm/system.h>
+#include <asm/msr.h>
+#include <asm/apic.h>
+
+#include "mce.h"
+
+/* as supported by the P4/Xeon family */
+struct intel_mce_extended_msrs {
+	u32 eax;
+	u32 ebx;
+	u32 ecx;
+	u32 edx;
+	u32 esi;
+	u32 edi;
+	u32 ebp;
+	u32 esp;
+	u32 eflags;
+	u32 eip;
+	/* u32 *reserved[]; */
+};
+
+static int mce_num_extended_msrs = 0;
+
+
+#ifdef CONFIG_X86_MCE_P4THERMAL
+static void unexpected_thermal_interrupt(struct pt_regs *regs)
+{	
+	printk(KERN_ERR "CPU#%d: Unexpected LVT TMR interrupt!\n", smp_processor_id());
+}
+
+/* P4/Xeon Thermal transition interrupt handler */
+static void intel_thermal_interrupt(struct pt_regs *regs)
+{
+	u32 l, h;
+	unsigned int cpu = smp_processor_id();
+
+	ack_APIC_irq();
+
+	rdmsr (MSR_IA32_THERM_STATUS, l, h);
+	if (l & 1) {
+		printk(KERN_EMERG "CPU#%d: Temperature above threshold\n", cpu);
+		printk(KERN_EMERG "CPU#%d: Running in modulated clock mode\n", cpu);
+	} else {
+		printk(KERN_INFO "CPU#%d: Temperature/speed normal\n", cpu);
+	}
+}
+
+/* Thermal interrupt handler for this CPU setup */
+static void (*vendor_thermal_interrupt)(struct pt_regs *regs) = unexpected_thermal_interrupt;
+
+asmlinkage void smp_thermal_interrupt(struct pt_regs regs)
+{
+	irq_enter();
+	vendor_thermal_interrupt(&regs);
+	irq_exit();
+}
+
+/* P4/Xeon Thermal regulation detect and init */
+static void __init intel_init_thermal(struct cpuinfo_x86 *c)
+{
+	u32 l, h;
+	unsigned int cpu = smp_processor_id();
+
+	/* Thermal monitoring */
+	if (!cpu_has(c, X86_FEATURE_ACPI))
+		return;	/* -ENODEV */
+
+	/* Clock modulation */
+	if (!cpu_has(c, X86_FEATURE_ACC))
+		return;	/* -ENODEV */
+
+	/* first check if its enabled already, in which case there might
+	 * be some SMM goo which handles it, so we can't even put a handler
+	 * since it might be delivered via SMI already -zwanem.
+	 */
+	rdmsr (MSR_IA32_MISC_ENABLE, l, h);
+	h = apic_read(APIC_LVTTHMR);
+	if ((l & (1<<3)) && (h & APIC_DM_SMI)) {
+		printk(KERN_DEBUG "CPU#%d: Thermal monitoring handled by SMI\n", cpu);
+		return; /* -EBUSY */
+	}
+
+	/* check whether a vector already exists, temporarily masked? */	
+	if (h & APIC_VECTOR_MASK) {
+		printk(KERN_DEBUG "CPU#%d: Thermal LVT vector (%#x) already installed\n",
+			cpu, (h & APIC_VECTOR_MASK));
+		return; /* -EBUSY */
+	}
+
+	/* The temperature transition interrupt handler setup */
+	h = THERMAL_APIC_VECTOR;		/* our delivery vector */
+	h |= (APIC_DM_FIXED | APIC_LVT_MASKED);	/* we'll mask till we're ready */
+	apic_write_around(APIC_LVTTHMR, h);
+
+	rdmsr (MSR_IA32_THERM_INTERRUPT, l, h);
+	wrmsr (MSR_IA32_THERM_INTERRUPT, l | 0x03 , h);
+
+	/* ok we're good to go... */
+	vendor_thermal_interrupt = intel_thermal_interrupt;
+	
+	rdmsr (MSR_IA32_MISC_ENABLE, l, h);
+	wrmsr (MSR_IA32_MISC_ENABLE, l | (1<<3), h);
+	
+	l = apic_read (APIC_LVTTHMR);
+	apic_write_around (APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
+	printk (KERN_INFO "CPU#%d: Thermal monitoring enabled\n", cpu);
+	return;
+}
+#endif /* CONFIG_X86_MCE_P4THERMAL */
+
+
+/* P4/Xeon Extended MCE MSR retrieval, return 0 if unsupported */
+static int inline intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
+{
+	u32 h;
+
+	if (mce_num_extended_msrs == 0)
+		goto done;
+
+	rdmsr (MSR_IA32_MCG_EAX, r->eax, h);
+	rdmsr (MSR_IA32_MCG_EBX, r->ebx, h);
+	rdmsr (MSR_IA32_MCG_ECX, r->ecx, h);
+	rdmsr (MSR_IA32_MCG_EDX, r->edx, h);
+	rdmsr (MSR_IA32_MCG_ESI, r->esi, h);
+	rdmsr (MSR_IA32_MCG_EDI, r->edi, h);
+	rdmsr (MSR_IA32_MCG_EBP, r->ebp, h);
+	rdmsr (MSR_IA32_MCG_ESP, r->esp, h);
+	rdmsr (MSR_IA32_MCG_EFLAGS, r->eflags, h);
+	rdmsr (MSR_IA32_MCG_EIP, r->eip, h);
+
+	/* can we rely on kmalloc to do a dynamic
+	 * allocation for the reserved registers?
+	 */
+done:
+	return mce_num_extended_msrs;
+}
+
+static void intel_machine_check(struct pt_regs * regs, long error_code)
+{
+	int recover=1;
+	u32 alow, ahigh, high, low;
+	u32 mcgstl, mcgsth;
+	int i;
+	struct intel_mce_extended_msrs dbg;
+
+	rdmsr (MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
+	if (mcgstl & (1<<0))	/* Recoverable ? */
+		recover=0;
+
+	printk (KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n",
+		smp_processor_id(), mcgsth, mcgstl);
+
+	if (intel_get_extended_msrs(&dbg)) {
+		printk (KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n",
+			smp_processor_id(), dbg.eip, dbg.eflags);
+		printk (KERN_DEBUG "\teax: %08x ebx: %08x ecx: %08x edx: %08x\n",
+			dbg.eax, dbg.ebx, dbg.ecx, dbg.edx);
+		printk (KERN_DEBUG "\tesi: %08x edi: %08x ebp: %08x esp: %08x\n",
+			dbg.esi, dbg.edi, dbg.ebp, dbg.esp);
+	}
+
+	for (i=0; i<nr_mce_banks; i++) {
+		rdmsr (MSR_IA32_MC0_STATUS+i*4,low, high);
+		if (high & (1<<31)) {
+			if (high & (1<<29))
+				recover |= 1;
+			if (high & (1<<25))
+				recover |= 2;
+			printk (KERN_EMERG "Bank %d: %08x%08x", i, high, low);
+			high &= ~(1<<31);
+			if (high & (1<<27)) {
+				rdmsr (MSR_IA32_MC0_MISC+i*4, alow, ahigh);
+				printk ("[%08x%08x]", ahigh, alow);
+			}
+			if (high & (1<<26)) {
+				rdmsr (MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
+				printk (" at %08x%08x", ahigh, alow);
+			}
+			printk ("\n");
+		}
+	}
+
+	if (recover & 2)
+		panic ("CPU context corrupt");
+	if (recover & 1)
+		panic ("Unable to continue");
+
+	printk(KERN_EMERG "Attempting to continue.\n");
+	/* 
+	 * Do not clear the MSR_IA32_MCi_STATUS if the error is not 
+	 * recoverable/continuable.This will allow BIOS to look at the MSRs
+	 * for errors if the OS could not log the error.
+	 */
+	for (i=0; i<nr_mce_banks; i++) {
+		u32 msr;
+		msr = MSR_IA32_MC0_STATUS+i*4;
+		rdmsr (msr, low, high);
+		if (high&(1<<31)) {
+			/* Clear it */
+			wrmsr(msr, 0UL, 0UL);
+			/* Serialize */
+			wmb();
+		}
+	}
+	mcgstl &= ~(1<<2);
+	wrmsr (MSR_IA32_MCG_STATUS,mcgstl, mcgsth);
+}
+
+
+void __init intel_p4_mcheck_init(struct cpuinfo_x86 *c)
+{
+	u32 l, h;
+	int i;
+	
+	machine_check_vector = intel_machine_check;
+	wmb();
+
+	printk (KERN_INFO "Intel machine check architecture supported.\n");
+	rdmsr (MSR_IA32_MCG_CAP, l, h);
+	if (l & (1<<8))	/* Control register present ? */
+		wrmsr (MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
+	nr_mce_banks = l & 0xff;
+
+	for (i=0; i<nr_mce_banks; i++) {
+		wrmsr (MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
+		wrmsr (MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
+	}
+
+	set_in_cr4 (X86_CR4_MCE);
+	printk (KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n",
+		smp_processor_id());
+
+	/* Check for P4/Xeon extended MCE MSRs */
+	rdmsr (MSR_IA32_MCG_CAP, l, h);
+	if (l & (1<<9))	{/* MCG_EXT_P */
+		mce_num_extended_msrs = (l >> 16) & 0xff;
+		printk (KERN_INFO "CPU#%d: Intel P4/Xeon Extended MCE MSRs (%d) available\n",
+			smp_processor_id(), mce_num_extended_msrs);
+
+#ifdef CONFIG_X86_MCE_P4THERMAL
+		/* Check for P4/Xeon Thermal monitor */
+		intel_init_thermal(c);
+#endif
+	}
+#ifdef CONFIG_X86_MCE_NONFATAL
+	init_nonfatal_mce_checker();
+#endif
+}
diff -Nru a/arch/i386/kernel/cpu/mcheck/p5.c b/arch/i386/kernel/cpu/mcheck/p5.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mcheck/p5.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,52 @@
+/*
+ * P5 specific Machine Check Exception Reporting
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+
+#include <asm/processor.h> 
+#include <asm/system.h>
+#include <asm/msr.h>
+
+#include "mce.h"
+
+/* Machine check handler for Pentium class Intel */
+static void pentium_machine_check(struct pt_regs * regs, long error_code)
+{
+	u32 loaddr, hi, lotype;
+	rdmsr(MSR_IA32_P5_MC_ADDR, loaddr, hi);
+	rdmsr(MSR_IA32_P5_MC_TYPE, lotype, hi);
+	printk(KERN_EMERG "CPU#%d: Machine Check Exception:  0x%8X (type 0x%8X).\n", smp_processor_id(), loaddr, lotype);
+	if(lotype&(1<<5))
+		printk(KERN_EMERG "CPU#%d: Possible thermal failure (CPU on fire ?).\n", smp_processor_id());
+}
+
+/* Set up machine check reporting for processors with Intel style MCE */
+void __init intel_p5_mcheck_init(struct cpuinfo_x86 *c)
+{
+	u32 l, h;
+	
+	/*Check for MCE support */
+	if( !cpu_has(c, X86_FEATURE_MCE) )
+		return;	
+
+	/* Default P5 to off as its often misconnected */
+	if(mce_disabled != -1)
+		return;
+	machine_check_vector = pentium_machine_check;
+	wmb();
+
+	/* Read registers before enabling */
+	rdmsr(MSR_IA32_P5_MC_ADDR, l, h);
+	rdmsr(MSR_IA32_P5_MC_TYPE, l, h);
+	printk(KERN_INFO "Intel old style machine check architecture supported.\n");
+
+ 	/* Enable MCE */
+	set_in_cr4(X86_CR4_MCE);
+	printk(KERN_INFO "Intel old style machine check reporting enabled on CPU#%d.\n", smp_processor_id());
+}
diff -Nru a/arch/i386/kernel/cpu/mcheck/p6.c b/arch/i386/kernel/cpu/mcheck/p6.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mcheck/p6.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,113 @@
+/*
+ * P6 specific Machine Check Exception Reporting
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/smp.h>
+
+#include <asm/processor.h> 
+#include <asm/system.h>
+#include <asm/msr.h>
+
+#include "mce.h"
+
+/* Machine Check Handler For PII/PIII */
+static void intel_machine_check(struct pt_regs * regs, long error_code)
+{
+	int recover=1;
+	u32 alow, ahigh, high, low;
+	u32 mcgstl, mcgsth;
+	int i;
+
+	rdmsr (MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
+	if (mcgstl & (1<<0))	/* Recoverable ? */
+		recover=0;
+
+	printk (KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n",
+		smp_processor_id(), mcgsth, mcgstl);
+
+	for (i=0; i<nr_mce_banks; i++) {
+		rdmsr (MSR_IA32_MC0_STATUS+i*4,low, high);
+		if (high & (1<<31)) {
+			if (high & (1<<29))
+				recover |= 1;
+			if (high & (1<<25))
+				recover |= 2;
+			printk (KERN_EMERG "Bank %d: %08x%08x", i, high, low);
+			high &= ~(1<<31);
+			if (high & (1<<27)) {
+				rdmsr (MSR_IA32_MC0_MISC+i*4, alow, ahigh);
+				printk ("[%08x%08x]", ahigh, alow);
+			}
+			if (high & (1<<26)) {
+				rdmsr (MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
+				printk (" at %08x%08x", ahigh, alow);
+			}
+			printk ("\n");
+		}
+	}
+
+	if (recover & 2)
+		panic ("CPU context corrupt");
+	if (recover & 1)
+		panic ("Unable to continue");
+
+	printk (KERN_EMERG "Attempting to continue.\n");
+	/* 
+	 * Do not clear the MSR_IA32_MCi_STATUS if the error is not 
+	 * recoverable/continuable.This will allow BIOS to look at the MSRs
+	 * for errors if the OS could not log the error.
+	 */
+	for (i=0; i<nr_mce_banks; i++) {
+		unsigned int msr;
+		msr = MSR_IA32_MC0_STATUS+i*4;
+		rdmsr (msr,low, high);
+		if (high & (1<<31)) {
+			/* Clear it */
+			wrmsr (msr, 0UL, 0UL);
+			/* Serialize */
+			wmb();
+		}
+	}
+	mcgstl &= ~(1<<2);
+	wrmsr (MSR_IA32_MCG_STATUS,mcgstl, mcgsth);
+}
+
+/* Set up machine check reporting for processors with Intel style MCE */
+void __init intel_p6_mcheck_init(struct cpuinfo_x86 *c)
+{
+	u32 l, h;
+	int i;
+	
+	/* Check for MCE support */
+	if (!cpu_has(c, X86_FEATURE_MCE))
+		return;
+
+	/* Check for PPro style MCA */
+ 	if (!cpu_has(c, X86_FEATURE_MCA))
+		return;
+
+	/* Ok machine check is available */
+	machine_check_vector = intel_machine_check;
+	wmb();
+
+	printk (KERN_INFO "Intel machine check architecture supported.\n");
+	rdmsr (MSR_IA32_MCG_CAP, l, h);
+	if (l & (1<<8))	/* Control register present ? */
+		wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
+	nr_mce_banks = l & 0xff;
+
+	/* Don't enable bank 0 on intel P6 cores, it goes bang quickly. */
+	for (i=1; i<nr_mce_banks; i++) {
+		wrmsr (MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
+		wrmsr (MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
+	}
+
+	set_in_cr4 (X86_CR4_MCE);
+	printk (KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n",
+		smp_processor_id());
+}
diff -Nru a/arch/i386/kernel/cpu/mcheck/winchip.c b/arch/i386/kernel/cpu/mcheck/winchip.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/kernel/cpu/mcheck/winchip.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,35 @@
+/*
+ * IDT Winchip specific Machine Check Exception Reporting
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+
+#include <asm/processor.h> 
+#include <asm/system.h>
+#include <asm/msr.h>
+
+#include "mce.h"
+
+/* Machine check handler for WinChip C6 */
+static void winchip_machine_check(struct pt_regs * regs, long error_code)
+{
+	printk(KERN_EMERG "CPU0: Machine Check Exception.\n");
+}
+
+/* Set up machine check reporting on the Winchip C6 series */
+void __init winchip_mcheck_init(struct cpuinfo_x86 *c)
+{
+	u32 lo, hi;
+	machine_check_vector = winchip_machine_check;
+	wmb();
+	rdmsr(MSR_IDT_FCR1, lo, hi);
+	lo|= (1<<2);	/* Enable EIERRINT (int 18 MCE) */
+	lo&= ~(1<<4);	/* Enable MCE */
+	wrmsr(MSR_IDT_FCR1, lo, hi);
+	set_in_cr4(X86_CR4_MCE);
+	printk(KERN_INFO "Winchip machine check reporting enabled on CPU#0.\n");
+}
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Sun Nov 10 19:28:38 2002
+++ b/arch/i386/kernel/entry.S	Sun Nov 10 19:28:38 2002
@@ -471,10 +471,12 @@
 	pushl $do_page_fault
 	jmp error_code
 
+#ifdef CONFIG_X86_MCE
 ENTRY(machine_check)
 	pushl $0
 	pushl $do_machine_check
 	jmp error_code
+#endif
 
 ENTRY(spurious_interrupt_bug)
 	pushl $0
diff -Nru a/arch/i386/kernel/i387.c b/arch/i386/kernel/i387.c
--- a/arch/i386/kernel/i387.c	Sun Nov 10 19:28:41 2002
+++ b/arch/i386/kernel/i387.c	Sun Nov 10 19:28:41 2002
@@ -528,3 +528,40 @@
 
 	return fpvalid;
 }
+
+int dump_task_fpu(struct task_struct *tsk, struct user_i387_struct *fpu)
+{
+	int fpvalid = tsk->used_math;
+
+	if (fpvalid) {
+		if (tsk == current)
+			unlazy_fpu(tsk);
+		if (cpu_has_fxsr)
+			copy_fpu_fxsave(tsk, fpu);
+		else
+			copy_fpu_fsave(tsk, fpu);
+	}
+	return fpvalid;
+}
+
+int dump_task_extended_fpu(struct task_struct *tsk, struct user_fxsr_struct *fpu)
+{
+	int fpvalid = tsk->used_math && cpu_has_fxsr;
+
+	if (fpvalid) {
+		if (tsk == current)
+		       unlazy_fpu(tsk);
+		memcpy(fpu, &tsk->thread.i387.fxsave, sizeof(*fpu));
+	}
+	return fpvalid;
+}
+
+
+#ifdef CONFIG_SMP
+void dump_smp_unlazy_fpu(void)
+{
+	unlazy_fpu(current);
+	return;
+}
+#endif
+
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c	Sun Nov 10 19:28:36 2002
+++ b/arch/i386/kernel/process.c	Sun Nov 10 19:28:36 2002
@@ -19,6 +19,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
+#include <linux/elfcore.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/stddef.h>
@@ -372,6 +373,25 @@
 	dump->regs.ss = regs->xss;
 
 	dump->u_fpvalid = dump_fpu (regs, &dump->i387);
+}
+
+/* 
+ * Capture the user space registers if the task is not running (in user space)
+ */
+int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs)
+{
+	struct pt_regs ptregs;
+	
+	ptregs = *(struct pt_regs *)
+		((unsigned long)tsk->thread_info+THREAD_SIZE - sizeof(ptregs));
+	ptregs.xcs &= 0xffff;
+	ptregs.xds &= 0xffff;
+	ptregs.xes &= 0xffff;
+	ptregs.xss &= 0xffff;
+
+	elf_core_copy_regs(regs, &ptregs);
+
+	return 1;
 }
 
 /*
diff -Nru a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
--- a/arch/i386/kernel/time.c	Sun Nov 10 19:28:39 2002
+++ b/arch/i386/kernel/time.c	Sun Nov 10 19:28:39 2002
@@ -61,6 +61,7 @@
 #include <asm/arch_hooks.h>
 
 extern spinlock_t i8259A_lock;
+int pit_latch_buggy;              /* extern */
 
 #include "do_timer.h"
 
diff -Nru a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
--- a/arch/i386/kernel/timers/timer_tsc.c	Sun Nov 10 19:28:40 2002
+++ b/arch/i386/kernel/timers/timer_tsc.c	Sun Nov 10 19:28:40 2002
@@ -60,6 +60,8 @@
 static void mark_offset_tsc(void)
 {
 	int count;
+	int countmp;
+	static int count1=0, count2=LATCH;
 	/*
 	 * It is important that these two operations happen almost at
 	 * the same time. We do the RDTSC stuff first, since it's
@@ -83,6 +85,20 @@
 	count |= inb(0x40) << 8;
 	spin_unlock(&i8253_lock);
 
+	if (pit_latch_buggy) {
+		/* get center value of last 3 time lutch */
+		if ((count2 >= count && count >= count1)
+		    || (count1 >= count && count >= count2)) {
+			count2 = count1; count1 = count;
+		} else if ((count1 >= count2 && count2 >= count)
+			   || (count >= count2 && count2 >= count1)) {
+			countmp = count;count = count2;
+			count2 = count1;count1 = countmp;
+		} else {
+			count2 = count1; count1 = count; count = count1;
+		}
+	}
+
 	count = ((LATCH-1) - count) * TICK_SIZE;
 	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
 }
@@ -111,10 +127,12 @@
 	 * Set the Gate high, program CTC channel 2 for mode 0,
 	 * (interrupt on terminal count mode), binary count,
 	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.
+	 *
+	 * Some devices need a delay here.
 	 */
 	outb(0xb0, 0x43);			/* binary, mode 0, LSB/MSB, Ch 2 */
-	outb(CALIBRATE_LATCH & 0xff, 0x42);	/* LSB of count */
-	outb(CALIBRATE_LATCH >> 8, 0x42);	/* MSB of count */
+	outb_p(CALIBRATE_LATCH & 0xff, 0x42);	/* LSB of count */
+	outb_p(CALIBRATE_LATCH >> 8, 0x42);       /* MSB of count */
 
 	{
 		unsigned long startlow, starthigh;
@@ -238,8 +256,6 @@
  	 *	moaned if you have the only one in the world - you fix it!
  	 */
  
- 	dodgy_tsc();
- 	
 	if (cpu_has_tsc) {
 		unsigned long tsc_quotient = calibrate_tsc();
 		if (tsc_quotient) {
diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
--- a/arch/i386/kernel/traps.c	Sun Nov 10 19:28:37 2002
+++ b/arch/i386/kernel/traps.c	Sun Nov 10 19:28:37 2002
@@ -526,12 +526,17 @@
  
 asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
 {
-	int cpu = smp_processor_id();
+	int cpu;
 
+	nmi_enter();
+
+	cpu = smp_processor_id();
 	++nmi_count(cpu);
 
 	if (!nmi_callback(regs, cpu))
 		default_do_nmi(regs);
+
+	nmi_exit();
 }
 
 void set_nmi_callback(nmi_callback_t callback)
@@ -906,7 +911,9 @@
 	set_trap_gate(15,&spurious_interrupt_bug);
 	set_trap_gate(16,&coprocessor_error);
 	set_trap_gate(17,&alignment_check);
+#ifdef CONFIG_X86_MCE
 	set_trap_gate(18,&machine_check);
+#endif
 	set_trap_gate(19,&simd_coprocessor_error);
 
 	set_system_gate(SYSCALL_VECTOR,&system_call);
diff -Nru a/arch/i386/mach-generic/do_timer.h b/arch/i386/mach-generic/do_timer.h
--- a/arch/i386/mach-generic/do_timer.h	Sun Nov 10 19:28:41 2002
+++ b/arch/i386/mach-generic/do_timer.h	Sun Nov 10 19:28:41 2002
@@ -1,5 +1,7 @@
 /* defines for inline arch setup functions */
 
+#include <asm/apic.h>
+
 /**
  * do_timer_interrupt_hook - hook into timer tick
  * @regs:	standard registers from interrupt
diff -Nru a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c
--- a/arch/i386/mm/hugetlbpage.c	Sun Nov 10 19:28:41 2002
+++ b/arch/i386/mm/hugetlbpage.c	Sun Nov 10 19:28:41 2002
@@ -12,21 +12,22 @@
 #include <linux/pagemap.h>
 #include <linux/smp_lock.h>
 #include <linux/slab.h>
-
+#include <linux/module.h>
 #include <asm/mman.h>
 #include <asm/pgalloc.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 
-struct vm_operations_struct hugetlb_vm_ops;
-struct list_head htlbpage_freelist;
-spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED;
-extern long htlbpagemem;
+static long    htlbpagemem;
+int     htlbpage_max;
+static long    htlbzone_pages;
 
-void zap_hugetlb_resources(struct vm_area_struct *);
+struct vm_operations_struct hugetlb_vm_ops;
+static LIST_HEAD(htlbpage_freelist);
+static spinlock_t htlbpage_lock = SPIN_LOCK_UNLOCKED;
 
 #define MAX_ID 	32
-struct htlbpagekey {
+static struct htlbpagekey {
 	struct inode *in;
 	int key;
 } htlbpagek[MAX_ID];
@@ -108,7 +109,7 @@
 	return page ? 1 : -1;
 }
 
-int make_hugetlb_pages_present(unsigned long addr, unsigned long end, int flags)
+static int make_hugetlb_pages_present(unsigned long addr, unsigned long end, int flags)
 {
 	int write;
 	struct mm_struct *mm = current->mm;
@@ -143,7 +144,7 @@
 out_error:		/* Error case, remove the partial lp_resources. */
 	if (addr > vma->vm_start) {
 		vma->vm_end = addr;
-		zap_hugetlb_resources(vma);
+		zap_hugepage_range(vma, vma->vm_start, vma->vm_end - vma->vm_start);
 		vma->vm_end = end;
 	}
 	spin_unlock(&mm->page_table_lock);
@@ -235,22 +236,55 @@
 	free_huge_page(page);
 }
 
+static void
+free_rsrc(struct inode * inode)
+{
+	int i;
+	spin_lock(&htlbpage_lock);
+	for (i=0;i<MAX_ID;i++) 
+		if (htlbpagek[i].key == inode->i_ino) {
+			htlbpagek[i].key = 0;
+			htlbpagek[i].in = NULL;
+			break;
+		}
+	spin_unlock(&htlbpage_lock);
+	kfree(inode);
+}
+
 void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigned long end)
 {
 	struct mm_struct *mm = vma->vm_mm;
 	unsigned long address;
 	pte_t *pte;
 	struct page *page;
+	int free_more = 0;
+	struct inode *inode = NULL;
 
 	BUG_ON(start & (HPAGE_SIZE - 1));
 	BUG_ON(end & (HPAGE_SIZE - 1));
 
+	if (start < end) {
+		pte = huge_pte_offset(mm, start);
+		page = pte_page(*pte);
+		if ((page->mapping != NULL) && (page_count(page) == 2) &&
+			((inode=page->mapping->host)->i_mapping->a_ops == NULL)) 
+			free_more = 1;
+	}
 	for (address = start; address < end; address += HPAGE_SIZE) {
 		pte = huge_pte_offset(mm, address);
 		page = pte_page(*pte);
+		if (free_more) {
+			ClearPageDirty(page);
+			SetPageLocked(page);
+			remove_from_page_cache(page);
+			ClearPageLocked(page);
+			set_page_count(page, 1);
+		}
 		huge_page_release(page);
 		pte_clear(pte);
 	}
+	if (free_more)
+		free_rsrc(inode);
 	mm->rss -= (end - start) >> PAGE_SHIFT;
 	flush_tlb_range(vma, start, end);
 }
@@ -263,30 +297,6 @@
 	spin_unlock(&mm->page_table_lock);
 }
 
-void zap_hugetlb_resources(struct vm_area_struct *vma)
-{
-	zap_hugepage_range(vma, vma->vm_start, vma->vm_end);
-}
-
-static void unlink_vma(struct vm_area_struct *mpnt)
-{
-	struct mm_struct *mm = current->mm;
-	struct vm_area_struct *vma;
-
-	vma = mm->mmap;
-	if (vma == mpnt) {
-		mm->mmap = vma->vm_next;
-	} else {
-		while (vma->vm_next != mpnt) {
-			vma = vma->vm_next;
-		}
-		vma->vm_next = mpnt->vm_next;
-	}
-	rb_erase(&mpnt->vm_rb, &mm->mm_rb);
-	mm->mmap_cache = NULL;
-	mm->map_count--;
-}
-
 static struct inode *set_new_inode(unsigned long len, int prot, int flag, int key)
 {
 	struct inode *inode;
@@ -397,7 +407,7 @@
 		unsigned long raddr;
 		raddr = vma->vm_end;
 		vma->vm_end = addr;
-		zap_hugetlb_resources(vma);
+		zap_hugepage_range(vma, vma->vm_start, vma->vm_end - vma->vm_start);
 		vma->vm_end = raddr;
 	}
 	spin_unlock(&mm->page_table_lock);
@@ -534,6 +544,53 @@
 		__free_pages(page, HUGETLB_PAGE_ORDER);
 	}
 	return (int) htlbzone_pages;
+}
+
+int hugetlb_sysctl_handler(ctl_table *table, int write, struct file *file, void *buffer, size_t *length)
+{
+	proc_dointvec(table, write, file, buffer, length);
+	htlbpage_max = set_hugetlb_mem_size(htlbpage_max);
+	return 0;
+}
+
+static int __init hugetlb_setup(char *s)
+{
+	if (sscanf(s, "%d", &htlbpage_max) <= 0)
+		htlbpage_max = 0;
+	return 1;
+}
+__setup("hugepages=", hugetlb_setup);
+
+static int __init hugetlb_init(void)
+{
+	int i, j;
+	struct page *page;
+
+	for (i = 0; i < htlbpage_max; ++i) {
+		page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER);
+		if (!page)
+			break;
+		for (j = 0; j < HPAGE_SIZE/PAGE_SIZE; ++j)
+			SetPageReserved(&page[j]);
+		spin_lock(&htlbpage_lock);
+		list_add(&page->list, &htlbpage_freelist);
+		spin_unlock(&htlbpage_lock);
+	}
+	htlbpage_max = htlbpagemem = htlbzone_pages = i;
+	printk("Total HugeTLB memory allocated, %ld\n", htlbpagemem);
+	return 0;
+}
+module_init(hugetlb_init);
+
+int hugetlb_report_meminfo(char *buf)
+{
+	return sprintf(buf,
+			"HugePages_Total: %5lu\n"
+			"HugePages_Free:  %5lu\n"
+			"Hugepagesize:    %5lu kB\n",
+			htlbzone_pages,
+			htlbpagemem,
+			HPAGE_SIZE/1024);
 }
 
 static struct page * hugetlb_nopage(struct vm_area_struct * area, unsigned long address, int unused)
diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c
--- a/arch/i386/mm/init.c	Sun Nov 10 19:28:40 2002
+++ b/arch/i386/mm/init.c	Sun Nov 10 19:28:40 2002
@@ -422,13 +422,6 @@
 extern void set_max_mapnr_init(void);
 #endif /* !CONFIG_DISCONTIGMEM */
 
-#ifdef CONFIG_HUGETLB_PAGE
-long    htlbpagemem = 0;
-int     htlbpage_max;
-long    htlbzone_pages;
-extern struct list_head htlbpage_freelist;
-#endif
-
 void __init mem_init(void)
 {
 	extern int ppro_with_ram_bug(void);
@@ -496,30 +489,6 @@
 	 */
 #ifndef CONFIG_SMP
 	zap_low_mappings();
-#endif
-#ifdef CONFIG_HUGETLB_PAGE
-	{
-		long	i, j;
-		struct	page	*page, *map;
-		/*For now reserve quarter for hugetlb_pages.*/
-		htlbzone_pages = (max_low_pfn >> ((HPAGE_SHIFT - PAGE_SHIFT) + 2)) ;
-		/*Will make this kernel command line. */
-		INIT_LIST_HEAD(&htlbpage_freelist);
-		for (i=0; i<htlbzone_pages; i++) {
-			page = alloc_pages(__GFP_HIGHMEM, HUGETLB_PAGE_ORDER);
-			if (page == NULL)
-				break;
-			map = page;
-			for (j=0; j<(HPAGE_SIZE/PAGE_SIZE); j++) {
-				SetPageReserved(map);
-				map++;
-			}
-			list_add(&page->list, &htlbpage_freelist);
-		}
-		printk("Total Huge_TLB_Page memory pages allocated %ld\n", i);
-		htlbzone_pages = htlbpagemem = i;
-		htlbpage_max = i;
-	}
 #endif
 }
 
diff -Nru a/arch/i386/pci/common.c b/arch/i386/pci/common.c
--- a/arch/i386/pci/common.c	Sun Nov 10 19:28:39 2002
+++ b/arch/i386/pci/common.c	Sun Nov 10 19:28:39 2002
@@ -90,6 +90,11 @@
 	}
 }
 
+void __devinit
+pcibios_fixup_pbus_ranges (struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
+{
+}
+
 /*
  *  Called after each bus is probed, but before its children
  *  are examined.
diff -Nru a/arch/i386/pci/fixup.c b/arch/i386/pci/fixup.c
--- a/arch/i386/pci/fixup.c	Sun Nov 10 19:28:40 2002
+++ b/arch/i386/pci/fixup.c	Sun Nov 10 19:28:40 2002
@@ -138,7 +138,7 @@
 #define VIA_8363_KL133_REVISION_ID 0x81
 #define VIA_8363_KM133_REVISION_ID 0x84
 
-static void __init pci_fixup_via_northbridge_bug(struct pci_dev *d)
+static void __devinit pci_fixup_via_northbridge_bug(struct pci_dev *d)
 {
 	u8 v;
 	u8 revision;
@@ -180,7 +180,7 @@
  * system to PCI bus no matter what are their window settings, so they are
  * "transparent" (or subtractive decoding) from programmers point of view.
  */
-static void __init pci_fixup_transparent_bridge(struct pci_dev *dev)
+static void __devinit pci_fixup_transparent_bridge(struct pci_dev *dev)
 {
 	if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI &&
 	    (dev->device & 0xff00) == 0x2400)
diff -Nru a/arch/i386/vmlinux.lds.S b/arch/i386/vmlinux.lds.S
--- a/arch/i386/vmlinux.lds.S	Sun Nov 10 19:28:37 2002
+++ b/arch/i386/vmlinux.lds.S	Sun Nov 10 19:28:37 2002
@@ -79,7 +79,7 @@
   __initcall_end = .;
   . = ALIGN(4096);
   __initramfs_start = .;
-  .init.ramfs : { *(.init.initramfs) }
+  .init.ramfs : { *(.init.ramfs) }
   __initramfs_end = .;
   . = ALIGN(32);
   __per_cpu_start = .;
diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
--- a/arch/ia64/kernel/process.c	Sun Nov 10 19:28:39 2002
+++ b/arch/ia64/kernel/process.c	Sun Nov 10 19:28:39 2002
@@ -384,6 +384,31 @@
 void
 do_copy_regs (struct unw_frame_info *info, void *arg)
 {
+	do_copy_task_regs(current, info, arg);
+}
+
+void
+do_dump_fpu (struct unw_frame_info *info, void *arg)
+{
+	do_dump_task_fpu(current, info, arg);
+}
+
+void
+ia64_elf_core_copy_regs (struct pt_regs *pt, elf_gregset_t dst)
+{
+	unw_init_running(do_copy_regs, dst);
+}
+
+int
+dump_fpu (struct pt_regs *pt, elf_fpregset_t dst)
+{
+	unw_init_running(do_dump_fpu, dst);
+	return 1;	/* f0-f31 are always valid so we always return 1 */
+}
+
+static void
+do_copy_task_regs (struct task_struct *task, struct unw_frame_info *info, void *arg)
+{
 	unsigned long mask, sp, nat_bits = 0, ip, ar_rnat, urbs_end, cfm;
 	elf_greg_t *dst = arg;
 	struct pt_regs *pt;
@@ -398,12 +423,12 @@
 	unw_get_sp(info, &sp);
 	pt = (struct pt_regs *) (sp + 16);
 
-	urbs_end = ia64_get_user_rbs_end(current, pt, &cfm);
+	urbs_end = ia64_get_user_rbs_end(task, pt, &cfm);
 
-	if (ia64_sync_user_rbs(current, info->sw, pt->ar_bspstore, urbs_end) < 0)
+	if (ia64_sync_user_rbs(task, info->sw, pt->ar_bspstore, urbs_end) < 0)
 		return;
 
-	ia64_peek(current, info->sw, urbs_end, (long) ia64_rse_rnat_addr((long *) urbs_end),
+	ia64_peek(task, info->sw, urbs_end, (long) ia64_rse_rnat_addr((long *) urbs_end),
 		  &ar_rnat);
 
 	/*
@@ -452,7 +477,7 @@
 }
 
 void
-do_dump_fpu (struct unw_frame_info *info, void *arg)
+do_dump_task_fpu (struct task_struct *task, struct unw_frame_info *info, void *arg)
 {
 	elf_fpreg_t *dst = arg;
 	int i;
@@ -467,22 +492,41 @@
 	for (i = 2; i < 32; ++i)
 		unw_get_fr(info, i, dst + i);
 
-	ia64_flush_fph(current);
-	if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0)
-		memcpy(dst + 32, current->thread.fph, 96*16);
+	ia64_flush_fph(task);
+	if ((task->thread.flags & IA64_THREAD_FPH_VALID) != 0)
+		memcpy(dst + 32, task->thread.fph, 96*16);
 }
 
-void
-ia64_elf_core_copy_regs (struct pt_regs *pt, elf_gregset_t dst)
+int dump_task_regs(struct task_struct *task, elf_gregset_t *regs)
 {
-	unw_init_running(do_copy_regs, dst);
+	struct unw_frame_info tcore_info;
+
+	if(current == task) {
+		unw_init_running(do_copy_regs, regs);
+	}
+	else {
+		memset(&tcore_info, 0, sizeof(tcore_info));	
+		unw_init_from_blocked_task(&tcore_info, task);
+		do_copy_task_regs(task, &tcore_info, regs);
+	}
+
+	return 1;
 }
 
-int
-dump_fpu (struct pt_regs *pt, elf_fpregset_t dst)
+int dump_task_fpu (struct task_struct *task, elf_fpregset_t *dst)
 {
-	unw_init_running(do_dump_fpu, dst);
-	return 1;	/* f0-f31 are always valid so we always return 1 */
+	struct unw_frame_info tcore_info;
+
+	if(current == task) {
+		unw_init_running(do_dump_fpu, dst);
+	}
+	else {
+		memset(&tcore_info, 0, sizeof(tcore_info));	
+		unw_init_from_blocked_task(&tcore_info, task);
+		do_dump_task_fpu(task, &tcore_info, dst);
+	}
+
+	return 1; 
 }
 
 asmlinkage long
diff -Nru a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
--- a/arch/ia64/sn/kernel/irq.c	Sun Nov 10 19:28:37 2002
+++ b/arch/ia64/sn/kernel/irq.c	Sun Nov 10 19:28:37 2002
@@ -294,7 +294,7 @@
 #ifdef ajmtestintr
 
 #include <linux/timer.h>
-struct timer_list intr_test_timer;
+struct timer_list intr_test_timer = TIMER_INITIALIZER(NULL, 0, 0);
 int intr_test_icount[NR_IRQS];
 struct intr_test_reg_struct {
 	pcibr_soft_t pcibr_soft;
diff -Nru a/arch/ia64/sn/kernel/mca.c b/arch/ia64/sn/kernel/mca.c
--- a/arch/ia64/sn/kernel/mca.c	Sun Nov 10 19:28:37 2002
+++ b/arch/ia64/sn/kernel/mca.c	Sun Nov 10 19:28:37 2002
@@ -238,7 +238,7 @@
 #include <linux/timer.h>
 
 #define CPEI_INTERVAL   (HZ/100)
-struct timer_list sn_cpei_timer;
+struct timer_list sn_cpei_timer = TIMER_INITIALIZER(NULL, 0, 0);
 void sn_init_cpei_timer(void);
 
 void
diff -Nru a/arch/m68k/Kconfig b/arch/m68k/Kconfig
--- a/arch/m68k/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/arch/m68k/Kconfig	Sun Nov 10 19:28:40 2002
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 config M68K
 	bool
diff -Nru a/arch/m68k/amiga/amisound.c b/arch/m68k/amiga/amisound.c
--- a/arch/m68k/amiga/amisound.c	Sun Nov 10 19:28:41 2002
+++ b/arch/m68k/amiga/amisound.c	Sun Nov 10 19:28:41 2002
@@ -62,7 +62,7 @@
 }
 
 static void nosound( unsigned long ignored );
-static struct timer_list sound_timer = { function: nosound };
+static struct timer_list sound_timer = TIMER_INITIALIZER(nosound, 0, 0);
 
 void amiga_mksound( unsigned int hz, unsigned int ticks )
 {
diff -Nru a/arch/m68k/mac/macboing.c b/arch/m68k/mac/macboing.c
--- a/arch/m68k/mac/macboing.c	Sun Nov 10 19:28:41 2002
+++ b/arch/m68k/mac/macboing.c	Sun Nov 10 19:28:41 2002
@@ -56,7 +56,8 @@
 /*
  * our timer to start/continue/stop the bell
  */
-static struct timer_list mac_sound_timer = { function: mac_nosound };
+static struct timer_list mac_sound_timer =
+		TIMER_INITIALIZER(mac_nosound, 0, 0);
 
 /*
  * Sort of initialize the sound chip (called from mac_mksound on the first
diff -Nru a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
--- a/arch/m68knommu/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/arch/m68knommu/Kconfig	Sun Nov 10 19:28:40 2002
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 
 mainmenu "uClinux/68k (w/o MMU) Kernel Configuration"
diff -Nru a/arch/mips/Kconfig b/arch/mips/Kconfig
--- a/arch/mips/Kconfig	Sun Nov 10 19:28:39 2002
+++ b/arch/mips/Kconfig	Sun Nov 10 19:28:39 2002
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 config MIPS
 	bool
diff -Nru a/arch/mips/ddb5074/pci.c b/arch/mips/ddb5074/pci.c
--- a/arch/mips/ddb5074/pci.c	Sun Nov 10 19:28:39 2002
+++ b/arch/mips/ddb5074/pci.c	Sun Nov 10 19:28:39 2002
@@ -297,8 +297,8 @@
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
-void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus,
-				      struct pbus_set_ranges_data *ranges)
+void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *bus,
+					 struct pbus_set_ranges_data *ranges)
 {
 }
 
diff -Nru a/arch/mips/ddb5476/pci.c b/arch/mips/ddb5476/pci.c
--- a/arch/mips/ddb5476/pci.c	Sun Nov 10 19:28:39 2002
+++ b/arch/mips/ddb5476/pci.c	Sun Nov 10 19:28:39 2002
@@ -341,8 +341,8 @@
 	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
 }
 
-void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus,
-				      struct pbus_set_ranges_data *ranges)
+void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *bus,
+					 struct pbus_set_ranges_data *ranges)
 {
 	/*
 	 * our caller figure out range by going through the dev structures.  
diff -Nru a/arch/mips64/Kconfig b/arch/mips64/Kconfig
--- a/arch/mips64/Kconfig	Sun Nov 10 19:28:38 2002
+++ b/arch/mips64/Kconfig	Sun Nov 10 19:28:38 2002
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 
 mainmenu "Linux Kernel Configuration"
diff -Nru a/arch/mips64/sgi-ip27/ip27-pci.c b/arch/mips64/sgi-ip27/ip27-pci.c
--- a/arch/mips64/sgi-ip27/ip27-pci.c	Sun Nov 10 19:28:40 2002
+++ b/arch/mips64/sgi-ip27/ip27-pci.c	Sun Nov 10 19:28:40 2002
@@ -234,7 +234,7 @@
 	pci_fixup_irqs(pci_swizzle, pci_map_irq);
 }
 
-void __init
+void __devinit
 pcibios_fixup_pbus_ranges(struct pci_bus * bus,
                           struct pbus_set_ranges_data * ranges)
 {
diff -Nru a/arch/mips64/sgi-ip32/ip32-pci.c b/arch/mips64/sgi-ip32/ip32-pci.c
--- a/arch/mips64/sgi-ip32/ip32-pci.c	Sun Nov 10 19:28:41 2002
+++ b/arch/mips64/sgi-ip32/ip32-pci.c	Sun Nov 10 19:28:41 2002
@@ -349,8 +349,8 @@
 }
 
 /* XXX anybody know what this is supposed to do? */
-void __init pcibios_fixup_pbus_ranges(struct pci_bus * bus,
-				      struct pbus_set_ranges_data * ranges)
+void __devinit pcibios_fixup_pbus_ranges(struct pci_bus * bus,
+					 struct pbus_set_ranges_data * ranges)
 {
 }
 
diff -Nru a/arch/parisc/Kconfig b/arch/parisc/Kconfig
--- a/arch/parisc/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/arch/parisc/Kconfig	Sun Nov 10 19:28:40 2002
@@ -22,6 +22,10 @@
 	bool
 	default y
 
+config STACK_GROWSUP
+	bool
+	default y
+
 config UID16
 	bool
 
@@ -93,10 +97,27 @@
 config PARISC64
 	bool "64-bit kernel"
 	depends on PA8X00
+	help
+	  Enable this if you want to support 64bit kernel on PA-RISC platform.
+	  
+	  At the moment, only people willing to use more than 2GB of RAM,
+	  or having a 64bit-only capable PA-RISC machine should say Y here.
+
+	  Since there is no 64bit userland on PA-RISC, there is no point to
+	  enable this option otherwise. The 64bit kernel is significantly bigger
+	  and slower than the 32bit one.
 
 config PDC_NARROW
 	bool "32-bit firmware"
 	depends on PARISC64
+	help
+	  This option will enable owners of C160, C180, C200, C240, C360, J280,
+	  J282, J2240 and some D/K/R class to run a 64bit kernel with their
+	  32bit PDC firmware.
+	
+	  Nobody should try this option unless they know what they are doing.
+	
+	  If unsure, say N.
 
 config SMP
 	bool "Symmetric multi-processing support"
@@ -211,14 +232,11 @@
 
 source "drivers/block/Kconfig"
 
-menu "ATA/IDE/MFM/RLL support"
-	depends on SUPERIO
 
+menu "ATA/IDE/MFM/RLL support"
 config IDE
 	tristate "ATA/IDE/MFM/RLL support"
-
 source "drivers/ide/Kconfig"
-
 endmenu
 
 menu "SCSI support"
@@ -245,6 +263,7 @@
 
 source drivers/scsi/Kconfig
 
+
 endmenu
 
 source "drivers/md/Kconfig"
@@ -323,9 +342,21 @@
 config STI_CONSOLE
 	bool "STI console"
 	help
-	  The STI console is the builtin display/keyboard on HP-PARISC
-	  machines.  Say Y here to build support for it into your kernel.
+	  STI refers to the HP "Standard Text Interface" which is a set of
+	  BIOS routines contained in a ROM chip in HP PA-RISC based machines.
+	  Enabling this option will give you an 8 color text console on
+	  most of the PA-RISC systems.
+	  Really old HP boxes may not have STI, in which case you must use the
+	  PDC console or your primary serial port as a console.
+	
+	  The text console uses a strange memory layout, and changing the 
+	  plane mask to create colored characters requires calls to the STI 
+	  routines. Because of that do not expect it to be actually very fast,
+	  but it is sufficient for basic text console functions, including fonts.
+	
 	  The alternative is to use your primary serial port as a console.
+	
+	  It is safe to enable this option, so you should probably say "Y".
 
 config DUMMY_CONSOLE
 	bool
diff -Nru a/arch/parisc/Makefile b/arch/parisc/Makefile
--- a/arch/parisc/Makefile	Sun Nov 10 19:28:41 2002
+++ b/arch/parisc/Makefile	Sun Nov 10 19:28:41 2002
@@ -20,7 +20,7 @@
 ifdef CONFIG_PARISC64
 CROSS_COMPILE := hppa64-linux-
 UTS_MACHINE := parisc64
-#CFLAGS += -b hppa64-linux
+LDFLAGS_BLOB := --format binary --oformat elf64-hppa-linux
 
 else
 MACHINE	:= $(subst 64,,$(shell uname -m))
@@ -28,6 +28,7 @@
 # cross compilation
 CROSS_COMPILE := hppa-linux-
 endif
+LDFLAGS_BLOB := --format binary --oformat elf32-hppa-linux
 endif
 
 FINAL_LD=$(CROSS_COMPILE)ld --warn-common --warn-section-align 
diff -Nru a/arch/parisc/kernel/irq.c b/arch/parisc/kernel/irq.c
--- a/arch/parisc/kernel/irq.c	Sun Nov 10 19:28:39 2002
+++ b/arch/parisc/kernel/irq.c	Sun Nov 10 19:28:39 2002
@@ -235,7 +235,7 @@
 #ifdef CONFIG_SMP
 		for (; j < NR_CPUS; j++)
 #endif
-		    seq_printf(p, "%10u ", kstat.irqs[j][regnr][irq_no]);
+		    seq_printf(p, "%10u ", kstat_cpu(j).irqs[regnr][irq_no]);
 
 		seq_printf(p, " %14s",
 			    region->data.name ? region->data.name : "N/A");
@@ -372,7 +372,7 @@
 	int cpu = smp_processor_id();
 
 	irq_enter();
-	++kstat.irqs[cpu][IRQ_REGION(irq)][IRQ_OFFSET(irq)];
+	++kstat_cpu(cpu).irqs[IRQ_REGION(irq)][IRQ_OFFSET(irq)];
 
 	DBG_IRQ(irq, ("do_irq(%d) %d+%d\n", irq, IRQ_REGION(irq), IRQ_OFFSET(irq)));
 
diff -Nru a/arch/parisc/kernel/keyboard.c b/arch/parisc/kernel/keyboard.c
--- a/arch/parisc/kernel/keyboard.c	Sun Nov 10 19:28:38 2002
+++ b/arch/parisc/kernel/keyboard.c	Sun Nov 10 19:28:38 2002
@@ -54,14 +54,14 @@
 static char def_sysrq_xlate[NR_KEYS];
 
 #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,
+	.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
diff -Nru a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
--- a/arch/parisc/kernel/pci.c	Sun Nov 10 19:28:36 2002
+++ b/arch/parisc/kernel/pci.c	Sun Nov 10 19:28:36 2002
@@ -345,7 +345,7 @@
 /*
 ** called by drivers/pci/setup-res.c:pci_setup_bridge().
 */
-void pcibios_fixup_pbus_ranges(
+void __devinit pcibios_fixup_pbus_ranges(
 	struct pci_bus *bus,
 	struct pbus_set_ranges_data *ranges
 	)
diff -Nru a/arch/parisc/kernel/pdc_chassis.c b/arch/parisc/kernel/pdc_chassis.c
--- a/arch/parisc/kernel/pdc_chassis.c	Sun Nov 10 19:28:39 2002
+++ b/arch/parisc/kernel/pdc_chassis.c	Sun Nov 10 19:28:39 2002
@@ -79,8 +79,8 @@
 
 
 static struct notifier_block pdc_chassis_panic_block = {
-	notifier_call: pdc_chassis_panic_event,
-	priority: INT_MAX,
+	.notifier_call = pdc_chassis_panic_event,
+	.priority = INT_MAX,
 };
 
 
@@ -99,8 +99,8 @@
 
 
 static struct notifier_block pdc_chassis_reboot_block = {
-	notifier_call: pdc_chassis_reboot_event,
-	priority: INT_MAX,
+	.notifier_call = pdc_chassis_reboot_event,
+	.priority = INT_MAX,
 };
 
 
diff -Nru a/arch/parisc/kernel/pdc_cons.c b/arch/parisc/kernel/pdc_cons.c
--- a/arch/parisc/kernel/pdc_cons.c	Sun Nov 10 19:28:38 2002
+++ b/arch/parisc/kernel/pdc_cons.c	Sun Nov 10 19:28:38 2002
@@ -52,26 +52,23 @@
 	return 0;
 }
 
-#ifdef CONFIG_PDC_CONSOLE
+#if defined(CONFIG_PDC_CONSOLE) || defined(CONFIG_SERIAL_MUX)
+#define PDC_CONSOLE_DEVICE pdc_console_device
 static kdev_t pdc_console_device (struct console *c)
 {
         return mk_kdev(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,
-	index:		-1,
+	.name =		"ttyB",
+	.write =	pdc_console_write,
+	.device =	PDC_CONSOLE_DEVICE,
+	.setup =	pdc_console_setup,
+	.flags =	CON_BOOT|CON_PRINTBUFFER|CON_ENABLED,
+	.index =	-1,
 };
 
 static int pdc_console_initialized;
@@ -93,9 +90,9 @@
 	register_console(&pdc_cons);
 }
 
-void pdc_console_init(void)
+void __init pdc_console_init(void)
 {
-#if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE)
+#if defined(EARLY_BOOTUP_DEBUG) || defined(CONFIG_PDC_CONSOLE) || defined(CONFIG_SERIAL_MUX)
 	pdc_console_init_force();
 #endif
 #ifdef EARLY_BOOTUP_DEBUG
diff -Nru a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c
--- a/arch/parisc/kernel/perf.c	Sun Nov 10 19:28:38 2002
+++ b/arch/parisc/kernel/perf.c	Sun Nov 10 19:28:38 2002
@@ -481,12 +481,12 @@
 }
 
 static struct file_operations perf_fops = {
-	llseek: no_llseek,
-	read: perf_read,
-	write: perf_write,
-	ioctl: perf_ioctl,
-	open: perf_open,
-	release: perf_release
+	.llseek = no_llseek,
+	.read = perf_read,
+	.write = perf_write,
+	.ioctl = perf_ioctl,
+	.open = perf_open,
+	.release = perf_release
 };
 	
 static struct miscdevice perf_dev = {
diff -Nru a/arch/parisc/kernel/processor.c b/arch/parisc/kernel/processor.c
--- a/arch/parisc/kernel/processor.c	Sun Nov 10 19:28:41 2002
+++ b/arch/parisc/kernel/processor.c	Sun Nov 10 19:28:41 2002
@@ -370,9 +370,9 @@
 };
 
 static struct parisc_driver cpu_driver = {
-	name:		"CPU",
-	id_table:	processor_tbl,
-	probe:		processor_probe
+	.name		= "CPU",
+	.id_table	= processor_tbl,
+	.probe		= processor_probe
 };
 
 /**
diff -Nru a/arch/parisc/kernel/setup.c b/arch/parisc/kernel/setup.c
--- a/arch/parisc/kernel/setup.c	Sun Nov 10 19:28:41 2002
+++ b/arch/parisc/kernel/setup.c	Sun Nov 10 19:28:41 2002
@@ -179,10 +179,10 @@
 }
 
 struct seq_operations cpuinfo_op = {
-	start:	c_start,
-	next:	c_next,
-	stop:	c_stop,
-	show:	show_cpuinfo
+	.start	= c_start,
+	.next	= c_next,
+	.stop	= c_stop,
+	.show	= show_cpuinfo
 };
 
 static void parisc_proc_mkdir(void)
@@ -216,24 +216,24 @@
 }
 
 static struct resource central_bus = {
-	name:	"Central Bus",
-	start:	(unsigned long)0xfffffffffff80000,
-	end:    (unsigned long)0xfffffffffffaffff,
-	flags:	IORESOURCE_MEM,
+	.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,
+	.name	= "Local Broadcast",
+	.start	= (unsigned long)0xfffffffffffb0000,
+	.end	= (unsigned long)0xfffffffffffdffff,
+	.flags	= IORESOURCE_MEM,
 };
 
 static struct resource global_broadcast = {
-	name:	"Global Broadcast",
-	start:	(unsigned long)0xfffffffffffe0000,
-	end:	(unsigned long)0xffffffffffffffff,
-	flags:	IORESOURCE_MEM,
+	.name	= "Global Broadcast",
+	.start	= (unsigned long)0xfffffffffffe0000,
+	.end	= (unsigned long)0xffffffffffffffff,
+	.flags	= IORESOURCE_MEM,
 };
 
 int __init parisc_init_resources(void)
diff -Nru a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c
--- a/arch/parisc/kernel/sys_parisc.c	Sun Nov 10 19:28:41 2002
+++ b/arch/parisc/kernel/sys_parisc.c	Sun Nov 10 19:28:41 2002
@@ -149,24 +149,42 @@
 
 /* Fucking broken ABI */
 
+#ifdef CONFIG_PARISC64
+extern asmlinkage long sys_truncate(const char *, unsigned long);
+extern asmlinkage long sys_ftruncate(unsigned int, unsigned long);
+asmlinkage long parisc_truncate64(const char * path,
+					unsigned int high, unsigned int low)
+{
+	return sys_truncate(path, (long)high << 32 | low);
+}
+
+asmlinkage long parisc_ftruncate64(unsigned int fd,
+					unsigned int high, unsigned int low)
+{
+	return sys_ftruncate(fd, (long)high << 32 | low);
+}
+#else
+
 extern asmlinkage long sys_truncate64(const char *, loff_t);
 extern asmlinkage long sys_ftruncate64(unsigned int, loff_t);
-extern asmlinkage ssize_t sys_pread64(unsigned int fd, char *buf,
-					size_t count, loff_t pos);
-extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char *buf,
-					size_t count, loff_t pos);
 
 asmlinkage long parisc_truncate64(const char * path,
 					unsigned int high, unsigned int low)
 {
-	return sys_truncate(path, (loff_t)high << 32 | low);
+	return sys_truncate64(path, (loff_t)high << 32 | low);
 }
 
 asmlinkage long parisc_ftruncate64(unsigned int fd,
 					unsigned int high, unsigned int low)
 {
-	return sys_ftruncate(fd, (loff_t)high << 32 | low);
+	return sys_ftruncate64(fd, (loff_t)high << 32 | low);
 }
+#endif
+
+extern asmlinkage ssize_t sys_pread64(unsigned int fd, char *buf,
+					size_t count, loff_t pos);
+extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char *buf,
+					size_t count, loff_t pos);
 
 asmlinkage ssize_t parisc_pread64(unsigned int fd, char *buf, size_t count,
 					unsigned int high, unsigned int low)
diff -Nru a/arch/parisc/lib/Makefile b/arch/parisc/lib/Makefile
--- a/arch/parisc/lib/Makefile	Sun Nov 10 19:28:40 2002
+++ b/arch/parisc/lib/Makefile	Sun Nov 10 19:28:40 2002
@@ -2,4 +2,5 @@
 # Makefile for parisc-specific library files
 #
 
+L_TARGET := lib.a
 obj-y	:= lusercopy.o bitops.o checksum.o io.o memset.o
diff -Nru a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
--- a/arch/parisc/mm/init.c	Sun Nov 10 19:28:39 2002
+++ b/arch/parisc/mm/init.c	Sun Nov 10 19:28:39 2002
@@ -38,20 +38,20 @@
 #endif
 
 static struct resource data_resource = {
-	name:	"Kernel data",
-	flags:	IORESOURCE_BUSY | IORESOURCE_MEM,
+	.name	= "Kernel data",
+	.flags	= IORESOURCE_BUSY | IORESOURCE_MEM,
 };
 
 static struct resource code_resource = {
-	name:	"Kernel code",
-	flags:	IORESOURCE_BUSY | IORESOURCE_MEM,
+	.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,
+	.name	= "PDC data (Page Zero)",
+	.start	= 0,
+	.end	= 0x9ff,
+	.flags	= IORESOURCE_BUSY | IORESOURCE_MEM,
 };
 
 static struct resource sysram_resources[MAX_PHYSMEM_RANGES];
diff -Nru a/arch/parisc/vmlinux.lds.S b/arch/parisc/vmlinux.lds.S
--- a/arch/parisc/vmlinux.lds.S	Sun Nov 10 19:28:37 2002
+++ b/arch/parisc/vmlinux.lds.S	Sun Nov 10 19:28:37 2002
@@ -79,6 +79,10 @@
 	*(.initcall7.init)
   }
   __initcall_end = .;
+  . = ALIGN(4096);
+  __initramfs_start = .;
+  .init.ramfs : { *(.init.ramfs) }
+  __initramfs_end = .;
   . = ALIGN(32);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
diff -Nru a/arch/ppc/8xx_io/cs4218_tdm.c b/arch/ppc/8xx_io/cs4218_tdm.c
--- a/arch/ppc/8xx_io/cs4218_tdm.c	Sun Nov 10 19:28:37 2002
+++ b/arch/ppc/8xx_io/cs4218_tdm.c	Sun Nov 10 19:28:37 2002
@@ -1375,8 +1375,7 @@
 	restore_flags(flags);
 }
 
-static struct timer_list beep_timer = {
-	.function = cs_nosound
+static struct timer_list beep_timer = TIMER_INITIALIZER(cs_nosound, 0, 0);
 };
 
 static void cs_mksound(unsigned int hz, unsigned int ticks)
diff -Nru a/arch/ppc/Kconfig b/arch/ppc/Kconfig
--- a/arch/ppc/Kconfig	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/Kconfig	Sun Nov 10 19:28:41 2002
@@ -1,5 +1,5 @@
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 
 config MMU
@@ -1209,6 +1209,9 @@
 
 	  Unless you know what you are doing, say N here.
 
+comment "Default settings for advanced configuration options are used"
+	depends on !ADVANCED_OPTIONS
+
 config HIGHMEM_START_BOOL
 	bool "Set high memory pool address"
 	depends on ADVANCED_OPTIONS && HIGHMEM
@@ -1224,6 +1227,11 @@
 	depends on HIGHMEM_START_BOOL
 	default "0xfe000000"
 
+config HIGHMEM_START
+	hex
+	depends on !HIGHMEM_START_BOOL
+	default "0xfe000000"
+
 config LOWMEM_SIZE_BOOL
 	bool "Set maximum low memory"
 	depends on ADVANCED_OPTIONS && HIGHMEM
@@ -1241,6 +1249,11 @@
 	depends on LOWMEM_SIZE_BOOL
 	default "0x20000000"
 
+config LOWMEM_SIZE
+	hex
+	depends on !LOWMEM_SIZE_BOOL
+	default "0x20000000"
+
 config KERNEL_START_BOOL
 	bool "Set custom kernel base address"
 	depends on ADVANCED_OPTIONS
@@ -1257,6 +1270,11 @@
 	depends on KERNEL_START_BOOL
 	default "0xc0000000"
 
+config KERNEL_START
+	hex
+	depends on !KERNEL_START_BOOL
+	default "0xc0000000"
+
 config TASK_SIZE_BOOL
 	bool "Set custom user task size"
 	depends on ADVANCED_OPTIONS
@@ -1270,6 +1288,11 @@
 config TASK_SIZE
 	hex "Size of user task space"
 	depends on TASK_SIZE_BOOL
+	default "0x80000000"
+
+config TASK_SIZE
+	hex
+	depends on !TASK_SIZE_BOOL
 	default "0x80000000"
 
 config PIN_TLB
diff -Nru a/arch/ppc/Makefile b/arch/ppc/Makefile
--- a/arch/ppc/Makefile	Sun Nov 10 19:28:36 2002
+++ b/arch/ppc/Makefile	Sun Nov 10 19:28:36 2002
@@ -12,13 +12,10 @@
 # Rewritten by Cort Dougan and Paul Mackerras
 #
 
-# Be sure to change PAGE_OFFSET in include/asm-ppc/page.h to match
-ifdef CONFIG_KERNEL_START_BOOL
+# This must match PAGE_OFFSET in include/asm-ppc/page.h.
 KERNELLOAD	=$(CONFIG_KERNEL_START)
-else
-KERNELLOAD	=0xc0000000
-endif
 
+LDFLAGS_BLOB	:= --format binary --oformat elf32-powerpc
 LDFLAGS_vmlinux	= -Ttext $(KERNELLOAD) -Bstatic
 CPPFLAGS	:= $(CPPFLAGS) -I$(TOPDIR)/arch/$(ARCH)
 AFLAGS		:= $(AFLAGS) -I$(TOPDIR)/arch/$(ARCH)
@@ -54,7 +51,7 @@
 endif
 
 core-y				+= arch/ppc/kernel/ arch/ppc/platforms/ \
-				   arch/ppc/mm/ arch/ppc/lib/
+				   arch/ppc/mm/ arch/ppc/lib/ arch/ppc/syslib/
 core-$(CONFIG_4xx)		+= arch/ppc/platforms/4xx/
 core-$(CONFIG_MATH_EMULATION)	+= arch/ppc/math-emu/
 core-$(CONFIG_XMON)		+= arch/ppc/xmon/
@@ -68,6 +65,8 @@
 
 BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd pImage vmlinux.sm
 
+.PHONY: $(BOOT_TARGETS) clean archclean archmrproper
+
 AFLAGS_vmlinux.lds.o	:= -Upowerpc
 
 # All the instructions talk about "make bzImage".
@@ -81,7 +80,7 @@
 	cp -f arch/ppc/configs/$(@:config=defconfig) .config
 
 archclean:
-	+@$(call makeboot,clean)
+	$(MAKE) -f scripts/Makefile.clean obj=arch/ppc/boot
 
 archmrproper:
 
diff -Nru a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile
--- a/arch/ppc/boot/Makefile	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc/boot/Makefile	Sun Nov 10 19:28:40 2002
@@ -15,8 +15,12 @@
 AFLAGS	+= -D__BOOTER__
 OBJCOPY_ARGS = -O elf32-powerpc
 
-subdir-y			:= simple
-subdir-$(CONFIG_ALL_PPC)	:= openfirmware prep
+bootdir-y			:= simple
+bootdir-$(CONFIG_ALL_PPC)	:= openfirmware prep
+
+# for cleaning...
+subdir-				:= images simple openfirmware prep \
+				   lib common of1275
 
 HOSTCFLAGS += -Iarch/$(ARCH)/boot/include
 
@@ -35,20 +39,15 @@
 
 host-progs			:= $(addprefix utils/,$(tools-y))
 
-include $(TOPDIR)/Rules.make
-
-zImage zImage.initrd znetboot znetboot.initrd: $(subdir-y)
-
-simple openfirmware prep: lib common images
-openfirmware prep: of1275
+zImage zImage.initrd znetboot znetboot.initrd: $(addprefix $(obj)/,$(bootdir-y))
 
-lib common of1275 images: FORCE
-	+@$(call descend,$(obj)/$@,)
+.PHONY: FORCE
 
-openfirmware prep simple: FORCE
-	+@$(call descend,$(obj)/$@,$(MAKECMDGOALS))
+$(obj)/simple $(obj)/openfirmware $(obj)/prep: $(obj)/lib $(obj)/common $(obj)/images
+$(obj)/openfirmware $(obj)/prep: $(obj)/of1275
 
-CLEAN_FILES += $(addprefix $(obj)/utils,$(all-tools))
+$(obj)/lib $(obj)/common $(obj)/of1275 $(obj)/images: FORCE
+	+@$(call descend,$@,)
 
-clean: FORCE
-	+@$(call descend,$(obj)/images,clean)
+$(obj)/openfirmware $(obj)/prep $(obj)/simple: FORCE
+	+@$(call descend,$@,$(MAKECMDGOALS))
diff -Nru a/arch/ppc/boot/common/misc-common.c b/arch/ppc/boot/common/misc-common.c
--- a/arch/ppc/boot/common/misc-common.c	Sun Nov 10 19:28:39 2002
+++ b/arch/ppc/boot/common/misc-common.c	Sun Nov 10 19:28:39 2002
@@ -33,6 +33,7 @@
 
 #include <stdarg.h>	/* for va_ bits */
 #include <linux/config.h>
+#include <linux/string.h>
 #include "zlib.h"
 #include "nonstdio.h"
 
diff -Nru a/arch/ppc/boot/images/Makefile b/arch/ppc/boot/images/Makefile
--- a/arch/ppc/boot/images/Makefile	Sun Nov 10 19:28:37 2002
+++ b/arch/ppc/boot/images/Makefile	Sun Nov 10 19:28:37 2002
@@ -2,15 +2,13 @@
 # This dir holds all of the images for PPC machines.
 # Tom Rini	January 2001
 
-all:	$(obj)/vmlinux.gz
-
-include $(TOPDIR)/Rules.make
+EXTRA_TARGETS	:= vmlinux.gz
 
 GZIP_FLAGS = -v9f
 
 $(obj)/vmlinux.gz: vmlinux
-	$(OBJCOPY) -S -O binary vmlinux $(obj)/vmlinux
-	gzip $(GZIP_FLAGS) $(obj)/vmlinux
+	$(OBJCOPY) -O binary $< $(@:.gz=)
+	gzip $(GZIP_FLAGS) $(@:.gz=)
 
 clean:
 	rm -f $(obj)/sImage $(obj)/vmapus $(obj)/vmlinux* $(obj)/miboot* 
diff -Nru a/arch/ppc/boot/include/nonstdio.h b/arch/ppc/boot/include/nonstdio.h
--- a/arch/ppc/boot/include/nonstdio.h	Sun Nov 10 19:28:39 2002
+++ b/arch/ppc/boot/include/nonstdio.h	Sun Nov 10 19:28:39 2002
@@ -21,12 +21,9 @@
 
 extern int getc(void);
 extern int printf(const char *format, ...);
-extern int strlen(const char *s);
 extern int sprintf(char *str, const char *format, ...);
 extern int tstc(void);
 extern void exit(void);
-extern void *memcpy(void *dest, const void *src, int n);
-extern void *memmove(void *dest, const void *src, int n);
 extern void outb(int port, unsigned char val);
 extern void putc(const char c);
 extern void puthex(unsigned long val);
diff -Nru a/arch/ppc/boot/openfirmware/chrpmain.c b/arch/ppc/boot/openfirmware/chrpmain.c
--- a/arch/ppc/boot/openfirmware/chrpmain.c	Sun Nov 10 19:28:36 2002
+++ b/arch/ppc/boot/openfirmware/chrpmain.c	Sun Nov 10 19:28:36 2002
@@ -6,6 +6,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
+#include <linux/string.h>
 #include "nonstdio.h"
 #include "of1275.h"
 #include <asm/processor.h>
@@ -34,7 +35,7 @@
 
 #define RAM_FREE	((unsigned long)(_end+0x1000)&~0xFFF)
 #define PROG_START	0x00010000
-#define PROG_SIZE	0x00400000 /* 4MB */
+#define PROG_SIZE	0x007f0000 /* 8MB */
 
 #define SCRATCH_SIZE	(128 << 10)
 
diff -Nru a/arch/ppc/boot/openfirmware/coffmain.c b/arch/ppc/boot/openfirmware/coffmain.c
--- a/arch/ppc/boot/openfirmware/coffmain.c	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc/boot/openfirmware/coffmain.c	Sun Nov 10 19:28:40 2002
@@ -6,6 +6,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
+#include <linux/string.h>
 #include <asm/processor.h>
 #include <asm/page.h>
 
@@ -35,7 +36,7 @@
 #define RAM_END		(RAM_START + 0x800000)	/* only 8M mapped with BATs */
 
 #define PROG_START	RAM_START
-#define PROG_SIZE	0x00400000
+#define PROG_SIZE	0x00700000
 
 #define SCRATCH_SIZE	(128 << 10)
 
diff -Nru a/arch/ppc/boot/openfirmware/common.c b/arch/ppc/boot/openfirmware/common.c
--- a/arch/ppc/boot/openfirmware/common.c	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/boot/openfirmware/common.c	Sun Nov 10 19:28:41 2002
@@ -10,6 +10,7 @@
 #include "zlib.h"
 #include "nonstdio.h"
 #include "of1275.h"
+#include <linux/string.h>
 #include <asm/bootinfo.h>
 #include <asm/page.h>
 
diff -Nru a/arch/ppc/boot/openfirmware/newworldmain.c b/arch/ppc/boot/openfirmware/newworldmain.c
--- a/arch/ppc/boot/openfirmware/newworldmain.c	Sun Nov 10 19:28:36 2002
+++ b/arch/ppc/boot/openfirmware/newworldmain.c	Sun Nov 10 19:28:36 2002
@@ -6,6 +6,7 @@
  * as published by the Free Software Foundation; either version
  * 2 of the License, or (at your option) any later version.
  */
+#include <linux/string.h>
 #include "nonstdio.h"
 #include "of1275.h"
 #include <asm/processor.h>
@@ -30,7 +31,7 @@
 #define RAM_END		(16 << 20)
 
 #define PROG_START	0x00010000
-#define PROG_SIZE	0x003f0000
+#define PROG_SIZE	0x007f0000
 
 #define SCRATCH_SIZE	(128 << 10)
 
diff -Nru a/arch/ppc/boot/simple/Makefile b/arch/ppc/boot/simple/Makefile
--- a/arch/ppc/boot/simple/Makefile	Sun Nov 10 19:28:36 2002
+++ b/arch/ppc/boot/simple/Makefile	Sun Nov 10 19:28:36 2002
@@ -26,6 +26,12 @@
 
 boot: zImage
 
+boot				:= arch/ppc/boot
+common				:= $(boot)/common
+utils				:= $(boot)/utils
+bootlib				:= $(boot)/lib
+images				:= $(boot)/images
+
 # Normally, we use the 'misc.c' file for decompress_kernel and
 # whatnot.  Sometimes we need to override this however.
 MISC				:= misc.o
@@ -161,16 +167,8 @@
 boot-$(CONFIG_GT64260_CONSOLE)	+= gt64260_tty.o
 endif
 
-boot				:= arch/ppc/boot
-common				:= $(boot)/common
-utils				:= $(boot)/utils
-bootlib				:= $(boot)/lib
-images				:= $(boot)/images
-
 EXTRA_TARGETS			:= $(boot-y)
 LIBS				:=  $(common)/lib.a $(bootlib)/lib.a
-
-include $(TOPDIR)/Rules.make
 
 OBJS				:= $(addprefix $(obj)/,$(boot-y))
 
diff -Nru a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
--- a/arch/ppc/kernel/Makefile	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/kernel/Makefile	Sun Nov 10 19:28:41 2002
@@ -9,9 +9,6 @@
 EXTRA_AFLAGS		:= -Wa,-m405
 endif
 
-CFLAGS_prom_init.o	+= -mrelocatable-lib
-CFLAGS_btext.o		+= -mrelocatable-lib
-
 # Start off with 'head.o', change as needed.
 HEAD-y				:= head.o
 HEAD-$(CONFIG_40x)		:= head_4xx.o
@@ -20,71 +17,27 @@
 
 EXTRA_TARGETS	:= $(HEAD-y)
 
-export-objs			:= ppc_ksyms.o time.o ppc405_dma.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 \
 					semaphore.o syscalls.o setup.o \
 					cputable.o ppc_htab.o
-obj-$(CONFIG_6xx)		+= l2cr.o
+obj-$(CONFIG_6xx)		+= l2cr.o ppc6xx_idle.o
+obj-$(CONFIG_ALL_PPC)		+= ppc6xx_idle.o
 obj-$(CONFIG_MODULES)		+= ppc_ksyms.o
 obj-$(CONFIG_PCI)		+= pci.o 
 ifneq ($(CONFIG_PPC_ISERIES),y)
 obj-$(CONFIG_PCI)		+= pci-dma.o
 endif
-obj-$(CONFIG_PPCBUG_NVRAM)	+= prep_nvram.o
 obj-$(CONFIG_KGDB)		+= ppc-stub.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_TAU)		+= temp.o
-ifeq ($(CONFIG_4xx),y)
-obj-$(CONFIG_4xx)		+= ppc4xx_setup.o ppc4xx_pic.o ppc4xx_serial.o
-obj-$(CONFIG_PPC_RTC)		+= todc_time.o
-obj-$(CONFIG_KGDB)		+= ppc4xx_kgdb.o
-obj-$(CONFIG_405_DMA)		+= ppc405_dma.o
-obj-$(CONFIG_PCI)		+= ppc405_pci.o indirect_pci.o pci_auto.o
-obj-$(CONFIG_PM)		+= ppc4xx_pm.o
-endif
-obj-$(CONFIG_8xx)		+= m8xx_setup.o ppc8xx_pic.o
 ifeq ($(CONFIG_8xx),y)
-obj-$(CONFIG_PCI)		+= qspan_pci.o i8259.o
 ifneq ($(CONFIG_MATH_EMULATION),n)
 obj-y				+= softemu8xx.o
 endif
 endif
-obj-$(CONFIG_ALL_PPC)		+= prom_init.o prom.o open_pic.o \
-					indirect_pci.o i8259.o
-obj-$(CONFIG_ADIR)		+= i8259.o indirect_pci.o pci_auto.o \
-					todc_time.o
-obj-$(CONFIG_EV64260)		+= gt64260_common.o gt64260_pic.o \
-					indirect_pci.o todc_time.o pci_auto.o
-obj-$(CONFIG_GEMINI)		+= open_pic.o i8259.o indirect_pci.o
-obj-$(CONFIG_K2)		+= i8259.o indirect_pci.o todc_time.o \
-					pci_auto.o
-obj-$(CONFIG_LOPEC)		+= mpc10x_common.o indirect_pci.o pci_auto.o \
-					open_pic.o i8259.o todc_time.o
-obj-$(CONFIG_MCPN765)		+= todc_time.o indirect_pci.o pci_auto.o \
-					open_pic.o i8259.o pplus_common.o
-obj-$(CONFIG_MENF1)		+= todc_time.o i8259.o mpc10x_common.o \
-					pci_auto.o indirect_pci.o
-obj-$(CONFIG_MVME5100)		+= open_pic.o todc_time.o indirect_pci.o \
-					i8259.o pci_auto.o pplus_common.o
-obj-$(CONFIG_PCORE)		+= mpc10x_common.o todc_time.o i8259.o \
-					indirect_pci.o pci_auto.o
-obj-$(CONFIG_POWERPMC250)	+= open_pic.o mpc10x_common.o \
-					indirect_pci.o pci_auto.o
-obj-$(CONFIG_PPLUS)		+= pplus_common.o open_pic.o i8259.o \
-				   indirect_pci.o todc_time.o pci_auto.o
-obj-$(CONFIG_PRPMC750)		+= open_pic.o indirect_pci.o pci_auto.o \
-					pplus_common.o
-obj-$(CONFIG_PRPMC800)		+= open_pic.o indirect_pci.o pci_auto.o \
-					pplus_common.o harrier.o
-obj-$(CONFIG_SANDPOINT)		+= i8259.o open_pic.o mpc10x_common.o \
-					pci_auto.o indirect_pci.o todc_time.o
-obj-$(CONFIG_SPRUCE)		+= indirect_pci.o pci_auto.o todc_time.o
-obj-$(CONFIG_ZX4500)		+= indirect_pci.o pci_auto.o mpc10x_common.o \
-					i8259.o open_pic.o
-obj-$(CONFIG_8260)		+= m8260_setup.o ppc8260_pic.o
-obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
 obj-$(CONFIG_PPC_ISERIES)	+= iSeries_misc.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/arch/ppc/kernel/asm-offsets.c b/arch/ppc/kernel/asm-offsets.c
--- a/arch/ppc/kernel/asm-offsets.c	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc/kernel/asm-offsets.c	Sun Nov 10 19:28:40 2002
@@ -114,6 +114,7 @@
 	DEFINE(RESULT, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, result));
 	DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap));
 	DEFINE(CLONE_VM, CLONE_VM);
+	DEFINE(CLONE_UNTRACED, CLONE_UNTRACED);
 	DEFINE(MM_PGD, offsetof(struct mm_struct, pgd));
 
 	/* About the CPU features table */
diff -Nru a/arch/ppc/kernel/btext.c b/arch/ppc/kernel/btext.c
--- a/arch/ppc/kernel/btext.c	Sun Nov 10 19:28:36 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,861 +0,0 @@
-/*
- * Procedures for drawing on the screen early on in the boot process.
- *
- * Benjamin Herrenschmidt <benh@kernel.crashing.org>
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/version.h>
-
-#include <asm/sections.h>
-#include <asm/bootx.h>
-#include <asm/btext.h>
-#include <asm/prom.h>
-#include <asm/page.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/io.h>
-#include <asm/processor.h>
-
-#define NO_SCROLL
-
-#ifndef NO_SCROLL
-static void scrollscreen(void);
-#endif
-
-static void draw_byte(unsigned char c, long locX, long locY);
-static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb);
-static void draw_byte_16(unsigned char *bits, unsigned long *base, int rb);
-static void draw_byte_8(unsigned char *bits, unsigned long *base, int rb);
-
-static int g_loc_X;
-static int g_loc_Y;
-static int g_max_loc_X;
-static int g_max_loc_Y;
-
-unsigned long disp_BAT[2] __initdata = {0, 0};
-
-#define cmapsz	(16*256)
-
-static unsigned char vga_font[cmapsz];
-
-int boot_text_mapped;
-int force_printk_to_btext = 0;
-
-boot_infos_t disp_bi;
-
-extern char *klimit;
-
-/*
- * Powermac can use btext_* after boot for xmon,
- * chrp only uses it during early boot.
- */
-#ifdef CONFIG_XMON
-#define BTEXT	__pmac
-#define BTDATA	__pmacdata
-#else
-#define BTEXT	__init
-#define BTDATA	__initdata
-#endif /* CONFIG_XMON */
-
-/*
- * This is called only when we are booted via BootX.
- */
-void __init
-btext_init(boot_infos_t *bi)
-{
-	g_loc_X = 0;
-	g_loc_Y = 0;
-	g_max_loc_X = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
-	g_max_loc_Y = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
-	disp_bi = *bi;
-	boot_text_mapped = 1;
-}
-
-void __init
-btext_welcome(void)
-{
-	unsigned long flags;
-	unsigned long pvr;
-	boot_infos_t* bi = &disp_bi;
-
-	btext_drawstring("Welcome to Linux, kernel " UTS_RELEASE "\n");
-	btext_drawstring("\nlinked at        : 0x");
-	btext_drawhex(KERNELBASE);
-	btext_drawstring("\nframe buffer at  : 0x");
-	btext_drawhex((unsigned long)bi->dispDeviceBase);
-	btext_drawstring(" (phys), 0x");
-	btext_drawhex((unsigned long)bi->logicalDisplayBase);
-	btext_drawstring(" (log)");
-	btext_drawstring("\nklimit           : 0x");
-	btext_drawhex((unsigned long)klimit);
-	btext_drawstring("\nMSR              : 0x");
-	__asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
-	btext_drawhex(flags);
-	__asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
-	pvr >>= 16;
-	if (pvr > 1) {
-	    btext_drawstring("\nHID0             : 0x");
-	    __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
-	    btext_drawhex(flags);
-	}
-	if (pvr == 8 || pvr == 12 || pvr == 0x800c) {
-	    btext_drawstring("\nICTC             : 0x");
-	    __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
-	    btext_drawhex(flags);
-	}
-	btext_drawstring("\n\n");
-}
-
-/* Calc BAT values for mapping the display and store them
- * in disp_BAT.  Those values are then used from head.S to map
- * the display during identify_machine() and MMU_Init()
- * 
- * The display is mapped to virtual address 0xD0000000, rather
- * than 1:1, because some some CHRP machines put the frame buffer
- * in the region starting at 0xC0000000 (KERNELBASE).
- * This mapping is temporary and will disappear as soon as the
- * setup done by MMU_Init() is applied.
- * 
- * For now, we align the BAT and then map 8Mb on 601 and 16Mb
- * on other PPCs. This may cause trouble if the framebuffer
- * is really badly aligned, but I didn't encounter this case
- * yet.
- */
-void __init
-btext_prepare_BAT(void)
-{
-	boot_infos_t* bi = &disp_bi;
-	unsigned long vaddr = KERNELBASE + 0x10000000;
-	unsigned long addr;
-	unsigned long lowbits;
-
-	addr = (unsigned long)bi->dispDeviceBase;
-	if (!addr) {
-		boot_text_mapped = 0;
-		return;
-	}
-	if (PVR_VER(mfspr(PVR)) != 1) {
-		/* 603, 604, G3, G4, ... */
-		lowbits = addr & ~0xFF000000UL;
-		addr &= 0xFF000000UL;
-		disp_BAT[0] = vaddr | (BL_16M<<2) | 2;
-		disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);		
-	} else {
-		/* 601 */
-		lowbits = addr & ~0xFF800000UL;
-		addr &= 0xFF800000UL;
-		disp_BAT[0] = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4;
-		disp_BAT[1] = addr | BL_8M | 0x40;
-	}
-	bi->logicalDisplayBase = (void *) (vaddr + lowbits);
-}
-
-/* This function will enable the early boot text when doing OF booting. This
- * way, xmon output should work too
- */
-void __init
-btext_setup_display(int width, int height, int depth, int pitch,
-		    unsigned long address)
-{
-	boot_infos_t* bi = &disp_bi;
-
-	g_loc_X = 0;
-	g_loc_Y = 0;
-	g_max_loc_X = width / 8;
-	g_max_loc_Y = height / 16;
-	bi->logicalDisplayBase = (unsigned char *)address;
-	bi->dispDeviceBase = (unsigned char *)address;
-	bi->dispDeviceRowBytes = pitch;
-	bi->dispDeviceDepth = depth;
-	bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
-	bi->dispDeviceRect[2] = width;
-	bi->dispDeviceRect[3] = height;
-	boot_text_mapped = 1;
-}
-
-/* Here's a small text engine to use during early boot
- * or for debugging purposes
- * 
- * todo:
- * 
- *  - build some kind of vgacon with it to enable early printk
- *  - move to a separate file
- *  - add a few video driver hooks to keep in sync with display
- *    changes.
- */
-
-void __openfirmware
-map_boot_text(void)
-{
-	unsigned long base, offset, size;
-	boot_infos_t *bi = &disp_bi;
-	unsigned char *vbase;
-
-	/* By default, we are no longer mapped */
-	boot_text_mapped = 0;
-	if (bi->dispDeviceBase == 0)
-		return;
-	base = ((unsigned long) bi->dispDeviceBase) & 0xFFFFF000UL;
-	offset = ((unsigned long) bi->dispDeviceBase) - base;
-	size = bi->dispDeviceRowBytes * bi->dispDeviceRect[3] + offset
-		+ bi->dispDeviceRect[0];
-	vbase = ioremap(base, size);
-	if (vbase == 0)
-		return;
-	bi->logicalDisplayBase = vbase + offset;
-	boot_text_mapped = 1;
-}
-
-/* Calc the base address of a given point (x,y) */
-static unsigned char * BTEXT
-calc_base(boot_infos_t *bi, int x, int y)
-{
-	unsigned char *base;
-
-	base = bi->logicalDisplayBase;
-	if (base == 0)
-		base = bi->dispDeviceBase;
-	base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3);
-	base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes;
-	return base;
-}
-
-/* Adjust the display to a new resolution */
-void
-btext_update_display(unsigned long phys, int width, int height,
-		     int depth, int pitch)
-{
-	boot_infos_t *bi = &disp_bi;
-
-	if (bi->dispDeviceBase == 0)
-		return;
-
-	/* check it's the same frame buffer (within 256MB) */
-	if ((phys ^ (unsigned long)bi->dispDeviceBase) & 0xf0000000)
-		return;
-
-	bi->dispDeviceBase = (__u8 *) phys;
-	bi->dispDeviceRect[0] = 0;
-	bi->dispDeviceRect[1] = 0;
-	bi->dispDeviceRect[2] = width;
-	bi->dispDeviceRect[3] = height;
-	bi->dispDeviceDepth = depth;
-	bi->dispDeviceRowBytes = pitch;
-	if (boot_text_mapped) {
-		iounmap(bi->logicalDisplayBase);
-		boot_text_mapped = 0;
-	}
-	map_boot_text();
-	g_loc_X = 0;
-	g_loc_Y = 0;
-	g_max_loc_X = width / 8;
-	g_max_loc_Y = height / 16;
-}
-
-void BTEXT btext_clearscreen(void)
-{
-	boot_infos_t* bi	= &disp_bi;
-	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
-	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
-					(bi->dispDeviceDepth >> 3)) >> 2;
-	int i,j;
-	
-	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
-	{
-		unsigned long *ptr = base;
-		for(j=width; j; --j)
-			*(ptr++) = 0;
-		base += (bi->dispDeviceRowBytes >> 2);
-	}
-}
-
-__inline__ void dcbst(const void* addr)
-{
-	__asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr));
-}
-
-void BTEXT btext_flushscreen(void)
-{
-	boot_infos_t* bi	= &disp_bi;
-	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
-	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
-					(bi->dispDeviceDepth >> 3)) >> 2;
-	int i,j;
-	
-	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
-	{
-		unsigned long *ptr = base;
-		for(j=width; j>0; j-=8) {
-			dcbst(ptr);
-			ptr += 8;
-		}
-		base += (bi->dispDeviceRowBytes >> 2);
-	}
-}
-
-#ifndef NO_SCROLL
-static BTEXT void
-scrollscreen(void)
-{
-	boot_infos_t* bi		= &disp_bi;
-	unsigned long *src		= (unsigned long *)calc_base(bi,0,16);
-	unsigned long *dst		= (unsigned long *)calc_base(bi,0,0);
-	unsigned long width		= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
-						(bi->dispDeviceDepth >> 3)) >> 2;
-	int i,j;
-	
-#ifdef CONFIG_ADB_PMU
-	pmu_suspend();	/* PMU will not shut us down ! */
-#endif
-	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++)
-	{
-		unsigned long *src_ptr = src;
-		unsigned long *dst_ptr = dst;
-		for(j=width; j; --j)
-			*(dst_ptr++) = *(src_ptr++);
-		src += (bi->dispDeviceRowBytes >> 2);
-		dst += (bi->dispDeviceRowBytes >> 2);
-	}
-	for (i=0; i<16; i++)
-	{
-		unsigned long *dst_ptr = dst;
-		for(j=width; j; --j)
-			*(dst_ptr++) = 0;
-		dst += (bi->dispDeviceRowBytes >> 2);
-	}
-#ifdef CONFIG_ADB_PMU
-	pmu_resume();	/* PMU will not shut us down ! */
-#endif
-}
-#endif /* ndef NO_SCROLL */
-
-void BTEXT btext_drawchar(char c)
-{
-	int cline = 0, x;
-
-	if (!boot_text_mapped)
-		return;
-
-	switch (c) {
-	case '\b':
-		if (g_loc_X > 0)
-			--g_loc_X;
-		break;
-	case '\t':
-		g_loc_X = (g_loc_X & -8) + 8;
-		break;
-	case '\r':
-		g_loc_X = 0;
-		break;
-	case '\n':
-		g_loc_X = 0;
-		g_loc_Y++;
-		cline = 1;
-		break;
-	default:
-		draw_byte(c, g_loc_X++, g_loc_Y);
-	}
-	if (g_loc_X >= g_max_loc_X) {
-		g_loc_X = 0;
-		g_loc_Y++;
-		cline = 1;
-	}
-#ifndef NO_SCROLL
-	while (g_loc_Y >= g_max_loc_Y) {
-		scrollscreen();
-		g_loc_Y--;
-	}
-#else
-	/* wrap around from bottom to top of screen so we don't
-	   waste time scrolling each line.  -- paulus. */
-	if (g_loc_Y >= g_max_loc_Y)
-		g_loc_Y = 0;
-	if (cline) {
-		for (x = 0; x < g_max_loc_X; ++x)
-			draw_byte(' ', x, g_loc_Y);
-	}
-#endif
-}
-
-void BTEXT
-btext_drawstring(const char *c)
-{
-	if (!boot_text_mapped)
-		return;
-	while (*c)
-		btext_drawchar(*c++);
-}
-
-void BTEXT
-btext_drawhex(unsigned long v)
-{
-	static char hex_table[] = "0123456789abcdef";
-	
-	if (!boot_text_mapped)
-		return;
-	btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >>  8) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >>  4) & 0x0000000FUL]);
-	btext_drawchar(hex_table[(v >>  0) & 0x0000000FUL]);
-	btext_drawchar(' ');
-}
-
-static void BTEXT
-draw_byte(unsigned char c, long locX, long locY)
-{
-	boot_infos_t* bi	= &disp_bi;
-	unsigned char *base	= calc_base(bi, locX << 3, locY << 4);
-	unsigned char *font	= &vga_font[((unsigned long)c) * 16];
-	int rb			= bi->dispDeviceRowBytes;
-	
-	switch(bi->dispDeviceDepth) {
-	case 24:
-	case 32:
-		draw_byte_32(font, (unsigned long *)base, rb);
-		break;
-	case 15:
-	case 16:
-		draw_byte_16(font, (unsigned long *)base, rb);
-		break;
-	case 8:
-		draw_byte_8(font, (unsigned long *)base, rb);
-		break;
-	}
-}
-
-static unsigned long expand_bits_8[16] BTDATA = {
-	0x00000000,
-	0x000000ff,
-	0x0000ff00,
-	0x0000ffff,
-	0x00ff0000,
-	0x00ff00ff,
-	0x00ffff00,
-	0x00ffffff,
-	0xff000000,
-	0xff0000ff,
-	0xff00ff00,
-	0xff00ffff,
-	0xffff0000,
-	0xffff00ff,
-	0xffffff00,
-	0xffffffff
-};
-
-static unsigned long expand_bits_16[4] BTDATA = {
-	0x00000000,
-	0x0000ffff,
-	0xffff0000,
-	0xffffffff
-};
-
-
-static void BTEXT
-draw_byte_32(unsigned char *font, unsigned long *base, int rb)
-{
-	int l, bits;	
-	int fg = 0xFFFFFFFFUL;
-	int bg = 0x00000000UL;
-	
-	for (l = 0; l < 16; ++l)
-	{
-		bits = *font++;
-		base[0] = (-(bits >> 7) & fg) ^ bg;
-		base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
-		base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
-		base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
-		base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
-		base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
-		base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
-		base[7] = (-(bits & 1) & fg) ^ bg;
-		base = (unsigned long *) ((char *)base + rb);
-	}
-}
-
-static void BTEXT
-draw_byte_16(unsigned char *font, unsigned long *base, int rb)
-{
-	int l, bits;	
-	int fg = 0xFFFFFFFFUL;
-	int bg = 0x00000000UL;
-	unsigned long *eb = expand_bits_16;
-
-	for (l = 0; l < 16; ++l)
-	{
-		bits = *font++;
-		base[0] = (eb[bits >> 6] & fg) ^ bg;
-		base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
-		base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
-		base[3] = (eb[bits & 3] & fg) ^ bg;
-		base = (unsigned long *) ((char *)base + rb);
-	}
-}
-
-static void BTEXT
-draw_byte_8(unsigned char *font, unsigned long *base, int rb)
-{
-	int l, bits;	
-	int fg = 0x0F0F0F0FUL;
-	int bg = 0x00000000UL;
-	unsigned long *eb = expand_bits_8;
-
-	for (l = 0; l < 16; ++l)
-	{
-		bits = *font++;
-		base[0] = (eb[bits >> 4] & fg) ^ bg;
-		base[1] = (eb[bits & 0xf] & fg) ^ bg;
-		base = (unsigned long *) ((char *)base + rb);
-	}
-}
-
-static unsigned char vga_font[cmapsz] BTDATA = {
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
-0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
-0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
-0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
-0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
-0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
-0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
-0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
-0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
-0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
-0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
-0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
-0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
-0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
-0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
-0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
-0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
-0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
-0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
-0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
-0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
-0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
-0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
-0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
-0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
-0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
-0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
-0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
-0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
-0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
-0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
-0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
-0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
-0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
-0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
-0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
-0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
-0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
-0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
-0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
-0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
-0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
-0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
-0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
-0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
-0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
-0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
-0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
-0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
-0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
-0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
-0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
-0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
-0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
-0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
-0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
-0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
-0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
-0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
-0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
-0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
-0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
-0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
-0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
-0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
-0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
-0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
-0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
-0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
-0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
-0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
-0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
-0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
-0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
-0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
-0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
-0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
-0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
-0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
-0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
-0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
-0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
-0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
-0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
-0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
-0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
-0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
-0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
-0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
-0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
-0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
-0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
-0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
-0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
-0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
-0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
-0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
-0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
-0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
-0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
-0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
-0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
-0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
-0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
-0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
-0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
-0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
-0x00, 0x00, 0x00, 0x00, 
-};
diff -Nru a/arch/ppc/kernel/gt64260_common.c b/arch/ppc/kernel/gt64260_common.c
--- a/arch/ppc/kernel/gt64260_common.c	Sun Nov 10 19:28:36 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1666 +0,0 @@
-/*
- * arch/ppc/kernel/gt64260_common.c
- * 
- * Common routines for the Marvell/Galileo GT64260 (Discovery) host bridge,
- * interrupt controller, memory controller, serial controller, enet controller,
- * etc.
- *
- * Author: Mark A. Greer <mgreer@mvista.com>
- *
- * Copyright 2001 MontaVista Software 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.
- */
-
-/*
- * The GT64260 port is the result of hard work from many people from
- * many companies.  In particular, employees of Marvell/Galileo, Mission
- * Critical Linux, Xyterra, and MontaVista Software were heavily involved.
- */
-
-/*
- * At last count, the 64260-B-0 has 65 errata and 24 restrictions.  The odds of
- * you getting it to work well, under stress, for a long period of time are
- * low.  If nothing else, you will likely run into an interrupt controller
- * bug.
- *
- * The newer 64260A-B-0 is much improved but has its own problems.
- * Dave Wilhardt <dwilhardt@zyterra.com> has discovered that you must set
- * up your PCI snoop regions to be prefetchable with 4-word bursts AND set the
- * "Memory Write and Invalidate bit" (bit 4) in the cmd reg of each PCI device
- * before coherency works between PCI and other devices.  Many thanks to Dave.
- *
- * So far this code has been tested on Marvell/Galileo EV-64260-BP and
- * an EV-64260A-BP uni-processor boards with 750 and 7400 processors.
- * It has not yet been tested with a 7410 or 7450, or on an smp system.
- *
- * Note: I have not had any luck moving the base register address of the bridge
- * 	 with the gt64260_set_base() routine.  I move it in the bootloader
- * 	 before starting the kernel.  I haven't really looked into it so it
- * 	 may be an easy fix. -- MAG
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <asm/gt64260.h>
-#include <asm/delay.h>
-
-
-u32	gt64260_base; /* Virtual base address of 64260's regs */
-u32	gt64260_revision; /* Revision of the chip */
-u8	gt64260_pci_exclude_bridge = TRUE;
-
-
-/*
- *****************************************************************************
- *
- *	Bridge Initialization Routines
- *
- *****************************************************************************
- */
-static void gt64260_check_errata(struct pci_controller *hose_a,
-				 struct pci_controller *hose_b);
-
-/*
- * Typical '_find_bridges()' routine for boards with a GT64260 bridge.
- */
-int __init
-gt64260_find_bridges(u32 phys_base_addr, gt64260_bridge_info_t *info,
-	int ((*map_irq)(struct pci_dev *, unsigned char, unsigned char)))
-{
-	struct pci_controller		*hose_a, *hose_b;
-	u32				io_base_a, io_base_b;
-	int				rc;
-
-
-	gt64260_base = (u32)ioremap(phys_base_addr,GT64260_INTERNAL_SPACE_SIZE);
-
-	hose_a = pcibios_alloc_controller();
-	if (!hose_a)
-		return -1;
-
-	hose_b = pcibios_alloc_controller();
-	if (!hose_b)
-		return -1;
-
-	info->hose_a = hose_a;
-	info->hose_b = hose_b;
-
-	/* Ends up mapping PCI Config addr/data pairs twice */
-	setup_indirect_pci(hose_a,
-			   phys_base_addr + GT64260_PCI_0_CONFIG_ADDR,
-			   phys_base_addr + GT64260_PCI_0_CONFIG_DATA);
-
-	setup_indirect_pci(hose_b,
-			   phys_base_addr + GT64260_PCI_1_CONFIG_ADDR,
-			   phys_base_addr + GT64260_PCI_1_CONFIG_DATA);
-
-	if ((rc = gt64260_bridge_init(info)) != 0) {
-		iounmap((void *)hose_a->cfg_addr);
-		iounmap((void *)hose_a->cfg_data);
-		iounmap((void *)hose_b->cfg_addr);
-		iounmap((void *)hose_b->cfg_data);
-		iounmap((void *)gt64260_base);
-		return rc;
-	}
-
-	/* ioremap PCI I/O regions */
-	io_base_b = (u32)ioremap(info->pci_1_io_start_proc,info->pci_1_io_size);
-	io_base_a = (u32)ioremap(info->pci_0_io_start_proc,info->pci_0_io_size);
-	isa_io_base = io_base_a;
-
-	hose_a->first_busno = 0;
-	hose_a->last_busno  = 0xff;
-
-	pci_init_resource(&hose_a->io_resource,
-			  0,	/* really: io_base_a - isa_io_base */
-			  info->pci_0_io_size - 1,
-			  IORESOURCE_IO,
-			  "host bridge PCI bus 0");
-	hose_a->io_space.start = info->pci_0_io_start_pci;
-	hose_a->io_space.end   = info->pci_0_io_start_pci +
-					info->pci_0_io_size - 1;
-	hose_a->io_base_virt = (void *)isa_io_base;
-
-	pci_init_resource(&hose_a->mem_resources[0],
-			  info->pci_0_mem_start_proc,
-			  info->pci_0_mem_start_proc + info->pci_0_mem_size - 1,
-			  IORESOURCE_MEM,
-			  "host bridge PCI bus 0");
-	hose_a->mem_space.start = info->pci_0_mem_start_pci_lo;
-	hose_a->mem_space.end   = info->pci_0_mem_start_pci_lo +
-					info->pci_0_mem_size - 1;
-	hose_a->pci_mem_offset = (info->pci_0_mem_start_proc -
-					info->pci_0_mem_start_pci_lo);
-
-	hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
-
-
-	hose_b->first_busno = hose_a->last_busno + 1;
-	hose_b->bus_offset  = hose_b->first_busno;
-	hose_b->last_busno  = 0xff;
-
-	pci_init_resource(&hose_b->io_resource,
-			  io_base_b - isa_io_base,
-			  io_base_b - isa_io_base + info->pci_1_io_size - 1,
-			  IORESOURCE_IO,
-			  "host bridge PCI bus 1");
-	hose_b->io_space.start = info->pci_1_io_start_pci;
-	hose_b->io_space.end   = info->pci_1_io_start_pci +
-					info->pci_1_io_size - 1;
-	hose_b->io_base_virt = (void *)isa_io_base;
-
-	pci_init_resource(&hose_b->mem_resources[0],
-			  info->pci_1_mem_start_proc,
-			  info->pci_1_mem_start_proc + info->pci_1_mem_size - 1,
-			  IORESOURCE_MEM,
-			  "host bridge PCI bus 1");
-	hose_b->mem_space.start = info->pci_1_mem_start_pci_lo;
-	hose_b->mem_space.end   = info->pci_1_mem_start_pci_lo +
-					info->pci_1_mem_size - 1;
-	hose_b->pci_mem_offset = (info->pci_1_mem_start_proc -
-					info->pci_1_mem_start_pci_lo);
-
-	hose_b->last_busno = pciauto_bus_scan(hose_b, hose_b->first_busno);
-
-
-	ppc_md.pci_exclude_device = gt64260_pci_exclude_device;
-	ppc_md.pci_swizzle        = common_swizzle;
-	ppc_md.pci_map_irq        = map_irq;
-
-	return 0;
-} /* gt64260_find_bridges() */
-
-/*
- * gt64260_bridge_init()
- *
- * Perform bridge initialization for a "typical" setup for a PPC system.
- */
-int __init
-gt64260_bridge_init(gt64260_bridge_info_t *info)
-{
-	int	window;
-	u16	u16_val;
-	u32	u32_val;
-	int	rc = 0;
-	u8	save_exclude;
-
-	/*
-	 * Count on firmware to set/clear other bits in this register.
-	 *
-	 * Set CPU CONFIG Reg bit:
-	 *	bit 13 - Pipeline
-	 *	bit 16 - RdOOO
-	 *
-	 * Clear CPU Config Reg bit:
-	 * 	bit 12 - endianess
-	 *	bit 27 - RemapWrDis
-	 */
-	u32_val = gt_read(GT64260_CPU_CONFIG);
-	u32_val |= ((1<<13) | (1<<16));
-	u32_val &= ~((1<<8) | (1<<12) | (1<<27));
-	gt_write(GT64260_CPU_CONFIG, u32_val);
-
-	/* PCI 0/1 Timeout and Retry limits */
-	u32_val = gt_read(GT64260_PCI_0_TO_RETRY);
-	u32_val |= 0x0000ffff;
-	gt_write(GT64260_PCI_0_TO_RETRY, u32_val);
-
-	u32_val = gt_read(GT64260_PCI_1_TO_RETRY);
-	u32_val |= 0x0000ffff;
-	gt_write(GT64260_PCI_1_TO_RETRY, u32_val);
-
-	save_exclude = gt64260_pci_exclude_bridge;
-	gt64260_pci_exclude_bridge = FALSE;
-
-	/* Set class code to indicate host bridge */
-	early_read_config_dword(info->hose_a,
-			        info->hose_a->first_busno,
-			        PCI_DEVFN(0,0),
-			        PCI_CLASS_REVISION,
-			        &u32_val);
-	u32_val &= 0x000000ff;
-	gt64260_revision = u32_val;	/* a 64260 or 64260A? */
-	u32_val |= (PCI_CLASS_BRIDGE_HOST << 16);
-	early_write_config_dword(info->hose_a,
-				 info->hose_a->first_busno,
-				 PCI_DEVFN(0,0),
-				 PCI_CLASS_REVISION,
-				 u32_val);
-
-	early_read_config_dword(info->hose_b,
-			        info->hose_b->first_busno,
-			        PCI_DEVFN(0,0),
-			        PCI_CLASS_REVISION,
-			        &u32_val);
-	u32_val &= 0x000000ff;
-	u32_val |= (PCI_CLASS_BRIDGE_HOST << 16);
-	early_write_config_dword(info->hose_b,
-				 info->hose_b->first_busno,
-				 PCI_DEVFN(0,0),
-				 PCI_CLASS_REVISION,
-				 u32_val);
-
-	/* Enable 64260 to be PCI master & respond to PCI MEM cycles */
-	early_read_config_word(info->hose_a,
-			       info->hose_a->first_busno,
-			       PCI_DEVFN(0,0),
-			       PCI_COMMAND,
-			       &u16_val);
-	u16_val |= (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
-	early_write_config_word(info->hose_a,
-				info->hose_a->first_busno,
-				PCI_DEVFN(0,0),
-				PCI_COMMAND,
-				u16_val);
-
-	early_read_config_word(info->hose_b,
-			       info->hose_b->first_busno,
-			       PCI_DEVFN(0,0),
-			       PCI_COMMAND,
-			       &u16_val);
-	u16_val |= (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
-	early_write_config_word(info->hose_b,
-				info->hose_b->first_busno,
-				PCI_DEVFN(0,0),
-				PCI_COMMAND,
-				u16_val);
-
-	gt64260_pci_exclude_bridge = save_exclude;
-
-	/*
-	 * Disable all CPU windows on the bridge except for SCS 0 which
-	 * is covering all of system memory.:
-	 */
-	gt64260_cpu_disable_all_windows();
-
-	/*
-	 * Set CPU snoop window to indicate all of system memory
-	 * is covered with wirte-back cache.
-	 */
-	gt64260_cpu_snoop_set_window(0,
-				     0x00000000,
-				     info->mem_size,
-				     GT64260_CPU_SNOOP_WB);
-
-	/*
-	 * Set up CPU->PCI mappings (so CPU can get at PCI dev regs/mem).
-	 * Will only use one of the four CPU->PCI MEM windows on each bus.
-	 */
-	gt64260_cpu_set_pci_io_window(0,
-				      info->pci_0_io_start_proc,
-				      info->pci_0_io_start_pci,
-				      info->pci_0_io_size,
-				      info->pci_0_io_swap);
-
-	gt64260_cpu_set_pci_mem_window(0,
-				       0,
-				       info->pci_0_mem_start_proc,
-				       info->pci_0_mem_start_pci_hi,
-				       info->pci_0_mem_start_pci_lo,
-				       info->pci_0_mem_size,
-				       info->pci_0_mem_swap);
-
-	gt64260_cpu_set_pci_io_window(1,
-				      info->pci_1_io_start_proc,
-				      info->pci_1_io_start_pci,
-				      info->pci_1_io_size,
-				      info->pci_1_io_swap);
-
-	gt64260_cpu_set_pci_mem_window(1,
-				       0,
-				       info->pci_1_mem_start_proc,
-				       info->pci_1_mem_start_pci_hi,
-				       info->pci_1_mem_start_pci_lo,
-				       info->pci_1_mem_size,
-				       info->pci_1_mem_swap);
-
-	/*
-	 * Set up PCI MEM->system memory mapping (bridge slave PCI window).
-	 *
-	 * Set BAR enables to allow only the SCS0 slave window to respond
-	 * to PCI read/write cycles.
-	 */
-	gt64260_pci_bar_enable(0, GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_0);
-	gt64260_pci_bar_enable(1, GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_0);
-
-	/*
-	 * For virt_to_bus & bus_to_virt to work correctly, this mapping
-	 * must be the same on both PCI buses.
-	 */
-	gt64260_pci_slave_scs_set_window(info->hose_a,
-					 0,
-					 0x00000000,
-					 0x00000000,
-					 info->mem_size);
-
-	gt64260_pci_slave_scs_set_window(info->hose_b,
-					 0,
-					 0x00000000,
-					 0x00000000,
-					 info->mem_size);
-	pci_dram_offset = 0; /* System mem at same addr on PCI & cpu bus */
-
-	/* Disable all the access control windows */
-	for (window=0; window<GT64260_PCI_ACC_CNTL_WINDOWS; window++) {
-		gt64260_pci_acc_cntl_set_window(0, window, 0, 0, 0, 0); 
-		gt64260_pci_acc_cntl_set_window(1, window, 0, 0, 0, 0); 
-	}
-
-	/* Disable all the PCI snoop regions */
-	for (window=0; window<GT64260_PCI_SNOOP_WINDOWS; window++) {
-		gt64260_pci_snoop_set_window(0, window, 0, 0, 0, 0); 
-		gt64260_pci_snoop_set_window(1, window, 0, 0, 0, 0); 
-	}
-
-	gt64260_pci_acc_cntl_set_window(0,
-					0,
-					0x00000000,
-					0x00000000,
-					info->mem_size,
-					(GT64260_PCI_ACC_CNTL_PREFETCHEN |
-					 GT64260_PCI_ACC_CNTL_MBURST_4_WORDS |
-					 GT64260_PCI_ACC_CNTL_SWAP_BYTE));
-
-	gt64260_pci_acc_cntl_set_window(1,
-					0,
-					0x00000000,
-					0x00000000,
-					info->mem_size,
-					(GT64260_PCI_ACC_CNTL_PREFETCHEN |
-					 GT64260_PCI_ACC_CNTL_MBURST_4_WORDS |
-					 GT64260_PCI_ACC_CNTL_SWAP_BYTE));
-
-	gt64260_pci_snoop_set_window(0,
-				     0,
-				     0x00000000,
-				     0x00000000,
-				     info->mem_size,
-				     GT64260_PCI_SNOOP_WB);
-					
-	gt64260_pci_snoop_set_window(1,
-				     0,
-				     0x00000000,
-				     0x00000000,
-				     info->mem_size,
-				     GT64260_PCI_SNOOP_WB);
-
-	gt64260_check_errata(info->hose_a, info->hose_b);
-
-
-	/* Set latency timer (to 64) & cacheline size; clear BIST */
-	gt64260_pci_exclude_bridge = FALSE;
-	u32_val = ((0x04 << 8) | (L1_CACHE_LINE_SIZE / 4));
-
-	early_write_config_dword(info->hose_a,
-				 info->hose_a->first_busno,
-				 PCI_DEVFN(0,0),
-				 PCI_CACHE_LINE_SIZE,
-				 u32_val);
-	early_write_config_dword(info->hose_b,
-				 info->hose_b->first_busno,
-				 PCI_DEVFN(0,0),
-				 PCI_CACHE_LINE_SIZE,
-				 u32_val);
-	gt64260_pci_exclude_bridge = TRUE;
-
-	return rc;
-} /* gt64260_bridge_init() */
-
-/*
- * gt64260_check_errata()
- *
- * Apply applicable errata and restrictions from 0.5 of the
- * Errata and Restrictions document from Marvell/Galileo.
- */
-static void __init
-gt64260_check_errata(struct pci_controller *hose_a,
-		     struct pci_controller *hose_b)
-{
-	u32	val;
-	u8	save_exclude;
-
-	/* Currently 2 versions, 64260 and 64260A */
-	if (gt64260_revision == GT64260) {
-		save_exclude = gt64260_pci_exclude_bridge;
-		gt64260_pci_exclude_bridge = FALSE;
-
-		/* FEr#5, FEr#12 */
-		early_read_config_dword(hose_a,
-					hose_a->first_busno,
-					PCI_DEVFN(0,0),
-					PCI_COMMAND,
-					&val);
-		val &= ~(PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY);
-		early_write_config_dword(hose_a,
-					 hose_a->first_busno,
-					 PCI_DEVFN(0,0),
-					 PCI_COMMAND,
-					 val);
-
-		early_read_config_dword(hose_b,
-					hose_b->first_busno,
-					PCI_DEVFN(0,0),
-					PCI_COMMAND,
-					&val);
-		val &= ~(PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY);
-		early_write_config_dword(hose_b,
-					 hose_b->first_busno,
-					 PCI_DEVFN(0,0),
-					 PCI_COMMAND,
-					 val);
-		gt64260_pci_exclude_bridge = save_exclude;
-
-		/* FEr#12, FEr#13 */
-		gt_clr_bits(GT64260_PCI_0_CMD, ((1<<4) | (1<<5) | (1<<9)));
-		gt_clr_bits(GT64260_PCI_1_CMD, ((1<<4) | (1<<5) | (1<<9)));
-
-		/* FEr#54 */
-		gt_clr_bits(GT64260_CPU_SNOOP_BASE_0, 0xfffcf000);
-		gt_clr_bits(GT64260_CPU_SNOOP_BASE_1, 0xfffcf000);
-		gt_clr_bits(GT64260_CPU_SNOOP_BASE_2, 0xfffcf000);
-		gt_clr_bits(GT64260_CPU_SNOOP_BASE_3, 0xfffcf000);
-
-		/* R#18 */
-		gt_set_bits(GT64260_SDRAM_CONFIG, (1<<26));
-
-	} else if (gt64260_revision == GT64260A) {
-		/* R#18 */
-		gt_set_bits(GT64260_SDRAM_CONFIG, (1<<26));
-
-		/* No longer errata so turn on */
-		gt_set_bits(GT64260_PCI_0_CMD, ((1<<4) | (1<<5) | (1<<9)));
-		gt_set_bits(GT64260_PCI_1_CMD, ((1<<4) | (1<<5) | (1<<9)));
-	}
-} /* gt64260_check_errata() */
-
-
-/*
- *****************************************************************************
- *
- *	General Window Setting Routines
- *
- *****************************************************************************
- */
-
-static int
-gt64260_set_32bit_window(u32 base_addr,
-			 u32 size,
-			 u32 other_bits,
-			 u32 bot_reg,
-			 u32 top_reg)
-{
-	u32	val;
-
-	if (size > 0) {
-		/* Set up the window on the CPU side */
-		gt_write(bot_reg, (base_addr >> 20) | other_bits);
-		gt_write(top_reg, (base_addr + size - 1) >> 20);
-	} else { /* Disable window */
-		gt_write(top_reg, 0x00000000);
-		gt_write(bot_reg, 0x00000fff | other_bits);
-	}
-
-	val = gt_read(bot_reg); /* Flush FIFO */
-	return 0;
-} /* gt64260_set_32bit_window() */
-
-static int
-gt64260_set_64bit_window(u32 base_addr_hi,
-			 u32 base_addr_lo,
-			 u32 size,
-			 u32 other_bits,
-			 u32 bot_reg_hi,
-			 u32 bot_reg_lo,
-			 u32 top_reg)
-{
-	int	rc;
-
-	if ((rc = gt64260_set_32bit_window(base_addr_lo,
-					   size,
-					   other_bits,
-					   bot_reg_lo,
-					   top_reg)) == 0) {
-
-		gt_write(bot_reg_hi, base_addr_hi);
-		base_addr_hi = gt_read(bot_reg_hi); /* Flush FIFO */
-	}
-
-	return rc;
-} /* gt64260_set_64bit_window() */
-
-
-/*
- *****************************************************************************
- *
- *	CPU Configuration Routines
- *
- *****************************************************************************
- */
-
-int
-gt64260_cpu_scs_set_window(u32 window,
-			   u32 base_addr,
-			   u32 size)
-{
-	static u32
-	cpu_scs_windows[GT64260_CPU_SCS_DECODE_WINDOWS][2] = {
-		{ GT64260_CPU_SCS_DECODE_0_BOT, GT64260_CPU_SCS_DECODE_0_TOP },
-		{ GT64260_CPU_SCS_DECODE_1_BOT, GT64260_CPU_SCS_DECODE_1_TOP },
-		{ GT64260_CPU_SCS_DECODE_2_BOT, GT64260_CPU_SCS_DECODE_2_TOP },
-		{ GT64260_CPU_SCS_DECODE_3_BOT, GT64260_CPU_SCS_DECODE_3_TOP },
-	}; /* cpu_scs_windows[][] */
-	int	rc = -1;
-
-	if (window < GT64260_CPU_SCS_DECODE_WINDOWS) {
-		rc = gt64260_set_32bit_window(base_addr,
-					      size,
-					      0,
-					      cpu_scs_windows[window][0],
-					      cpu_scs_windows[window][1]);
-	}
-
-	return rc;
-} /* gt64260_cpu_scs_set_window() */
-
-int
-gt64260_cpu_cs_set_window(u32 window,
-			  u32 base_addr,
-			  u32 size)
-{
-	static u32
-	cpu_cs_windows[GT64260_CPU_CS_DECODE_WINDOWS][2] = {
-		{ GT64260_CPU_CS_DECODE_0_BOT, GT64260_CPU_CS_DECODE_0_TOP },
-		{ GT64260_CPU_CS_DECODE_1_BOT, GT64260_CPU_CS_DECODE_1_TOP },
-		{ GT64260_CPU_CS_DECODE_2_BOT, GT64260_CPU_CS_DECODE_2_TOP },
-		{ GT64260_CPU_CS_DECODE_3_BOT, GT64260_CPU_CS_DECODE_3_TOP },
-	}; /* cpu_cs_windows[][] */
-	int	rc = -1;
-
-	if (window < GT64260_CPU_CS_DECODE_WINDOWS) {
-		rc = gt64260_set_32bit_window(base_addr,
-					      size,
-					      0,
-					      cpu_cs_windows[window][0],
-					      cpu_cs_windows[window][1]);
-	}
-
-	return rc;
-} /* gt64260_cpu_cs_set_window() */
-
-int
-gt64260_cpu_boot_set_window(u32 base_addr,
-			    u32 size)
-{
-	int	rc;
-
-	rc = gt64260_set_32bit_window(base_addr,
-				      size,
-				      0,
-				      GT64260_CPU_BOOT_CS_DECODE_0_BOT,
-				      GT64260_CPU_BOOT_CS_DECODE_0_TOP);
-
-	return rc;
-} /* gt64260_cpu_boot_set_window() */
-
-/*
- * gt64260_cpu_set_pci_io_window()
- *
- * Set up a CPU window into PCI I/O or MEM space.
- * Always do Read/Modify/Write to window regs.
- */
-static int
-gt64260_cpu_pci_set_window(u32 cpu_base_addr,
-			   u32 pci_base_addr,
-			   u32 size,
-			   u32 other_bits,
-			   u32 bot_reg,
-			   u32 top_reg,
-			   u32 remap_reg)
-{
-	u32	val;
-	int	rc;
-
-	if ((rc = gt64260_set_32bit_window(cpu_base_addr,
-					   size,
-					   other_bits,
-					   bot_reg,
-					   top_reg)) == 0) {
-
-		/* Set up CPU->PCI remapping (on lower 32 bits) */
-		gt_write(remap_reg, pci_base_addr >> 20);
-		val = gt_read(bot_reg); /* Flush FIFO */
-	}
-
-	return rc;
-} /* gt64260_cpu_pci_set_window() */
-
-
-/*
- * gt64260_cpu_set_pci_io_window()
- *
- * Set up a CPU window into PCI I/O space.
- * Always do Read/Modify/Write to window regs.
- */
-int
-gt64260_cpu_set_pci_io_window(u32 pci_bus,
-			      u32 cpu_base_addr,
-			      u32 pci_base_addr,
-			      u32 size,
-			      u32 swap)
-{
-	/* 2 PCI buses with 1 I/O window each (from CPU point of view) */
-	static u32
-	cpu_pci_io_windows[GT64260_PCI_BUSES][3] = {
-		{ GT64260_CPU_PCI_0_IO_DECODE_BOT,
-		  GT64260_CPU_PCI_0_IO_DECODE_TOP,
-		  GT64260_CPU_PCI_0_IO_REMAP },
-
-		{ GT64260_CPU_PCI_1_IO_DECODE_BOT,
-		  GT64260_CPU_PCI_1_IO_DECODE_TOP,
-		  GT64260_CPU_PCI_1_IO_REMAP },
-	}; /* cpu_pci_io_windows[][] */
-	int	rc = -1;
-
-	if (pci_bus < GT64260_PCI_BUSES) {
-		rc =  gt64260_cpu_pci_set_window(cpu_base_addr,
-					  pci_base_addr,
-					  size,
-					  swap,
-					  cpu_pci_io_windows[pci_bus][0],
-					  cpu_pci_io_windows[pci_bus][1],
-					  cpu_pci_io_windows[pci_bus][2]);
-	}
-
-	return rc;
-} /* gt64260_cpu_set_pci_io_window() */
-
-/*
- * gt64260_cpu_set_pci_mem_window()
- *
- * Set up a CPU window into PCI MEM space (4 PCI MEM windows per PCI bus).
- * Always do Read/Modify/Write to window regs.
- */
-int
-gt64260_cpu_set_pci_mem_window(u32 pci_bus,
-			       u32 window,
-			       u32 cpu_base_addr,
-			       u32 pci_base_addr_hi,
-			       u32 pci_base_addr_lo,
-			       u32 size,
-			       u32 swap_64bit)
-{
-	/* 2 PCI buses with 4 memory windows each (from CPU point of view) */
-	static u32
-	cpu_pci_mem_windows[GT64260_PCI_BUSES][GT64260_PCI_MEM_WINDOWS_PER_BUS][4] = {
-		{ /* PCI 0 */
-			{ GT64260_CPU_PCI_0_MEM_0_DECODE_BOT,
-			  GT64260_CPU_PCI_0_MEM_0_DECODE_TOP,
-			  GT64260_CPU_PCI_0_MEM_0_REMAP_HI,
-			  GT64260_CPU_PCI_0_MEM_0_REMAP_LO },
-
-			{ GT64260_CPU_PCI_0_MEM_1_DECODE_BOT,
-			  GT64260_CPU_PCI_0_MEM_1_DECODE_TOP,
-			  GT64260_CPU_PCI_0_MEM_1_REMAP_HI,
-			  GT64260_CPU_PCI_0_MEM_1_REMAP_LO },
-
-			{ GT64260_CPU_PCI_0_MEM_2_DECODE_BOT,
-			  GT64260_CPU_PCI_0_MEM_2_DECODE_TOP,
-			  GT64260_CPU_PCI_0_MEM_2_REMAP_HI,
-			  GT64260_CPU_PCI_0_MEM_2_REMAP_LO },
-
-			{ GT64260_CPU_PCI_0_MEM_3_DECODE_BOT,
-			  GT64260_CPU_PCI_0_MEM_3_DECODE_TOP,
-			  GT64260_CPU_PCI_0_MEM_3_REMAP_HI,
-			  GT64260_CPU_PCI_0_MEM_3_REMAP_LO }
-		},
-
-		{ /* PCI 1 */
-			{ GT64260_CPU_PCI_1_MEM_0_DECODE_BOT,
-			  GT64260_CPU_PCI_1_MEM_0_DECODE_TOP,
-			  GT64260_CPU_PCI_1_MEM_0_REMAP_HI,
-			  GT64260_CPU_PCI_1_MEM_0_REMAP_LO },
-
-			{ GT64260_CPU_PCI_1_MEM_1_DECODE_BOT,
-			  GT64260_CPU_PCI_1_MEM_1_DECODE_TOP,
-			  GT64260_CPU_PCI_1_MEM_1_REMAP_HI,
-			  GT64260_CPU_PCI_1_MEM_1_REMAP_LO },
-
-			{ GT64260_CPU_PCI_1_MEM_2_DECODE_BOT,
-			  GT64260_CPU_PCI_1_MEM_2_DECODE_TOP,
-			  GT64260_CPU_PCI_1_MEM_2_REMAP_HI,
-			  GT64260_CPU_PCI_1_MEM_2_REMAP_LO },
-
-			{ GT64260_CPU_PCI_1_MEM_3_DECODE_BOT,
-			  GT64260_CPU_PCI_1_MEM_3_DECODE_TOP,
-			  GT64260_CPU_PCI_1_MEM_3_REMAP_HI,
-			  GT64260_CPU_PCI_1_MEM_3_REMAP_LO },
-		}
-	}; /* cpu_pci_mem_windows[][][] */
-	u32		remap_reg, remap;
-	int		rc = -1;
-
-	if ((pci_bus < GT64260_PCI_BUSES) &&
-	    (window < GT64260_PCI_MEM_WINDOWS_PER_BUS)) {
-
-		if (gt64260_cpu_pci_set_window(
-			cpu_base_addr,
-			pci_base_addr_lo,
-			size,
-			swap_64bit,
-			cpu_pci_mem_windows[pci_bus][window][0],
-			cpu_pci_mem_windows[pci_bus][window][1],
-			cpu_pci_mem_windows[pci_bus][window][3]) == 0) {
-
-			remap_reg = cpu_pci_mem_windows[pci_bus][window][2];
-			gt_write(remap_reg, pci_base_addr_hi);
-
-			remap = gt_read(remap_reg); /* Flush FIFO */
-
-			rc = 0;
-		}
-	}
-
-	return rc;
-} /* gt64260_cpu_set_pci_mem_window() */
-
-int
-gt64260_cpu_prot_set_window(u32 window,
-			    u32 base_addr,
-			    u32 size,
-			    u32 access_bits)
-{
-	static u32
-	cpu_prot_windows[GT64260_CPU_PROT_WINDOWS][2] = {
-		{ GT64260_CPU_PROT_BASE_0, GT64260_CPU_PROT_TOP_0 },
-		{ GT64260_CPU_PROT_BASE_1, GT64260_CPU_PROT_TOP_1 },
-		{ GT64260_CPU_PROT_BASE_2, GT64260_CPU_PROT_TOP_2 },
-		{ GT64260_CPU_PROT_BASE_3, GT64260_CPU_PROT_TOP_3 },
-		{ GT64260_CPU_PROT_BASE_4, GT64260_CPU_PROT_TOP_4 },
-		{ GT64260_CPU_PROT_BASE_5, GT64260_CPU_PROT_TOP_5 },
-		{ GT64260_CPU_PROT_BASE_6, GT64260_CPU_PROT_TOP_6 },
-		{ GT64260_CPU_PROT_BASE_7, GT64260_CPU_PROT_TOP_7 },
-	}; /* cpu_prot_windows[][] */
-	int	rc = -1;
-
-	if (window < GT64260_CPU_PROT_WINDOWS) {
-		rc = gt64260_set_32bit_window(base_addr,
-					      size,
-					      access_bits,
-					      cpu_prot_windows[window][0],
-					      cpu_prot_windows[window][1]);
-	}
-
-	return rc;
-} /* gt64260_cpu_prot_set_window() */
-
-int
-gt64260_cpu_snoop_set_window(u32 window,
-			     u32 base_addr,
-			     u32 size,
-			     u32  snoop_type)
-{
-	static u32
-	cpu_snoop_windows[GT64260_CPU_SNOOP_WINDOWS][2] = {
-		{ GT64260_CPU_SNOOP_BASE_0, GT64260_CPU_SNOOP_TOP_0 },
-		{ GT64260_CPU_SNOOP_BASE_1, GT64260_CPU_SNOOP_TOP_1 },
-		{ GT64260_CPU_SNOOP_BASE_2, GT64260_CPU_SNOOP_TOP_2 },
-		{ GT64260_CPU_SNOOP_BASE_3, GT64260_CPU_SNOOP_TOP_3 },
-	}; /* cpu_snoop_windows[][] */
-	int	rc = -1;
-
-	if ((window < GT64260_CPU_SNOOP_WINDOWS) &&
-	    (snoop_type <= GT64260_CPU_SNOOP_WB)) {
-
-		rc = gt64260_set_32bit_window(base_addr,
-					      size,
-					      snoop_type,
-					      cpu_snoop_windows[window][0],
-					      cpu_snoop_windows[window][1]);
-	}
-
-	return rc;
-} /* gt64260_cpu_snoop_set_window() */
-
-void
-gt64260_cpu_disable_all_windows(void)
-{
-	int	pci_bus, window;
-
-	/* Don't disable SCS windows b/c we need to access system memory */
-
-	for (window=0; window<GT64260_CPU_CS_DECODE_WINDOWS; window++) {
-		gt64260_cpu_cs_set_window(window, 0, 0);
-	}
-
-	gt64260_cpu_boot_set_window(0, 0);
-
-	for (pci_bus=0; pci_bus<GT64260_PCI_BUSES; pci_bus++) {
-		gt64260_cpu_set_pci_io_window(pci_bus, 0, 0, 0, 0);
-
-		for (window=0;window<GT64260_PCI_MEM_WINDOWS_PER_BUS;window++) {
-			gt64260_cpu_set_pci_mem_window(pci_bus,
-						       window,
-						       0, 0, 0, 0, 0);
-		}
-	}
-
-	for (window=0; window<GT64260_CPU_PROT_WINDOWS; window++) {
-		gt64260_cpu_prot_set_window(window, 0, 0, 0);
-	}
-
-	for (window=0; window<GT64260_CPU_SNOOP_WINDOWS; window++) {
-		gt64260_cpu_snoop_set_window(window, 0, 0, 0);
-	}
-
-	return;
-} /* gt64260_cpu_disable_all_windows() */
-
-
-/*
- *****************************************************************************
- *
- *	PCI Slave Window Configuration Routines
- *
- *****************************************************************************
- */
-
-int
-gt64260_pci_bar_enable(u32 pci_bus,
-		       u32 enable_bits)
-{
-	u32	reg, val;
-	int	rc = -1;
-
-	if (pci_bus < GT64260_PCI_BUSES) {
-		reg = (pci_bus == 0) ? GT64260_PCI_0_SLAVE_BAR_REG_ENABLES :
-				       GT64260_PCI_1_SLAVE_BAR_REG_ENABLES;
-
-
-		/* Note: '0' enables, '1' disables */
-		val = gt_read(reg);
-		val |= 0xffffffff;	/* Disable everything by default */
-		val &= ~enable_bits;
-		gt_write(reg, val);
-
-		gt_read(reg); /* Flush FIFO */
-
-		rc = 0;
-	}
-
-	return rc;
-} /* gt64260_pci_bar_enable() */
-
-static int
-gt64260_pci_slave_set_window(struct pci_controller *hose,
-			     u32 pci_base_addr,
-			     u32 cpu_base_addr,
-			     u32 bar_size,
-			     u32 pci_cfg_fcn,
-			     u32 pci_cfg_hdr_offset,
-			     u32 bar_size_reg,
-			     u32 remap_reg)
-{
-	u32	val;
-	int	devfn;
-	u8	save_exclude;
-
-	pci_base_addr &= 0xfffff000;
-	cpu_base_addr &= 0xfffff000;
-	bar_size &= 0xfffff000;
-	devfn = PCI_DEVFN(0, pci_cfg_fcn);
-
-	gt_write(bar_size_reg, (bar_size - 1) & 0xfffff000);
-	gt_write(remap_reg, cpu_base_addr);
-	gt_read(remap_reg); /* Flush FIFO */
-
-	save_exclude = gt64260_pci_exclude_bridge;
-	gt64260_pci_exclude_bridge = FALSE;
-	early_read_config_dword(hose,
-				hose->first_busno,
-				devfn,
-				pci_cfg_hdr_offset,
-				&val);
-	val &= 0x0000000f;
-	early_write_config_dword(hose,
-				 hose->first_busno,
-				 devfn,
-				 pci_cfg_hdr_offset,
-				 pci_base_addr | val);
-	gt64260_pci_exclude_bridge = save_exclude;
-
-	return 0;
-} /* gt64260_pci_slave_set_window() */
-
-int
-gt64260_pci_slave_scs_set_window(struct pci_controller *hose,
-				 u32 window,
-				 u32 pci_base_addr,
-				 u32 cpu_base_addr,
-				 u32 size)
-{
-	static u32
-	pci_scs_windows[GT64260_PCI_BUSES][GT64260_PCI_SCS_WINDOWS][4] = {
-		{ /* PCI 0 */
-			{ 0, 0x10,
-			  GT64260_PCI_0_SLAVE_SCS_0_SIZE,
-			  GT64260_PCI_0_SLAVE_SCS_0_REMAP },
-			{ 0, 0x14,
-			  GT64260_PCI_0_SLAVE_SCS_1_SIZE,
-			  GT64260_PCI_0_SLAVE_SCS_1_REMAP },
-			{ 0, 0x18,
-			  GT64260_PCI_0_SLAVE_SCS_2_SIZE,
-			  GT64260_PCI_0_SLAVE_SCS_2_REMAP },
-			{ 0, 0x1c,
-			  GT64260_PCI_0_SLAVE_SCS_3_SIZE,
-			  GT64260_PCI_0_SLAVE_SCS_3_REMAP },
-		},
-		{ /* PCI 1 */
-			{ 0, 0x10,
-			  GT64260_PCI_1_SLAVE_SCS_0_SIZE,
-			  GT64260_PCI_1_SLAVE_SCS_0_REMAP },
-			{ 0, 0x14,
-			  GT64260_PCI_1_SLAVE_SCS_1_SIZE,
-			  GT64260_PCI_1_SLAVE_SCS_1_REMAP },
-			{ 0, 0x18,
-			  GT64260_PCI_1_SLAVE_SCS_2_SIZE,
-			  GT64260_PCI_1_SLAVE_SCS_2_REMAP },
-			{ 0, 0x1c,
-			  GT64260_PCI_1_SLAVE_SCS_3_SIZE,
-			  GT64260_PCI_1_SLAVE_SCS_3_REMAP },
-		}
-	}; /* pci_scs_windows[][][] */
-	int	pci_bus;
-	int	rc = -1;
-
-	if (window < GT64260_PCI_SCS_WINDOWS) {
-		pci_bus = (hose->first_busno == 0) ? 0 : 1;
-
-		rc = gt64260_pci_slave_set_window(
-				hose,
-				pci_base_addr,
-				cpu_base_addr,
-				size,
-				pci_scs_windows[pci_bus][window][0],
-				pci_scs_windows[pci_bus][window][1],
-				pci_scs_windows[pci_bus][window][2],
-				pci_scs_windows[pci_bus][window][3]);
-	}
-
-	return rc;
-} /* gt64260_pci_slave_scs_set_window() */
-
-int
-gt64260_pci_slave_cs_set_window(struct pci_controller *hose,
-				u32 window,
-				u32 pci_base_addr,
-				u32 cpu_base_addr,
-				u32 size)
-{
-	static u32
-	pci_cs_windows[GT64260_PCI_BUSES][GT64260_PCI_CS_WINDOWS][4] = {
-		{ /* PCI 0 */
-			{ 1, 0x10,
-			  GT64260_PCI_0_SLAVE_CS_0_SIZE,
-			  GT64260_PCI_0_SLAVE_CS_0_REMAP },
-			{ 1, 0x14,
-			  GT64260_PCI_0_SLAVE_CS_1_SIZE,
-			  GT64260_PCI_0_SLAVE_CS_1_REMAP },
-			{ 1, 0x18,
-			  GT64260_PCI_0_SLAVE_CS_2_SIZE,
-			  GT64260_PCI_0_SLAVE_CS_2_REMAP },
-			{ 1, 0x1c,
-			  GT64260_PCI_0_SLAVE_CS_3_SIZE,
-			  GT64260_PCI_0_SLAVE_CS_3_REMAP },
-		},
-		{ /* PCI 1 */
-			{ 1, 0x10,
-			  GT64260_PCI_1_SLAVE_CS_0_SIZE,
-			  GT64260_PCI_1_SLAVE_CS_0_REMAP },
-			{ 1, 0x14,
-			  GT64260_PCI_1_SLAVE_CS_1_SIZE,
-			  GT64260_PCI_1_SLAVE_CS_1_REMAP },
-			{ 1, 0x18,
-			  GT64260_PCI_1_SLAVE_CS_2_SIZE,
-			  GT64260_PCI_1_SLAVE_CS_2_REMAP },
-			{ 1, 0x1c,
-			  GT64260_PCI_1_SLAVE_CS_3_SIZE,
-			  GT64260_PCI_1_SLAVE_CS_3_REMAP },
-		}
-	}; /* pci_cs_windows[][][] */
-	int	pci_bus;
-	int	rc = -1;
-
-	if (window < GT64260_PCI_CS_WINDOWS) {
-		pci_bus = (hose->first_busno == 0) ? 0 : 1;
-
-		rc = gt64260_pci_slave_set_window(
-				hose,
-				pci_base_addr,
-				cpu_base_addr,
-				size,
-				pci_cs_windows[pci_bus][window][0],
-				pci_cs_windows[pci_bus][window][1],
-				pci_cs_windows[pci_bus][window][2],
-				pci_cs_windows[pci_bus][window][3]);
-	}
-
-	return rc;
-} /* gt64260_pci_slave_cs_set_window() */
-
-int
-gt64260_pci_slave_boot_set_window(struct pci_controller *hose,
-				  u32 pci_base_addr,
-				  u32 cpu_base_addr,
-				  u32 size)
-{
-	int	rc;
-
-	rc = gt64260_pci_slave_set_window(hose,
-					  pci_base_addr,
-					  cpu_base_addr,
-					  size,
-					  1,
-					  0x20,
-					  GT64260_PCI_1_SLAVE_BOOT_SIZE,
-					  GT64260_PCI_1_SLAVE_BOOT_REMAP);
-
-	return rc;
-} /* gt64260_pci_slave_boot_set_window() */
-
-int
-gt64260_pci_slave_p2p_mem_set_window(struct pci_controller *hose,
-				     u32 window,
-				     u32 pci_base_addr,
-				     u32 other_bus_base_addr,
-				     u32 size)
-{
-	static u32 
-	pci_p2p_mem_windows[GT64260_PCI_BUSES][GT64260_PCI_P2P_MEM_WINDOWS][4]={
-		{ /* PCI 0 */
-			{ 2, 0x10,
-			  GT64260_PCI_0_SLAVE_P2P_MEM_0_SIZE,
-			  GT64260_PCI_0_SLAVE_P2P_MEM_0_REMAP_LO },
-			{ 2, 0x14,
-			  GT64260_PCI_0_SLAVE_P2P_MEM_1_SIZE,
-			  GT64260_PCI_0_SLAVE_P2P_MEM_1_REMAP_LO },
-		},
-		{ /* PCI 1 */
-			{ 2, 0x10,
-			  GT64260_PCI_1_SLAVE_P2P_MEM_0_SIZE,
-			  GT64260_PCI_1_SLAVE_P2P_MEM_0_REMAP_LO },
-			{ 2, 0x14,
-			  GT64260_PCI_1_SLAVE_P2P_MEM_1_SIZE,
-			  GT64260_PCI_1_SLAVE_P2P_MEM_1_REMAP_LO },
-		}
-	}; /* pci_p2p_mem_windows[][][] */
-	int	pci_bus;
-	int	rc = -1;
-
-	if (window < GT64260_PCI_P2P_MEM_WINDOWS) {
-		pci_bus = (hose->first_busno == 0) ? 0 : 1;
-
-		rc = gt64260_pci_slave_set_window(
-				hose,
-				pci_base_addr,
-				other_bus_base_addr,
-				size,
-				pci_p2p_mem_windows[pci_bus][window][0],
-				pci_p2p_mem_windows[pci_bus][window][1],
-				pci_p2p_mem_windows[pci_bus][window][2],
-				pci_p2p_mem_windows[pci_bus][window][3]);
-	}
-
-	return rc;
-} /* gt64260_pci_slave_p2p_mem_set_window() */
-
-int
-gt64260_pci_slave_p2p_io_set_window(struct pci_controller *hose,
-				    u32 pci_base_addr,
-				    u32 other_bus_base_addr,
-				    u32 size)
-{
-	int	rc;
-
-	rc = gt64260_pci_slave_set_window(hose,
-					  pci_base_addr,
-					  other_bus_base_addr,
-					  size,
-					  2,
-					  0x18,
-					  GT64260_PCI_1_SLAVE_P2P_IO_SIZE,
-					  GT64260_PCI_1_SLAVE_P2P_IO_REMAP);
-
-	return rc;
-} /* gt64260_pci_slave_p2p_io_set_window() */
-
-int
-gt64260_pci_slave_dac_scs_set_window(struct pci_controller *hose,
-				     u32 window,
-				     u32 pci_base_addr_hi,
-				     u32 pci_base_addr_lo,
-				     u32 cpu_base_addr,
-				     u32 size)
-{
-	static u32 
-	pci_dac_scs_windows[GT64260_PCI_BUSES][GT64260_PCI_DAC_SCS_WINDOWS][5]={
-		{ /* PCI 0 */
-			{ 4, 0x10, 0x14,
-			  GT64260_PCI_0_SLAVE_DAC_SCS_0_SIZE,
-			  GT64260_PCI_0_SLAVE_DAC_SCS_0_REMAP },
-			{ 4, 0x18, 0x1c,
-			  GT64260_PCI_0_SLAVE_DAC_SCS_1_SIZE,
-			  GT64260_PCI_0_SLAVE_DAC_SCS_1_REMAP },
-			{ 5, 0x10, 0x14,
-			  GT64260_PCI_0_SLAVE_DAC_SCS_2_SIZE,
-			  GT64260_PCI_0_SLAVE_DAC_SCS_2_REMAP },
-			{ 5, 0x18, 0x1c,
-			  GT64260_PCI_0_SLAVE_DAC_SCS_3_SIZE,
-			  GT64260_PCI_0_SLAVE_DAC_SCS_3_REMAP },
-		},
-		{ /* PCI 1 */
-			{ 4, 0x10, 0x14,
-			  GT64260_PCI_1_SLAVE_DAC_SCS_0_SIZE,
-			  GT64260_PCI_1_SLAVE_DAC_SCS_0_REMAP },
-			{ 4, 0x18, 0x1c,
-			  GT64260_PCI_1_SLAVE_DAC_SCS_1_SIZE,
-			  GT64260_PCI_1_SLAVE_DAC_SCS_1_REMAP },
-			{ 5, 0x10, 0x14,
-			  GT64260_PCI_1_SLAVE_DAC_SCS_2_SIZE,
-			  GT64260_PCI_1_SLAVE_DAC_SCS_2_REMAP },
-			{ 5, 0x18, 0x1c,
-			  GT64260_PCI_1_SLAVE_DAC_SCS_3_SIZE,
-			  GT64260_PCI_1_SLAVE_DAC_SCS_3_REMAP },
-		}
-	}; /* pci_dac_scs_windows[][][] */
-	int	pci_bus;
-	int	rc = -1;
-
-	if (window < GT64260_PCI_DAC_SCS_WINDOWS) {
-		pci_bus = (hose->first_busno == 0) ? 0 : 1;
-
-		rc = gt64260_pci_slave_set_window(
-				hose,
-				pci_base_addr_lo,
-				cpu_base_addr,
-				size,
-				pci_dac_scs_windows[pci_bus][window][0],
-				pci_dac_scs_windows[pci_bus][window][1],
-				pci_dac_scs_windows[pci_bus][window][3],
-				pci_dac_scs_windows[pci_bus][window][4]);
-
-		early_write_config_dword(
-			hose,
-			hose->first_busno,
-			PCI_DEVFN(0, pci_dac_scs_windows[pci_bus][window][0]),
-			pci_dac_scs_windows[pci_bus][window][2],
-			pci_base_addr_hi);
-	}
-
-	return rc;
-} /* gt64260_pci_slave_dac_scs_set_window() */
-
-int
-gt64260_pci_slave_dac_cs_set_window(struct pci_controller *hose,
-				    u32 window,
-				    u32 pci_base_addr_hi,
-				    u32 pci_base_addr_lo,
-				    u32 cpu_base_addr,
-				    u32 size)
-{
-	static u32 
-	pci_dac_cs_windows[GT64260_PCI_BUSES][GT64260_PCI_DAC_CS_WINDOWS][5] = {
-		{ /* PCI 0 */
-			{ 6, 0x10, 0x14,
-			  GT64260_PCI_0_SLAVE_DAC_CS_0_SIZE,
-			  GT64260_PCI_0_SLAVE_DAC_CS_0_REMAP },
-			{ 6, 0x18, 0x1c,
-			  GT64260_PCI_0_SLAVE_DAC_CS_1_SIZE,
-			  GT64260_PCI_0_SLAVE_DAC_CS_1_REMAP },
-			{ 6, 0x20, 0x24,
-			  GT64260_PCI_0_SLAVE_DAC_CS_2_SIZE,
-			  GT64260_PCI_0_SLAVE_DAC_CS_2_REMAP },
-			{ 7, 0x10, 0x14,
-			  GT64260_PCI_0_SLAVE_DAC_CS_3_SIZE,
-			  GT64260_PCI_0_SLAVE_DAC_CS_3_REMAP },
-		},
-		{ /* PCI 1 */
-			{ 6, 0x10, 0x14,
-			  GT64260_PCI_1_SLAVE_DAC_CS_0_SIZE,
-			  GT64260_PCI_1_SLAVE_DAC_CS_0_REMAP },
-			{ 6, 0x18, 0x1c,
-			  GT64260_PCI_1_SLAVE_DAC_CS_1_SIZE,
-			  GT64260_PCI_1_SLAVE_DAC_CS_1_REMAP },
-			{ 6, 0x20, 0x24,
-			  GT64260_PCI_1_SLAVE_DAC_CS_2_SIZE,
-			  GT64260_PCI_1_SLAVE_DAC_CS_2_REMAP },
-			{ 7, 0x10, 0x14,
-			  GT64260_PCI_1_SLAVE_DAC_CS_3_SIZE,
-			  GT64260_PCI_1_SLAVE_DAC_CS_3_REMAP },
-		}
-	}; /* pci_dac_cs_windows[][][] */
-	int	pci_bus;
-	int	rc = -1;
-
-	if (window < GT64260_PCI_CS_WINDOWS) {
-		pci_bus = (hose->first_busno == 0) ? 0 : 1;
-
-		rc = gt64260_pci_slave_set_window(
-				hose,
-				pci_base_addr_lo,
-				cpu_base_addr,
-				size,
-				pci_dac_cs_windows[pci_bus][window][0],
-				pci_dac_cs_windows[pci_bus][window][1],
-				pci_dac_cs_windows[pci_bus][window][3],
-				pci_dac_cs_windows[pci_bus][window][4]);
-
-		early_write_config_dword(
-			hose,
-			hose->first_busno,
-			PCI_DEVFN(0, pci_dac_cs_windows[pci_bus][window][0]),
-			pci_dac_cs_windows[pci_bus][window][2],
-			pci_base_addr_hi);
-	}
-
-	return rc;
-} /* gt64260_pci_slave_dac_cs_set_window() */
-
-int
-gt64260_pci_slave_dac_boot_set_window(struct pci_controller *hose,
-				      u32 pci_base_addr_hi,
-				      u32 pci_base_addr_lo,
-				      u32 cpu_base_addr,
-				      u32 size)
-{
-	int	rc;
-
-	rc = gt64260_pci_slave_set_window(hose,
-					  pci_base_addr_lo,
-					  cpu_base_addr,
-					  size,
-					  7,
-					  0x18,
-					  GT64260_PCI_1_SLAVE_BOOT_SIZE,
-					  GT64260_PCI_1_SLAVE_BOOT_REMAP);
-
-	early_write_config_dword(hose,
-				 hose->first_busno,
-				 PCI_DEVFN(0, 7),
-				 0x1c,
-				 pci_base_addr_hi);
-
-	return rc;
-} /* gt64260_pci_slave_dac_boot_set_window() */
-
-int
-gt64260_pci_slave_dac_p2p_mem_set_window(struct pci_controller *hose,
-				         u32 window,
-				         u32 pci_base_addr_hi,
-				         u32 pci_base_addr_lo,
-				         u32 other_bus_base_addr,
-				         u32 size)
-{
-	static u32 
-	pci_dac_p2p_mem_windows[GT64260_PCI_BUSES][GT64260_PCI_DAC_P2P_MEM_WINDOWS][5] = {
-		{ /* PCI 0 */
-			{ 4, 0x20, 0x24,
-			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_SIZE,
-			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_REMAP_LO },
-			{ 5, 0x20, 0x24,
-			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_SIZE,
-			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_REMAP_LO },
-		},
-		{ /* PCI 1 */
-			{ 4, 0xa0, 0xa4,
-			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_SIZE,
-			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_REMAP_LO },
-			{ 5, 0xa0, 0xa4,
-			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_SIZE,
-			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_REMAP_LO },
-		}
-	}; /* pci_dac_p2p_windows[][][] */
-	int	pci_bus;
-	int	rc = -1;
-
-	if (window < GT64260_PCI_P2P_MEM_WINDOWS) {
-		pci_bus = (hose->first_busno == 0) ? 0 : 1;
-
-		rc = gt64260_pci_slave_set_window(
-				hose,
-				pci_base_addr_lo,
-				other_bus_base_addr,
-				size,
-				pci_dac_p2p_mem_windows[pci_bus][window][0],
-				pci_dac_p2p_mem_windows[pci_bus][window][1],
-				pci_dac_p2p_mem_windows[pci_bus][window][3],
-				pci_dac_p2p_mem_windows[pci_bus][window][4]);
-
-		early_write_config_dword(
-		    hose,
-		    hose->first_busno,
-		    PCI_DEVFN(0, pci_dac_p2p_mem_windows[pci_bus][window][0]),
-		    pci_dac_p2p_mem_windows[pci_bus][window][2],
-		    pci_base_addr_hi);
-	}
-
-	return rc;
-} /* gt64260_pci_slave_dac_p2p_mem_set_window() */
-
-
-/*
- *****************************************************************************
- *
- *	PCI Control Configuration Routines
- *
- *****************************************************************************
- */
-
-
-int
-gt64260_pci_acc_cntl_set_window(u32 pci_bus,
-			        u32 window,
-			        u32 base_addr_hi,
-			        u32 base_addr_lo,
-			        u32 size,
-			        u32 features)
-{
-	static u32
-	pci_acc_cntl_windows[GT64260_PCI_BUSES][GT64260_PCI_ACC_CNTL_WINDOWS][3] = {
-		{ /* PCI 0 */
-			{ GT64260_PCI_0_ACC_CNTL_0_BASE_HI,
-			  GT64260_PCI_0_ACC_CNTL_0_BASE_LO,
-			  GT64260_PCI_0_ACC_CNTL_0_TOP },
-
-			{ GT64260_PCI_0_ACC_CNTL_1_BASE_HI,
-			  GT64260_PCI_0_ACC_CNTL_1_BASE_LO,
-			  GT64260_PCI_0_ACC_CNTL_1_TOP },
-
-			{ GT64260_PCI_0_ACC_CNTL_2_BASE_HI,
-			  GT64260_PCI_0_ACC_CNTL_2_BASE_LO,
-			  GT64260_PCI_0_ACC_CNTL_2_TOP },
-
-			{ GT64260_PCI_0_ACC_CNTL_3_BASE_HI,
-			  GT64260_PCI_0_ACC_CNTL_3_BASE_LO,
-			  GT64260_PCI_0_ACC_CNTL_3_TOP },
-
-			{ GT64260_PCI_0_ACC_CNTL_4_BASE_HI,
-			  GT64260_PCI_0_ACC_CNTL_4_BASE_LO,
-			  GT64260_PCI_0_ACC_CNTL_4_TOP },
-
-			{ GT64260_PCI_0_ACC_CNTL_5_BASE_HI,
-			  GT64260_PCI_0_ACC_CNTL_5_BASE_LO,
-			  GT64260_PCI_0_ACC_CNTL_5_TOP },
-
-			{ GT64260_PCI_0_ACC_CNTL_6_BASE_HI,
-			  GT64260_PCI_0_ACC_CNTL_6_BASE_LO,
-			  GT64260_PCI_0_ACC_CNTL_6_TOP },
-
-			{ GT64260_PCI_0_ACC_CNTL_7_BASE_HI,
-			  GT64260_PCI_0_ACC_CNTL_7_BASE_LO,
-			  GT64260_PCI_0_ACC_CNTL_7_TOP },
-		},
-		{ /* PCI 1 */
-			{ GT64260_PCI_1_ACC_CNTL_0_BASE_HI,
-			  GT64260_PCI_1_ACC_CNTL_0_BASE_LO,
-			  GT64260_PCI_1_ACC_CNTL_0_TOP },
-
-			{ GT64260_PCI_1_ACC_CNTL_1_BASE_HI,
-			  GT64260_PCI_1_ACC_CNTL_1_BASE_LO,
-			  GT64260_PCI_1_ACC_CNTL_1_TOP },
-
-			{ GT64260_PCI_1_ACC_CNTL_2_BASE_HI,
-			  GT64260_PCI_1_ACC_CNTL_2_BASE_LO,
-			  GT64260_PCI_1_ACC_CNTL_2_TOP },
-
-			{ GT64260_PCI_1_ACC_CNTL_3_BASE_HI,
-			  GT64260_PCI_1_ACC_CNTL_3_BASE_LO,
-			  GT64260_PCI_1_ACC_CNTL_3_TOP },
-
-			{ GT64260_PCI_1_ACC_CNTL_4_BASE_HI,
-			  GT64260_PCI_1_ACC_CNTL_4_BASE_LO,
-			  GT64260_PCI_1_ACC_CNTL_4_TOP },
-
-			{ GT64260_PCI_1_ACC_CNTL_5_BASE_HI,
-			  GT64260_PCI_1_ACC_CNTL_5_BASE_LO,
-			  GT64260_PCI_1_ACC_CNTL_5_TOP },
-
-			{ GT64260_PCI_1_ACC_CNTL_6_BASE_HI,
-			  GT64260_PCI_1_ACC_CNTL_6_BASE_LO,
-			  GT64260_PCI_1_ACC_CNTL_6_TOP },
-
-			{ GT64260_PCI_1_ACC_CNTL_7_BASE_HI,
-			  GT64260_PCI_1_ACC_CNTL_7_BASE_LO,
-			  GT64260_PCI_1_ACC_CNTL_7_TOP },
-		}
-	}; /* pci_acc_cntl_windows[][][] */
-	int	rc = -1;
-
-	if ((pci_bus < GT64260_PCI_BUSES) &&
-	    (window < GT64260_PCI_ACC_CNTL_WINDOWS)) {
-
-		rc = gt64260_set_64bit_window(
-			      base_addr_hi,
-			      base_addr_lo,
-			      size,
-			      features,
-			      pci_acc_cntl_windows[pci_bus][window][0],
-			      pci_acc_cntl_windows[pci_bus][window][1],
-			      pci_acc_cntl_windows[pci_bus][window][2]);
-	}
-
-	return rc;
-} /* gt64260_pci_acc_cntl_set_window() */
-
-int
-gt64260_pci_snoop_set_window(u32 pci_bus,
-			     u32 window,
-			     u32 base_addr_hi,
-			     u32 base_addr_lo,
-			     u32 size,
-			     u32 snoop_type)
-{
-	static u32
-	pci_snoop_windows[GT64260_PCI_BUSES][GT64260_PCI_SNOOP_WINDOWS][3] = {
-		{ /* PCI 0 */
-			{ GT64260_PCI_0_SNOOP_0_BASE_HI,
-			  GT64260_PCI_0_SNOOP_0_BASE_LO,
-			  GT64260_PCI_0_SNOOP_0_TOP },
-
-			{ GT64260_PCI_0_SNOOP_1_BASE_HI,
-			  GT64260_PCI_0_SNOOP_1_BASE_LO,
-			  GT64260_PCI_0_SNOOP_1_TOP },
-
-			{ GT64260_PCI_0_SNOOP_2_BASE_HI,
-			  GT64260_PCI_0_SNOOP_2_BASE_LO,
-			  GT64260_PCI_0_SNOOP_2_TOP },
-
-			{ GT64260_PCI_0_SNOOP_3_BASE_HI,
-			  GT64260_PCI_0_SNOOP_3_BASE_LO,
-			  GT64260_PCI_0_SNOOP_3_TOP },
-		},
-		{ /* PCI 1 */
-			{ GT64260_PCI_1_SNOOP_0_BASE_HI,
-			  GT64260_PCI_1_SNOOP_0_BASE_LO,
-			  GT64260_PCI_1_SNOOP_0_TOP },
-
-			{ GT64260_PCI_1_SNOOP_1_BASE_HI,
-			  GT64260_PCI_1_SNOOP_1_BASE_LO,
-			  GT64260_PCI_1_SNOOP_1_TOP },
-
-			{ GT64260_PCI_1_SNOOP_2_BASE_HI,
-			  GT64260_PCI_1_SNOOP_2_BASE_LO,
-			  GT64260_PCI_1_SNOOP_2_TOP },
-
-			{ GT64260_PCI_1_SNOOP_3_BASE_HI,
-			  GT64260_PCI_1_SNOOP_3_BASE_LO,
-			  GT64260_PCI_1_SNOOP_3_TOP },
-		},
-	}; /* pci_snoop_windows[][][] */
-	int	rc = -1;
-
-	if ((pci_bus < GT64260_PCI_BUSES) &&
-	    (window < GT64260_PCI_SNOOP_WINDOWS)) {
-
-		rc = gt64260_set_64bit_window(
-			      base_addr_hi,
-			      base_addr_lo,
-			      size,
-			      snoop_type,
-			      pci_snoop_windows[pci_bus][window][0],
-			      pci_snoop_windows[pci_bus][window][1],
-			      pci_snoop_windows[pci_bus][window][2]);
-	}
-
-	return rc;
-} /* gt64260_pci_snoop_set_window() */
-
-/*
- *****************************************************************************
- *
- *	64260's Register Base Address Routines
- *
- *****************************************************************************
- */
-
-/*
- * gt64260_remap_bridge_regs()
- *
- * Move the bridge's register to the specified base address.
- * Assume that there are no other windows overlapping this area and that
- * all but the highest 3 nibbles are 0.
- */
-int
-gt64260_set_base(u32 new_base)
-{
-	u32	val;
-	int	limit = 100000;
-	int	rc = 0;
-
-	val = gt_read(GT64260_INTERNAL_SPACE_DECODE);
-	val = (new_base >> 20) | (val & 0xffff0000);
-	gt_write(GT64260_INTERNAL_SPACE_DECODE, val);
-
-	iounmap((void *)gt64260_base);
-	gt64260_base = (u32)ioremap((new_base & 0xfff00000),
-				    GT64260_INTERNAL_SPACE_SIZE);
-
-	do { /* Wait for bridge to move its regs */
-		val = gt_read(GT64260_INTERNAL_SPACE_DECODE);
-	} while ((val != 0xffffffff) && (limit-- > 0));
-
-	if (limit <= 0) {
-		rc = -1;
-	}
-
-	return rc;
-} /* gt64260_remap_bridge_regs() */
-
-/*
- * gt64260_get_base()
- *
- * Return the current virtual base address of the 64260's registers.
- */
-int
-gt64260_get_base(u32 *base)
-{
-	*base = gt64260_base;
-	return 0;
-} /* gt64260_remap_bridge_regs() */
-
-/*
- *****************************************************************************
- *
- *	Exclude PCI config space access to bridge itself
- *
- *****************************************************************************
- */
-
-/*
- * gt64260_exclude_pci_device()
- *
- * This routine causes the PCI subsystem to skip the PCI device in slot 0
- * (which is the 64260 itself) unless explicitly allowed.
- */
-int
-gt64260_pci_exclude_device(u8 bus, u8 devfn)
-{
-	struct pci_controller	*hose;
-
-	hose = pci_bus_to_hose(bus);
-
-	/* Skip slot 0 and 1 on both hoses */
-	if ((gt64260_pci_exclude_bridge == TRUE) &&
-	    (PCI_SLOT(devfn) == 0) &&
-	    (hose->first_busno == bus)) {
-
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	}
-	else {
-		return PCIBIOS_SUCCESSFUL;
-	}
-} /* gt64260_pci_exclude_device() */
-
-#if defined(CONFIG_SERIAL_TEXT_DEBUG)
-
-/*
- * gt64260_putc()
- *
- * Dump a character out the MPSC port for gt64260_mpsc_progress
- * this assumes the baud rate has already been set up and the 
- * MPSC initialized by the bootloader or firmware.
- */
-
-static inline void
-gt_putc(char c){
-	mb();
-	gt_write(GT64260_MPSC_0_CHR_1, c);
-	mb();
-	gt_write(GT64260_MPSC_0_CHR_2, 0x200);
-	mb();
-
-	udelay(10000);
-}
-
-void
-puthex(unsigned long val){
-
-        int i;
-
-        for (i = 7;  i >= 0;  i--) {
-		gt_putc("0123456789ABCDEF"[(val>>28) & 0x0f]);
-		val <<= 4;
-	}
-	gt_putc('\r');
-	gt_putc('\n');	
-	
-}
-
-
-void
-gt64260_mpsc_progress(char *s, unsigned short hex){
-	/* spit stuff out the 64260 mpsc */
-	
-	volatile char	c;
-	while ((c = *s++) != 0){
-		gt_putc(c);
-		if ( c == '\n' ) gt_putc('\r');	
-	}
-	gt_putc('\n');
-	gt_putc('\r');
-
-	return;
-}
-
-#endif /* CONFIG_DEBUG_TEXT */
diff -Nru a/arch/ppc/kernel/gt64260_pic.c b/arch/ppc/kernel/gt64260_pic.c
--- a/arch/ppc/kernel/gt64260_pic.c	Sun Nov 10 19:28:40 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,245 +0,0 @@
-/*
- * arch/ppc/kernel/gt64260_pic.c
- * 
- * Interrupt controller support for Galileo's GT64260.
- *
- * Author: Chris Zankel <chris@mvista.com>
- * Modified by: Mark A. Greer <mgreer@mvista.com>
- *
- * Based on sources from Rabeeh Khoury / Galileo Technology
- *
- * Copyright 2001 MontaVista Software 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 file contains the specific functions to support the GT64260
- * interrupt controller.
- *
- * The GT64260 has two main interrupt registers (high and low) that
- * summarizes the interrupts generated by the units of the GT64260.
- * Each bit is assigned to an interrupt number, where the low register
- * are assigned from IRQ0 to IRQ31 and the high cause register
- * from IRQ32 to IRQ63 
- * The GPP (General Purpose Port) interrupts are assigned from IRQ64 (GPP0) 
- * to IRQ95 (GPP31). 
- * get_irq() returns the lowest interrupt number that is currently asserted.
- *
- * Note: 
- *  - This driver does not initialize the GPP when used as an interrupt 
- *    input.
- */
-
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/stddef.h>
-#include <linux/delay.h>
-#include <linux/irq.h>
-
-#include <asm/io.h>
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/gt64260.h>
-
-
-/* ========================== forward declaration ========================== */
-
-static void gt64260_unmask_irq(unsigned int);
-static void gt64260_mask_irq(unsigned int);
-
-/* ========================== local declarations =========================== */
-
-struct hw_interrupt_type gt64260_pic = {
-	" GT64260_PIC ",		/* typename */
-	NULL,				/* startup */
-	NULL,				/* shutdown */
-	gt64260_unmask_irq,		/* enable */
-	gt64260_mask_irq,		/* disable */
-	gt64260_mask_irq,		/* ack */
-	NULL,				/* end */
-	NULL				/* set_affinity */
-};
-
-u32 gt64260_irq_base = 0;      /* GT64260 handles the next 96 IRQs from here */
-
-/* gt64260_init_irq()
- *
- *  This function initializes the interrupt controller. It assigns
- *  all interrupts from IRQ0 to IRQ95 to the gt64260 interrupt controller.
- *
- * Input Variable(s):
- *  None.
- *
- * Outpu. Variable(s):
- *  None.
- *
- * Returns:
- *  void
- *
- * Note:
- *  We register all GPP inputs as interrupt source, but disable them.
- */
-
-__init void
-gt64260_init_irq(void)
-{
-	int i;
-
-	if ( ppc_md.progress ) ppc_md.progress("gt64260_init_irq: enter", 0x0);
-
-	ppc_cached_irq_mask[0] = 0;
-	ppc_cached_irq_mask[1] = 0x0f000000; /* Enable GPP intrs */
-	ppc_cached_irq_mask[2] = 0;
-
-	/* disable all interrupts and clear current interrupts */
-	gt_write(GT64260_GPP_INTR_MASK, ppc_cached_irq_mask[2]);
-	gt_write(GT64260_GPP_INTR_CAUSE,0);
-	gt_write(GT64260_IC_CPU_INTR_MASK_LO, ppc_cached_irq_mask[0]);
-	gt_write(GT64260_IC_CPU_INTR_MASK_HI, ppc_cached_irq_mask[1]);
-
-	/* use the gt64260 for all (possible) interrupt sources */
-	for( i = gt64260_irq_base;  i < (gt64260_irq_base + 96);  i++ )  {
-		irq_desc[i].handler = &gt64260_pic;
-	}
-
-	if ( ppc_md.progress ) ppc_md.progress("gt64260_init_irq: exit", 0x0);
-}
-
-
-/* gt64260_get_irq()
- *
- *  This function returns the lowest interrupt number of all interrupts that
- *  are currently asserted. 
- *
- * Input Variable(s):
- *  struct pt_regs*	not used
- *
- * Output Variable(s):
- *  None.
- *
- * Returns:
- *  int	<interrupt number> or -2 (bogus interrupt)
- * 
- */
-int
-gt64260_get_irq(struct pt_regs *regs)
-{
-	int irq;
-	int irq_gpp;
-
-	irq = gt_read(GT64260_IC_MAIN_CAUSE_LO);
-	irq = __ilog2((irq & 0x3dfffffe) & ppc_cached_irq_mask[0]);
-
-	if (irq == -1) {
-		irq = gt_read(GT64260_IC_MAIN_CAUSE_HI);
-		irq = __ilog2((irq & 0x0f000db7) & ppc_cached_irq_mask[1]);
-
-		if (irq == -1) {
-			irq = -2;   /* bogus interrupt, should never happen */
-		} else {
-			if (irq >= 24) {
-				irq_gpp = gt_read(GT64260_GPP_INTR_CAUSE);
-				irq_gpp = __ilog2(irq_gpp &
-						  ppc_cached_irq_mask[2]);
-
-				if (irq_gpp == -1) {
-					irq = -2;
-				} else {
-					irq = irq_gpp + 64;
-					gt_write(GT64260_GPP_INTR_CAUSE, ~(1<<(irq-64)));
-				}
-			} else {
-				irq += 32;
-			}
-		}
-	}
-
-	if( irq < 0 )  {
-		return( irq );
-	} else  {
-		return( gt64260_irq_base + irq );
-	}
-}
-
-/* gt64260_unmask_irq()
- *
- *  This function enables an interrupt.
- *
- * Input Variable(s):
- *  unsigned int	interrupt number (IRQ0...IRQ95).
- *
- * Output Variable(s):
- *  None.
- *
- * Returns:
- *  void
- */
-
-static void
-gt64260_unmask_irq(unsigned int irq)
-{
-	irq -= gt64260_irq_base;
-	if (irq > 31) {
-		if (irq > 63) {
-			/* unmask GPP irq */
-			gt_write(GT64260_GPP_INTR_MASK,  
-				     ppc_cached_irq_mask[2] |= (1<<(irq-64)));
-		} else {
-			/* mask high interrupt register */
-			gt_write(GT64260_IC_CPU_INTR_MASK_HI, 
-				     ppc_cached_irq_mask[1] |= (1<<(irq-32)));
-		}
-	} else {
-		/* mask low interrupt register */
-		gt_write(GT64260_IC_CPU_INTR_MASK_LO, 
-			     ppc_cached_irq_mask[0] |= (1<<irq));
-	}
-}
-
-
-/* gt64260_mask_irq()
- *
- *  This funktion disables the requested interrupt.
- *
- * Input Variable(s):
- *  unsigned int	interrupt number (IRQ0...IRQ95).
- *
- * Output Variable(s):
- *  None.
- *
- * Returns:
- *  void
- */
-
-static void
-gt64260_mask_irq(unsigned int irq)
-{
-	irq -= gt64260_irq_base;
-	if (irq > 31) {
-		if (irq > 63) {
-			/* mask GPP irq */
-			gt_write(GT64260_GPP_INTR_MASK,  
-				     ppc_cached_irq_mask[2] &= ~(1<<(irq-64)));
-		} else {
-			/* mask high interrupt register */
-			gt_write(GT64260_IC_CPU_INTR_MASK_HI, 
-				     ppc_cached_irq_mask[1] &= ~(1<<(irq-32)));
-		}
-	} else {
-		/* mask low interrupt register */
-		gt_write(GT64260_IC_CPU_INTR_MASK_LO, 
-			     ppc_cached_irq_mask[0] &= ~(1<<irq));
-	}
-
-	if (irq == 36) { /* Seems necessary for SDMA interrupts */
-		udelay(1);
-	}
-}
-
diff -Nru a/arch/ppc/kernel/harrier.c b/arch/ppc/kernel/harrier.c
--- a/arch/ppc/kernel/harrier.c	Sun Nov 10 19:28:39 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,214 +0,0 @@
-/*
- * arch/ppc/kernel/harrier.c
- * 
- * Motorola MCG Harrier northbridge/memory controller support
- *
- * Author: Dale Farnsworth
- *         dale.farnsworth@mvista.com
- *
- * Copyright 2001 MontaVista Software 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.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/pci.h>
-#include <asm/pci-bridge.h>
-#include <asm/open_pic.h>
-#include <asm/harrier.h>
-
-/*
- * Initialize the Motorola MCG Harrier host bridge.
- *
- * This means setting up the PPC bus to PCI memory and I/O space mappings,
- * setting the PCI memory space address of the MPIC (mapped straight
- * through), and ioremap'ing the mpic registers.
- * 'OpenPIC_Addr' will be set correctly by this routine.
- * This routine will not change the PCI_CONFIG_ADDR or PCI_CONFIG_DATA
- * addresses and assumes that the mapping of PCI memory space back to system
- * memory is set up correctly by PPCBug.
- */
-int __init
-harrier_init(struct pci_controller *hose,
-	     uint ppc_reg_base,
-	     ulong processor_pci_mem_start,
-	     ulong processor_pci_mem_end,
-	     ulong processor_pci_io_start,
-	     ulong processor_pci_io_end,
-	     ulong processor_mpic_base)
-{
-	uint		addr, offset;
-
-	/*
-	 * Some sanity checks...
-	 */
-	if (((processor_pci_mem_start&0xffff0000) != processor_pci_mem_start) ||
-	    ((processor_pci_io_start &0xffff0000) != processor_pci_io_start)) {
-		printk("harrier_init: %s\n",
-			"PPC to PCI mappings must start on 64 KB boundaries");
-		return -1;
-	}
-
-	if (((processor_pci_mem_end  &0x0000ffff) != 0x0000ffff) ||
-	    ((processor_pci_io_end   &0x0000ffff) != 0x0000ffff)) {
-		printk("harrier_init: PPC to PCI mappings %s\n",
-			"must end just before a 64 KB boundaries");
-		return -1;
-	}
-
-	if (((processor_pci_mem_end - processor_pci_mem_start) !=
-	     (hose->mem_space.end - hose->mem_space.start)) ||
-	    ((processor_pci_io_end - processor_pci_io_start) !=
-	     (hose->io_space.end - hose->io_space.start))) {
-		printk("harrier_init: %s\n",
-			"PPC and PCI memory or I/O space sizes don't match");
-		return -1;
-	}
-
-	if ((processor_mpic_base & 0xfffc0000) != processor_mpic_base) {
-		printk("harrier_init: %s\n",
-			"MPIC address must start on 256 KB boundary");
-		return -1;
-	}
-
-	if ((pci_dram_offset & 0xffff0000) != pci_dram_offset) {
-		printk("harrier_init: %s\n",
-			"pci_dram_offset must be multiple of 64 KB");
-		return -1;
-	}
-
-	/*
-	 * Program the OTAD/OTOF registers to set up the PCI Mem & I/O
-	 * space mappings.  These are the mappings going from the processor to
-	 * the PCI bus.
-	 *
-	 * Note: Don't need to 'AND' start/end addresses with 0xffff0000
-	 *	 because sanity check above ensures that they are properly
-	 *	 aligned.
-	 */
-
-	/* Set up PPC->PCI Mem mapping */
-	addr = processor_pci_mem_start | (processor_pci_mem_end >> 16);
-	offset = (hose->mem_space.start - processor_pci_mem_start) | 0x92;
-	out_be32((uint *)(ppc_reg_base + HARRIER_OTAD0_OFF), addr);
-	out_be32((uint *)(ppc_reg_base + HARRIER_OTOF0_OFF), offset);
-
-	/* Set up PPC->PCI I/O mapping -- Contiguous I/O space */
-	addr = processor_pci_io_start | (processor_pci_io_end >> 16);
-	offset = (hose->io_space.start - processor_pci_io_start) | 0x80;
-	out_be32((uint *)(ppc_reg_base + HARRIER_OTAD1_OFF), addr);
-	out_be32((uint *)(ppc_reg_base + HARRIER_OTOF1_OFF), offset);
-
-	/* Enable MPIC */
-	OpenPIC_Addr = (void *)processor_mpic_base;
-	addr = (processor_mpic_base >> 16) | 1;
-	out_be16((ushort *)(ppc_reg_base + HARRIER_MBAR_OFF), addr);
-	out_8((u_char *)(ppc_reg_base + HARRIER_MPIC_CSR_OFF),
-		HARRIER_MPIC_OPI_ENABLE);
-
-	return 0;
-}
-
-/*
- * Find the amount of RAM present.
- * This assumes that PPCBug has initialized the memory controller (SMC)
- * on the Harrier correctly (i.e., it does no sanity checking).
- * It also assumes that the memory base registers are set to configure the
- * memory as contigous starting with "RAM A BASE", "RAM B BASE", etc.
- * however, RAM base registers can be skipped (e.g. A, B, C are set,
- * D is skipped but E is set is okay).
- */
-#define	MB	(1024*1024UL)
-
-static uint harrier_size_table[] __initdata = {
-	   0 * MB, /* 0 ==>    0 MB */
-	  32 * MB, /* 1 ==>   32 MB */
-	  64 * MB, /* 2 ==>   64 MB */
-	  64 * MB, /* 3 ==>   64 MB */
-	 128 * MB, /* 4 ==>  128 MB */
-	 128 * MB, /* 5 ==>  128 MB */
-	 128 * MB, /* 6 ==>  128 MB */
-	 256 * MB, /* 7 ==>  256 MB */
-	 256 * MB, /* 8 ==>  256 MB */
-	 256 * MB, /* 9 ==>  256 MB */
-	 512 * MB, /* a ==>  512 MB */
-	 512 * MB, /* b ==>  512 MB */
-	 512 * MB, /* c ==>  512 MB */
-	1024 * MB, /* d ==> 1024 MB */
-	1024 * MB, /* e ==> 1024 MB */
-	2048 * MB, /* f ==> 2048 MB */
-};
-
-/*
- * *** WARNING: You MUST have a BAT set up to map in the XCSR regs ***
- *
- * Read the memory controller's registers to determine the amount of system
- * memory.  Assumes that the memory controller registers are already mapped
- * into virtual memory--too early to use ioremap().
- */
-unsigned long __init
-harrier_get_mem_size(uint xcsr_base)
-{
-	ulong		last_addr;
-	int		i;
-	uint		vend_dev_id;
-	uint		*size_table;
-	uint		val;
-	uint		*csrp;
-	uint		size;
-	int		size_table_entries;
-
-	vend_dev_id = in_be32((uint *)xcsr_base + PCI_VENDOR_ID);
-
-	if (((vend_dev_id & 0xffff0000) >> 16) != PCI_VENDOR_ID_MOTOROLA) {
-		printk("harrier_get_mem_size: %s (0x%x)\n",
-			"Not a Motorola Memory Controller", vend_dev_id);
-		return 0;
-	}
-
-	vend_dev_id &= 0x0000ffff;
-
-	if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_HARRIER) {
-		size_table = harrier_size_table;
-		size_table_entries = sizeof(harrier_size_table) /
-				     sizeof(harrier_size_table[0]);
-	}
-	else {
-		printk("harrier_get_mem_size: %s (0x%x)\n",
-			"Not a Harrier", vend_dev_id);
-		return 0;
-	}
-
-	last_addr = 0;
-
-	csrp = (uint *)(xcsr_base + HARRIER_SDBA_OFF);
-	for (i=0; i<8; i++) {
-		val = in_be32(csrp++);
-
-		if (val & 0x100) {	/* If enabled */
-			size = val >> HARRIER_SDB_SIZE_SHIFT;
-			size &= HARRIER_SDB_SIZE_MASK;
-			if (size >= size_table_entries) {
-				break;	/* Register not set correctly */
-			}
-			size = size_table[size];
-			
-			val &= ~(size-1);
-			val += size;
-
-			if (val > last_addr) {
-				last_addr = val;
-			}
-		}
-	}
-
-	return last_addr;
-}
diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S
--- a/arch/ppc/kernel/head.S	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc/kernel/head.S	Sun Nov 10 19:28:40 2002
@@ -358,9 +358,12 @@
 #ifdef CONFIG_ALL_PPC
 	mfspr	r4,SPRG2
 	cmpwi	cr1,r4,0
-	bne	cr1,machine_check_in_rtas
+	bne	cr1,1f
 #endif
 	EXC_XFER_STD(0x200, MachineCheckException)
+#ifdef CONFIG_ALL_PPC
+1:	b	machine_check_in_rtas
+#endif
 
 /* Data access exception. */
 	. = 0x300
diff -Nru a/arch/ppc/kernel/i8259.c b/arch/ppc/kernel/i8259.c
--- a/arch/ppc/kernel/i8259.c	Sun Nov 10 19:28:39 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,199 +0,0 @@
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <asm/io.h>
-#include <asm/i8259.h>
-
-static volatile unsigned char *pci_intack; /* RO, gives us the irq vector */
-
-unsigned char cached_8259[2] = { 0xff, 0xff };
-#define cached_A1 (cached_8259[0])
-#define cached_21 (cached_8259[1])
-
-static spinlock_t i8259_lock = SPIN_LOCK_UNLOCKED;
-
-int i8259_pic_irq_offset;
-
-/*
- * Acknowledge the IRQ using either the PCI host bridge's interrupt
- * acknowledge feature or poll.  How i8259_init() is called determines
- * which is called.  It should be noted that polling is broken on some
- * IBM and Motorola PReP boxes so we must use the int-ack feature on them.
- */
-int
-i8259_irq(struct pt_regs *regs)
-{
-	int irq;
-
-	spin_lock(&i8259_lock);
-
-	/* Either int-ack or poll for the IRQ */
-	if (pci_intack)
-		irq = *pci_intack;
-	else {
-		/* Perform an interrupt acknowledge cycle on controller 1. */
-		outb(0x0C, 0x20);		/* prepare for poll */
-		irq = inb(0x20) & 7;
-		if (irq == 2 ) {
-			/*
-			 * Interrupt is cascaded so perform interrupt
-			 * acknowledge on controller 2.
-			 */
-			outb(0x0C, 0xA0);	/* prepare for poll */
-			irq = (inb(0xA0) & 7) + 8;
-		}
-	}
-
-	if (irq == 7) {
-		/*
-		 * This may be a spurious interrupt.
-		 *
-		 * Read the interrupt status register (ISR). If the most
-		 * significant bit is not set then there is no valid
-		 * interrupt.
-		 */
-		if (!pci_intack)
-			outb(0x0B, 0x20);	/* ISR register */
-		if(~inb(0x20) & 0x80)
-			irq = -1;
-	}
-
-	spin_unlock(&i8259_lock);
-	return irq;
-}
-
-static void i8259_mask_and_ack_irq(unsigned int irq_nr)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&i8259_lock, flags);
-	if ( irq_nr >= i8259_pic_irq_offset )
-		irq_nr -= i8259_pic_irq_offset;
-
-	if (irq_nr > 7) {
-		cached_A1 |= 1 << (irq_nr-8);
-		inb(0xA1); /* DUMMY */
-		outb(cached_A1,0xA1);
-		outb(0x20,0xA0); /* Non-specific EOI */
-		outb(0x20,0x20); /* Non-specific EOI to cascade */
-	} else {
-		cached_21 |= 1 << irq_nr;
-		inb(0x21); /* DUMMY */
-		outb(cached_21,0x21);
-		outb(0x20,0x20); /* Non-specific EOI */
-	}
-	spin_unlock_irqrestore(&i8259_lock, flags);
-}
-
-static void i8259_set_irq_mask(int irq_nr)
-{
-	outb(cached_A1,0xA1);
-	outb(cached_21,0x21);
-}
- 
-static void i8259_mask_irq(unsigned int irq_nr)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&i8259_lock, flags);
-	if ( irq_nr >= i8259_pic_irq_offset )
-		irq_nr -= i8259_pic_irq_offset;
-	if ( irq_nr < 8 )
-		cached_21 |= 1 << irq_nr;
-	else
-		cached_A1 |= 1 << (irq_nr-8);
-	i8259_set_irq_mask(irq_nr);
-	spin_unlock_irqrestore(&i8259_lock, flags);
-}
-
-static void i8259_unmask_irq(unsigned int irq_nr)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&i8259_lock, flags);
-	if ( irq_nr >= i8259_pic_irq_offset )
-		irq_nr -= i8259_pic_irq_offset;
-	if ( irq_nr < 8 )
-		cached_21 &= ~(1 << irq_nr);
-	else
-		cached_A1 &= ~(1 << (irq_nr-8));
-	i8259_set_irq_mask(irq_nr);
-	spin_unlock_irqrestore(&i8259_lock, flags);
-}
-
-static void i8259_end_irq(unsigned int irq)
-{
-	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))
-	    && irq_desc[irq].action)
-		i8259_unmask_irq(irq);
-}
-
-struct hw_interrupt_type i8259_pic = {
-	" i8259    ",
-	NULL,
-	NULL,
-	i8259_unmask_irq,
-	i8259_mask_irq,
-	i8259_mask_and_ack_irq,
-	i8259_end_irq,
-	NULL
-};
-
-static struct resource pic1_iores = {
-	"8259 (master)", 0x20, 0x21, IORESOURCE_BUSY
-};
-
-static struct resource pic2_iores = {
-	"8259 (slave)", 0xa0, 0xa1, IORESOURCE_BUSY
-};
-
-static struct resource pic_edgectrl_iores = {
-	"8259 edge control", 0x4d0, 0x4d1, IORESOURCE_BUSY
-};
-
-/*
- * i8259_init()
- * intack_addr - PCI interrupt acknowledge (real) address which will return
- *               the active irq from the 8259
- */
-void __init
-i8259_init(long intack_addr)
-{
-	unsigned long flags;
-
-	spin_lock_irqsave(&i8259_lock, flags);
-	/* init master interrupt controller */
-	outb(0x11, 0x20); /* Start init sequence */
-	outb(0x00, 0x21); /* Vector base */
-	outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
-	outb(0x01, 0x21); /* Select 8086 mode */
-
-	/* init slave interrupt controller */
-	outb(0x11, 0xA0); /* Start init sequence */
-	outb(0x08, 0xA1); /* Vector base */
-	outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
-	outb(0x01, 0xA1); /* Select 8086 mode */
-
-	/* always read ISR */
-	outb(0x0B, 0x20);
-	outb(0x0B, 0xA0);
-
-	/* Mask all interrupts */
-	outb(cached_A1, 0xA1);
-	outb(cached_21, 0x21);
-
-	spin_unlock_irqrestore(&i8259_lock, flags);
-
-	/* reserve our resources */
-	request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT,
-				"82c59 secondary cascade", NULL );
-	request_resource(&ioport_resource, &pic1_iores);
-	request_resource(&ioport_resource, &pic2_iores);
-	request_resource(&ioport_resource, &pic_edgectrl_iores);
-
-	if (intack_addr != 0)
-		pci_intack = ioremap(intack_addr, 1);
-}
diff -Nru a/arch/ppc/kernel/iSeries_idle.c b/arch/ppc/kernel/iSeries_idle.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/kernel/iSeries_idle.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,124 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * Idle task for iSeries.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/mmu.h>
+#include <asm/cache.h>
+#include <asm/cputable.h>
+#include <asm/machdep.h>
+#include <asm/time.h>
+#include <asm/iSeries/LparData.h>
+#include <asm/iSeries/HvCall.h>
+#include <asm/hardirq.h>
+
+static void yield_shared_processor(void);
+static void run_light_on(int on);
+
+extern unsigned long yield_count;
+
+void iSeries_idle(void)
+{
+	if (!need_resched()) {
+		/* Turn off the run light */
+		run_light_on(0);
+		yield_shared_processor(); 
+		HMT_low();
+
+#ifdef CONFIG_SMP
+		set_thread_flag(TIF_POLLING_NRFLAG);
+		while (!need_resched())
+			barrier();
+		clear_thread_flag(TIF_POLLING_NRFLAG);
+#endif
+	}
+
+	if (need_resched()) {
+		run_light_on(1);
+		schedule();
+		return;
+	}
+
+}
+
+extern void fake_interrupt(void);
+extern u64  get_tb64(void);
+
+static void run_light_on(int on)
+{
+	unsigned long CTRL;
+
+	CTRL = mfspr(CTRLF);
+	CTRL = on? (CTRL | RUNLATCH): (CTRL & ~RUNLATCH);
+	mtspr(CTRLT, CTRL);
+}
+
+static void yield_shared_processor(void)
+{
+	struct Paca *paca;
+	u64 tb;
+
+	/* Poll for I/O events */
+	local_irq_disable();
+	local_irq_enable();
+	
+	paca = (struct Paca *)mfspr(SPRG1);
+	if ( paca->xLpPaca.xSharedProc ) {
+		HvCall_setEnabledInterrupts( HvCall_MaskIPI |
+                        HvCall_MaskLpEvent |
+                        HvCall_MaskLpProd |
+                        HvCall_MaskTimeout );
+
+		/*
+		 * Check here for any of the above pending...
+		 * IPI and Decrementers are indicated in ItLpPaca
+		 * LpEvents are indicated on the LpQueue
+		 *
+		 * Disabling/enabling will check for LpEvents, IPIs
+		 * and decrementers
+		 */
+		local_irq_disable();
+		local_irq_enable();
+
+		++yield_count;
+
+		/* Get current tb value */
+		tb = get_tb64();
+		/* Compute future tb value when yield will expire */
+		tb += tb_ticks_per_jiffy;
+		HvCall_yieldProcessor( HvCall_YieldTimed, tb );
+
+		/* Check here for any of the above pending or timeout expired*/
+		local_irq_disable();
+		/*
+		 * The decrementer stops during the yield.  Just force
+		 * a fake decrementer now and the timer_interrupt
+		 * code will straighten it all out
+		 */
+		paca->xLpPaca.xDecrInt = 1;
+		local_irq_enable();
+	}
+}
diff -Nru a/arch/ppc/kernel/idle.c b/arch/ppc/kernel/idle.c
--- a/arch/ppc/kernel/idle.c	Sun Nov 10 19:28:36 2002
+++ b/arch/ppc/kernel/idle.c	Sun Nov 10 19:28:36 2002
@@ -2,7 +2,8 @@
  * Idle daemon for PowerPC.  Idle daemon will handle any action
  * that needs to be taken when the system becomes idle.
  *
- * Written by Cort Dougan (cort@cs.nmt.edu)
+ * Written by Cort Dougan (cort@cs.nmt.edu).  Subsequently hacked
+ * on by Tom Rini, Armin Kuster, Paul Mackerras and others.
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -29,175 +30,39 @@
 #include <asm/mmu.h>
 #include <asm/cache.h>
 #include <asm/cputable.h>
-#ifdef CONFIG_PPC_ISERIES
-#include <asm/time.h>
-#include <asm/iSeries/LparData.h>
-#include <asm/iSeries/HvCall.h>
-#include <asm/hardirq.h>
-
-static void yield_shared_processor(void);
-static void run_light_on(int on);
-
-extern unsigned long yield_count;
-
-#else /* CONFIG_PPC_ISERIES */
-#define run_light_on(x)         do { } while (0)
-#endif /* CONFIG_PPC_ISERIES */
-
-void power_save(void);
-
-unsigned long zero_paged_on;
-unsigned long powersave_nap;
+#include <asm/machdep.h>
 
 void default_idle(void)
 {
-	int do_power_save = 0;
+	void (*powersave)(void);
 
-	/* Check if CPU can powersave */
-	if (cur_cpu_spec[smp_processor_id()]->cpu_features &
-		(CPU_FTR_CAN_DOZE | CPU_FTR_CAN_NAP))
-		do_power_save = 1;
+	powersave = ppc_md.power_save;
 
-#ifdef CONFIG_PPC_ISERIES
-	if (!current->need_resched) {
-		/* Turn off the run light */
-		run_light_on(0);
-		yield_shared_processor(); 
-	}
-	HMT_low();
-#endif
+	if (!need_resched()) {
+		if (powersave != NULL)
+			powersave();
 #ifdef CONFIG_SMP
-	if (!do_power_save) {
-		if (!need_resched()) {
+		else {
 			set_thread_flag(TIF_POLLING_NRFLAG);
-			while (!test_thread_flag(TIF_NEED_RESCHED))
+			while (!need_resched())
 				barrier();
 			clear_thread_flag(TIF_POLLING_NRFLAG);
 		}
-	}
 #endif
-	if (do_power_save && !need_resched())
-		power_save();
-
-	if (need_resched()) {
-		run_light_on(1);
-		schedule();
 	}
-#ifdef CONFIG_PPC_ISERIES
-	else {
-		run_light_on(0);
-		yield_shared_processor();
-		HMT_low();
-	}
-#endif /* CONFIG_PPC_ISERIES */
+	if (need_resched())
+		schedule();
 }
 
 /*
- * SMP entry into the idle task - calls the same thing as the
- * non-smp versions. -- Cort
+ * The body of the idle task.
  */
 int cpu_idle(void)
 {
 	for (;;)
-		default_idle();
+		if (ppc_md.idle != NULL)
+			ppc_md.idle();
+		else
+			default_idle();
 	return 0; 
 }
-
-void power_save(void)
-{
-	unsigned long hid0;
-	int nap = powersave_nap;
-	
-	/* 7450 has no DOZE mode mode, we return if powersave_nap
-	 * isn't enabled
-	 */
-	if (!(nap || (cur_cpu_spec[smp_processor_id()]->cpu_features & CPU_FTR_CAN_DOZE)))
-		return;
-	/*
-	 * Disable interrupts to prevent a lost wakeup
-	 * when going to sleep.  This is necessary even with
-	 * RTLinux since we are not guaranteed an interrupt
-	 * didn't come in and is waiting for a local_irq_enable() before
-	 * emulating one.  This way, we really do hard disable.
-	 * 
-	 * We assume that we're sti-ed when we come in here.  We
-	 * are in the idle loop so if we're cli-ed then it's a bug
-	 * anyway.
-	 *  -- Cort
-	 */
-	_nmask_and_or_msr(MSR_EE, 0);
-	if (!need_resched())
-	{
-		asm("mfspr %0,1008" : "=r" (hid0) :);
-		hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
-		hid0 |= (powersave_nap? HID0_NAP: HID0_DOZE) | HID0_DPM;
-		asm("mtspr 1008,%0" : : "r" (hid0));
-		
-		/* set the POW bit in the MSR, and enable interrupts
-		 * so we wake up sometime! */
-		_nmask_and_or_msr(0, MSR_POW | MSR_EE);
-	}
-	_nmask_and_or_msr(0, MSR_EE);
-}
-
-#ifdef CONFIG_PPC_ISERIES
-
-extern void fake_interrupt(void);
-extern u64  get_tb64(void);
-
-void run_light_on(int on)
-{
-	unsigned long CTRL;
-
-	CTRL = mfspr(CTRLF);
-	CTRL = on? (CTRL | RUNLATCH): (CTRL & ~RUNLATCH);
-	mtspr(CTRLT, CTRL);
-}
-
-void yield_shared_processor(void)
-{
-	struct Paca *paca;
-	u64 tb;
-
-	/* Poll for I/O events */
-	local_irq_disable();
-	local_irq_enable();
-	
-	paca = (struct Paca *)mfspr(SPRG1);
-	if ( paca->xLpPaca.xSharedProc ) {
-		HvCall_setEnabledInterrupts( HvCall_MaskIPI |
-                        HvCall_MaskLpEvent |
-                        HvCall_MaskLpProd |
-                        HvCall_MaskTimeout );
-
-		/*
-		 * Check here for any of the above pending...
-		 * IPI and Decrementers are indicated in ItLpPaca
-		 * LpEvents are indicated on the LpQueue
-		 *
-		 * Disabling/enabling will check for LpEvents, IPIs
-		 * and decrementers
-		 */
-		local_irq_disable();
-		local_irq_enable();
-
-		++yield_count;
-
-		/* Get current tb value */
-		tb = get_tb64();
-		/* Compute future tb value when yield will expire */
-		tb += tb_ticks_per_jiffy;
-		HvCall_yieldProcessor( HvCall_YieldTimed, tb );
-
-		/* Check here for any of the above pending or timeout expired*/
-		local_irq_disable();
-		/*
-		 * The decrementer stops during the yield.  Just force
-		 * a fake decrementer now and the timer_interrupt
-		 * code will straighten it all out
-		 */
-		paca->xLpPaca.xDecrInt = 1;
-		local_irq_enable();
-	}
-}
-#endif /* CONFIG_PPC_ISERIES */
diff -Nru a/arch/ppc/kernel/indirect_pci.c b/arch/ppc/kernel/indirect_pci.c
--- a/arch/ppc/kernel/indirect_pci.c	Sun Nov 10 19:28:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,118 +0,0 @@
-/*
- * Support for indirect PCI bridges.
- *
- * Copyright (C) 1998 Gabriel Paubert.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-
-#include <asm/io.h>
-#include <asm/prom.h>
-#include <asm/pci-bridge.h>
-#include <asm/machdep.h>
-
-static int
-indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
-		     int len, u32 *val)
-{
-	struct pci_controller *hose = bus->sysdata;
-	volatile unsigned char *cfg_data;
-	u8 cfg_type = 0;
-
-	if (ppc_md.pci_exclude_device)
-		if (ppc_md.pci_exclude_device(bus->number, devfn))
-			return PCIBIOS_DEVICE_NOT_FOUND;
-	
-	if (hose->set_cfg_type)
-		if (bus->number != hose->first_busno)
-			cfg_type = 1;
-
-	out_be32(hose->cfg_addr,
-		 (((offset & 0xfc) | cfg_type) << 24) | (devfn << 16)
-		 | ((bus->number - hose->bus_offset) << 8) | 0x80);
-	/*
-	 * Note: the caller has already checked that offset is
-	 * suitably aligned and that len is 1, 2 or 4.
-	 */
-	cfg_data = hose->cfg_data + (offset & 3);
-	switch (len) {
-	case 1:
-		*val = in_8((u8 *)cfg_data);
-		break;
-	case 2:
-		*val = in_le16((u16 *)cfg_data);
-		break;
-	default:
-		*val = in_le32((u32 *)cfg_data);
-		break;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
-		      int len, u32 val)
-{
-	struct pci_controller *hose = bus->sysdata;
-	volatile unsigned char *cfg_data;
-	u8 cfg_type = 0;
-
-	if (ppc_md.pci_exclude_device)
-		if (ppc_md.pci_exclude_device(bus->number, devfn))
-			return PCIBIOS_DEVICE_NOT_FOUND;
-
-	if (hose->set_cfg_type)
-		if (bus->number != hose->first_busno)
-			cfg_type = 1;
-
-	out_be32(hose->cfg_addr,
-		 (((offset & 0xfc) | cfg_type) << 24) | (devfn << 16)
-		 | ((bus->number - hose->bus_offset) << 8) | 0x80);
-	/*
-	 * Note: the caller has already checked that offset is
-	 * suitably aligned and that len is 1, 2 or 4.
-	 */
-	cfg_data = hose->cfg_data + (offset & 3);
-	switch (len) {
-	case 1:
-		out_8((u8 *)cfg_data, val);
-		break;
-	case 2:
-		out_le16((u16 *)cfg_data, val);
-		break;
-	default:
-		out_le32((u32 *)cfg_data, val);
-		break;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops indirect_pci_ops =
-{
-	indirect_read_config,
-	indirect_write_config
-};
-
-void __init
-setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
-{
-	unsigned long base = cfg_addr & PAGE_MASK;
-	char *mbase;
-
-	mbase = ioremap(base, PAGE_SIZE);
-	hose->cfg_addr = (unsigned int *)(mbase + (cfg_addr & ~PAGE_MASK));
-	if ((cfg_data & PAGE_MASK) != base)
-		mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
-	hose->cfg_data = (unsigned char *)(mbase + (cfg_data & ~PAGE_MASK));
-	hose->ops = &indirect_pci_ops;
-}
diff -Nru a/arch/ppc/kernel/m8260_setup.c b/arch/ppc/kernel/m8260_setup.c
--- a/arch/ppc/kernel/m8260_setup.c	Sun Nov 10 19:28:39 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,275 +0,0 @@
-/*
- *  arch/ppc/kernel/setup.c
- *
- *  Copyright (C) 1995  Linus Torvalds
- *  Adapted from 'alpha' version by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu)
- *  Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
- *  Further modified for generic 8xx and 8260 by Dan.
- */
-
-/*
- * 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/ide.h>
-#include <linux/seq_file.h>
-
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/ide.h>
-#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);
-static unsigned long m8260_get_rtc_time(void);
-static void m8260_calibrate_decr(void);
-
-unsigned char __res[sizeof(bd_t)];
-
-extern void m8260_cpm_reset(void);
-
-static void __init
-m8260_setup_arch(void)
-{
-	/* Reset the Communication Processor Module.
-	*/
-	m8260_cpm_reset();
-}
-
-static void
-abort(void)
-{
-#ifdef CONFIG_XMON
-	extern void xmon(void *);
-	xmon(0);
-#endif
-	machine_restart(NULL);
-}
-
-/* The decrementer counts at the system (internal) clock frequency
- * divided by four.
- */
-static void __init
-m8260_calibrate_decr(void)
-{
-	bd_t	*binfo = (bd_t *)__res;
-	int freq, divisor;
-
-	freq = binfo->bi_busfreq;
-        divisor = 4;
-        tb_ticks_per_jiffy = freq / HZ / divisor;
-	tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
-}
-
-/* The 8260 has an internal 1-second timer update register that
- * we should use for this purpose.
- */
-static uint rtc_time;
-
-static static int
-m8260_set_rtc_time(unsigned long time)
-{
-#ifdef CONFIG_TQM8260
-	((immap_t *)IMAP_ADDR)->im_sit.sit_tmcnt = time;
-	((immap_t *)IMAP_ADDR)->im_sit.sit_tmcntsc = 0x3;
-#else
-	rtc_time = time;
-#endif
-	return(0);
-}
-
-static unsigned long
-m8260_get_rtc_time(void)
-{
-#ifdef CONFIG_TQM8260
-	return ((immap_t *)IMAP_ADDR)->im_sit.sit_tmcnt;
-#else
-	/* Get time from the RTC.
-	*/
-	return((unsigned long)rtc_time);
-#endif
-}
-
-static void
-m8260_restart(char *cmd)
-{
-	extern void m8260_gorom(bd_t *bi, uint addr);
-	uint	startaddr;
-
-	/* Most boot roms have a warmstart as the second instruction
-	 * of the reset vector.  If that doesn't work for you, change this
-	 * or the reboot program to send a proper address.
-	 */
-#ifdef CONFIG_TQM8260
-	startaddr = 0x40000104;
-#else
-	startaddr = 0xff000104;
-#endif
-	if (cmd != NULL) {
-		if (!strncmp(cmd, "startaddr=", 10))
-			startaddr = simple_strtoul(&cmd[10], NULL, 0);
-	}
-
-	m8260_gorom((unsigned int)__pa(__res), startaddr);
-}
-
-static void
-m8260_power_off(void)
-{
-   m8260_restart(NULL);
-}
-
-static void
-m8260_halt(void)
-{
-   m8260_restart(NULL);
-}
-
-
-static int
-m8260_show_percpuinfo(struct seq_file *m, int i)
-{
-	bd_t	*bp;
-
-	bp = (bd_t *)__res;
-
-	seq_printf(m, "core clock\t: %d MHz\n"
-		   "CPM  clock\t: %d MHz\n"
-		   "bus  clock\t: %d MHz\n",
-		   bp->bi_intfreq / 1000000,
-		   bp->bi_cpmfreq / 1000000,
-		   bp->bi_busfreq / 1000000);
-	return 0;
-}
-
-/* Initialize the internal interrupt controller.  The number of
- * interrupts supported can vary with the processor type, and the
- * 8260 family can have up to 64.
- * External interrupts can be either edge or level triggered, and
- * need to be initialized by the appropriate driver.
- */
-static void __init
-m8260_init_IRQ(void)
-{
-	int i;
-	void cpm_interrupt_init(void);
-
-#if 0
-        ppc8260_pic.irq_offset = 0;
-#endif
-        for ( i = 0 ; i < NR_SIU_INTS ; i++ )
-                irq_desc[i].handler = &ppc8260_pic;
-
-	/* Initialize the default interrupt mapping priorities,
-	 * in case the boot rom changed something on us.
-	 */
-	immr->im_intctl.ic_sicr = 0;
-	immr->im_intctl.ic_siprr = 0x05309770;
-	immr->im_intctl.ic_scprrh = 0x05309770;
-	immr->im_intctl.ic_scprrl = 0x05309770;
-
-}
-
-/*
- * Same hack as 8xx
- */
-static unsigned long __init
-m8260_find_end_of_memory(void)
-{
-	bd_t	*binfo;
-	extern unsigned char __res[];
-
-	binfo = (bd_t *)__res;
-
-	return binfo->bi_memsize;
-}
-
-/* Map the IMMR, plus anything else we can cover
- * in that upper space according to the memory controller
- * chip select mapping.  Grab another bunch of space
- * below that for stuff we can't cover in the upper.
- */
-static void __init
-m8260_map_io(void)
-{
-	io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
-	io_block_mapping(0xe0000000, 0xe0000000, 0x10000000, _PAGE_IO);
-}
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-	      unsigned long r6, unsigned long r7)
-{
-	parse_bootinfo(find_bootinfo());
-
-	if ( r3 )
-		memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* take care of initrd if we have one */
-	if ( r4 ) {
-		initrd_start = r4 + KERNELBASE;
-		initrd_end = r5 + KERNELBASE;
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-	/* take care of cmd line */
-	if ( r6 ) {
-		*(char *)(r7+KERNELBASE) = 0;
-		strcpy(cmd_line, (char *)(r6+KERNELBASE));
-	}
-
-	ppc_md.setup_arch		= m8260_setup_arch;
-	ppc_md.show_percpuinfo		= m8260_show_percpuinfo;
-	ppc_md.irq_cannonicalize	= NULL;
-	ppc_md.init_IRQ			= m8260_init_IRQ;
-	ppc_md.get_irq			= m8260_get_irq;
-	ppc_md.init			= NULL;
-
-	ppc_md.restart			= m8260_restart;
-	ppc_md.power_off		= m8260_power_off;
-	ppc_md.halt			= m8260_halt;
-
-	ppc_md.time_init		= NULL;
-	ppc_md.set_rtc_time		= m8260_set_rtc_time;
-	ppc_md.get_rtc_time		= m8260_get_rtc_time;
-	ppc_md.calibrate_decr		= m8260_calibrate_decr;
-
-	ppc_md.find_end_of_memory	= m8260_find_end_of_memory;
-	ppc_md.setup_io_mappings	= m8260_map_io;
-}
-
-/* Mainly for ksyms.
-*/
-int
-request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-		       unsigned long flag, const char *naem, void *dev)
-{
-	panic("request IRQ\n");
-}
diff -Nru a/arch/ppc/kernel/m8xx_setup.c b/arch/ppc/kernel/m8xx_setup.c
--- a/arch/ppc/kernel/m8xx_setup.c	Sun Nov 10 19:28:39 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,400 +0,0 @@
-/*
- *  arch/ppc/kernel/setup.c
- *
- *  Copyright (C) 1995  Linus Torvalds
- *  Adapted from 'alpha' version by Gary Thomas
- *  Modified by Cort Dougan (cort@cs.nmt.edu)
- *  Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
- *  Further modified for generic 8xx by Dan.
- */
-
-/*
- * 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/bootmem.h>
-#include <linux/seq_file.h>
-#include <linux/root_dev.h>
-
-#include <asm/mmu.h>
-#include <asm/processor.h>
-#include <asm/residual.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#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);
-static unsigned long m8xx_get_rtc_time(void);
-void m8xx_calibrate_decr(void);
-
-unsigned char __res[sizeof(bd_t)];
-
-extern void m8xx_ide_init(void);
-
-extern unsigned long find_available_memory(void);
-extern void m8xx_cpm_reset(uint);
-extern void rpxfb_alloc_pages(void);
-
-void __init
-m8xx_setup_arch(void)
-{
-	int	cpm_page;
-
-	cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE);
-
-	/* Reset the Communication Processor Module.
-	*/
-	m8xx_cpm_reset(cpm_page);
-
-#ifdef CONFIG_FB_RPX
-	rpxfb_alloc_pages();
-#endif
-
-#ifdef notdef
-	ROOT_DEV = Root_HDA1; /* hda1 */
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
-#if 0
-	ROOT_DEV = Root_FD0; /* floppy */
-	rd_prompt = 1;
-	rd_doload = 1;
-	rd_image_start = 0;
-#endif
-#if 0	/* XXX this may need to be updated for the new bootmem stuff,
-	   or possibly just deleted (see set_phys_avail() in init.c).
-	   - paulus. */
-	/* initrd_start and size are setup by boot/head.S and kernel/head.S */
-	if ( initrd_start )
-	{
-		if (initrd_end > *memory_end_p)
-		{
-			printk("initrd extends beyond end of memory "
-			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
-			       initrd_end,*memory_end_p);
-			initrd_start = 0;
-		}
-	}
-#endif
-#endif
-}
-
-void
-abort(void)
-{
-#ifdef CONFIG_XMON
-	xmon(0);
-#endif
-	machine_restart(NULL);
-
-	/* not reached */
-	for (;;);
-}
-
-/* A place holder for time base interrupts, if they are ever enabled. */
-void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
-{
-	printk ("timebase_interrupt()\n");
-}
-
-/* The decrementer counts at the system (internal) clock frequency divided by
- * sixteen, or external oscillator divided by four.  We force the processor
- * to use system clock divided by sixteen.
- */
-void __init m8xx_calibrate_decr(void)
-{
-	bd_t	*binfo = (bd_t *)__res;
-	int freq, fp, divisor;
-
-	/* Unlock the SCCR. */
-	((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = ~KAPWR_KEY;
-	((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = KAPWR_KEY;
-
-	/* Force all 8xx processors to use divide by 16 processor clock. */
-	((volatile immap_t *)IMAP_ADDR)->im_clkrst.car_sccr |= 0x02000000;
-
-	/* Processor frequency is MHz.
-	 * The value 'fp' is the number of decrementer ticks per second.
-	 */
-	fp = binfo->bi_intfreq / 16;
-	freq = fp*60;	/* try to make freq/1e6 an integer */
-        divisor = 60;
-        printk("Decrementer Frequency = %d/%d\n", freq, divisor);
-        tb_ticks_per_jiffy = freq / HZ / divisor;
-	tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
-
-	/* Perform some more timer/timebase initialization.  This used
-	 * to be done elsewhere, but other changes caused it to get
-	 * called more than once....that is a bad thing.
-	 *
-	 * First, unlock all of the registers we are going to modify.
-	 * To protect them from corruption during power down, registers
-	 * that are maintained by keep alive power are "locked".  To
-	 * modify these registers we have to write the key value to
-	 * the key location associated with the register.
-	 * Some boards power up with these unlocked, while others
-	 * are locked.  Writing anything (including the unlock code?)
-	 * to the unlocked registers will lock them again.  So, here
-	 * we guarantee the registers are locked, then we unlock them
-	 * for our use.
-	 */
-	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = ~KAPWR_KEY;
-	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = ~KAPWR_KEY;
-	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk    = ~KAPWR_KEY;
-	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk =  KAPWR_KEY;
-	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck =  KAPWR_KEY;
-	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk    =  KAPWR_KEY;
-
-	/* Disable the RTC one second and alarm interrupts. */
-	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &=
-						~(RTCSC_SIE | RTCSC_ALE);
-	/* Enable the RTC */
-	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc |=
-						(RTCSC_RTF | RTCSC_RTE);
-
-	/* Enabling the decrementer also enables the timebase interrupts
-	 * (or from the other point of view, to get decrementer interrupts
-	 * we have to enable the timebase).  The decrementer interrupt
-	 * is wired into the vector table, nothing to do here for that.
-	 */
-	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_tbscr =
-				((mk_int_int_mask(DEC_INTERRUPT) << 8) |
-					 (TBSCR_TBF | TBSCR_TBE));
-
-	if (request_8xxirq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
-		panic("Could not allocate timer IRQ!");
-}
-
-/* The RTC on the MPC8xx is an internal register.
- * We want to protect this during power down, so we need to unlock,
- * modify, and re-lock.
- */
-static int
-m8xx_set_rtc_time(unsigned long time)
-{
-	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
-	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time;
-	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
-	return(0);
-}
-
-static unsigned long
-m8xx_get_rtc_time(void)
-{
-	/* Get time from the RTC. */
-	return((unsigned long)(((immap_t *)IMAP_ADDR)->im_sit.sit_rtc));
-}
-
-static void
-m8xx_restart(char *cmd)
-{
-	__volatile__ unsigned char dummy;
-	uint	msr;
-
-	cli();
-	((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr |= 0x00000080;
-
-	/* Clear the ME bit in MSR to cause checkstop on machine check
-	*/
-	__asm__("mfmsr %0" : "=r" (msr) );
-	msr &= ~0x1000;
-	__asm__("mtmsr %0" : : "r" (msr) );
-
-	dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0];
-	printk("Restart failed\n");
-	while(1);
-}
-
-static void
-m8xx_power_off(void)
-{
-   m8xx_restart(NULL);
-}
-
-static void
-m8xx_halt(void)
-{
-   m8xx_restart(NULL);
-}
-
-
-static int
-m8xx_show_percpuinfo(struct seq_file *m, int i)
-{
-	bd_t	*bp;
-
-	bp = (bd_t *)__res;
-
-	seq_printf(m, "clock\t\t: %dMHz\n"
-		   "bus clock\t: %dMHz\n",
-		   bp->bi_intfreq / 1000000,
-		   bp->bi_busfreq / 1000000);
-
-	return 0;
-}
-
-/* Initialize the internal interrupt controller.  The number of
- * interrupts supported can vary with the processor type, and the
- * 82xx family can have up to 64.
- * External interrupts can be either edge or level triggered, and
- * need to be initialized by the appropriate driver.
- */
-static void __init
-m8xx_init_IRQ(void)
-{
-	int i;
-	void cpm_interrupt_init(void);
-
-        for ( i = 0 ; i < NR_SIU_INTS ; i++ )
-                irq_desc[i].handler = &ppc8xx_pic;
-
-	/* We could probably incorporate the CPM into the multilevel
-	 * interrupt structure.
-	 */
-	cpm_interrupt_init();
-        unmask_irq(CPM_INTERRUPT);
-
-#if defined(CONFIG_PCI)
-        for ( i = NR_SIU_INTS ; i < (NR_SIU_INTS + NR_8259_INTS) ; i++ )
-                irq_desc[i].handler = &i8259_pic;
-        i8259_pic.irq_offset = NR_SIU_INTS;
-        i8259_init();
-        request_8xxirq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
-        enable_irq(ISA_BRIDGE_INT);
-#endif
-}
-
-/* -------------------------------------------------------------------- */
-
-/*
- * This is a big hack right now, but it may turn into something real
- * someday.
- *
- * For the 8xx boards (at this time anyway), there is nothing to initialize
- * associated the PROM.  Rather than include all of the prom.c
- * functions in the image just to get prom_init, all we really need right
- * now is the initialization of the physical memory region.
- */
-static unsigned long __init
-m8xx_find_end_of_memory(void)
-{
-	bd_t	*binfo;
-	extern unsigned char __res[];
-
-	binfo = (bd_t *)__res;
-
-	return binfo->bi_memsize;
-}
-
-/*
- * Now map in some of the I/O space that is generically needed
- * or shared with multiple devices.
- * All of this fits into the same 4Mbyte region, so it only
- * requires one page table page.  (or at least it used to  -- paulus)
- */
-static void __init
-m8xx_map_io(void)
-{
-        io_block_mapping(IMAP_ADDR, IMAP_ADDR, IMAP_SIZE, _PAGE_IO);
-#ifdef CONFIG_MBX
-        io_block_mapping(NVRAM_ADDR, NVRAM_ADDR, NVRAM_SIZE, _PAGE_IO);
-        io_block_mapping(MBX_CSR_ADDR, MBX_CSR_ADDR, MBX_CSR_SIZE, _PAGE_IO);
-        io_block_mapping(PCI_CSR_ADDR, PCI_CSR_ADDR, PCI_CSR_SIZE, _PAGE_IO);
-
-	/* Map some of the PCI/ISA I/O space to get the IDE interface.
-	*/
-        io_block_mapping(PCI_ISA_IO_ADDR, PCI_ISA_IO_ADDR, 0x4000, _PAGE_IO);
-        io_block_mapping(PCI_IDE_ADDR, PCI_IDE_ADDR, 0x4000, _PAGE_IO);
-#endif
-#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
-	io_block_mapping(RPX_CSR_ADDR, RPX_CSR_ADDR, RPX_CSR_SIZE, _PAGE_IO);
-#if !defined(CONFIG_PCI)
-	io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO);
-#endif
-#endif
-#ifdef CONFIG_HTDMSOUND
-	io_block_mapping(HIOX_CSR_ADDR, HIOX_CSR_ADDR, HIOX_CSR_SIZE, _PAGE_IO);
-#endif
-#ifdef CONFIG_FADS
-	io_block_mapping(BCSR_ADDR, BCSR_ADDR, BCSR_SIZE, _PAGE_IO);
-#endif
-#ifdef CONFIG_PCI
-        io_block_mapping(PCI_CSR_ADDR, PCI_CSR_ADDR, PCI_CSR_SIZE, _PAGE_IO);
-#endif
-}
-
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-		unsigned long r6, unsigned long r7)
-{
-	parse_bootinfo(find_bootinfo());
-
-	if ( r3 )
-		memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
-
-#ifdef CONFIG_PCI
-	m8xx_setup_pci_ptrs();
-#endif
-
-#ifdef CONFIG_BLK_DEV_INITRD
-	/* take care of initrd if we have one */
-	if ( r4 )
-	{
-		initrd_start = r4 + KERNELBASE;
-		initrd_end = r5 + KERNELBASE;
-	}
-#endif /* CONFIG_BLK_DEV_INITRD */
-	/* take care of cmd line */
-	if ( r6 )
-	{
-		*(char *)(r7+KERNELBASE) = 0;
-		strcpy(cmd_line, (char *)(r6+KERNELBASE));
-	}
-
-	ppc_md.setup_arch		= m8xx_setup_arch;
-	ppc_md.show_percpuinfo		= m8xx_show_percpuinfo;
-	ppc_md.irq_cannonicalize	= NULL;
-	ppc_md.init_IRQ			= m8xx_init_IRQ;
-	ppc_md.get_irq			= m8xx_get_irq;
-	ppc_md.init			= NULL;
-
-	ppc_md.restart			= m8xx_restart;
-	ppc_md.power_off		= m8xx_power_off;
-	ppc_md.halt			= m8xx_halt;
-
-	ppc_md.time_init		= NULL;
-	ppc_md.set_rtc_time		= m8xx_set_rtc_time;
-	ppc_md.get_rtc_time		= m8xx_get_rtc_time;
-	ppc_md.calibrate_decr		= m8xx_calibrate_decr;
-
-	ppc_md.find_end_of_memory	= m8xx_find_end_of_memory;
-	ppc_md.setup_io_mappings	= m8xx_map_io;
-
-#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-	m8xx_ide_init();
-#endif
-}
diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
--- a/arch/ppc/kernel/misc.S	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/kernel/misc.S	Sun Nov 10 19:28:41 2002
@@ -1290,6 +1290,11 @@
 	.long sys_ni_syscall	/* reserved for alloc_hugepages */
 	.long sys_ni_syscall	/* reserved for free_hugepages */
 	.long sys_exit_group
+	.long sys_lookup_dcookie /* 235 */
+	.long sys_epoll_create
+	.long sys_epoll_ctl
+	.long sys_epoll_wait
+ 	.long sys_remap_file_pages
 
 	.rept NR_syscalls-(.-sys_call_table)/4
 		.long sys_ni_syscall
diff -Nru a/arch/ppc/kernel/mpc10x_common.c b/arch/ppc/kernel/mpc10x_common.c
--- a/arch/ppc/kernel/mpc10x_common.c	Sun Nov 10 19:28:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,378 +0,0 @@
-
-/*
- * arch/ppc/kernel/mpc10x_common.c
- * 
- * Common routines for the Motorola SPS MPC106, MPC107 and MPC8240 Host bridge,
- * Mem ctlr, EPIC, etc.
- *
- * Author: Mark A. Greer
- *         mgreer@mvista.com
- *
- * Copyright 2001 MontaVista Software 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.
- */
-
-/*
- * *** WARNING - A BAT MUST be set to access the PCI config addr/data regs ***
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-#include <asm/open_pic.h>
-#include <asm/mpc10x.h>
-
-
-/* Set resources to match bridge memory map */
-void __init
-mpc10x_bridge_set_resources(int map, struct pci_controller *hose)
-{
-
-	switch (map) {
-		case MPC10X_MEM_MAP_A:
-			pci_init_resource(&hose->io_resource,
-					0x00000000,
-					0x3f7fffff,
-					IORESOURCE_IO,
-					"PCI host bridge");
-
-			pci_init_resource (&hose->mem_resources[0],
-					0xc0000000,
-					0xfeffffff,
-					IORESOURCE_MEM,
-					"PCI host bridge");
-			break;
-		case MPC10X_MEM_MAP_B:
-			pci_init_resource(&hose->io_resource,
-					0x00000000,
-					0x00bfffff,
-					IORESOURCE_IO,
-					"PCI host bridge");
-
-			pci_init_resource (&hose->mem_resources[0],
-					0x80000000,
-					0xfcffffff,
-					IORESOURCE_MEM,
-					"PCI host bridge");
-			break;
-		default:
-			printk("mpc10x_bridge_set_resources: "
-					"Invalid map specified\n");
-			if (ppc_md.progress)
-				ppc_md.progress("mpc10x:exit1", 0x100);
-	}
-}
-/*
- * Do some initialization and put the EUMB registers at the specified address
- * (also map the EPIC registers into virtual space--OpenPIC_Addr will be set).
- *
- * The EPIC is not on the 106, only the 8240 and 107.
- */
-int __init
-mpc10x_bridge_init(struct pci_controller *hose,
-		   uint current_map,
-		   uint new_map,
-		   uint phys_eumb_base)
-{
-	int	host_bridge, picr1, picr1_bit;
-	ulong	pci_config_addr, pci_config_data;
-	u_char	pir, byte;
-
-	if (ppc_md.progress) ppc_md.progress("mpc10x:enter", 0x100);
-
-	/* Set up for current map so we can get at config regs */
-	switch (current_map) {
-		case MPC10X_MEM_MAP_A:
-			setup_indirect_pci(hose,
-					   MPC10X_MAPA_CNFG_ADDR,
-					   MPC10X_MAPA_CNFG_DATA);
-			break;
-		case MPC10X_MEM_MAP_B:
-			setup_indirect_pci(hose,
-					   MPC10X_MAPB_CNFG_ADDR,
-					   MPC10X_MAPB_CNFG_DATA);
-			break;
-		default:
-			printk("mpc10x_bridge_init: %s\n",
-				"Invalid current map specified");
-			if (ppc_md.progress)
-				ppc_md.progress("mpc10x:exit1", 0x100);
-			return -1;
-	}
-
-	/* Make sure its a supported bridge */
-	early_read_config_dword(hose,
-			        0,
-			        PCI_DEVFN(0,0),
-			        PCI_VENDOR_ID,
-			        &host_bridge);
-
-	switch (host_bridge) {
-		case MPC10X_BRIDGE_106:
-		case MPC10X_BRIDGE_8240:
-		case MPC10X_BRIDGE_107:
-		case MPC10X_BRIDGE_8245:
-			break;
-		default:
-			if (ppc_md.progress)
-				ppc_md.progress("mpc10x:exit2", 0x100);
-			return -1;
-	}
-
-	switch (new_map) {
-		case MPC10X_MEM_MAP_A:
-			MPC10X_SETUP_HOSE(hose, A);
-			pci_config_addr = MPC10X_MAPA_CNFG_ADDR;
-			pci_config_data = MPC10X_MAPA_CNFG_DATA;
-			picr1_bit = MPC10X_CFG_PICR1_ADDR_MAP_A;
-			break;
-		case MPC10X_MEM_MAP_B:
-			MPC10X_SETUP_HOSE(hose, B);
-			pci_config_addr = MPC10X_MAPB_CNFG_ADDR;
-			pci_config_data = MPC10X_MAPB_CNFG_DATA;
-			picr1_bit = MPC10X_CFG_PICR1_ADDR_MAP_B;
-			break;
-		default:
-			printk("mpc10x_bridge_init: %s\n",
-				"Invalid new map specified");
-			if (ppc_md.progress)
-				ppc_md.progress("mpc10x:exit3", 0x100);
-			return -1;
-	}
-
-	/* Make bridge use the 'new_map', if not already usng it */
-	if (current_map != new_map) {
-		early_read_config_dword(hose,
-					0,
-					PCI_DEVFN(0,0),
-					MPC10X_CFG_PICR1_REG,
-					&picr1);
-
-		picr1 = (picr1 & ~MPC10X_CFG_PICR1_ADDR_MAP_MASK) |
-			 picr1_bit;
-
-		early_write_config_dword(hose,
-					 0,
-					 PCI_DEVFN(0,0),
-					 MPC10X_CFG_PICR1_REG,
-					 picr1);
-
-		asm volatile("sync");
-
-		/* Undo old mappings & map in new cfg data/addr regs */
-		iounmap((void *)hose->cfg_addr);
-		iounmap((void *)hose->cfg_data);
-
-		setup_indirect_pci(hose,
-				   pci_config_addr,
-				   pci_config_data);
-	}
-
-	/* Setup resources to match map */
-	mpc10x_bridge_set_resources(new_map, hose);
-
-	/*
-	 * Want processor accesses of 0xFDxxxxxx to be mapped
-	 * to PCI memory space at 0x00000000.  Do not want
-	 * host bridge to respond to PCI memory accesses of
-	 * 0xFDxxxxxx.  Do not want host bridge to respond
-	 * to PCI memory addresses 0xFD000000-0xFDFFFFFF;
-	 * want processor accesses from 0x000A0000-0x000BFFFF
-	 * to be forwarded to system memory.
-	 *
-	 * Only valid if not in agent mode and using MAP B.
-	 */
-	if (new_map == MPC10X_MEM_MAP_B) {
-		early_read_config_byte(hose,
-				       0,
-				       PCI_DEVFN(0,0),
-				       MPC10X_CFG_MAPB_OPTIONS_REG,
-				       &byte);
-
-		byte &= ~(MPC10X_CFG_MAPB_OPTIONS_PFAE  |
-			  MPC10X_CFG_MAPB_OPTIONS_PCICH |
-			  MPC10X_CFG_MAPB_OPTIONS_PROCCH);
-
-		if (host_bridge != MPC10X_BRIDGE_106) {
-			byte |= MPC10X_CFG_MAPB_OPTIONS_CFAE;
-		}
-
-		early_write_config_byte(hose,
-					0,
-					PCI_DEVFN(0,0),
-					MPC10X_CFG_MAPB_OPTIONS_REG,
-					byte);
-	}
-
-	if (host_bridge != MPC10X_BRIDGE_106) {
-		early_read_config_byte(hose,
-				       0,
-				       PCI_DEVFN(0,0),
-				       MPC10X_CFG_PIR_REG,
-				       &pir);
-
-		if (pir != MPC10X_CFG_PIR_HOST_BRIDGE) {
-			printk("Host bridge in Agent mode\n");
-			/* Read or Set LMBAR & PCSRBAR? */
-		}
-		       
-		/* Set base addr of the 8240/107 EUMB.  */
-		early_write_config_dword(hose,
-					 0,
-					 PCI_DEVFN(0,0),
-					 MPC10X_CFG_EUMBBAR,
-					 phys_eumb_base);
-
-		/* Map EPIC register part of EUMB into vitual memory */
-		OpenPIC_Addr = 
-			ioremap(phys_eumb_base + MPC10X_EUMB_EPIC_OFFSET,
-				MPC10X_EUMB_EPIC_SIZE);
-	}
-
-#ifdef CONFIG_MPC10X_STORE_GATHERING
-	mpc10x_enable_store_gathering(hose);
-#endif
-
-	if (ppc_md.progress) ppc_md.progress("mpc10x:exit", 0x100);
-	return 0;
-}
-
-/*
- * Need to make our own PCI config space access macros because
- * mpc10x_get_mem_size() is called before the data structures are set up for
- * the 'early_xxx' and 'indirect_xxx' routines to work.
- * Assumes bus 0.
- */
-#define MPC10X_CFG_read(val, addr, type, op)	*val = op((type)(addr))
-#define MPC10X_CFG_write(val, addr, type, op)	op((type *)(addr), (val))
-
-#define MPC10X_PCI_OP(rw, size, type, op, mask)			 	\
-static void								\
-mpc10x_##rw##_config_##size(uint *cfg_addr, uint *cfg_data, int devfn, int offset, type val) \
-{									\
-	out_be32(cfg_addr, 						\
-		 ((offset & 0xfc) << 24) | (devfn << 16)		\
-		 | (0 << 8) | 0x80);					\
-	MPC10X_CFG_##rw(val, cfg_data + (offset & mask), type, op);	\
-	return;    					 		\
-}
-
-MPC10X_PCI_OP(read,  byte,  u8 *, in_8, 3)
-MPC10X_PCI_OP(read,  dword, u32 *, in_le32, 0)
-#if 0	/* Not used */
-MPC10X_PCI_OP(write, byte,  u8, out_8, 3)
-MPC10X_PCI_OP(read,  word,  u16 *, in_le16, 2)
-MPC10X_PCI_OP(write, word,  u16, out_le16, 2)
-MPC10X_PCI_OP(write, dword, u32, out_le32, 0)
-#endif
-
-/*
- * Read the memory controller registers to determine the amount of memory in
- * the system.  This assumes that the firmware has correctly set up the memory
- * controller registers.
- */
-unsigned long __init
-mpc10x_get_mem_size(uint mem_map)
-{
-	uint			*config_addr, *config_data, val;
-	ulong			start, end, total, offset;
-	int			i;
-	u_char			bank_enables;
-
-	switch (mem_map) {
-		case MPC10X_MEM_MAP_A:
-			config_addr = (uint *)MPC10X_MAPA_CNFG_ADDR;
-			config_data = (uint *)MPC10X_MAPA_CNFG_DATA;
-			break;
-		case MPC10X_MEM_MAP_B:
-			config_addr = (uint *)MPC10X_MAPB_CNFG_ADDR;
-			config_data = (uint *)MPC10X_MAPB_CNFG_DATA;
-			break;
-		default:
-			return 0;
-	}
-
-	mpc10x_read_config_byte(config_addr,
-				config_data,
-				PCI_DEVFN(0,0),
-			        MPC10X_MCTLR_MEM_BANK_ENABLES,
-			        &bank_enables);
-
-	total = 0;
-
-	for (i=0; i<8; i++) {
-		if (bank_enables & (1 << i)) {
-			offset = MPC10X_MCTLR_MEM_START_1 + ((i > 3) ? 4 : 0);
-			mpc10x_read_config_dword(config_addr,
-						 config_data,
-						 PCI_DEVFN(0,0),
-						 offset,
-						 &val);
-			start = (val >> ((i & 3) << 3)) & 0xff;
-
-			offset = MPC10X_MCTLR_EXT_MEM_START_1 + ((i>3) ? 4 : 0);
-			mpc10x_read_config_dword(config_addr,
-						 config_data,
-						 PCI_DEVFN(0,0),
-						 offset,
-						 &val);
-			val = (val >> ((i & 3) << 3)) & 0x03;
-			start = (val << 28) | (start << 20);
-
-			offset = MPC10X_MCTLR_MEM_END_1 + ((i > 3) ? 4 : 0);
-			mpc10x_read_config_dword(config_addr,
-						 config_data,
-						 PCI_DEVFN(0,0),
-						 offset,
-						 &val);
-			end = (val >> ((i & 3) << 3)) & 0xff;
-
-			offset = MPC10X_MCTLR_EXT_MEM_END_1 + ((i > 3) ? 4 : 0);
-			mpc10x_read_config_dword(config_addr,
-						 config_data,
-						 PCI_DEVFN(0,0),
-						 offset,
-						 &val);
-			val = (val >> ((i & 3) << 3)) & 0x03;
-			end = (val << 28) | (end << 20) | 0xfffff;
-
-			total += (end - start + 1);
-		}
-	}
-
-	return total;
-}
-
-int __init
-mpc10x_enable_store_gathering(struct pci_controller *hose)
-{
-	uint picr1;
-
-	early_read_config_dword(hose,
-				0,
-				PCI_DEVFN(0,0),
-			        MPC10X_CFG_PICR1_REG,
-			        &picr1);
-
-	picr1 |= MPC10X_CFG_PICR1_ST_GATH_EN;
-
-	early_write_config_dword(hose,
-				0,
-				PCI_DEVFN(0,0),
-				MPC10X_CFG_PICR1_REG,
-				picr1);
-
-	return 0;
-}
diff -Nru a/arch/ppc/kernel/open_pic.c b/arch/ppc/kernel/open_pic.c
--- a/arch/ppc/kernel/open_pic.c	Sun Nov 10 19:28:40 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,927 +0,0 @@
-/*
- *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
- *
- *  Copyright (C) 1997 Geert Uytterhoeven
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive
- *  for more details.
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/init.h>
-#include <linux/irq.h>
-#include <asm/ptrace.h>
-#include <asm/signal.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-#include <asm/sections.h>
-#include <asm/open_pic.h>
-#include <asm/i8259.h>
-#include <asm/hardirq.h>
-
-#include "open_pic_defs.h"
-
-#ifdef CONFIG_PRPMC800
-#define OPENPIC_BIG_ENDIAN
-#endif
-
-void* OpenPIC_Addr;
-static volatile struct OpenPIC *OpenPIC = NULL;
-/*
- * We define OpenPIC_InitSenses table thusly:
- * bit 0x1: sense, 0 for edge and 1 for level.
- * bit 0x2: polarity, 0 for negative, 1 for positive.
- */
-u_int OpenPIC_NumInitSenses __initdata = 0;
-u_char *OpenPIC_InitSenses __initdata = NULL;
-extern int use_of_interrupt_tree;
-
-static u_int NumProcessors;
-static u_int NumSources;
-static int open_pic_irq_offset;
-static volatile OpenPIC_Source *ISR[NR_IRQS];
-
-/* Global Operations */
-static void openpic_disable_8259_pass_through(void);
-static void openpic_set_priority(u_int pri);
-static void openpic_set_spurious(u_int vector);
-
-#ifdef CONFIG_SMP
-/* Interprocessor Interrupts */
-static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
-static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
-#endif
-
-/* Timer Interrupts */
-static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
-static void openpic_maptimer(u_int timer, u_int cpumask);
-
-/* Interrupt Sources */
-static void openpic_enable_irq(u_int irq);
-static void openpic_disable_irq(u_int irq);
-static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
-			    int is_level);
-static void openpic_mapirq(u_int irq, u_int cpumask, u_int keepmask);
-
-/*
- * These functions are not used but the code is kept here
- * for completeness and future reference.
- */
-#ifdef notused
-static void openpic_enable_8259_pass_through(void);
-static u_int openpic_get_priority(void);
-static u_int openpic_get_spurious(void);
-static void openpic_set_sense(u_int irq, int sense);
-#endif /* notused */
-
-/*
- * Description of the openpic for the higher-level irq code
- */
-static void openpic_end_irq(unsigned int irq_nr);
-static void openpic_ack_irq(unsigned int irq_nr);
-static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
-
-struct hw_interrupt_type open_pic = {
-	" OpenPIC  ",
-	NULL,
-	NULL,
-	openpic_enable_irq,
-	openpic_disable_irq,
-	openpic_ack_irq,
-	openpic_end_irq,
-	openpic_set_affinity
-};
-
-#ifdef CONFIG_SMP
-static void openpic_end_ipi(unsigned int irq_nr);
-static void openpic_ack_ipi(unsigned int irq_nr);
-static void openpic_enable_ipi(unsigned int irq_nr);
-static void openpic_disable_ipi(unsigned int irq_nr);
-
-struct hw_interrupt_type open_pic_ipi = {
-	" OpenPIC  ",
-	NULL,
-	NULL,
-	openpic_enable_ipi,
-	openpic_disable_ipi,
-	openpic_ack_ipi,
-	openpic_end_ipi,
-	0
-};
-#endif /* CONFIG_SMP */
-
-/*
- *  Accesses to the current processor's openpic registers
- */
-#ifdef CONFIG_SMP
-#define THIS_CPU		Processor[cpu]
-#define DECL_THIS_CPU		int cpu = smp_hw_index[smp_processor_id()]
-#define CHECK_THIS_CPU		check_arg_cpu(cpu)
-#else
-#define THIS_CPU		Processor[0]
-#define DECL_THIS_CPU
-#define CHECK_THIS_CPU
-#endif /* CONFIG_SMP */
-
-#if 1
-#define check_arg_ipi(ipi) \
-    if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
-	printk("open_pic.c:%d: illegal ipi %d\n", __LINE__, ipi);
-#define check_arg_timer(timer) \
-    if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
-	printk("open_pic.c:%d: illegal timer %d\n", __LINE__, timer);
-#define check_arg_vec(vec) \
-    if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
-	printk("open_pic.c:%d: illegal vector %d\n", __LINE__, vec);
-#define check_arg_pri(pri) \
-    if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
-	printk("open_pic.c:%d: illegal priority %d\n", __LINE__, pri);
-/*
- * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
- * data has probably been corrupted and we're going to panic or deadlock later
- * anyway --Troy
- */
-#define check_arg_irq(irq) \
-    if (irq < open_pic_irq_offset || irq >= NumSources+open_pic_irq_offset \
-	|| ISR[irq - open_pic_irq_offset] == 0) { \
-      printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
-      dump_stack(); }
-#define check_arg_cpu(cpu) \
-    if (cpu < 0 || cpu >= NumProcessors){ \
-	printk("open_pic.c:%d: illegal cpu %d\n", __LINE__, cpu); \
-	dump_stack(); }
-#else
-#define check_arg_ipi(ipi)	do {} while (0)
-#define check_arg_timer(timer)	do {} while (0)
-#define check_arg_vec(vec)	do {} while (0)
-#define check_arg_pri(pri)	do {} while (0)
-#define check_arg_irq(irq)	do {} while (0)
-#define check_arg_cpu(cpu)	do {} while (0)
-#endif
-
-u_int openpic_read(volatile u_int *addr)
-{
-	u_int val;
-
-#ifdef OPENPIC_BIG_ENDIAN
-	val = in_be32(addr);
-#else
-	val = in_le32(addr);
-#endif
-	return val;
-}
-
-static inline void openpic_write(volatile u_int *addr, u_int val)
-{
-#ifdef OPENPIC_BIG_ENDIAN
-	out_be32(addr, val);
-#else
-	out_le32(addr, val);
-#endif
-}
-
-static inline u_int openpic_readfield(volatile u_int *addr, u_int mask)
-{
-	u_int val = openpic_read(addr);
-	return val & mask;
-}
-
-inline void openpic_writefield(volatile u_int *addr, u_int mask,
-			       u_int field)
-{
-	u_int val = openpic_read(addr);
-	openpic_write(addr, (val & ~mask) | (field & mask));
-}
-
-static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
-{
-	openpic_writefield(addr, mask, 0);
-}
-
-static inline void openpic_setfield(volatile u_int *addr, u_int mask)
-{
-	openpic_writefield(addr, mask, mask);
-}
-
-static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
-				    u_int field)
-{
-	openpic_setfield(addr, OPENPIC_MASK);
-	while (openpic_read(addr) & OPENPIC_ACTIVITY);
-	openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
-}
-
-#ifdef CONFIG_SMP
-/* yes this is right ... bug, feature, you decide! -- tgall */
-u_int openpic_read_IPI(volatile u_int* addr)
-{
-         u_int val = 0;
-#if defined(OPENPIC_BIG_ENDIAN) || defined(CONFIG_POWER3)
-        val = in_be32(addr);
-#else
-        val = in_le32(addr);
-#endif
-        return val;
-}
-
-/* because of the power3 be / le above, this is needed */
-inline void openpic_writefield_IPI(volatile u_int* addr, u_int mask, u_int field)
-{
-        u_int  val = openpic_read_IPI(addr);
-        openpic_write(addr, (val & ~mask) | (field & mask));
-}
-
-static inline void openpic_clearfield_IPI(volatile u_int *addr, u_int mask)
-{
-        openpic_writefield_IPI(addr, mask, 0);
-}
-
-static inline void openpic_setfield_IPI(volatile u_int *addr, u_int mask)
-{
-        openpic_writefield_IPI(addr, mask, mask);
-}
-
-static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int field)
-{
-        openpic_setfield_IPI(addr, OPENPIC_MASK);
-
-        /* wait until it's not in use */
-        /* BenH: Is this code really enough ? I would rather check the result
-         *       and eventually retry ...
-         */
-        while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY);
-
-        openpic_writefield_IPI(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
-}
-#endif /* CONFIG_SMP */
-
-#if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PMAC_PBOOK)
-static void openpic_reset(void)
-{
-	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
-			 OPENPIC_CONFIG_RESET);
-	while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
-				 OPENPIC_CONFIG_RESET))
-		mb();
-}
-#endif
-
-#ifdef CONFIG_EPIC_SERIAL_MODE
-static void openpic_enable_sie(void)
-{
-	openpic_setfield(&OpenPIC->Global.Global_Configuration1,
-			 OPENPIC_EICR_SIE);
-}
-
-static void openpic_eicr_set_clk(u_int clkval)
-{
-	openpic_writefield(&OpenPIC->Global.Global_Configuration1,
-			 OPENPIC_EICR_S_CLK_MASK, (clkval << 28));
-}
-#endif
-
-void openpic_set_sources(int first_irq, int num_irqs, void *first_ISR)
-{
-	volatile OpenPIC_Source *src = first_ISR;
-	int i, last_irq;
-
-	last_irq = first_irq + num_irqs;
-	if (last_irq > NumSources)
-		NumSources = last_irq;
-	if (src == 0)
-		src = &((struct OpenPIC *)OpenPIC_Addr)->Source[first_irq];
-	for (i = first_irq; i < last_irq; ++i, ++src)
-		ISR[i] = src;
-}
-
-void __init openpic_init(int linux_irq_offset)
-{
-	u_int t, i;
-	u_int timerfreq;
-	const char *version;
-
-	if (!OpenPIC_Addr) {
-		printk("No OpenPIC found !\n");
-		return;
-	}
-	OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
-
-#ifdef CONFIG_EPIC_SERIAL_MODE
-	/* Have to start from ground zero.
-	*/
-	openpic_reset();
-#endif
-
-	if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122);
-
-	t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
-	switch (t & OPENPIC_FEATURE_VERSION_MASK) {
-	case 1:
-		version = "1.0";
-		break;
-	case 2:
-		version = "1.2";
-		break;
-	case 3:
-		version = "1.3";
-		break;
-	default:
-		version = "?";
-		break;
-	}
-	NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
-			 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
-	if (NumSources == 0)
-		openpic_set_sources(0,
-				    ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
-				     OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1,
-				    NULL);
-	printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n",
-	       version, NumProcessors, NumSources, OpenPIC);
-	timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
-	if (timerfreq)
-		printk("OpenPIC timer frequency is %d.%06d MHz\n",
-		       timerfreq / 1000000, timerfreq % 1000000);
-
-	open_pic_irq_offset = linux_irq_offset;
-
-	/* Initialize timer interrupts */
-	if ( ppc_md.progress ) ppc_md.progress("openpic: timer",0x3ba);
-	for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
-		/* Disabled, Priority 0 */
-		openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+linux_irq_offset);
-		/* No processor */
-		openpic_maptimer(i, 0);
-	}
-
-#ifdef CONFIG_SMP
-	/* Initialize IPI interrupts */
-	if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb);
-	for (i = 0; i < OPENPIC_NUM_IPI; i++) {
-		/* Disabled, Priority 10..13 */
-		openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+linux_irq_offset);
-		/* IPIs are per-CPU */
-		irq_desc[OPENPIC_VEC_IPI+i+linux_irq_offset].status |=
-			IRQ_PER_CPU;
-		irq_desc[OPENPIC_VEC_IPI+i+linux_irq_offset].handler =
-			&open_pic_ipi;
-	}
-#endif
-
-	/* Initialize external interrupts */
-	if (ppc_md.progress) ppc_md.progress("openpic: external",0x3bc);
-
-	openpic_set_priority(0xf);
-
-	/* Init all external sources, including possibly the cascade. */
-	for (i = 0; i < NumSources; i++) {
-		int sense;
-
-		if (ISR[i] == 0)
-			continue;
-
-		/* the bootloader may have left it enabled (bad !) */
-		openpic_disable_irq(i+linux_irq_offset);
-
-		/*
-		 * We find the value from either the InitSenses table
-		 * or assume a negative polarity level interrupt.
-		 */
-		sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
-
-		if ((sense & IRQ_SENSE_MASK) == 1)
-			irq_desc[i+linux_irq_offset].status = IRQ_LEVEL;
-
-		/* Enabled, Priority 8 */
-		openpic_initirq(i, 8, i + linux_irq_offset,
-				(sense & IRQ_POLARITY_MASK),
-				(sense & IRQ_SENSE_MASK));
-		/* Processor 0 */
-		openpic_mapirq(i, 1<<0, 0);
-	}
-
-	/* Init descriptors */
-	for (i = linux_irq_offset; i < NumSources + linux_irq_offset; i++)
-		irq_desc[i].handler = &open_pic;
-
-	/* Initialize the spurious interrupt */
-	if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd);
-	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+linux_irq_offset);
-
-	/* Initialize the cascade */
-	if (linux_irq_offset) {
-		if (request_irq(linux_irq_offset, no_action, SA_INTERRUPT,
-				"82c59 cascade", NULL))
-			printk("Unable to get OpenPIC IRQ 0 for cascade\n");
-	}
- 	openpic_disable_8259_pass_through();
-#ifdef CONFIG_EPIC_SERIAL_MODE
-	openpic_eicr_set_clk(7);	/* Slowest value until we know better */
-	openpic_enable_sie();
-#endif
-	openpic_set_priority(0);
-
-	if (ppc_md.progress) ppc_md.progress("openpic: exit",0x222);
-}
-
-#ifdef notused
-static void openpic_enable_8259_pass_through(void)
-{
-	openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
-			   OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
-}
-#endif /* notused */
-
-static void openpic_disable_8259_pass_through(void)
-{
-	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
-			 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
-}
-
-/*
- *  Find out the current interrupt
- */
-u_int openpic_irq(void)
-{
-	u_int vec;
-	DECL_THIS_CPU;
-
-	CHECK_THIS_CPU;
-	vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
-				OPENPIC_VECTOR_MASK);
-	return vec;
-}
-
-void openpic_eoi(void)
-{
-	DECL_THIS_CPU;
-
-	CHECK_THIS_CPU;
-	openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
-	/* Handle PCI write posting */
-	(void)openpic_read(&OpenPIC->THIS_CPU.EOI);
-}
-
-#ifdef notused
-static u_int openpic_get_priority(void)
-{
-	DECL_THIS_CPU;
-
-	CHECK_THIS_CPU;
-	return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
-				 OPENPIC_CURRENT_TASK_PRIORITY_MASK);
-}
-#endif /* notused */
-
-static void openpic_set_priority(u_int pri)
-{
-	DECL_THIS_CPU;
-
-	CHECK_THIS_CPU;
-	check_arg_pri(pri);
-	openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
-			   OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
-}
-
-/*
- *  Get/set the spurious vector
- */
-#ifdef notused
-static u_int openpic_get_spurious(void)
-{
-	return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
-				 OPENPIC_VECTOR_MASK);
-}
-#endif /* notused */
-
-static void openpic_set_spurious(u_int vec)
-{
-	check_arg_vec(vec);
-	openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
-			   vec);
-}
-
-#ifdef CONFIG_SMP
-/*
- * Convert a cpu mask from logical to physical cpu numbers.
- */
-static inline u32 physmask(u32 cpumask)
-{
-	int i;
-	u32 mask = 0;
-
-	for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1)
-		if (cpu_online(i))
-			mask |= (cpumask & 1) << smp_hw_index[i];
-	return mask;
-}
-#else
-#define physmask(cpumask)	(cpumask)
-#endif
-
-void openpic_reset_processor_phys(u_int mask)
-{
-	openpic_write(&OpenPIC->Global.Processor_Initialization, mask);
-}
-
-#if defined(CONFIG_SMP) || defined(CONFIG_PMAC_PBOOK)
-static spinlock_t openpic_setup_lock = SPIN_LOCK_UNLOCKED;
-#endif
-
-#ifdef CONFIG_SMP
-/*
- *  Initialize an interprocessor interrupt (and disable it)
- *
- *  ipi: OpenPIC interprocessor interrupt number
- *  pri: interrupt source priority
- *  vec: the vector it will produce
- */
-static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec)
-{
-	check_arg_ipi(ipi);
-	check_arg_pri(pri);
-	check_arg_vec(vec);
-	openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi),
-				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
-				(pri << OPENPIC_PRIORITY_SHIFT) | vec);
-}
-
-/*
- *  Send an IPI to one or more CPUs
- *  
- *  Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
- *  and not a system-wide interrupt number
- */
-void openpic_cause_IPI(u_int ipi, u_int cpumask)
-{
-	DECL_THIS_CPU;
-
-	CHECK_THIS_CPU;
-	check_arg_ipi(ipi);
-	openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
-		      physmask(cpumask));
-}
-
-void openpic_request_IPIs(void)
-{
-	int i;
-	
-	/*
-	 * Make sure this matches what is defined in smp.c for 
-	 * smp_message_{pass|recv}() or what shows up in 
-	 * /proc/interrupts will be wrong!!! --Troy */
-	
-	if (OpenPIC == NULL)
-		return;
-
-	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset,
-		    openpic_ipi_action, 0, "IPI0 (call function)", 0);
-	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+1,
-		    openpic_ipi_action, 0, "IPI1 (reschedule)", 0);
-	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+2,
-		    openpic_ipi_action, 0, "IPI2 (invalidate tlb)", 0);
-	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+3,
-		    openpic_ipi_action, 0, "IPI3 (xmon break)", 0);
-
-	for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
-		openpic_enable_ipi(OPENPIC_VEC_IPI+open_pic_irq_offset+i);
-}
-
-/*
- * Do per-cpu setup for SMP systems.
- *
- * Get IPI's working and start taking interrupts.
- *   -- Cort
- */
-
-void __devinit do_openpic_setup_cpu(void)
-{
- 	int i;
-	u32 msk = 1 << smp_hw_index[smp_processor_id()];
-
-	spin_lock(&openpic_setup_lock);
-
-#ifdef CONFIG_IRQ_ALL_CPUS
- 	/* let the openpic know we want intrs. default affinity
- 	 * is 0xffffffff until changed via /proc
- 	 * That's how it's done on x86. If we want it differently, then
- 	 * we should make sure we also change the default values of irq_affinity
- 	 * in irq.c.
- 	 */
- 	for (i = 0; i < NumSources; i++)
-		openpic_mapirq(i, msk, ~0U);
-#endif /* CONFIG_IRQ_ALL_CPUS */
- 	openpic_set_priority(0);
-
-	spin_unlock(&openpic_setup_lock);
-}
-#endif /* CONFIG_SMP */
-
-/*
- *  Initialize a timer interrupt (and disable it)
- *
- *  timer: OpenPIC timer number
- *  pri: interrupt source priority
- *  vec: the vector it will produce
- */
-static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec)
-{
-	check_arg_timer(timer);
-	check_arg_pri(pri);
-	check_arg_vec(vec);
-	openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
-				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
-				(pri << OPENPIC_PRIORITY_SHIFT) | vec);
-}
-
-/*
- *  Map a timer interrupt to one or more CPUs
- */
-static void __init openpic_maptimer(u_int timer, u_int cpumask)
-{
-	check_arg_timer(timer);
-	openpic_write(&OpenPIC->Global.Timer[timer].Destination,
-		      physmask(cpumask));
-}
-
-/*
- * Initalize the interrupt source which will generate an NMI (and disable it).
- *
- * irq: The logical IRQ which generates an NMI.
- */
-void __init
-openpic_init_nmi_irq(u_int irq)
-{
-	int sense;
-
-	/* If this wasn't given, assume a level, negative polarity interrupt. */
-	sense = (irq < OpenPIC_NumInitSenses) ? OpenPIC_InitSenses[irq] :
-		(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE);
-
-	openpic_safe_writefield(&ISR[irq]->Vector_Priority,
-				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
-				OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
-				(9 << OPENPIC_PRIORITY_SHIFT) |
-				(irq + open_pic_irq_offset) |
-				((sense & IRQ_POLARITY_MASK) ?
-				 OPENPIC_POLARITY_POSITIVE :
-				 OPENPIC_POLARITY_NEGATIVE) |
-				((sense & IRQ_SENSE_MASK) ? OPENPIC_SENSE_LEVEL
-				 : OPENPIC_SENSE_EDGE));
-}
-
-/*
- *
- * All functions below take an offset'ed irq argument
- *
- */
-
-
-/*
- *  Enable/disable an external interrupt source
- *
- *  Externally called, irq is an offseted system-wide interrupt number
- */
-static void openpic_enable_irq(u_int irq)
-{
-	volatile u_int *vpp;
-
-	check_arg_irq(irq);
-	vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority;
-	openpic_clearfield(vpp, OPENPIC_MASK);
-	/* make sure mask gets to controller before we return to user */
-	do {
-		mb(); /* sync is probably useless here */
-	} while (openpic_readfield(vpp, OPENPIC_MASK));
-}
-
-static void openpic_disable_irq(u_int irq)
-{
-	volatile u_int *vpp;
-	u32 vp;
-	
-	check_arg_irq(irq);
-	vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority;
-	openpic_setfield(vpp, OPENPIC_MASK);
-	/* make sure mask gets to controller before we return to user */
-	do {
-		mb();  /* sync is probably useless here */
-		vp = openpic_readfield(vpp, OPENPIC_MASK | OPENPIC_ACTIVITY);
-	} while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
-}
-
-#ifdef CONFIG_SMP
-/*
- *  Enable/disable an IPI interrupt source
- *  
- *  Externally called, irq is an offseted system-wide interrupt number
- */
-void openpic_enable_ipi(u_int irq)
-{
-	irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
-	check_arg_ipi(irq);
-	openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
-
-}
-
-void openpic_disable_ipi(u_int irq)
-{
-	irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
-	check_arg_ipi(irq);
-	openpic_setfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
-}
-#endif
-
-/*
- *  Initialize an interrupt source (and disable it!)
- *
- *  irq: OpenPIC interrupt number
- *  pri: interrupt source priority
- *  vec: the vector it will produce
- *  pol: polarity (1 for positive, 0 for negative)
- *  sense: 1 for level, 0 for edge
- */
-static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
-{
-	openpic_safe_writefield(&ISR[irq]->Vector_Priority,
-				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
-				OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
-				(pri << OPENPIC_PRIORITY_SHIFT) | vec |
-				(pol ? OPENPIC_POLARITY_POSITIVE :
-			    		OPENPIC_POLARITY_NEGATIVE) |
-				(sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
-}
-
-/*
- *  Map an interrupt source to one or more CPUs
- */
-static void openpic_mapirq(u_int irq, u_int physmask, u_int keepmask)
-{
-	if (ISR[irq] == 0)
-		return;
-	if (keepmask != 0)
-		physmask |= openpic_read(&ISR[irq]->Destination) & keepmask;
-	openpic_write(&ISR[irq]->Destination, physmask);
-}
-
-#ifdef notused
-/*
- *  Set the sense for an interrupt source (and disable it!)
- *
- *  sense: 1 for level, 0 for edge
- */
-static void openpic_set_sense(u_int irq, int sense)
-{
-	if (ISR[irq] != 0)
-		openpic_safe_writefield(&ISR[irq]->Vector_Priority,
-					OPENPIC_SENSE_LEVEL,
-					(sense ? OPENPIC_SENSE_LEVEL : 0));
-}
-#endif /* notused */
-
-/* No spinlocks, should not be necessary with the OpenPIC
- * (1 register = 1 interrupt and we have the desc lock).
- */
-static void openpic_ack_irq(unsigned int irq_nr)
-{
-	openpic_disable_irq(irq_nr);
-	openpic_eoi();
-}
-
-static void openpic_end_irq(unsigned int irq_nr)
-{
-	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
-	    && irq_desc[irq_nr].action)
-		openpic_enable_irq(irq_nr);
-}
-
-static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
-{
-	openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask), 0);
-}
-
-#ifdef CONFIG_SMP
-static void openpic_ack_ipi(unsigned int irq_nr)
-{
-	openpic_eoi();
-}
-
-static void openpic_end_ipi(unsigned int irq_nr)
-{
-}
-
-static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset, regs);
-}
-
-#endif /* CONFIG_SMP */
-
-int
-openpic_get_irq(struct pt_regs *regs)
-{
-	int irq = openpic_irq();
-
-	/*
-	 * This needs to be cleaned up.  We don't necessarily have
-	 * an i8259 cascaded or even a cascade.
-	 */
-	if (open_pic_irq_offset && irq == open_pic_irq_offset) {
-		/* Get the IRQ from the cascade. */
-		irq = i8259_irq(regs);
-		openpic_eoi();
-	} else if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
-		irq = -1;
-	return irq;
-}
-
-#ifdef CONFIG_SMP
-void
-smp_openpic_message_pass(int target, int msg, unsigned long data, int wait)
-{
-	/* make sure we're sending something that translates to an IPI */
-	if (msg > 0x3) {
-		printk("SMP %d: smp_message_pass: unknown msg %d\n",
-		       smp_processor_id(), msg);
-		return;
-	}
-	switch (target) {
-	case MSG_ALL:
-		openpic_cause_IPI(msg, 0xffffffff);
-		break;
-	case MSG_ALL_BUT_SELF:
-		openpic_cause_IPI(msg,
-				  0xffffffff & ~(1 << smp_processor_id()));
-		break;
-	default:
-		openpic_cause_IPI(msg, 1<<target);
-		break;
-	}
-}
-#endif /* CONFIG_SMP */
-
-#ifdef CONFIG_PMAC_PBOOK
-static u32 save_ipi_vp[OPENPIC_NUM_IPI];
-static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES];
-static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES];
-static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS];
-
-void __pmac
-openpic_sleep_save_intrs(void)
-{
-	int	i;
-	unsigned long flags;
-	
-	spin_lock_irqsave(&openpic_setup_lock, flags);
-
-	for (i=0; i<NumProcessors; i++) {
-		save_cpu_task_pri[i] = openpic_read(&OpenPIC->Processor[i].Current_Task_Priority);
-		openpic_writefield(&OpenPIC->Processor[i].Current_Task_Priority,
-				   OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf);
-	}
-
-	for (i=0; i<OPENPIC_NUM_IPI; i++)
-		save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i));
-	for (i=0; i<NumSources; i++) {
-		if (ISR[i] == 0)
-			continue;
-		save_irq_src_vp[i] = openpic_read(&ISR[i]->Vector_Priority)
-			& ~OPENPIC_ACTIVITY;
-		save_irq_src_dest[i] = openpic_read(&ISR[i]->Destination);
-	}
-	spin_unlock_irqrestore(&openpic_setup_lock, flags);
-}
-
-void __pmac
-openpic_sleep_restore_intrs(void)
-{
-	int		i;
-	unsigned long	flags;
-
-	spin_lock_irqsave(&openpic_setup_lock, flags);
-	
-	openpic_reset();
-
-	for (i=0; i<OPENPIC_NUM_IPI; i++)
-		openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i),
-			      save_ipi_vp[i]);
-	for (i=0; i<NumSources; i++) {
-		if (ISR[i] == 0)
-			continue;
-		openpic_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]);
-		openpic_write(&ISR[i]->Destination, save_irq_src_dest[i]);
-	}
-	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+open_pic_irq_offset);
-	openpic_disable_8259_pass_through();
-	for (i=0; i<NumProcessors; i++)
-		openpic_write(&OpenPIC->Processor[i].Current_Task_Priority,
-			      save_cpu_task_pri[i]);
-
-	spin_unlock_irqrestore(&openpic_setup_lock, flags);
-}
-#endif /* CONFIG_PMAC_PBOOK */
diff -Nru a/arch/ppc/kernel/open_pic_defs.h b/arch/ppc/kernel/open_pic_defs.h
--- a/arch/ppc/kernel/open_pic_defs.h	Sun Nov 10 19:28:40 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,292 +0,0 @@
-/*
- *  arch/ppc/kernel/open_pic_defs.h -- OpenPIC definitions
- *
- *  Copyright (C) 1997 Geert Uytterhoeven
- *
- *  This file is based on the following documentation:
- *
- *	The Open Programmable Interrupt Controller (PIC)
- *	Register Interface Specification Revision 1.2
- *
- *	Issue Date: October 1995
- *
- *	Issued jointly by Advanced Micro Devices and Cyrix Corporation
- *
- *	AMD is a registered trademark of Advanced Micro Devices, Inc.
- *	Copyright (C) 1995, Advanced Micro Devices, Inc. and Cyrix, Inc.
- *	All Rights Reserved.
- *
- *  To receive a copy of this documentation, send an email to openpic@amd.com.
- *
- *  This file is subject to the terms and conditions of the GNU General Public
- *  License.  See the file COPYING in the main directory of this archive
- *  for more details.
- */
-
-#ifndef _LINUX_OPENPIC_H
-#define _LINUX_OPENPIC_H
-
-#ifdef __KERNEL__
-
-    /*
-     *  OpenPIC supports up to 2048 interrupt sources and up to 32 processors
-     */
-
-#define OPENPIC_MAX_SOURCES	2048
-#define OPENPIC_MAX_PROCESSORS	32
-#define OPENPIC_MAX_ISU		16
-
-#define OPENPIC_NUM_TIMERS	4
-#define OPENPIC_NUM_IPI		4
-#define OPENPIC_NUM_PRI		16
-#define OPENPIC_NUM_VECTORS	256
-
-
-
-    /*
-     *  OpenPIC Registers are 32 bits and aligned on 128 bit boundaries
-     */
-
-typedef struct _OpenPIC_Reg {
-    u_int Reg;					/* Little endian! */
-    char Pad[0xc];
-} OpenPIC_Reg;
-
-
-    /*
-     *  Per Processor Registers
-     */
-
-typedef struct _OpenPIC_Processor {
-    /*
-     *  Private Shadow Registers (for SLiC backwards compatibility)
-     */
-    u_int IPI0_Dispatch_Shadow;			/* Write Only */
-    char Pad1[0x4];
-    u_int IPI0_Vector_Priority_Shadow;		/* Read/Write */
-    char Pad2[0x34];
-    /*
-     *  Interprocessor Interrupt Command Ports
-     */
-    OpenPIC_Reg _IPI_Dispatch[OPENPIC_NUM_IPI];	/* Write Only */
-    /*
-     *  Current Task Priority Register
-     */
-    OpenPIC_Reg _Current_Task_Priority;		/* Read/Write */
-    char Pad3[0x10];
-    /*
-     *  Interrupt Acknowledge Register
-     */
-    OpenPIC_Reg _Interrupt_Acknowledge;		/* Read Only */
-    /*
-     *  End of Interrupt (EOI) Register
-     */
-    OpenPIC_Reg _EOI;				/* Read/Write */
-    char Pad5[0xf40];
-} OpenPIC_Processor;
-
-
-    /*
-     *  Timer Registers
-     */
-
-typedef struct _OpenPIC_Timer {
-    OpenPIC_Reg _Current_Count;			/* Read Only */
-    OpenPIC_Reg _Base_Count;			/* Read/Write */
-    OpenPIC_Reg _Vector_Priority;		/* Read/Write */
-    OpenPIC_Reg _Destination;			/* Read/Write */
-} OpenPIC_Timer;
-
-
-    /*
-     *  Global Registers
-     */
-
-typedef struct _OpenPIC_Global {
-    /*
-     *  Feature Reporting Registers
-     */
-    OpenPIC_Reg _Feature_Reporting0;		/* Read Only */
-    OpenPIC_Reg _Feature_Reporting1;		/* Future Expansion */
-    /*
-     *  Global Configuration Registers
-     */
-    OpenPIC_Reg _Global_Configuration0;		/* Read/Write */
-    OpenPIC_Reg _Global_Configuration1;		/* Future Expansion */
-    /*
-     *  Vendor Specific Registers
-     */
-    OpenPIC_Reg _Vendor_Specific[4];
-    /*
-     *  Vendor Identification Register
-     */
-    OpenPIC_Reg _Vendor_Identification;		/* Read Only */
-    /*
-     *  Processor Initialization Register
-     */
-    OpenPIC_Reg _Processor_Initialization;	/* Read/Write */
-    /*
-     *  IPI Vector/Priority Registers
-     */
-    OpenPIC_Reg _IPI_Vector_Priority[OPENPIC_NUM_IPI];	/* Read/Write */
-    /*
-     *  Spurious Vector Register
-     */
-    OpenPIC_Reg _Spurious_Vector;		/* Read/Write */
-    /*
-     *  Global Timer Registers
-     */
-    OpenPIC_Reg _Timer_Frequency;		/* Read/Write */
-    OpenPIC_Timer Timer[OPENPIC_NUM_TIMERS];
-    char Pad1[0xee00];
-} OpenPIC_Global;
-
-
-    /*
-     *  Interrupt Source Registers
-     */
-
-typedef struct _OpenPIC_Source {
-    OpenPIC_Reg _Vector_Priority;		/* Read/Write */
-    OpenPIC_Reg _Destination;			/* Read/Write */
-} OpenPIC_Source, *OpenPIC_SourcePtr;
-
-
-    /*
-     *  OpenPIC Register Map
-     */
-
-struct OpenPIC {
-    char Pad1[0x1000];
-    /*
-     *  Global Registers
-     */
-    OpenPIC_Global Global;
-    /*
-     *  Interrupt Source Configuration Registers
-     */
-    OpenPIC_Source Source[OPENPIC_MAX_SOURCES];
-    /*
-     *  Per Processor Registers
-     */
-    OpenPIC_Processor Processor[OPENPIC_MAX_PROCESSORS];
-};
-
-extern volatile struct OpenPIC *OpenPIC;
-
-
-    /*
-     *  Current Task Priority Register
-     */
-
-#define OPENPIC_CURRENT_TASK_PRIORITY_MASK	0x0000000f
-
-    /*
-     *  Who Am I Register
-     */
-
-#define OPENPIC_WHO_AM_I_ID_MASK		0x0000001f
-
-    /*
-     *  Feature Reporting Register 0
-     */
-
-#define OPENPIC_FEATURE_LAST_SOURCE_MASK	0x07ff0000
-#define OPENPIC_FEATURE_LAST_SOURCE_SHIFT	16
-#define OPENPIC_FEATURE_LAST_PROCESSOR_MASK	0x00001f00
-#define OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT	8
-#define OPENPIC_FEATURE_VERSION_MASK		0x000000ff
-
-    /*
-     *  Global Configuration Register 0
-     */
-
-#define OPENPIC_CONFIG_RESET			0x80000000
-#define OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE	0x20000000
-#define OPENPIC_CONFIG_BASE_MASK		0x000fffff
-
-    /*
-     *  Global Configuration Register 1
-     *  This is the EICR on EPICs.
-     */
-
-#define OPENPIC_EICR_S_CLK_MASK			0x70000000
-#define OPENPIC_EICR_SIE			0x08000000
-
-    /*
-     *  Vendor Identification Register
-     */
-
-#define OPENPIC_VENDOR_ID_STEPPING_MASK		0x00ff0000
-#define OPENPIC_VENDOR_ID_STEPPING_SHIFT	16
-#define OPENPIC_VENDOR_ID_DEVICE_ID_MASK	0x0000ff00
-#define OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT	8
-#define OPENPIC_VENDOR_ID_VENDOR_ID_MASK	0x000000ff
-
-    /*
-     *  Vector/Priority Registers
-     */
-
-#define OPENPIC_MASK				0x80000000
-#define OPENPIC_ACTIVITY			0x40000000	/* Read Only */
-#define OPENPIC_PRIORITY_MASK			0x000f0000
-#define OPENPIC_PRIORITY_SHIFT			16
-#define OPENPIC_VECTOR_MASK			0x000000ff
-
-
-    /*
-     *  Interrupt Source Registers
-     */
-
-#define OPENPIC_POLARITY_POSITIVE		0x00800000
-#define OPENPIC_POLARITY_NEGATIVE		0x00000000
-#define OPENPIC_POLARITY_MASK			0x00800000
-#define OPENPIC_SENSE_LEVEL			0x00400000
-#define OPENPIC_SENSE_EDGE			0x00000000
-#define OPENPIC_SENSE_MASK			0x00400000
-
-
-    /*
-     *  Timer Registers
-     */
-
-#define OPENPIC_COUNT_MASK			0x7fffffff
-#define OPENPIC_TIMER_TOGGLE			0x80000000
-#define OPENPIC_TIMER_COUNT_INHIBIT		0x80000000
-
-
-    /*
-     *  Aliases to make life simpler
-     */
-
-/* Per Processor Registers */
-#define IPI_Dispatch(i)			_IPI_Dispatch[i].Reg
-#define Current_Task_Priority		_Current_Task_Priority.Reg
-#define Interrupt_Acknowledge		_Interrupt_Acknowledge.Reg
-#define EOI				_EOI.Reg
-
-/* Global Registers */
-#define Feature_Reporting0		_Feature_Reporting0.Reg
-#define Feature_Reporting1		_Feature_Reporting1.Reg
-#define Global_Configuration0		_Global_Configuration0.Reg
-#define Global_Configuration1		_Global_Configuration1.Reg
-#define Vendor_Specific(i)		_Vendor_Specific[i].Reg
-#define Vendor_Identification		_Vendor_Identification.Reg
-#define Processor_Initialization	_Processor_Initialization.Reg
-#define IPI_Vector_Priority(i)		_IPI_Vector_Priority[i].Reg
-#define Spurious_Vector			_Spurious_Vector.Reg
-#define Timer_Frequency			_Timer_Frequency.Reg
-
-/* Timer Registers */
-#define Current_Count			_Current_Count.Reg
-#define Base_Count			_Base_Count.Reg
-#define Vector_Priority			_Vector_Priority.Reg
-#define Destination			_Destination.Reg
-
-/* Interrupt Source Registers */
-#define Vector_Priority			_Vector_Priority.Reg
-#define Destination			_Destination.Reg
-
-#endif /* __KERNEL__ */
-
-#endif /* _LINUX_OPENPIC_H */
diff -Nru a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
--- a/arch/ppc/kernel/pci.c	Sun Nov 10 19:28:39 2002
+++ b/arch/ppc/kernel/pci.c	Sun Nov 10 19:28:39 2002
@@ -1107,7 +1107,7 @@
 	return PCI_SLOT(dev->devfn);
 }
 
-void __init
+void __devinit
 pcibios_fixup_pbus_ranges(struct pci_bus * bus, struct pbus_set_ranges_data * ranges)
 {
 }
diff -Nru a/arch/ppc/kernel/pci_auto.c b/arch/ppc/kernel/pci_auto.c
--- a/arch/ppc/kernel/pci_auto.c	Sun Nov 10 19:28:40 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,519 +0,0 @@
-/*
- * arch/ppc/kernel/pci_auto.c
- * 
- * PCI autoconfiguration library
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * Copyright 2001 MontaVista Software 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.
- */
-
-/*
- * The CardBus support is very preliminary.  Preallocating space is
- * the way to go but will require some change in card services to
- * make it useful.  Eventually this will ensure that we can put
- * multiple CB bridges behind multiple P2P bridges.  For now, at
- * least it ensures that we place the CB bridge BAR and assigned
- * initial bus numbers.  I definitely need to do something about
- * the lack of 16-bit I/O support. -MDP
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-
-#include <asm/pci-bridge.h>
-
-#define	PCIAUTO_IDE_MODE_MASK		0x05
-
-#undef DEBUG
-
-#ifdef DEBUG
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif /* DEBUG */
-
-static int pciauto_upper_iospc;
-static int pciauto_upper_memspc;
-
-void __init pciauto_setup_bars(struct pci_controller *hose,
-		int current_bus,
-		int pci_devfn,
-		int bar_limit)
-{
-	int bar_response, bar_size, bar_value;
-	int bar, addr_mask;
-	int * upper_limit;
-	int found_mem64 = 0;
-
-	DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n",
-		current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) );
-
-	for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) {
-		/* Tickle the BAR and get the response */
-		early_write_config_dword(hose,
-				current_bus,
-				pci_devfn,
-				bar,
-				0xffffffff);
-		early_read_config_dword(hose,
-				current_bus,
-				pci_devfn,
-				bar,
-				&bar_response);
-
-		/* If BAR is not implemented go to the next BAR */
-		if (!bar_response)
-			continue;
-
-		/* Check the BAR type and set our address mask */
-		if (bar_response & PCI_BASE_ADDRESS_SPACE) {
-			addr_mask = PCI_BASE_ADDRESS_IO_MASK;
-			upper_limit = &pciauto_upper_iospc;
-			DBG("PCI Autoconfig: BAR 0x%x, I/O, ", bar);
-		} else {
-			if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
-			PCI_BASE_ADDRESS_MEM_TYPE_64)
-				found_mem64 = 1;
-
-			addr_mask = PCI_BASE_ADDRESS_MEM_MASK;		
-			upper_limit = &pciauto_upper_memspc;
-			DBG("PCI Autoconfig: BAR 0x%x, Mem ", bar);
-		}
-
-		/* Calculate requested size */
-		bar_size = ~(bar_response & addr_mask) + 1;
-
-		/* Allocate a base address */
-		bar_value = (*upper_limit - bar_size) & ~(bar_size - 1);
-
-		/* Write it out and update our limit */
-		early_write_config_dword(hose,
-				current_bus,
-				pci_devfn,
-				bar,
-				bar_value);
-
-		*upper_limit = bar_value;
-
-		/*
-		 * If we are a 64-bit decoder then increment to the
-		 * upper 32 bits of the bar and force it to locate
-		 * in the lower 4GB of memory.
-		 */ 
-		if (found_mem64) {
-			bar += 4;
-			early_write_config_dword(hose,
-					current_bus,
-					pci_devfn,
-					bar,
-					0x00000000);
-			found_mem64 = 0;
-		}
-
-		DBG("size=0x%x, address=0x%x\n",
-			bar_size, bar_value);
-	}
-
-}
-
-void __init pciauto_prescan_setup_bridge(struct pci_controller *hose,
-		int current_bus,
-		int pci_devfn,
-		int sub_bus,
-		int *iosave,
-		int *memsave)
-{
-	/* Configure bus number registers */
-	early_write_config_byte(hose,
-			current_bus,
-			pci_devfn,
-			PCI_PRIMARY_BUS,
-			current_bus);
-	early_write_config_byte(hose,
-			current_bus,
-			pci_devfn,
-			PCI_SECONDARY_BUS,
-			sub_bus + 1);
-	early_write_config_byte(hose,
-			current_bus,
-			pci_devfn,
-			PCI_SUBORDINATE_BUS,
-			0xff);
-
-	/* Round memory allocator to 1MB boundary */
-	pciauto_upper_memspc &= ~(0x100000 - 1);
-	*memsave = pciauto_upper_memspc;
-
-	/* Round I/O allocator to 4KB boundary */
-	pciauto_upper_iospc &= ~(0x1000 - 1);
-	*iosave = pciauto_upper_iospc;
-
-	/* Set up memory and I/O filter limits, assume 32-bit I/O space */
-	early_write_config_word(hose,
-			current_bus,
-			pci_devfn,
-			PCI_MEMORY_LIMIT,
-			((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
-	early_write_config_byte(hose,
-			current_bus,
-			pci_devfn,
-			PCI_IO_LIMIT,
-			((pciauto_upper_iospc - 1) & 0x0000f000) >> 8);
-	early_write_config_word(hose,
-			current_bus,
-			pci_devfn,
-			PCI_IO_LIMIT_UPPER16,
-			((pciauto_upper_iospc - 1) & 0xffff0000) >> 16);
-
-	/* Zero upper 32 bits of prefetchable base/limit */
-	early_write_config_dword(hose,
-			current_bus,
-			pci_devfn,
-			PCI_PREF_BASE_UPPER32,
-			0);
-	early_write_config_dword(hose,
-			current_bus,
-			pci_devfn,
-			PCI_PREF_LIMIT_UPPER32,
-			0);
-}
-
-void __init pciauto_postscan_setup_bridge(struct pci_controller *hose,
-		int current_bus,
-		int pci_devfn,
-		int sub_bus,
-		int *iosave,
-		int *memsave)
-{
-	int cmdstat;
-
-	/* Configure bus number registers */
-	early_write_config_byte(hose,
-			current_bus,
-			pci_devfn,
-			PCI_SUBORDINATE_BUS,
-			sub_bus);
-
-	/*
-	 * Round memory allocator to 1MB boundary.
-	 * If no space used, allocate minimum.
-	 */
-	pciauto_upper_memspc &= ~(0x100000 - 1);
-	if (*memsave == pciauto_upper_memspc)
-		pciauto_upper_memspc -= 0x00100000;
-
-	early_write_config_word(hose,
-			current_bus,
-			pci_devfn,
-			PCI_MEMORY_BASE,
-			pciauto_upper_memspc >> 16);
-
-	/* Allocate 1MB for pre-fretch */
-	early_write_config_word(hose,
-			current_bus,
-			pci_devfn,
-			PCI_PREF_MEMORY_LIMIT,
-			((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
-
-	pciauto_upper_memspc -= 0x100000;
-
-	early_write_config_word(hose,
-			current_bus,
-			pci_devfn,
-			PCI_PREF_MEMORY_BASE,
-			pciauto_upper_memspc >> 16);
-
-	/* Round I/O allocator to 4KB boundary */
-	pciauto_upper_iospc &= ~(0x1000 - 1);
-	if (*iosave == pciauto_upper_iospc)
-		pciauto_upper_iospc -= 0x1000;
-
-	early_write_config_byte(hose,
-			current_bus,
-			pci_devfn,
-			PCI_IO_BASE,
-			(pciauto_upper_iospc & 0x0000f000) >> 8);
-	early_write_config_word(hose,
-			current_bus,
-			pci_devfn,
-			PCI_IO_BASE_UPPER16,
-			pciauto_upper_iospc >> 16);
-	
-	/* Enable memory and I/O accesses, enable bus master */
-	early_read_config_dword(hose,
-			current_bus,
-			pci_devfn,
-			PCI_COMMAND,
-			&cmdstat);
-	early_write_config_dword(hose,
-			current_bus,
-			pci_devfn,
-			PCI_COMMAND,
-			cmdstat |
-			PCI_COMMAND_IO |
-			PCI_COMMAND_MEMORY |
-			PCI_COMMAND_MASTER);
-}
-
-void __init pciauto_prescan_setup_cardbus_bridge(struct pci_controller *hose,
-		int current_bus,
-		int pci_devfn,
-		int sub_bus,
-		int *iosave,
-		int *memsave)
-{
-	/* Configure bus number registers */
-	early_write_config_byte(hose,
-			current_bus,
-			pci_devfn,
-			PCI_PRIMARY_BUS,
-			current_bus);
-	early_write_config_byte(hose,
-			current_bus,
-			pci_devfn,
-			PCI_SECONDARY_BUS,
-			sub_bus + 1);
-	early_write_config_byte(hose,
-			current_bus,
-			pci_devfn,
-			PCI_SUBORDINATE_BUS,
-			0xff);
-
-	/* Round memory allocator to 4KB boundary */
-	pciauto_upper_memspc &= ~(0x1000 - 1);
-	*memsave = pciauto_upper_memspc;
-
-	/* Round I/O allocator to 4 byte boundary */
-	pciauto_upper_iospc &= ~(0x4 - 1);
-	*iosave = pciauto_upper_iospc;
-
-	/* Set up memory and I/O filter limits, assume 32-bit I/O space */
-	early_write_config_dword(hose,
-			current_bus,
-			pci_devfn,
-			0x20,
-			pciauto_upper_memspc - 1);
-	early_write_config_dword(hose,
-			current_bus,
-			pci_devfn,
-			0x30,
-			pciauto_upper_iospc - 1);
-}
-
-void __init pciauto_postscan_setup_cardbus_bridge(struct pci_controller *hose,
-		int current_bus,
-		int pci_devfn,
-		int sub_bus,
-		int *iosave,
-		int *memsave)
-{
-	int cmdstat;
-
-	/*
-	 * Configure subordinate bus number.  The PCI subsystem
-	 * bus scan will renumber buses (reserving three additional
-	 * for this PCI<->CardBus bridge for the case where a CardBus
-	 * adapter contains a P2P or CB2CB bridge.
-	 */
-	early_write_config_byte(hose,
-			current_bus,
-			pci_devfn,
-			PCI_SUBORDINATE_BUS,
-			sub_bus);
-
-	/*
-	 * Reserve an additional 4MB for mem space and 16KB for
-	 * I/O space.  This should cover any additional space
-	 * requirement of unusual CardBus devices with 
-	 * additional bridges that can consume more address space.
-	 * 
-	 * Although pcmcia-cs currently will reprogram bridge
-	 * windows, the goal is to add an option to leave them
-	 * alone and use the bridge window ranges as the regions
-	 * that are searched for free resources upon hot-insertion
-	 * of a device.  This will allow a PCI<->CardBus bridge
-	 * configured by this routine to happily live behind a
-	 * P2P bridge in a system.
-	 */
-	pciauto_upper_memspc -= 0x00400000;
-	pciauto_upper_iospc -= 0x00004000;
-
-	/* Round memory allocator to 4KB boundary */
-	pciauto_upper_memspc &= ~(0x1000 - 1);
-
-	early_write_config_dword(hose,
-			current_bus,
-			pci_devfn,
-			0x1c,
-			pciauto_upper_memspc);
-
-	/* Round I/O allocator to 4 byte boundary */
-	pciauto_upper_iospc &= ~(0x4 - 1);
-	early_write_config_dword(hose,
-			current_bus,
-			pci_devfn,
-			0x2c,
-			pciauto_upper_iospc);
-	
-	/* Enable memory and I/O accesses, enable bus master */
-	early_read_config_dword(hose,
-			current_bus,
-			pci_devfn,
-			PCI_COMMAND,
-			&cmdstat);
-	early_write_config_dword(hose,
-			current_bus,
-			pci_devfn,
-			PCI_COMMAND,
-			cmdstat |
-			PCI_COMMAND_IO |
-			PCI_COMMAND_MEMORY |
-			PCI_COMMAND_MASTER);
-}
-
-int __init pciauto_bus_scan(struct pci_controller *hose, int current_bus)
-{
-	int sub_bus, pci_devfn, pci_class, cmdstat, found_multi = 0;
-	unsigned short vid;
-	unsigned char header_type;
-
-	/*
-	 * Fetch our I/O and memory space upper boundaries used
-	 * to allocated base addresses on this hose.
-	 */
-	if (current_bus == hose->first_busno) {
-		pciauto_upper_iospc = hose->io_space.end + 1;
-		pciauto_upper_memspc = hose->mem_space.end + 1;
-	}
-
-	sub_bus = current_bus;
-
-	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
-		/* Skip our host bridge */
-		if ( (current_bus == hose->first_busno) && (pci_devfn == 0) )
-			continue;
-
-		if (PCI_FUNC(pci_devfn) && !found_multi)
-			continue;
-
-		/* If config space read fails from this device, move on */
-		if (early_read_config_byte(hose,
-				current_bus,
-				pci_devfn,
-				PCI_HEADER_TYPE,
-				&header_type))
-			continue;
-
-		if (!PCI_FUNC(pci_devfn))
-			found_multi = header_type & 0x80;
-
-		early_read_config_word(hose,
-				current_bus,
-				pci_devfn,
-				PCI_VENDOR_ID,
-				&vid);
-
-		if (vid != 0xffff) {
-			early_read_config_dword(hose,
-					current_bus,
-					pci_devfn,
-					PCI_CLASS_REVISION, &pci_class);
-			if ( (pci_class >> 16) == PCI_CLASS_BRIDGE_PCI ) {
-				int iosave, memsave;
-
-				DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn));
-				/* Allocate PCI I/O and/or memory space */
-				pciauto_setup_bars(hose,
-						current_bus,
-						pci_devfn,
-						PCI_BASE_ADDRESS_1);
-
-				pciauto_prescan_setup_bridge(hose,
-						current_bus,
-						pci_devfn,
-						sub_bus,
-						&iosave,
-						&memsave);
-				sub_bus = pciauto_bus_scan(hose, sub_bus+1);
-				pciauto_postscan_setup_bridge(hose,
-						current_bus,
-						pci_devfn,
-						sub_bus,
-						&iosave,
-						&memsave);
-			} else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) {
-				int iosave, memsave;
-
-				DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn));
-				/* Place CardBus Socket/ExCA registers */
-				pciauto_setup_bars(hose,
-						current_bus,
-						pci_devfn,
-						PCI_BASE_ADDRESS_0);
-
-				pciauto_prescan_setup_cardbus_bridge(hose,
-						current_bus,
-						pci_devfn,
-						sub_bus,
-						&iosave,
-						&memsave);
-				sub_bus = pciauto_bus_scan(hose, sub_bus+1);
-				pciauto_postscan_setup_cardbus_bridge(hose,
-						current_bus,
-						pci_devfn,
-						sub_bus,
-						&iosave,
-						&memsave);
-			} else {
-				if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) {
-					unsigned char prg_iface;
-
-					early_read_config_byte(hose,
-							current_bus,
-							pci_devfn,
-							PCI_CLASS_PROG,
-							&prg_iface);
-					if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
-						DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n");
-						continue;
-					}
-				}
-				/* Allocate PCI I/O and/or memory space */
-				pciauto_setup_bars(hose,
-						current_bus,
-						pci_devfn,
-						PCI_BASE_ADDRESS_5);
-
-				/*
-				 * Enable some standard settings
-				 */
-				early_read_config_dword(hose,
-						current_bus,
-						pci_devfn,
-						PCI_COMMAND,
-						&cmdstat);
-				early_write_config_dword(hose,
-						current_bus,
-						pci_devfn,
-						PCI_COMMAND,
-						cmdstat |
-						PCI_COMMAND_IO |
-						PCI_COMMAND_MEMORY |
-						PCI_COMMAND_MASTER);
-				early_write_config_byte(hose,
-						current_bus,
-						pci_devfn,
-						PCI_LATENCY_TIMER,
-						0x80);
-			}
-		}
-	}
-	return sub_bus;
-}
diff -Nru a/arch/ppc/kernel/ppc405_dma.c b/arch/ppc/kernel/ppc405_dma.c
--- a/arch/ppc/kernel/ppc405_dma.c	Sun Nov 10 19:28:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,511 +0,0 @@
-/*
- * linux/arch/ppc/kernel/ppc405_dma.c
- *
- * BRIEF MODULE DESCRIPTION
- *	IBM 405 DMA Controller Functions
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *         	ppopov@mvista.com or source@mvista.com
- *
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED   ``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  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 OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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/kernel.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <linux/mm.h>
-#include <linux/miscdevice.h>
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <asm/ppc405_dma.h>
-
-
-/*
- * Function prototypes
- */
-
-int hw_init_dma_channel(unsigned int,  ppc_dma_ch_t *);
-int init_dma_channel(unsigned int);
-int get_channel_config(unsigned int, ppc_dma_ch_t *);
-int set_channel_priority(unsigned int, unsigned int);
-unsigned int get_peripheral_width(unsigned int);
-int alloc_dma_handle(sgl_handle_t *, unsigned int, unsigned int);
-void free_dma_handle(sgl_handle_t);
-
-
-ppc_dma_ch_t dma_channels[MAX_405GP_DMA_CHANNELS];
-
-/*
- * Configures a DMA channel, including the peripheral bus width, if a
- * peripheral is attached to the channel, the polarity of the DMAReq and
- * DMAAck signals, etc.  This information should really be setup by the boot 
- * code, since most likely the configuration won't change dynamically.
- * If the kernel has to call this function, it's recommended that it's
- * called from platform specific init code.  The driver should not need to 
- * call this function.
- */
-int hw_init_dma_channel(unsigned int dmanr,  ppc_dma_ch_t *p_init)
-{
-    unsigned int polarity;
-    uint32_t control = 0;
-    ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
-
-#ifdef DEBUG_405DMA
-    if (!p_init) {
-        printk("hw_init_dma_channel: NULL p_init\n");
-        return DMA_STATUS_NULL_POINTER;
-    }
-    if (dmanr >= MAX_405GP_DMA_CHANNELS) {
-        printk("hw_init_dma_channel: bad channel %d\n", dmanr);
-        return DMA_STATUS_BAD_CHANNEL;
-    }
-#endif
-
-#if DCRN_POL > 0
-    polarity = mfdcr(DCRN_POL);
-#else
-    polarity = 0;
-#endif
-
-    /* Setup the control register based on the values passed to
-     * us in p_init.  Then, over-write the control register with this
-     * new value.
-     */
-
-    control |= ( 
-                SET_DMA_CIE_ENABLE(p_init->int_enable) | /* interrupt enable         */
-                SET_DMA_BEN(p_init->buffer_enable)     | /* buffer enable            */ 
-                SET_DMA_ETD(p_init->etd_output)        | /* end of transfer pin      */
-                SET_DMA_TCE(p_init->tce_enable)        | /* terminal count enable    */
-                SET_DMA_PL(p_init->pl)                 | /* peripheral location      */
-                SET_DMA_DAI(p_init->dai)               | /* dest addr increment      */
-                SET_DMA_SAI(p_init->sai)               | /* src addr increment       */
-                SET_DMA_PRIORITY(p_init->cp)           |  /* channel priority        */
-                SET_DMA_PW(p_init->pwidth)             |  /* peripheral/bus width    */
-                SET_DMA_PSC(p_init->psc)               |  /* peripheral setup cycles */
-                SET_DMA_PWC(p_init->pwc)               |  /* peripheral wait cycles  */
-                SET_DMA_PHC(p_init->phc)               |  /* peripheral hold cycles  */
-                SET_DMA_PREFETCH(p_init->pf)              /* read prefetch           */
-                );
-
-    switch (dmanr) {
-        case 0:
-            /* clear all polarity signals and then "or" in new signal levels */
-            polarity &= ~(DMAReq0_ActiveLow | DMAAck0_ActiveLow | EOT0_ActiveLow);
-            polarity |= p_dma_ch->polarity;
-#if DCRN_POL > 0
-            mtdcr(DCRN_POL, polarity);
-#endif
-            mtdcr(DCRN_DMACR0, control);
-            break;
-        case 1:
-            polarity &= ~(DMAReq1_ActiveLow | DMAAck1_ActiveLow | EOT1_ActiveLow);
-            polarity |= p_dma_ch->polarity;
-#if DCRN_POL > 0
-            mtdcr(DCRN_POL, polarity);
-#endif
-            mtdcr(DCRN_DMACR1, control);
-            break;
-        case 2:
-            polarity &= ~(DMAReq2_ActiveLow | DMAAck2_ActiveLow | EOT2_ActiveLow);
-            polarity |= p_dma_ch->polarity;
-#if DCRN_POL > 0
-            mtdcr(DCRN_POL, polarity);
-#endif
-            mtdcr(DCRN_DMACR2, control);
-            break;
-        case 3:
-            polarity &= ~(DMAReq3_ActiveLow | DMAAck3_ActiveLow | EOT3_ActiveLow);
-            polarity |= p_dma_ch->polarity;
-#if DCRN_POL > 0
-            mtdcr(DCRN_POL, polarity);
-#endif
-            mtdcr(DCRN_DMACR3, control);
-            break;
-        default:
-            return DMA_STATUS_BAD_CHANNEL;
-    }
-    
-    /* save these values in our dma channel structure */
-    memcpy(p_dma_ch, p_init, sizeof(ppc_dma_ch_t));
-
-    /*
-     * The peripheral width values written in the control register are:
-     *   PW_8                 0
-     *   PW_16                1
-     *   PW_32                2
-     *   PW_64                3
-     *
-     *   Since the DMA count register takes the number of "transfers",
-     *   we need to divide the count sent to us in certain
-     *   functions by the appropriate number.  It so happens that our
-     *   right shift value is equal to the peripheral width value.
-     */
-    p_dma_ch->shift = p_init->pwidth;
-
-    /*
-     * Save the control word for easy access.
-     */
-    p_dma_ch->control = control;
-
-    mtdcr(DCRN_DMASR, 0xffffffff); /* clear status register */
-    return DMA_STATUS_GOOD;
-}
-
-
-
-
-/*
- * This function returns the channel configuration.
- */
-int get_channel_config(unsigned int dmanr, ppc_dma_ch_t *p_dma_ch)
-{
-    unsigned int polarity;
-    unsigned int control;
-
-#if DCRN_POL > 0
-    polarity = mfdcr(DCRN_POL);
-#else
-    polarity = 0;
-#endif
-
-    switch (dmanr) {
-        case 0:
-            p_dma_ch->polarity = 
-                polarity & (DMAReq0_ActiveLow | DMAAck0_ActiveLow | EOT0_ActiveLow);
-            control = mfdcr(DCRN_DMACR0);
-            break;
-        case 1:
-            p_dma_ch->polarity = 
-                polarity & (DMAReq1_ActiveLow | DMAAck1_ActiveLow | EOT1_ActiveLow);
-            control = mfdcr(DCRN_DMACR1);
-            break;
-        case 2:
-            p_dma_ch->polarity = 
-                polarity & (DMAReq2_ActiveLow | DMAAck2_ActiveLow | EOT2_ActiveLow);
-            control = mfdcr(DCRN_DMACR2);
-            break;
-        case 3:
-            p_dma_ch->polarity = 
-                polarity & (DMAReq3_ActiveLow | DMAAck3_ActiveLow | EOT3_ActiveLow);
-            control = mfdcr(DCRN_DMACR3);
-            break;
-        default:
-            return DMA_STATUS_BAD_CHANNEL;
-    }
-
-    p_dma_ch->cp = GET_DMA_PRIORITY(control);
-    p_dma_ch->pwidth = GET_DMA_PW(control);
-    p_dma_ch->psc = GET_DMA_PSC(control);
-    p_dma_ch->pwc = GET_DMA_PWC(control);
-    p_dma_ch->phc = GET_DMA_PHC(control);
-    p_dma_ch->pf = GET_DMA_PREFETCH(control);
-    p_dma_ch->int_enable = GET_DMA_CIE_ENABLE(control);
-    p_dma_ch->shift = GET_DMA_PW(control);
-
-    return DMA_STATUS_GOOD;
-}
-
-/*
- * Sets the priority for the DMA channel dmanr.
- * Since this is setup by the hardware init function, this function 
- * can be used to dynamically change the priority of a channel.
- *
- * Acceptable priorities:
- *
- * PRIORITY_LOW
- * PRIORITY_MID_LOW
- * PRIORITY_MID_HIGH
- * PRIORITY_HIGH
- *
- */
-int set_channel_priority(unsigned int dmanr, unsigned int priority)
-{
-    unsigned int control;
-
-#ifdef DEBUG_405DMA
-    if ( (priority != PRIORITY_LOW) &&
-            (priority != PRIORITY_MID_LOW) &&
-            (priority != PRIORITY_MID_HIGH) &&
-            (priority != PRIORITY_HIGH)) {
-        printk("set_channel_priority: bad priority: 0x%x\n", priority);
-    }
-#endif
-
-    switch (dmanr) {
-        case 0:
-            control = mfdcr(DCRN_DMACR0);
-            control|= SET_DMA_PRIORITY(priority);
-            mtdcr(DCRN_DMACR0, control);
-            break;
-        case 1:
-            control = mfdcr(DCRN_DMACR1);
-            control|= SET_DMA_PRIORITY(priority);
-            mtdcr(DCRN_DMACR1, control);
-            break;
-        case 2:
-            control = mfdcr(DCRN_DMACR2);
-            control|= SET_DMA_PRIORITY(priority);
-            mtdcr(DCRN_DMACR2, control);
-            break;
-        case 3:
-            control = mfdcr(DCRN_DMACR3);
-            control|= SET_DMA_PRIORITY(priority);
-            mtdcr(DCRN_DMACR3, control);
-            break;
-        default:
-#ifdef DEBUG_405DMA
-            printk("set_channel_priority: bad channel: %d\n", dmanr);
-#endif
-            return DMA_STATUS_BAD_CHANNEL;
-    }
-    return DMA_STATUS_GOOD;
-}
-
-
-
-/*
- * Returns the width of the peripheral attached to this channel. This assumes
- * that someone who knows the hardware configuration, boot code or some other 
- * init code, already set the width.
- *
- * The return value is one of:
- *   PW_8
- *   PW_16
- *   PW_32
- *   PW_64
- *
- *   The function returns 0 on error.
- */
-unsigned int get_peripheral_width(unsigned int dmanr)
-{
-    unsigned int control;
-
-    switch (dmanr) {
-        case 0:
-            control = mfdcr(DCRN_DMACR0);
-            break;
-        case 1:
-            control = mfdcr(DCRN_DMACR1);
-            break;
-        case 2:
-            control = mfdcr(DCRN_DMACR2);
-            break;
-        case 3:
-            control = mfdcr(DCRN_DMACR3);
-            break;
-        default:
-#ifdef DEBUG_405DMA
-            printk("get_peripheral_width: bad channel: %d\n", dmanr);
-#endif
-            return 0;
-    }
-    return(GET_DMA_PW(control));
-}
-
-
-
-
-/*
- *   Create a scatter/gather list handle.  This is simply a structure which
- *   describes a scatter/gather list.
- *
- *   A handle is returned in "handle" which the driver should save in order to 
- *   be able to access this list later.  A chunk of memory will be allocated 
- *   to be used by the API for internal management purposes, including managing 
- *   the sg list and allocating memory for the sgl descriptors.  One page should 
- *   be more than enough for that purpose.  Perhaps it's a bit wasteful to use 
- *   a whole page for a single sg list, but most likely there will be only one 
- *   sg list per channel.
- *
- *   Interrupt notes:
- *   Each sgl descriptor has a copy of the DMA control word which the DMA engine
- *   loads in the control register.  The control word has a "global" interrupt 
- *   enable bit for that channel. Interrupts are further qualified by a few bits
- *   in the sgl descriptor count register.  In order to setup an sgl, we have to
- *   know ahead of time whether or not interrupts will be enabled at the completion
- *   of the transfers.  Thus, enable_dma_interrupt()/disable_dma_interrupt() MUST
- *   be called before calling alloc_dma_handle().  If the interrupt mode will never
- *   change after powerup, then enable_dma_interrupt()/disable_dma_interrupt() 
- *   do not have to be called -- interrupts will be enabled or disabled based
- *   on how the channel was configured after powerup by the hw_init_dma_channel()
- *   function.  Each sgl descriptor will be setup to interrupt if an error occurs;
- *   however, only the last descriptor will be setup to interrupt. Thus, an 
- *   interrupt will occur (if interrupts are enabled) only after the complete
- *   sgl transfer is done.
- */
-int alloc_dma_handle(sgl_handle_t *phandle, unsigned int mode, unsigned int dmanr)
-{
-    sgl_list_info_t *psgl;
-    dma_addr_t dma_addr;
-    ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
-    uint32_t sg_command;
-    void *ret;
-
-#ifdef DEBUG_405DMA
-    if (!phandle) {
-            printk("alloc_dma_handle: null handle pointer\n");
-            return DMA_STATUS_NULL_POINTER;
-    }
-    switch (mode) {
-        case DMA_MODE_READ:
-        case DMA_MODE_WRITE:
-        case DMA_MODE_MM:
-        case DMA_MODE_MM_DEVATSRC:
-        case DMA_MODE_MM_DEVATDST:
-            break;
-        default:
-            printk("alloc_dma_handle: bad mode 0x%x\n", mode);
-            return DMA_STATUS_BAD_MODE;
-    }
-    if (dmanr >= MAX_405GP_DMA_CHANNELS) {
-        printk("alloc_dma_handle: invalid channel 0x%x\n", dmanr);
-        return DMA_STATUS_BAD_CHANNEL;
-    }
-#endif
-
-    /* Get a page of memory, which is zeroed out by pci_alloc_consistent() */
-
-/* wrong not a pci device - armin */
-    /* psgl = (sgl_list_info_t *) pci_alloc_consistent(NULL, SGL_LIST_SIZE, &dma_addr);
-*/
-
-	ret = consistent_alloc(GFP_ATOMIC |GFP_DMA, SGL_LIST_SIZE, &dma_addr);
-	if (ret != NULL) {
-		memset(ret, 0,SGL_LIST_SIZE );
-		psgl = (sgl_list_info_t *) ret;
-	}
-
-
-    if (psgl == NULL) {
-        *phandle = (sgl_handle_t)NULL;
-        return DMA_STATUS_OUT_OF_MEMORY;
-    }
-
-    psgl->dma_addr = dma_addr;
-    psgl->dmanr = dmanr;
-
-    /*
-     * Modify and save the control word. These word will get written to each sgl
-     * descriptor.  The DMA engine then loads this control word into the control
-     * register every time it reads a new descriptor.
-     */
-    psgl->control = p_dma_ch->control;
-    psgl->control &= ~(DMA_TM_MASK | DMA_TD);  /* clear all "mode" bits first               */
-    psgl->control |= (mode | DMA_CH_ENABLE);   /* save the control word along with the mode */
-
-    if (p_dma_ch->int_enable) {
-        psgl->control |= DMA_CIE_ENABLE;       /* channel interrupt enabled                 */
-    }
-    else {
-        psgl->control &= ~DMA_CIE_ENABLE;
-    }
-
-#if DCRN_ASGC > 0
-    sg_command = mfdcr(DCRN_ASGC);
-    switch (dmanr) {
-        case 0:
-            sg_command |= SSG0_MASK_ENABLE;
-            break;
-        case 1:
-            sg_command |= SSG1_MASK_ENABLE;
-            break;
-        case 2:
-            sg_command |= SSG2_MASK_ENABLE;
-            break;
-        case 3:
-            sg_command |= SSG3_MASK_ENABLE;
-            break;
-        default:
-#ifdef DEBUG_405DMA
-            printk("alloc_dma_handle: bad channel: %d\n", dmanr);
-#endif
-            free_dma_handle((sgl_handle_t)psgl);
-            *phandle = (sgl_handle_t)NULL;
-            return DMA_STATUS_BAD_CHANNEL;
-    }
-
-    mtdcr(DCRN_ASGC, sg_command);  /* enable writing to this channel's sgl control bits */
-#else
-   (void)sg_command;
-#endif
-    psgl->sgl_control = SG_ERI_ENABLE | SG_LINK;   /* sgl descriptor control bits */
-
-    if (p_dma_ch->int_enable) {
-        if (p_dma_ch->tce_enable)
-            psgl->sgl_control |= SG_TCI_ENABLE;
-        else
-            psgl->sgl_control |= SG_ETI_ENABLE;
-    }
-
-    *phandle = (sgl_handle_t)psgl;
-    return DMA_STATUS_GOOD;
-}
-
-
-
-/*
- * Destroy a scatter/gather list handle that was created by alloc_dma_handle().
- * The list must be empty (contain no elements).
- */
-void free_dma_handle(sgl_handle_t handle)
-{
-    sgl_list_info_t *psgl = (sgl_list_info_t *)handle;
-
-    if (!handle) {
-#ifdef DEBUG_405DMA
-        printk("free_dma_handle: got NULL\n");
-#endif
-        return;
-    }
-    else if (psgl->phead) {
-#ifdef DEBUG_405DMA
-        printk("free_dma_handle: list not empty\n");
-#endif
-        return;
-    }
-    else if (!psgl->dma_addr) { /* should never happen */
-#ifdef DEBUG_405DMA
-        printk("free_dma_handle: no dma address\n");
-#endif
-        return;
-    }
-
-  /* wrong not a PCI device -armin */
-  /*  pci_free_consistent(NULL, SGL_LIST_SIZE, (void *)psgl, psgl->dma_addr); */
-	//	free_pages((unsigned long)psgl, get_order(SGL_LIST_SIZE));
-    	consistent_free((void *)psgl);
-
-
-}
-
-
-EXPORT_SYMBOL(hw_init_dma_channel);
-EXPORT_SYMBOL(get_channel_config);
-EXPORT_SYMBOL(set_channel_priority);
-EXPORT_SYMBOL(get_peripheral_width);
-EXPORT_SYMBOL(alloc_dma_handle);
-EXPORT_SYMBOL(free_dma_handle);
-EXPORT_SYMBOL(dma_channels);
diff -Nru a/arch/ppc/kernel/ppc405_pci.c b/arch/ppc/kernel/ppc405_pci.c
--- a/arch/ppc/kernel/ppc405_pci.c	Sun Nov 10 19:28:40 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,207 +0,0 @@
-/*
- * FILE NAME: ppc405_pci.c
- *
- * BRIEF MODULE DESCRIPTION: 
- * Based on arch/ppc/kernel/indirect.c, Copyright (C) 1998 Gabriel Paubert.
- *
- * Author: MontaVista Software, Inc.  <source@mvista.com>
- *         Frank Rowand <frank_rowand@mvista.com>
- *         Debbie Chu   <debbie_chu@mvista.com>
- *
- * Copyright 2000 MontaVista Software 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  SOFTWARE  IS PROVIDED   ``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  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 OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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/pci.h>
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/machdep.h>
-#include <linux/init.h>
-#include <asm/ibm4xx.h>
-#include <asm/pci-bridge.h>
-#include <platforms/ibm_ocp.h>
-
-#ifdef  CONFIG_DEBUG_BRINGUP
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-extern void bios_fixup(struct pci_controller *, void *);
-extern int ppc405_map_irq(struct pci_dev *dev, unsigned char idsel,
-			  unsigned char pin);
-extern struct pcil0_regs *PCIL_ADDR[];
-
-void
-ppc405_pcibios_fixup_resources(struct pci_dev *dev)
-{
-	int i;
-	unsigned long max_host_addr;
-	unsigned long min_host_addr;
-	struct resource *res;
-
-	/*
-	 * openbios puts some graphics cards in the same range as the host
-	 * controller uses to map to SDRAM.  Fix it.
-	 */
-
-	min_host_addr = 0;
-	max_host_addr = PPC405_PCI_MEM_BASE - 1;
-
-	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
-		res = dev->resource + i;
-		if (!res->start)
-			continue;
-		if ((res->flags & IORESOURCE_MEM) &&
-		    (((res->start >= min_host_addr)
-		      && (res->start <= max_host_addr))
-		     || ((res->end >= min_host_addr)
-			 && (res->end <= max_host_addr))
-		     || ((res->start < min_host_addr)
-			 && (res->end > max_host_addr))
-		    )
-		    ) {
-
-			DBG(KERN_ERR "PCI: 0x%lx <= resource[%d] <= 0x%lx"
-			    ", bus 0x%x dev 0x%2.2x.%1.1x,\n"
-			    KERN_ERR "  %s\n"
-			    KERN_ERR "  fixup will be attempted later\n",
-			    min_host_addr, i, max_host_addr,
-			    dev->bus->number, PCI_SLOT(dev->devfn),
-			    PCI_FUNC(dev->devfn), dev->name);
-
-			/* force pcibios_assign_resources() to assign a new address */
-			res->end -= res->start;
-			res->start = 0;
-		}
-	}
-}
-
-static int
-ppc4xx_exclude_device(unsigned char bus, unsigned char devfn)
-{
-	/* We prevent us from seeing ourselves to avoid having
-	 * the kernel try to remap our BAR #1 and fuck up bus
-	 * master from external PCI devices
-	 */
-	return (bus == 0 && devfn == 0);
-}
-
-void
-ppc4xx_find_bridges(void)
-{
-	struct pci_controller *hose_a;
-	struct pcil0_regs *pcip;
-	unsigned int tmp_addr;
-	unsigned int tmp_size;
-	unsigned int reg_index;
-	unsigned int new_pmm_max;
-	unsigned int new_pmm_min;
-
-	isa_io_base = 0;
-	isa_mem_base = 0;
-	pci_dram_offset = 0;
-	
-	/* Check if running in slave mode */
-	if ((mfdcr(DCRN_CHPSR) & PSR_PCI_ARBIT_EN) == 0) {
-		printk("Running as PCI slave, kernel PCI disabled !\n");
-		return;
-	}
-	/* Setup PCI32 hose */
-	hose_a = pcibios_alloc_controller();
-	if (!hose_a)
-		return;
-	setup_indirect_pci(hose_a, PPC405_PCI_CONFIG_ADDR,
-			   PPC405_PCI_CONFIG_DATA);
-	pcip = ioremap((unsigned long) PCIL_ADDR[0], PAGE_SIZE);
-	if (pcip != NULL) {
-
-#if defined(CONFIG_BIOS_FIXUP)
-		bios_fixup(hose_a, pcip);
-#endif
-		new_pmm_min = 0xffffffff;
-		for (reg_index = 0; reg_index < 3; reg_index++) {
-			tmp_size = in_le32((void *) &(pcip->pmm[reg_index].ma));	// *_PMM0MA
-			if (tmp_size & 0x1) {
-				tmp_addr = in_le32((void *) &(pcip->pmm[reg_index].pcila));	// *_PMM0PCILA
-				if (tmp_addr < PPC405_PCI_PHY_MEM_BASE) {
-					printk(KERN_DEBUG
-					       "Disabling mapping to PCI mem addr 0x%8.8x\n",
-					       tmp_addr);
-					out_le32((void *) &(pcip->pmm[reg_index].ma), tmp_size & ~1);	// *_PMMOMA
-				} else {
-					tmp_addr = in_le32((void *) &(pcip->pmm[reg_index].la));	// *_PMMOLA
-					if (tmp_addr < new_pmm_min)
-						new_pmm_min = tmp_addr;
-					tmp_addr =
-					    tmp_addr + (0xffffffff -
-							(tmp_size &
-							 0xffffc000));
-					if (tmp_addr > PPC405_PCI_UPPER_MEM) {
-						new_pmm_max = tmp_addr;	// PPC405_PCI_UPPER_MEM 
-					} else {
-						new_pmm_max =
-						    PPC405_PCI_UPPER_MEM;
-					}
-				}
-			}
-
-		}		// for
-
-		iounmap(pcip);
-	}
-	hose_a->first_busno      = 0;
-	hose_a->last_busno       = 0xff;
-	hose_a->pci_mem_offset   = 0;
-
-	/* Setup bridge memory/IO ranges & resources
-	 * TODO: Handle firmwares setting up a legacy ISA mem base
-	 */
-	hose_a->io_space.start		= PPC405_PCI_LOWER_IO;
-	hose_a->io_space.end		= PPC405_PCI_UPPER_IO;
-	hose_a->mem_space.start		= new_pmm_min;
-	hose_a->mem_space.end		= new_pmm_max;
-	hose_a->io_base_phys		= PPC405_PCI_PHY_IO_BASE;
-	hose_a->io_base_virt		= ioremap(hose_a->io_base_phys, 0x10000);
-	hose_a->io_resource.start	= 0;
-	hose_a->io_resource.end		= PPC405_PCI_UPPER_IO-PPC405_PCI_LOWER_IO;
-	hose_a->io_resource.flags	= IORESOURCE_IO;
-	hose_a->io_resource.name	= "PCI I/O";
-	hose_a->mem_resources[0].start	= new_pmm_min;
-	hose_a->mem_resources[0].end	= new_pmm_max;
-	hose_a->mem_resources[0].flags	= IORESOURCE_MEM;
-	hose_a->mem_resources[0].name	= "PCI Memory";
-	isa_io_base			= (int)hose_a->io_base_virt;
-	isa_mem_base			= 0;	      /*     ISA not implemented */
-	ISA_DMA_THRESHOLD		= 0x00ffffff; /* ??? ISA not implemented */
-
-	/* Scan busses & initial setup by pci_auto */
-	hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
-	hose_a->last_busno = 0;
-
-	/* Setup ppc_md */
-	ppc_md.pcibios_fixup     	= NULL;
-	ppc_md.pci_exclude_device	= ppc4xx_exclude_device;
-	ppc_md.pcibios_fixup_resources	= ppc405_pcibios_fixup_resources;
-	ppc_md.pci_swizzle		= common_swizzle;
-	ppc_md.pci_map_irq		= ppc405_map_irq;
-}
diff -Nru a/arch/ppc/kernel/ppc4xx_kgdb.c b/arch/ppc/kernel/ppc4xx_kgdb.c
--- a/arch/ppc/kernel/ppc4xx_kgdb.c	Sun Nov 10 19:28:40 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,124 +0,0 @@
-#include <linux/config.h>
-#include <linux/types.h>
-#include <asm/ibm4xx.h>
-#include <linux/kernel.h>
-
-
-
-#define LSR_DR		0x01 /* Data ready */
-#define LSR_OE		0x02 /* Overrun */
-#define LSR_PE		0x04 /* Parity error */
-#define LSR_FE		0x08 /* Framing error */
-#define LSR_BI		0x10 /* Break */
-#define LSR_THRE	0x20 /* Xmit holding register empty */
-#define LSR_TEMT	0x40 /* Xmitter empty */
-#define LSR_ERR		0x80 /* Error */
-
-#include <platforms/ibm_ocp.h>
-
-extern struct NS16550* COM_PORTS[];
-#ifndef NULL
-#define NULL 0x00
-#endif
-
-static volatile struct NS16550 *kgdb_debugport = NULL;
-
-volatile struct NS16550 *
-NS16550_init(int chan)
-{
-	volatile struct NS16550 *com_port;
-	int quot;
-#ifdef BASE_BAUD
-	quot = BASE_BAUD / 9600;
-#else
-	quot = 0x000c; /* 0xc = 9600 baud (on a pc) */
-#endif
-
-	com_port = (struct NS16550 *) COM_PORTS[chan];
-
-	com_port->lcr = 0x00;
-	com_port->ier = 0xFF;
-	com_port->ier = 0x00;
-	com_port->lcr = com_port->lcr | 0x80; /* Access baud rate */
-	com_port->dll = ( quot & 0x00ff ); /* 0xc = 9600 baud */
-	com_port->dlm = ( quot & 0xff00 ) >> 8;
-	com_port->lcr = 0x03; /* 8 data, 1 stop, no parity */
-	com_port->mcr = 0x00; /* RTS/DTR */
-	com_port->fcr = 0x07; /* Clear & enable FIFOs */
-
-	return( com_port );
-}
-
-
-void
-NS16550_putc(volatile struct NS16550 *com_port, unsigned char c)
-{
-	while ((com_port->lsr & LSR_THRE) == 0)
-		;
-	com_port->thr = c;
-	return;
-}
-
-unsigned char
-NS16550_getc(volatile struct NS16550 *com_port)
-{
-	while ((com_port->lsr & LSR_DR) == 0)
-		;
-	return (com_port->rbr);
-}
-
-unsigned char
-NS16550_tstc(volatile struct NS16550 *com_port)
-{
-	return ((com_port->lsr & LSR_DR) != 0);
-}
-
-
-#if defined(CONFIG_KGDB_TTYS0)
-#define KGDB_PORT 0
-#elif defined(CONFIG_KGDB_TTYS1)
-#define KGDB_PORT 1
-#elif defined(CONFIG_KGDB_TTYS2)
-#define KGDB_PORT 2
-#elif defined(CONFIG_KGDB_TTYS3)
-#define KGDB_PORT 3
-#else
-#error "invalid kgdb_tty port"
-#endif
-
-void putDebugChar( unsigned char c )
-{
-	if ( kgdb_debugport == NULL )
-		kgdb_debugport = NS16550_init(KGDB_PORT);
-	NS16550_putc( kgdb_debugport, c );
-}
-
-int getDebugChar( void )
-{
-	if (kgdb_debugport == NULL)
-		kgdb_debugport = NS16550_init(KGDB_PORT);
-
-	return(NS16550_getc(kgdb_debugport));
-}
-
-void kgdb_interruptible(int enable)
-{
-	return;
-}
-
-void putDebugString(char* str)
-{
-	while (*str != '\0') {
-		putDebugChar(*str);
-		str++;
-	}
-	putDebugChar('\r');
-	return;
-}
-
-void
-kgdb_map_scc(void)
-{
-	printk("kgdb init \n");
-	kgdb_debugport = NS16550_init(KGDB_PORT);
-}
diff -Nru a/arch/ppc/kernel/ppc4xx_pic.c b/arch/ppc/kernel/ppc4xx_pic.c
--- a/arch/ppc/kernel/ppc4xx_pic.c	Sun Nov 10 19:28:36 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,348 +0,0 @@
-/*
- *
- *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: ppc4xx_pic.c
- *
- *    Description:
- *      Interrupt controller driver for PowerPC 4xx-based processors.
- */
-
-/*
- * The PowerPC 403 cores' Asynchronous Interrupt Controller (AIC) has
- * 32 possible interrupts, a majority of which are not implemented on
- * all cores. There are six configurable, external interrupt pins and
- * there are eight internal interrupts for the on-chip serial port
- * (SPU), DMA controller, and JTAG controller.
- *
- * The PowerPC 405/440 cores' Universal Interrupt Controller (UIC) has
- * 32 possible interrupts as well.  Depending on the core and SoC
- * implementation, a portion of the interrrupts are used for on-chip
- * peripherals and a portion of the interrupts are available to be
- * configured for external devices generating interrupts.
- *
- * The PowerNP and 440GP (and most likely future implementations) have
- * cascaded UICs.
- *
- */
-
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/stddef.h>
-
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-#include <asm/ppc4xx_pic.h>
-
-/* Global Variables */
-struct hw_interrupt_type *ppc4xx_pic;
-
-/* Six of one, half dozen of the other....#ifdefs, separate files,
- * other tricks.....
- *
- * There are basically two types of interrupt controllers, the 403 AIC
- * and the "others" with UIC.  I just kept them both here separated
- * with #ifdefs, but it seems to change depending upon how supporting
- * files (like ppc4xx.h) change.		-- Dan.
- */
-
-#ifdef CONFIG_403
-
-/* Function Prototypes */
-
-static void ppc403_aic_enable(unsigned int irq);
-static void ppc403_aic_disable(unsigned int irq);
-static void ppc403_aic_disable_and_ack(unsigned int irq);
-
-static struct hw_interrupt_type ppc403_aic = {
-	"403GC AIC",
-	NULL,
-	NULL,
-	ppc403_aic_enable,
-	ppc403_aic_disable,
-	ppc403_aic_disable_and_ack,
-	0
-};
-
-int
-ppc403_pic_get_irq(struct pt_regs *regs)
-{
-	int irq;
-	unsigned long bits;
-
-	/*
-	 * Only report the status of those interrupts that are actually
-	 * enabled.
-	 */
-
-	bits = mfdcr(DCRN_EXISR) & mfdcr(DCRN_EXIER);
-
-	/*
-	 * Walk through the interrupts from highest priority to lowest, and
-	 * report the first pending interrupt found.
-	 * We want PPC, not C bit numbering, so just subtract the ffs()
-	 * result from 32.
-	 */
-	irq = 32 - ffs(bits);
-
-	if (irq == NR_AIC_IRQS)
-		irq = -1;
-
-	return (irq);
-}
-
-static void
-ppc403_aic_enable(unsigned int irq)
-{
-	int bit, word;
-
-	bit = irq & 0x1f;
-	word = irq >> 5;
-
-	ppc_cached_irq_mask[word] |= (1 << (31 - bit));
-	mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
-}
-
-static void
-ppc403_aic_disable(unsigned int irq)
-{
-	int bit, word;
-
-	bit = irq & 0x1f;
-	word = irq >> 5;
-
-	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
-	mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
-}
-
-static void
-ppc403_aic_disable_and_ack(unsigned int irq)
-{
-	int bit, word;
-
-	bit = irq & 0x1f;
-	word = irq >> 5;
-
-	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
-	mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
-	mtdcr(DCRN_EXISR, (1 << (31 - bit)));
-}
-
-#else
-
-#ifndef UIC1
-#define UIC1 UIC0
-#endif
-
-static void
-ppc405_uic_enable(unsigned int irq)
-{
-	int bit, word;
-
-	bit = irq & 0x1f;
-	word = irq >> 5;
-#ifdef UIC_DEBUG	
-	printk("ppc405_uic_enable - irq %d word %d bit 0x%x\n",irq, word , bit);
-#endif
-	ppc_cached_irq_mask[word] |= 1 << (31 - bit);
-	switch (word){
-		case 0:
-			mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
-		break;
-		case 1:
-			mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
-		break;
-	}
-}
-
-static void
-ppc405_uic_disable(unsigned int irq)
-{
-	int bit, word;
-
-	bit = irq & 0x1f;
-	word = irq >> 5;
-#ifdef UIC_DEBUG	
-	printk("ppc405_uic_disable - irq %d word %d bit 0x%x\n",irq, word , bit);
-#endif
-	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
-	switch (word){
-		case 0:
-			mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
-		break;
-		case 1:
-			mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
-		break;
-	}
-}
-
-static void
-ppc405_uic_disable_and_ack(unsigned int irq)
-{
-	int bit, word;
-
-	bit = irq & 0x1f;
-	word = irq >> 5;
-
-#ifdef UIC_DEBUG	
-printk("ppc405_uic_disable_and_ack - irq %d word %d bit 0x%x\n",irq, word , bit);
-#endif
-	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
-	switch (word){
-		case 0:
-			mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
-			mtdcr(DCRN_UIC_SR(UIC0), (1 << (31 - bit)));
-		break;
-		case 1:	
-			mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
-			mtdcr(DCRN_UIC_SR(UIC1), (1 << (31 - bit)));
-		break;
-	}
-}
-
-static void
-ppc405_uic_end(unsigned int irq)
-{
-	int bit, word;
-	unsigned int tr_bits;
-
-	bit = irq & 0x1f;
-	word = irq >> 5;
-
-#ifdef UIC_DEBUG	
-	printk("ppc405_uic_end - irq %d word %d bit 0x%x\n",irq, word , bit);
-#endif
-
-	switch (word){
-		case 0:
-			tr_bits = mfdcr(DCRN_UIC_TR(UIC0));
-		break;
-		case 1:
-			tr_bits = mfdcr(DCRN_UIC_TR(UIC1));
-		break;
-	}
-
-	if ((tr_bits & (1 << (31 - bit))) == 0) {
-		/* level trigger */
-		switch (word){
-			case 0:
-				mtdcr(DCRN_UIC_SR(UIC0), 1 << (31 - bit));
-			break;
-			case 1:
-				mtdcr(DCRN_UIC_SR(UIC1), 1 << (31 - bit));
-			break;
-		}
-	}
-
-	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))
-	    && irq_desc[irq].action) {
-		ppc_cached_irq_mask[word] |= 1 << (31 - bit);
-		switch (word){
-			case 0:
-				mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
-			break;
-			case 1:
-				mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
-			break;
-		}
-	}
-}
-
-static struct hw_interrupt_type ppc405_uic = {
-#if (NR_UICS == 1)
-	"IBM UIC",
-#else
-	"IBM UIC Cascade",
-#endif
-	NULL,
-	NULL,
-	ppc405_uic_enable,
-	ppc405_uic_disable,
-	ppc405_uic_disable_and_ack,
-	ppc405_uic_end,
-	0
-};
-
-int
-ppc405_pic_get_irq(struct pt_regs *regs)
-{
-	int irq, cas_irq;
-	unsigned long bits;
-	cas_irq = 0;
-	/*
-	 * Only report the status of those interrupts that are actually
-	 * enabled.
-	 */
-
-	bits = mfdcr(DCRN_UIC_MSR(UIC0));
-
-#if (NR_UICS > 1) 
-	if (bits & UIC_CASCADE_MASK){
-		bits = mfdcr(DCRN_UIC_MSR(UIC1));
-		cas_irq = 32 - ffs(bits);
-		irq = 32 + cas_irq;
-	} else {
-		irq = 32 - ffs(bits);
-		if (irq == 32)
-			irq= -1;
-	}
-#else
-	/*
-	 * Walk through the interrupts from highest priority to lowest, and
-	 * report the first pending interrupt found.
-	 * We want PPC, not C bit numbering, so just subtract the ffs()
-	 * result from 32.
-	 */
-	irq = 32 - ffs(bits);
-#endif
-	if (irq == (NR_UIC_IRQS * NR_UICS))
-		irq = -1;
-
-#ifdef UIC_DEBUG
-printk("ppc405_pic_get_irq - irq %d bit 0x%x\n",irq, bits);
-#endif
-
-	return (irq);
-}
-#endif
-
-void __init
-ppc4xx_pic_init(void)
-{
-	/*
-	 * Disable all external interrupts until they are
-	 * explicity requested.
-	 */
-	ppc_cached_irq_mask[0] = 0;
-	ppc_cached_irq_mask[1] = 0;
-
-#if defined CONFIG_403
-	mtdcr(DCRN_EXIER, ppc_cached_irq_mask[0]);
-
-	ppc4xx_pic = &ppc403_aic;
-	ppc_md.get_irq = ppc403_pic_get_irq;
-#else
-#if  (NR_UICS > 1) 
-	ppc_cached_irq_mask[0] |= 1 << (31 - UIC0_UIC1NC ); /* enable cascading interrupt */
-	mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
-	mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[1]);
-
-	/* Set all interrupts to non-critical.
-	 */
-	mtdcr(DCRN_UIC_CR(UIC0), 0);
-	mtdcr(DCRN_UIC_CR(UIC1), 0);
-
-#else	
-	mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
-
-	/* Set all interrupts to non-critical.
-	 */
-	mtdcr(DCRN_UIC_CR(UIC0), 0);
-#endif
-
-	ppc4xx_pic = &ppc405_uic;
-	ppc_md.get_irq = ppc405_pic_get_irq;
-#endif
-}
diff -Nru a/arch/ppc/kernel/ppc4xx_pm.c b/arch/ppc/kernel/ppc4xx_pm.c
--- a/arch/ppc/kernel/ppc4xx_pm.c	Sun Nov 10 19:28:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,75 +0,0 @@
-/*
- *	file: ppc4xx_pm.c
- *
- *	This an attempt to get Power Management going for the IBM 4xx processor.
- *	This was derived from the ppc4xx._setup.c file
- *
- *      Armin Kuster akuster@mvista.com
- *      Jan  2002
- *
- *
- * Copyright 2002 MontaVista Softare 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  SOFTWARE  IS PROVIDED   ``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  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 OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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.
- *
- *	Version 1.0 (02/14/01) - A. Kuster
- *	Initial version	 - moved pm code from ppc4xx_setup.c
- *
- *	1.1 02/21/01 - A. Kuster
- *		minor fixes, init value to 0 & += to &=
- *		added stb03 ifdef for 2nd i2c device
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-
-#include <asm/ibm4xx.h>
-
-void __init
-ppc4xx_pm_init(void)
-{
-
-	unsigned int value = 0;
-
-	/* turn off unused hardware to save power */
-#ifdef CONFIG_405GP
-	value |= CPM_DCP;	/* CodePack */
-#endif
-
-#if !defined(CONFIG_IBM_OCP_GPIO)
-	value |= CPM_GPIO0;
-#endif
-
-#if !defined(CONFIG_PPC405_I2C_ADAP)
-	value |= CPM_IIC0;
-#ifdef CONFIG_STB03xxx
-	value |= CPM_IIC1;
-#endif
-#endif
-
-
-#if !defined(CONFIG_405_DMA)
-	value |= CPM_DMA;
-#endif
-
-	mtdcr(DCRN_CPMFR, value);
-
-}
diff -Nru a/arch/ppc/kernel/ppc4xx_serial.c b/arch/ppc/kernel/ppc4xx_serial.c
--- a/arch/ppc/kernel/ppc4xx_serial.c	Sun Nov 10 19:28:36 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,190 +0,0 @@
-
-/*
- * linux/arch/ppc/kernel/ppc405_serial.c
- *
- * This is a fairly standard 165xx type device that will eventually
- * be merged with other similar processor/boards.	-- Dan
- *
- * BRIEF MODULE DESCRIPTION
- *	Console I/O support for Early kernel bringup. 
- *
- * Copyright 2000 MontaVista Software Inc.
- * Author: MontaVista Software, Inc.
- *         	frank_rowand@mvista.com or source@mvista.com
- * 	   	debbie_chu@mvista.com
- *
- *
- *  This program is free software; you can redistribute  it and/or modify it
- *  under  the terms of  the GNU General  Public License as published by the
- *  Free Software Foundation;  either version 2 of the  License, or (at your
- *  option) any later version.
- *
- *  THIS  SOFTWARE  IS PROVIDED   ``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  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 OUT OF THE USE OF
- *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *  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>
-
-#if defined(CONFIG_IBM405GP) || defined(CONFIG_IBM405CR)
-
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-#include <linux/init.h>
-#endif
-
-#ifdef CONFIG_DEBUG_BRINGUP
-
-#include <linux/console.h>
-
-extern void ftr_reset_preferred_console(void);
-
-
-static int ppc405_sercons_setup(struct console *co, char *options)
-{
-#ifdef CONFIG_UART0_DEBUG_CONSOLE
-    volatile unsigned char *uart_dll  = (char *)0xef600300;
-    volatile unsigned char *uart_fcr  = (char *)0xef600302;
-    volatile unsigned char *uart_lcr  = (char *)0xef600303;
-#endif
-
-#ifdef CONFIG_UART1_DEBUG_CONSOLE
-    volatile unsigned char *uart_dll  = (char *)0xef600400;
-    volatile unsigned char *uart_fcr  = (char *)0xef600402;
-    volatile unsigned char *uart_lcr  = (char *)0xef600403;
-#endif
-
-    *uart_lcr = *uart_lcr | 0x80;   /* DLAB on  */
-
-/* ftr revisit - there is no config option for this
-**  also see include/asm-ppc/ppc405_serial.h
-**
-** #define CONFIG_IBM405GP_INTERNAL_CLOCK
-*/
-
-
-#ifdef  CONFIG_IBM405GP_INTERNAL_CLOCK 
-    /* ftr revisit
-    ** why is bit 19 of chcr0 (0x1000) being set?
-    */
-    /* 0x2a results in data corruption, kgdb works with 0x28 */
-    *uart_dll = 0x28;		    /* 9600 baud */
-    _put_CHCR0((_get_CHCR0() & 0xffffe000) | 0x103e);
-#else
-    *uart_dll = 0x48;		    /* 9600 baud */
-#endif
-    *uart_lcr = *uart_lcr & 0x7f;   /* DLAB off */
-
-    return 0;
-}
-
-
-/*
- * This is a bringup hack, writing directly to uart0 or uart1
- */
-
-static void
-ppc405_sercons_write(struct console *co, const char *ptr,
-            unsigned nb)
-{ 
-    int i;
-
-#ifdef CONFIG_UART0_DEBUG_CONSOLE
-    volatile unsigned char *uart_xmit = (char *)0xef600300;
-    volatile unsigned char *uart_lsr  = (char *)0xef600305;
-#endif
-
-#ifdef CONFIG_UART1_DEBUG_CONSOLE
-    volatile unsigned char *uart_xmit = (char *)0xef600400;
-    volatile unsigned char *uart_lsr  = (char *)0xef600405;
-#endif
-
-    for (i = 0; i < nb; ++i) {
-
-	/* wait for transmit reg (possibly fifo) to empty */
-	while ((*uart_lsr & 0x40) == 0)
-	    ;
-
-	*uart_xmit = (ptr[i] & 0xff);
-
-	if (ptr[i] == '\n') {
-
-	    /* add a carriage return */
-	
-	    /* wait for transmit reg (possibly fifo) to empty */
-	    while ((*uart_lsr & 0x40) == 0)
-		;
-
-	    *uart_xmit = '\r';
-	}
-    }
-
-    return;
-}
-
-
-static int
-ppc405_sercons_read(struct console *co, char *ptr, unsigned nb)
-{ 
-#ifdef CONFIG_UART0_DEBUG_CONSOLE
-    volatile unsigned char *uart_rcv  = (char *)0xef600300;
-    volatile unsigned char *uart_lsr  = (char *)0xef600305;
-#endif
-
-#ifdef CONFIG_UART1_DEBUG_CONSOLE
-    volatile unsigned char *uart_rcv  = (char *)0xef600400;
-    volatile unsigned char *uart_lsr  = (char *)0xef600405;
-#endif
-
-
-    /* ftr revisit: not tested */
-
-    if (nb == 0)
-	return(0);
-
-    if (!ptr)
-	return(-1);
-
-    /* wait for receive reg (possibly fifo) to contain data */
-    while ((*uart_lsr & 0x01) == 0)
-	;
-
-    *ptr = *uart_rcv;
-
-    return(1);
-}
-
-static struct console ppc405_sercons = {
-	.name =		"dbg_cons",
-	.write =	ppc405_console_write,
-	.setup =	ppc405_console_setup,
-	.flags =	CON_PRINTBUFFER,
-	.index =	-1,
-};
-
-void
-register_debug_console(void)
-{
-	register_console(&ppc405_sercons); 
-}
-
-void
-unregister_debug_console(void)
-{
-	unregister_console(&ppc405_sercons);
-}
-
-#endif	/* CONFIG_DEBUG_BRINGUP */
-
-#endif	/* #if defined(CONFIG_IBM405GP) || defined(CONFIG_IBM405CR) */
diff -Nru a/arch/ppc/kernel/ppc4xx_setup.c b/arch/ppc/kernel/ppc4xx_setup.c
--- a/arch/ppc/kernel/ppc4xx_setup.c	Sun Nov 10 19:28:36 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,360 +0,0 @@
-/*
- *
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Copyright 2000-2001 MontaVista Software Inc.
- *      Completed implementation.
- *      Author: MontaVista Software, Inc.  <source@mvista.com>
- *              Frank Rowand <frank_rowand@mvista.com>
- *              Debbie Chu   <debbie_chu@mvista.com>
- *
- *    Module name: ppc4xx_setup.c
- *
- *    Description:
- *      Architecture- / platform-specific boot-time initialization code for
- *      IBM PowerPC 4xx based boards. Adapted from original
- *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
- *      <dan@net4x.com>.
- *
- * 	History: 11/09/2001 - armin
- *	rename board_setup_nvram_access to board_init. board_init is
- *	used for all other board specific instructions needed during
- *	platform_init.
- *	moved RTC to board.c files
- *	moved VT/FB to board.c files
- *	moved r/w4 ide to redwood.c
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/smp.h>
-#include <linux/threads.h>
-#include <linux/spinlock.h>
-#include <linux/irq.h>
-#include <linux/reboot.h>
-#include <linux/param.h>
-#include <linux/string.h>
-#include <linux/blk.h>
-#include <linux/pci.h>
-#include <linux/rtc.h>
-#include <linux/console.h>
-#include <linux/ide.h>
-#include <linux/serial_reg.h>
-#include <linux/seq_file.h>
-
-#include <asm/system.h>
-#include <asm/processor.h>
-#include <asm/machdep.h>
-#include <asm/page.h>
-#include <asm/kgdb.h>
-#include <asm/ibm4xx.h>
-#include <asm/time.h>
-#include <asm/todc.h>
-#include <asm/ppc4xx_pic.h>
-#include <asm/pci-bridge.h>
-#include <asm/bootinfo.h>
-
-/* Function Prototypes */
-extern void abort(void);
-extern void ppc4xx_find_bridges(void);
-
-extern void ppc4xx_wdt_heartbeat(void);
-extern int wdt_enable;
-extern unsigned long wdt_period;
-
-/* Board specific functions */
-extern void board_setup_arch(void);
-extern void board_io_mapping(void);
-extern void board_setup_irq(void);
-extern void board_init(void);
-
-/* Global Variables */
-unsigned char __res[sizeof (bd_t)];
-
-static void __init
-ppc4xx_setup_arch(void)
-{
-
-	/* Setup PCI host bridges */
-
-#ifdef CONFIG_PCI
-	ppc4xx_find_bridges();
-#endif
-
-#if defined(CONFIG_FB)
-	conswitchp = &dummy_con;
-#endif
-
-	board_setup_arch();
-}
-
-/*
- *   This routine pretty-prints the platform's internal CPU clock
- *   frequencies into the buffer for usage in /proc/cpuinfo.
- */
-
-static int
-ppc4xx_show_percpuinfo(struct seq_file *m, int i)
-{
-	bd_t *bip = (bd_t *) __res;
-
-	seq_printf(m, "clock\t\t: %ldMHz\n", (long) bip->bi_intfreq / 1000000);
-
-	return 0;
-}
-
-/*
- *   This routine pretty-prints the platform's internal bus clock
- *   frequencies into the buffer for usage in /proc/cpuinfo.
- */
-static int
-ppc4xx_show_cpuinfo(struct seq_file *m)
-{
-	bd_t *bip = (bd_t *) __res;
-
-	seq_printf(m, "machine\t\t: %s\n", PPC4xx_MACHINE_NAME);
-	seq_printf(m, "plb bus clock\t: %ldMHz\n",
-		   (long) bip->bi_busfreq / 1000000);
-#ifdef CONFIG_PCI
-	seq_printf(m, "pci bus clock\t: %dMHz\n",
-		   bip->bi_pci_busfreq / 1000000);
-#endif
-
-	return 0;
-}
-
-/*
- * Return the virtual address representing the top of physical RAM.
- */
-static unsigned long __init
-ppc4xx_find_end_of_memory(void)
-{
-	bd_t *bip = (bd_t *) __res;
-
-	return ((unsigned long) bip->bi_memsize);
-}
-
-static void __init
-m4xx_map_io(void)
-{
-	io_block_mapping(PPC4xx_ONB_IO_VADDR,
-			 PPC4xx_ONB_IO_PADDR, PPC4xx_ONB_IO_SIZE, _PAGE_IO);
-#ifdef CONFIG_PCI
-	io_block_mapping(PPC4xx_PCI_IO_VADDR,
-			 PPC4xx_PCI_IO_PADDR, PPC4xx_PCI_IO_SIZE, _PAGE_IO);
-	io_block_mapping(PPC4xx_PCI_CFG_VADDR,
-			 PPC4xx_PCI_CFG_PADDR, PPC4xx_PCI_CFG_SIZE, _PAGE_IO);
-	io_block_mapping(PPC4xx_PCI_LCFG_VADDR,
-			 PPC4xx_PCI_LCFG_PADDR, PPC4xx_PCI_LCFG_SIZE, _PAGE_IO);
-#endif
-	board_io_mapping();
-}
-
-static void __init
-ppc4xx_init_IRQ(void)
-{
-	int i;
-
-	ppc4xx_pic_init();
-
-	for (i = 0; i < NR_IRQS; i++)
-		irq_desc[i].handler = ppc4xx_pic;
-
-	/* give board specific code a chance to setup things */
-	board_setup_irq();
-	return;
-}
-
-static void
-ppc4xx_restart(char *cmd)
-{
-	printk("%s\n", cmd);
-	abort();
-}
-
-static void
-ppc4xx_power_off(void)
-{
-	printk("System Halted\n");
-	local_irq_disable();
-	while (1) ;
-}
-
-static void
-ppc4xx_halt(void)
-{
-	printk("System Halted\n");
-	local_irq_disable();
-	while (1) ;
-}
-
-/*
- * This routine retrieves the internal processor frequency from the board
- * information structure, sets up the kernel timer decrementer based on
- * that value, enables the 4xx programmable interval timer (PIT) and sets
- * it up for auto-reload.
- */
-static void __init
-ppc4xx_calibrate_decr(void)
-{
-	unsigned int freq;
-	bd_t *bip = (bd_t *) __res;
-
-#if defined(CONFIG_WALNUT) || defined(CONFIG_CEDER)
-	/* Walnut boot rom sets DCR CHCR1 (aka CPC0_CR1) bit CETE to 1 */
-	mtdcr(DCRN_CHCR1, mfdcr(DCRN_CHCR1) & ~CHR1_CETE);
-#endif
-#ifdef CONFIG_REDWOOD_5
-	freq = bip->bi_tbfreq;
-#else
-	freq = bip->bi_intfreq;
-
-#endif
-
-	tb_ticks_per_jiffy = freq / HZ;
-	tb_to_us = mulhwu_scale_factor(freq, 1000000);
-
-	/* Set the time base to zero.
-	   ** At 200 Mhz, time base will rollover in ~2925 years.
-	 */
-
-	mtspr(SPRN_TBWL, 0);
-	mtspr(SPRN_TBWU, 0);
-
-	/* Clear any pending timer interrupts */
-
-	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
-	mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
-
-	/* Set the PIT reload value and just let it run. */
-	mtspr(SPRN_PIT, tb_ticks_per_jiffy);
-}
-
-#ifdef CONFIG_DEBUG_TEXT
-static void
-ppc4xx_progress(char *s, unsigned short hex)
-{
-	printk("%s\n\r", s);
-}
-#endif
-
-/*
- * IDE stuff.
- * should be generic for every IDE PCI chipset
- */
-#ifdef  CONFIG_PCI
-static void
-ppc4xx_ide_init_hwif_ports(hw_regs_t * hw, ide_ioreg_t data_port,
-			   ide_ioreg_t ctrl_port, int *irq)
-{
-	int i;
-
-	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
-		hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
-
-	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
-}
-#endif
-
-TODC_ALLOC();
-
-/*
- * 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.
- */
-void __init
-platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
-	      unsigned long r6, unsigned long r7)
-{
-	parse_bootinfo(find_bootinfo());
-
-	/*
-	 * 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));
-	}
-#if defined(CONFIG_PPC405_WDT)
-/* Look for wdt= option on command line */
-	if (strstr(cmd_line, "wdt=")) {
-		int valid_wdt = 0;
-		char *p, *q;
-		for (q = cmd_line; (p = strstr(q, "wdt=")) != 0;) {
-			q = p + 4;
-			if (p > cmd_line && p[-1] != ' ')
-				continue;
-			wdt_period = simple_strtoul(q, &q, 0);
-			valid_wdt = 1;
-			++q;
-		}
-		wdt_enable = valid_wdt;
-	}
-#endif
-
-	/* Initialize machine-dependency vectors */
-
-	ppc_md.setup_arch = ppc4xx_setup_arch;
-	ppc_md.show_percpuinfo = ppc4xx_show_percpuinfo;
-	ppc_md.show_cpuinfo = ppc4xx_show_cpuinfo;
-	ppc_md.init_IRQ = ppc4xx_init_IRQ;
-
-	ppc_md.restart = ppc4xx_restart;
-	ppc_md.power_off = ppc4xx_power_off;
-	ppc_md.halt = ppc4xx_halt;
-
-	ppc_md.calibrate_decr = ppc4xx_calibrate_decr;
-
-#ifdef CONFIG_PPC405_WDT
-	ppc_md.heartbeat = ppc4xx_wdt_heartbeat;
-#endif
-	ppc_md.heartbeat_count = 0;
-
-	ppc_md.find_end_of_memory = ppc4xx_find_end_of_memory;
-	ppc_md.setup_io_mappings = m4xx_map_io;
-
-#ifdef CONFIG_DEBUG_TEXT
-	ppc_md.progress = ppc4xx_progress;
-#endif
-
-/*
-**   m8xx_setup.c, prep_setup.c use
-**     defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
-*/
-#ifdef CONFIG_IDE
-# ifdef CONFIG_PCI
-	ppc_ide_md.ide_init_hwif = ppc4xx_ide_init_hwif_ports;
-# endif
-#endif
-	board_init();
-
-	return;
-}
diff -Nru a/arch/ppc/kernel/ppc6xx_idle.c b/arch/ppc/kernel/ppc6xx_idle.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/kernel/ppc6xx_idle.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,76 @@
+/*
+ * BK Id: %F% %I% %G% %U% %#%
+ */
+/*
+ * power_save() rountine for classic PPC CPUs.
+ *
+ * Written by Cort Dougan (cort@cs.nmt.edu)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ */
+#include <linux/sched.h>
+#include <linux/smp.h>
+#include <linux/stringify.h>
+
+#include <asm/cputable.h>
+#include <asm/current.h>
+#include <asm/processor.h>
+
+unsigned long powersave_nap = 0;
+
+#define DSSALL		.long	(0x1f<<26)+(0x10<<21)+(0x336<<1)
+
+void
+ppc6xx_idle(void)
+{
+	unsigned long hid0;
+	int nap = powersave_nap;
+
+	/* 7450 has no DOZE mode mode, we return if powersave_nap
+	 * isn't enabled
+	 */
+	if (!(nap || (cur_cpu_spec[smp_processor_id()]->cpu_features
+		      & CPU_FTR_CAN_DOZE)))
+		return;
+	/*
+	 * Disable interrupts to prevent a lost wakeup
+	 * when going to sleep.  This is necessary even with
+	 * RTLinux since we are not guaranteed an interrupt
+	 * didn't come in and is waiting for a __sti() before
+	 * emulating one.  This way, we really do hard disable.
+	 *
+	 * We assume that we're sti-ed when we come in here.  We
+	 * are in the idle loop so if we're cli-ed then it's a bug
+	 * anyway.
+	 *  -- Cort
+	 */
+	_nmask_and_or_msr(MSR_EE, 0);
+	if (!need_resched()) {
+		__asm__ __volatile__("mfspr %0,1008":"=r"(hid0):);
+		hid0 &= ~(HID0_NAP | HID0_SLEEP | HID0_DOZE);
+		hid0 |= (powersave_nap ? HID0_NAP : HID0_DOZE) | HID0_DPM;
+		__asm__ __volatile__("mtspr 1008,%0"::"r"(hid0));
+		/* Flush pending data streams, consider this instruction
+		 * exist on all altivec capable CPUs
+		 */
+		__asm__ __volatile__("98:	" __stringify(DSSALL) "\n"
+				     "	sync\n"
+				     "99:\n"
+				     ".section __ftr_fixup,\"a\"\n"
+				     "	.long %0\n"
+				     "	.long %1\n"
+				     "	.long 98b\n"
+				     "	.long 99b\n"
+				     ".previous"::"i"
+				     (CPU_FTR_ALTIVEC), "i"(CPU_FTR_ALTIVEC));
+
+		/* set the POW bit in the MSR, and enable interrupts
+		 * so we wake up sometime! */
+		_nmask_and_or_msr(0, MSR_POW | MSR_EE);
+	}
+	_nmask_and_or_msr(0, MSR_EE);
+}
diff -Nru a/arch/ppc/kernel/ppc8260_pic.c b/arch/ppc/kernel/ppc8260_pic.c
--- a/arch/ppc/kernel/ppc8260_pic.c	Sun Nov 10 19:28:40 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,131 +0,0 @@
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <asm/irq.h>
-#include <asm/immap_8260.h>
-#include <asm/mpc8260.h>
-#include "ppc8260_pic.h"
-
-/* The 8260 internal interrupt controller.  It is usually
- * the only interrupt controller.
- * There are two 32-bit registers (high/low) for up to 64
- * possible interrupts.
- *
- * Now, the fun starts.....Interrupt Numbers DO NOT MAP
- * in a simple arithmetic fashion to mask or pending registers.
- * That is, interrupt 4 does not map to bit position 4.
- * We create two tables, indexed by vector number, to indicate
- * which register to use and which bit in the register to use.
- */
-static	u_char	irq_to_siureg[] = {
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0
-};
-
-static	u_char	irq_to_siubit[] = {
-	31, 16, 17, 18, 19, 20, 21, 22,
-	23, 24, 25, 26, 27, 28, 29, 30,
-	29, 30, 16, 17, 18, 19, 20, 21,
-	22, 23, 24, 25, 26, 27, 28, 31,
-	 0,  1,  2,  3,  4,  5,  6,  7,
-	 8,  9, 10, 11, 12, 13, 14, 15,
-	15, 14, 13, 12, 11, 10,  9,  8,
-	 7,  6,  5,  4,  3,  2,  1,  0
-};
-
-static void m8260_mask_irq(unsigned int irq_nr)
-{
-	int	bit, word;
-	volatile uint	*simr;
-
-	bit = irq_to_siubit[irq_nr];
-	word = irq_to_siureg[irq_nr];
-
-	simr = &(immr->im_intctl.ic_simrh);
-	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
-	simr[word] = ppc_cached_irq_mask[word];
-}
-
-static void m8260_unmask_irq(unsigned int irq_nr)
-{
-	int	bit, word;
-	volatile uint	*simr;
-
-	bit = irq_to_siubit[irq_nr];
-	word = irq_to_siureg[irq_nr];
-
-	simr = &(immr->im_intctl.ic_simrh);
-	ppc_cached_irq_mask[word] |= (1 << (31 - bit));
-	simr[word] = ppc_cached_irq_mask[word];
-}
-
-static void m8260_mask_and_ack(unsigned int irq_nr)
-{
-	int	bit, word;
-	volatile uint	*simr, *sipnr;
-
-	bit = irq_to_siubit[irq_nr];
-	word = irq_to_siureg[irq_nr];
-
-	simr = &(immr->im_intctl.ic_simrh);
-	sipnr = &(immr->im_intctl.ic_sipnrh);
-	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
-	simr[word] = ppc_cached_irq_mask[word];
-	sipnr[word] = 1 << (31 - bit);
-}
-
-static void m8260_end_irq(unsigned int irq_nr)
-{
-	int	bit, word;
-	volatile uint	*simr;
-
-	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
-			&& irq_desc[irq_nr].action) {
-
-		bit = irq_to_siubit[irq_nr];
-		word = irq_to_siureg[irq_nr];
-
-		simr = &(immr->im_intctl.ic_simrh);
-		ppc_cached_irq_mask[word] |= (1 << (31 - bit));
-		simr[word] = ppc_cached_irq_mask[word];
-	}
-}
-
-struct hw_interrupt_type ppc8260_pic = {
-	" 8260 SIU  ",
-	NULL,
-	NULL,
-	m8260_unmask_irq,
-	m8260_mask_irq,
-	m8260_mask_and_ack,
-	m8260_end_irq,
-	0
-};
-
-
-int
-m8260_get_irq(struct pt_regs *regs)
-{
-	int irq;
-        unsigned long bits;
-
-        /* For MPC8260, read the SIVEC register and shift the bits down
-         * to get the irq number.         */
-        bits = immr->im_intctl.ic_sivec;
-        irq = bits >> 26;
-
-	if (irq == 0)
-		return(-1);
-#if 0
-        irq += ppc8260_pic.irq_offset;
-#endif
-	return irq;
-}
-
diff -Nru a/arch/ppc/kernel/ppc8260_pic.h b/arch/ppc/kernel/ppc8260_pic.h
--- a/arch/ppc/kernel/ppc8260_pic.h	Sun Nov 10 19:28:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,13 +0,0 @@
-#ifndef _PPC_KERNEL_PPC8260_H
-#define _PPC_KERNEL_PPC8260_H
-
-#include <linux/irq.h>
-
-extern struct hw_interrupt_type ppc8260_pic;
-
-void m8260_pic_init(void);
-void m8260_do_IRQ(struct pt_regs *regs,
-                 int            cpu);
-int m8260_get_irq(struct pt_regs *regs);
-
-#endif /* _PPC_KERNEL_PPC8260_H */
diff -Nru a/arch/ppc/kernel/ppc8xx_pic.c b/arch/ppc/kernel/ppc8xx_pic.c
--- a/arch/ppc/kernel/ppc8xx_pic.c	Sun Nov 10 19:28:38 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,197 +0,0 @@
-#include <linux/config.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <asm/irq.h>
-#include <asm/8xx_immap.h>
-#include <asm/mpc8xx.h>
-#include "ppc8xx_pic.h"
-
-/* The 8xx internal interrupt controller.  It is usually
- * the only interrupt controller.  Some boards, like the MBX and
- * Sandpoint have the 8259 as a secondary controller.  Depending
- * upon the processor type, the internal controller can have as
- * few as 16 interrups or as many as 64.  We could use  the
- * "clear_bit()" and "set_bit()" functions like other platforms,
- * but they are overkill for us.
- */
-
-static void m8xx_mask_irq(unsigned int irq_nr)
-{
-	int	bit, word;
-
-	bit = irq_nr & 0x1f;
-	word = irq_nr >> 5;
-
-	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
-						ppc_cached_irq_mask[word];
-}
-
-static void m8xx_unmask_irq(unsigned int irq_nr)
-{
-	int	bit, word;
-
-	bit = irq_nr & 0x1f;
-	word = irq_nr >> 5;
-
-	ppc_cached_irq_mask[word] |= (1 << (31-bit));
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
-						ppc_cached_irq_mask[word];
-}
-
-static void m8xx_end_irq(unsigned int irq_nr)
-{
-	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
-			&& irq_desc[irq_nr].action) {
-		int bit, word;
-
-		bit = irq_nr & 0x1f;
-		word = irq_nr >> 5;
-
-		ppc_cached_irq_mask[word] |= (1 << (31-bit));
-		((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = 
-			ppc_cached_irq_mask[word];
-	}
-}
-
-
-static void m8xx_mask_and_ack(unsigned int irq_nr)
-{
-	int	bit, word;
-
-	bit = irq_nr & 0x1f;
-	word = irq_nr >> 5;
-
-	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
-						ppc_cached_irq_mask[word];
-	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-bit);
-}
-
-struct hw_interrupt_type ppc8xx_pic = {
-	" 8xx SIU  ",
-	NULL,
-	NULL,
-	m8xx_unmask_irq,
-	m8xx_mask_irq,
-	m8xx_mask_and_ack,
-	m8xx_end_irq,
-	0
-};
-
-#if 0
-void
-m8xx_do_IRQ(struct pt_regs *regs,
-	   int            cpu)
-{
-	int irq;
-        unsigned long bits = 0;
-
-        /* For MPC8xx, read the SIVEC register and shift the bits down
-         * to get the irq number.         */
-        bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
-        irq = bits >> 26;
-#if 0
-        irq += ppc8xx_pic.irq_offset;
-#endif
-        bits = 1UL << irq;
-
-	if (irq < 0) {
-		printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
-		       irq, regs->nip);
-		ppc_spurious_interrupts++;
-	}
-	else {
-                ppc_irq_dispatch_handler( regs, irq );
-	}
-
-}
-#endif
-
-
-/*
- * We either return a valid interrupt or -1 if there is nothing pending
- */
-int
-m8xx_get_irq(struct pt_regs *regs)
-{
-	int irq;
-
-	/* For MPC8xx, read the SIVEC register and shift the bits down
-	 * to get the irq number.
-	 */
-	irq = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec >> 26;
-
-	/*
-	 * When we read the sivec without an interrupt to process, we will 
-	 * get back SIU_LEVEL7.  In this case, return -1
-	 */
-	if (irq == SIU_LEVEL7)
-		return -1;
-
-	return irq;
-}
-
-/* The MBX is the only 8xx board that uses the 8259.
-*/
-#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
-void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
-	int bits, irq;
-
-	/* A bug in the QSpan chip causes it to give us 0xff always
-	 * when doing a character read.  So read 32 bits and shift.
-	 * This doesn't seem to return useful values anyway, but
-	 * read it to make sure things are acked.
-	 * -- Cort
-	 */
-	irq = (inl(0x508) >> 24)&0xff;
-	if ( irq != 0xff ) printk("iack %d\n", irq);
-	
-	outb(0x0C, 0x20);
-	irq = inb(0x20) & 7;
-	if (irq == 2)
-	{
-		outb(0x0C, 0xA0);
-		irq = inb(0xA0);
-		irq = (irq&7) + 8;
-	}
-	bits = 1UL << irq;
-	irq += i8259_pic.irq_offset;
-	ppc_irq_dispatch_handler( regs, irq );
-}
-#endif
-
-/* Only the MBX uses the external 8259.  This allows us to catch standard
- * drivers that may mess up the internal interrupt controllers, and also
- * allow them to run without modification on the MBX.
- */
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
-	unsigned long irqflags, const char * devname, void *dev_id)
-{
-
-#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
-	irq += i8259_pic.irq_offset;
-	return (request_8xxirq(irq, handler, irqflags, devname, dev_id));
-#else
-	/*
-	 * Handle other "well-known" interrupts, but panic on unknown ones.
-	 */
-	switch (irq) {
-#ifdef	IDE0_INTERRUPT
-		case IDE0_INTERRUPT:	/* IDE0 */
-			return (request_8xxirq(irq, handler, irqflags, devname,
-						dev_id));
-#endif
-#ifdef	IDE1_INTERRUPT
-		case IDE1_INTERRUPT:	/* IDE1 */
-			return (request_8xxirq(irq, handler, irqflags, devname,
-						dev_id));
-#endif
-	default:			/* unknown IRQ -> panic */
-		panic("request_irq");
-	}
-#endif
-}
diff -Nru a/arch/ppc/kernel/ppc8xx_pic.h b/arch/ppc/kernel/ppc8xx_pic.h
--- a/arch/ppc/kernel/ppc8xx_pic.h	Sun Nov 10 19:28:39 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,20 +0,0 @@
-#ifndef _PPC_KERNEL_PPC8xx_H
-#define _PPC_KERNEL_PPC8xx_H
-
-#include <linux/config.h>
-#include <linux/irq.h>
-
-extern struct hw_interrupt_type ppc8xx_pic;
-
-void m8xx_pic_init(void);
-void m8xx_do_IRQ(struct pt_regs *regs,
-                 int            cpu);
-int m8xx_get_irq(struct pt_regs *regs);
-
-#ifdef CONFIG_MBX
-#include <asm/i8259.h>
-#include <asm/io.h>
-void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs);
-#endif
-
-#endif /* _PPC_KERNEL_PPC8xx_H */
diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c
--- a/arch/ppc/kernel/ppc_ksyms.c	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/kernel/ppc_ksyms.c	Sun Nov 10 19:28:41 2002
@@ -44,6 +44,7 @@
 #include <asm/time.h>
 #include <asm/cputable.h>
 #include <asm/btext.h>
+#include <asm/div64.h>
 
 #ifdef  CONFIG_8xx
 #include <asm/commproc.h>
@@ -119,6 +120,7 @@
 EXPORT_SYMBOL(strcmp);
 EXPORT_SYMBOL(strncmp);
 EXPORT_SYMBOL(strcasecmp);
+EXPORT_SYMBOL(__div64_32);
 
 /* EXPORT_SYMBOL(csum_partial); already in net/netsyms.c */
 EXPORT_SYMBOL(csum_partial_copy_generic);
@@ -195,7 +197,6 @@
 EXPORT_SYMBOL(flush_icache_range);
 EXPORT_SYMBOL(flush_dcache_range);
 EXPORT_SYMBOL(flush_icache_user_range);
-EXPORT_SYMBOL(flush_icache_page);
 EXPORT_SYMBOL(flush_dcache_page);
 #ifdef CONFIG_ALTIVEC
 EXPORT_SYMBOL(last_task_used_altivec);
diff -Nru a/arch/ppc/kernel/pplus_common.c b/arch/ppc/kernel/pplus_common.c
--- a/arch/ppc/kernel/pplus_common.c	Sun Nov 10 19:28:40 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,317 +0,0 @@
-/*
- * arch/ppc/kernel/pplus_common.c
- * 
- * Common Motorola PowerPlus Platform--really Falcon/Raven or HAWK.
- *
- * Author: Mark A. Greer
- *         mgreer@mvista.com
- *
- * Copyright 2001 MontaVista Software 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.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/pci.h>
-#include <asm/pci-bridge.h>
-#include <asm/open_pic.h>
-#include <asm/pplus.h>
-
-/*
- * The Falcon/Raven and HAWK has 4 sets of registers:
- *   1) PPC Registers which define the mappings from PPC bus to PCI bus,
- *      etc.
- *   2) PCI Registers which define the mappings from PCI bus to PPC bus and the
- *      MPIC base address.
- *   3) MPIC registers.
- *   4) System Memory Controller (SMC) registers.
- */
-
-/*
- * Initialize the Motorola MCG Raven or HAWK host bridge.
- *
- * This means setting up the PPC bus to PCI memory and I/O space mappings,
- * setting the PCI memory space address of the MPIC (mapped straight
- * through), and ioremap'ing the mpic registers.
- * This routine will set the PCI_CONFIG_ADDR or PCI_CONFIG_DATA
- * addresses based on the PCI I/O address that is passed in.
- * 'OpenPIC_Addr' will be set correctly by this routine.
- */
-int __init
-pplus_init(struct pci_controller *hose,
-	     uint ppc_reg_base,
-	     ulong processor_pci_mem_start,
-	     ulong processor_pci_mem_end,
-	     ulong processor_pci_io_start,
-	     ulong processor_pci_io_end,
-	     ulong processor_mpic_base)
-{
-	uint		addr, offset;
-
-	/*
-	 * Some sanity checks...
-	 */
-	if (((processor_pci_mem_start&0xffff0000) != processor_pci_mem_start) ||
-	    ((processor_pci_io_start &0xffff0000) != processor_pci_io_start)) {
-		printk("pplus_init: %s\n",
-			"PPC to PCI mappings must start on 64 KB boundaries");
-		return -1;
-	}
-
-	if (((processor_pci_mem_end  &0x0000ffff) != 0x0000ffff) ||
-	    ((processor_pci_io_end   &0x0000ffff) != 0x0000ffff)) {
-		printk("pplus_init: PPC to PCI mappings %s\n",
-			"must end just before a 64 KB boundaries");
-		return -1;
-	}
-
-	if (((processor_pci_mem_end - processor_pci_mem_start) !=
-	     (hose->mem_space.end - hose->mem_space.start)) ||
-	    ((processor_pci_io_end - processor_pci_io_start) !=
-	     (hose->io_space.end - hose->io_space.start))) {
-		printk("pplus_init: %s\n",
-			"PPC and PCI memory or I/O space sizes don't match");
-		return -1;
-	}
-
-	if ((processor_mpic_base & 0xfffc0000) != processor_mpic_base) {
-		printk("pplus_init: %s\n",
-			"MPIC address must start on 256 MB boundary");
-		return -1;
-	}
-
-	if ((pci_dram_offset & 0xffff0000) != pci_dram_offset) {
-		printk("pplus_init: %s\n",
-			"pci_dram_offset must be multiple of 64 KB");
-		return -1;
-	}
-
-	/*
-	 * Disable previous PPC->PCI mappings.
-	 */
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF0_OFF), 0x00000000);
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF1_OFF), 0x00000000);
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF2_OFF), 0x00000000);
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF3_OFF), 0x00000000);
-
-	/*
-	 * Program the XSADD/XSOFF registers to set up the PCI Mem & I/O
-	 * space mappings.  These are the mappings going from the processor to
-	 * the PCI bus.
-	 *
-	 * Note: Don't need to 'AND' start/end addresses with 0xffff0000
-	 *	 because sanity check above ensures that they are properly
-	 *	 aligned.
-	 */
-
-	/* Set up PPC->PCI Mem mapping */
-	addr = processor_pci_mem_start | (processor_pci_mem_end >> 16);
-	offset = (hose->mem_space.start - processor_pci_mem_start) | 0xd2;
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD0_OFF), addr);
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF0_OFF), offset);
-
-	/* Set up PPC->MPIC mapping on the bridge */
-	addr = processor_mpic_base |
-	        (((processor_mpic_base + PPLUS_MPIC_SIZE) >> 16) - 1);
-	offset = 0xc2; /* No write posting for this PCI Mem space */
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD1_OFF), addr);
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF1_OFF), offset);
-
-	/* Set up PPC->PCI I/O mapping -- Contiguous I/O space */
-	addr = processor_pci_io_start | (processor_pci_io_end >> 16);
-	offset = (hose->io_space.start - processor_pci_io_start) | 0xc0;
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD3_OFF), addr);
-	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF3_OFF), offset);
-
-	hose->io_base_virt = (void *)ioremap(processor_pci_io_start,
-			(processor_pci_io_end - processor_pci_io_start + 1));
-
-	/*
-	 * Set up the indirect method of accessing PCI config space.
-	 * The PCI config addr/data pair based on start addr of PCI I/O space.
-	 */
-	setup_indirect_pci(hose,
-			   processor_pci_io_start + PPLUS_PCI_CONFIG_ADDR_OFF,
-			   processor_pci_io_start + PPLUS_PCI_CONFIG_DATA_OFF);
-
-	/*
-	 * Disable previous PCI->PPC mappings.
-	 */
-
-	/* XXXX Put in mappings from PCI bus to processor bus XXXX */
-
-	/*
-	 * Disable MPIC response to PCI I/O space (BAR 0).
-	 * Make MPIC respond to PCI Mem space at specified address.
-	 * (BAR 1).
-	 */
-	early_write_config_dword(hose,
-			         0,
-			         PCI_DEVFN(0,0),
-			         PCI_BASE_ADDRESS_0,
-			         0x00000000 | 0x1);
-
-	early_write_config_dword(hose,
-			         0,
-			         PCI_DEVFN(0,0),
-			         PCI_BASE_ADDRESS_1,
-			         processor_mpic_base | 0x0);
-
-	/* Map MPIC into vitual memory */
-	OpenPIC_Addr = ioremap(processor_mpic_base, PPLUS_MPIC_SIZE);
-
-	return 0;
-}
-
-/*
- * Find the amount of RAM present.
- * This assumes that PPCBug has initialized the memory controller (SMC)
- * on the Falcon/HAWK correctly (i.e., it does no sanity checking).
- * It also assumes that the memory base registers are set to configure the
- * memory as contigous starting with "RAM A BASE", "RAM B BASE", etc.
- * however, RAM base registers can be skipped (e.g. A, B, C are set,
- * D is skipped but E is set is okay).
- */
-#define	MB	(1024*1024)
-
-static uint reg_offset_table[] __initdata = {
-	PPLUS_SMC_RAM_A_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_B_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_C_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_D_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_E_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_F_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_G_SIZE_REG_OFF,
-	PPLUS_SMC_RAM_H_SIZE_REG_OFF
-};
-
-static uint falcon_size_table[] __initdata = {
-	   0 * MB, /* 0 ==>    0 MB */
-	  16 * MB, /* 1 ==>   16 MB */
-	  32 * MB, /* 2 ==>   32 MB */
-	  64 * MB, /* 3 ==>   64 MB */
-	 128 * MB, /* 4 ==>  128 MB */
-	 256 * MB, /* 5 ==>  256 MB */
-        1024 * MB, /* 6 ==> 1024 MB (1 GB) */
-};
-
-static uint hawk_size_table[] __initdata = {
-	  0 * MB, /* 0 ==>    0 MB */
-	 32 * MB, /* 1 ==>   32 MB */
-	 64 * MB, /* 2 ==>   64 MB */
-	 64 * MB, /* 3 ==>   64 MB */
-	128 * MB, /* 4 ==>  128 MB */
-	128 * MB, /* 5 ==>  128 MB */
-	128 * MB, /* 6 ==>  128 MB */
-	256 * MB, /* 7 ==>  256 MB */
-	256 * MB, /* 8 ==>  256 MB */
-	512 * MB, /* 9 ==>  512 MB */
-};
-
-/*
- * *** WARNING: You MUST have a BAT set up to map in the SMC regs ***
- *
- * Read the memory controller's registers to determine the amount of system
- * memory.  Assumes that the memory controller registers are already mapped
- * into virtual memory--too early to use ioremap().
- */
-unsigned long __init
-pplus_get_mem_size(uint smc_base)
-{
-	unsigned long	total;
-	int		i, size_table_entries, reg_limit;
-	uint		vend_dev_id;
-	uint		*size_table;
-	u_char		val;
-
-
-	vend_dev_id = in_be32((uint *)smc_base + PCI_VENDOR_ID);
-
-	if (((vend_dev_id & 0xffff0000) >> 16) != PCI_VENDOR_ID_MOTOROLA) {
-		printk("pplus_get_mem_size: %s (0x%x)\n",
-			"Not a Motorola Memory Controller", vend_dev_id);
-		return 0;
-	}
-
-	vend_dev_id &= 0x0000ffff;
-
-	if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_FALCON) {
-		size_table = falcon_size_table;
-		size_table_entries = sizeof(falcon_size_table) /
-				     sizeof(falcon_size_table[0]);
-
-		reg_limit = PPLUS_FALCON_SMC_REG_COUNT;
-	}
-	else if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_HAWK) {
-		size_table = hawk_size_table;
-		size_table_entries = sizeof(hawk_size_table) /
-				     sizeof(hawk_size_table[0]);
-		reg_limit = PPLUS_HAWK_SMC_REG_COUNT;
-	}
-	else {
-		printk("pplus_get_mem_size: %s (0x%x)\n",
-			"Not a Falcon or HAWK", vend_dev_id);
-		return 0;
-	}
-
-	total = 0;
-
-	/* Check every reg because PPCBug may skip some */
-	for (i=0; i<reg_limit; i++) {
-		val = in_8((u_char *)(smc_base + reg_offset_table[i]));
-
-		if (val & 0x80) {	/* If enabled */
-			val &= 0x0f;
-
-			/* Don't go past end of size_table */
-			if (val < size_table_entries) {
-				total += size_table[val];
-			}
-			else {	/* Register not set correctly */
-				break;
-			}
-		}
-	}
-
-	return total;
-}
-
-int __init
-pplus_mpic_init(unsigned int pci_mem_offset)
-{
-	unsigned short	devid;
-	unsigned int	pci_membase;
-
-	/* Check the first PCI device to see if it is a Raven or Hawk. */
-	early_read_config_word(0, 0, 0, PCI_DEVICE_ID, &devid);
-
-	switch (devid) {
-	case PCI_DEVICE_ID_MOTOROLA_RAVEN:
-	case PCI_DEVICE_ID_MOTOROLA_HAWK:
-		break;
-	default:
-		OpenPIC_Addr = NULL;
-		return 1;
-	}
-
-	/* 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 1;
-	}
-
-	/* Map the MPIC registers to virtual memory. */
-	OpenPIC_Addr = ioremap(pci_membase + pci_mem_offset, 0x22000);
-
-	return 0;
-}
diff -Nru a/arch/ppc/kernel/prep_nvram.c b/arch/ppc/kernel/prep_nvram.c
--- a/arch/ppc/kernel/prep_nvram.c	Sun Nov 10 19:28:39 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,145 +0,0 @@
-/*
- * arch/ppc/kernel/prep_nvram.c
- *
- * Copyright (C) 1998  Corey Minyard
- *
- * This reads the NvRAM on PReP compliant machines (generally from IBM or
- * Motorola).  Motorola kept the format of NvRAM in their ROM, PPCBUG, the
- * same, long after they had stopped producing PReP compliant machines.  So
- * this code is useful in those cases as well.
- *
- */
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include <linux/ioport.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>
-
-static char nvramData[MAX_PREP_NVRAM];
-static NVRAM_MAP *nvram=(NVRAM_MAP *)&nvramData[0];
-
-unsigned char __prep prep_nvram_read_val(int addr)
-{
-	outb(addr, PREP_NVRAM_AS0);
-	outb(addr>>8, PREP_NVRAM_AS1);
-	return inb(PREP_NVRAM_DATA);
-}
-  
-void __prep prep_nvram_write_val(int           addr,
-			  unsigned char val)
-{
-	outb(addr, PREP_NVRAM_AS0);
-	outb(addr>>8, PREP_NVRAM_AS1);
-   	outb(val, PREP_NVRAM_DATA);
-}
-  
-void __init init_prep_nvram(void)
-{
-	unsigned char *nvp;
-	int  i;
-	int  nvramSize;
-
-	/*
-	 * The following could fail if the NvRAM were corrupt but
-	 * we expect the boot firmware to have checked its checksum
-	 * before boot
-	 */
-	nvp = (char *) &nvram->Header;
-	for (i=0; i<sizeof(HEADER); i++)
-	{
-		*nvp = ppc_md.nvram_read_val(i);
-		nvp++;
-	}
-	
-	/*
-	 * The PReP NvRAM may be any size so read in the header to
-	 * determine how much we must read in order to get the complete
-	 * GE area
-	 */
-	nvramSize=(int)nvram->Header.GEAddress+nvram->Header.GELength;
-	if(nvramSize>MAX_PREP_NVRAM)
-	{
-		/*
-		 * NvRAM is too large
-		 */
-		nvram->Header.GELength=0;
-		return;
-	}
-
-	/*
-	 * Read the remainder of the PReP NvRAM
-	 */
-	nvp = (char *) &nvram->GEArea[0];
-	for (i=sizeof(HEADER); i<nvramSize; i++)
-	{
-		*nvp = ppc_md.nvram_read_val(i);
-		nvp++;
-	}
-}
-
-__prep
-char __prep *prep_nvram_get_var(const char *name)
-{
-	char *cp;
-	int  namelen;
-
-	namelen = strlen(name);
-	cp = prep_nvram_first_var();
-	while (cp != NULL) {
-		if ((strncmp(name, cp, namelen) == 0)
-		    && (cp[namelen] == '='))
-		{
-			return cp+namelen+1;
-		}
-		cp = prep_nvram_next_var(cp);
-	}
-
-	return NULL;
-}
-
-__prep
-char __prep *prep_nvram_first_var(void)
-{
-        if (nvram->Header.GELength == 0) {
-		return NULL;
-	} else {
-		return (((char *)nvram)
-			+ ((unsigned int) nvram->Header.GEAddress));
-	}
-}
-
-__prep
-char __prep *prep_nvram_next_var(char *name)
-{
-	char *cp;
-
-
-	cp = name;
-	while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength)
-	       && (*cp != '\0'))
-	{
-		cp++;
-	}
-
-	/* Skip over any null characters. */
-	while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength)
-	       && (*cp == '\0'))
-	{
-		cp++;
-	}
-
-	if ((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength) {
-		return cp;
-	} else {
-		return NULL;
-	}
-}
-
-
-
diff -Nru a/arch/ppc/kernel/prom.c b/arch/ppc/kernel/prom.c
--- a/arch/ppc/kernel/prom.c	Sun Nov 10 19:28:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1258 +0,0 @@
-/*
- * Procedures for interfacing to the Open Firmware PROM on
- * Power Macintosh computers.
- *
- * In particular, we are interested in the device tree
- * and in using some of its services (exit, write to stdout).
- *
- * Paul Mackerras	August 1996.
- * Copyright (C) 1996 Paul Mackerras.
- */
-#include <stdarg.h>
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/version.h>
-#include <linux/threads.h>
-#include <linux/spinlock.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/sections.h>
-#include <asm/prom.h>
-#include <asm/page.h>
-#include <asm/processor.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/bootx.h>
-#include <asm/system.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/btext.h>
-#include <asm/pci-bridge.h>
-#include <asm/open_pic.h>
-
-#ifdef CONFIG_FB
-#include <asm/linux_logo.h>
-#endif
-
-struct pci_address {
-	unsigned a_hi;
-	unsigned a_mid;
-	unsigned a_lo;
-};
-
-struct pci_reg_property {
-	struct pci_address addr;
-	unsigned size_hi;
-	unsigned size_lo;
-};
-
-struct isa_reg_property {
-	unsigned space;
-	unsigned address;
-	unsigned size;
-};
-
-typedef unsigned long interpret_func(struct device_node *, unsigned long,
-				     int, int);
-static interpret_func interpret_pci_props;
-static interpret_func interpret_dbdma_props;
-static interpret_func interpret_isa_props;
-static interpret_func interpret_macio_props;
-static interpret_func interpret_root_props;
-
-extern char *klimit;
-
-/* Set for a newworld or CHRP machine */
-int use_of_interrupt_tree;
-struct device_node *dflt_interrupt_controller;
-int num_interrupt_controllers;
-
-int pmac_newworld;
-
-extern unsigned int rtas_entry;  /* physical pointer */
-
-extern struct device_node *allnodes;
-
-static unsigned long finish_node(struct device_node *, unsigned long,
-				 interpret_func *, int, int);
-static unsigned long finish_node_interrupts(struct device_node *, unsigned long);
-static struct device_node *find_phandle(phandle);
-
-extern void enter_rtas(void *);
-void phys_call_rtas(int, int, int, ...);
-
-extern char cmd_line[512];	/* XXX */
-extern boot_infos_t *boot_infos;
-unsigned long dev_tree_size;
-
-void __openfirmware
-phys_call_rtas(int service, int nargs, int nret, ...)
-{
-	va_list list;
-	union {
-		unsigned long words[16];
-		double align;
-	} u;
-	void (*rtas)(void *, unsigned long);
-	int i;
-
-	u.words[0] = service;
-	u.words[1] = nargs;
-	u.words[2] = nret;
-	va_start(list, nret);
-	for (i = 0; i < nargs; ++i)
-		u.words[i+3] = va_arg(list, unsigned long);
-	va_end(list);
-
-	rtas = (void (*)(void *, unsigned long)) rtas_entry;
-	rtas(&u, rtas_data);
-}
-
-/*
- * finish_device_tree is called once things are running normally
- * (i.e. with text and data mapped to the address they were linked at).
- * It traverses the device tree and fills in the name, type,
- * {n_}addrs and {n_}intrs fields of each node.
- */
-void __init
-finish_device_tree(void)
-{
-	unsigned long mem = (unsigned long) klimit;
-	struct device_node *np;
-
-	/* All newworld pmac machines and CHRPs now use the interrupt tree */
-	for (np = allnodes; np != NULL; np = np->allnext) {
-		if (get_property(np, "interrupt-parent", 0)) {
-			use_of_interrupt_tree = 1;
-			break;
-		}
-	}
-	if (_machine == _MACH_Pmac && use_of_interrupt_tree)
-		pmac_newworld = 1;
-
-#ifdef CONFIG_BOOTX_TEXT
-	if (boot_infos && pmac_newworld) {
-		prom_print("WARNING ! BootX/miBoot booting is not supported on this machine\n");
-		prom_print("          You should use an Open Firmware bootloader\n");
-	}
-#endif /* CONFIG_BOOTX_TEXT */
-
-	if (use_of_interrupt_tree) {
-		/*
-		 * We want to find out here how many interrupt-controller
-		 * nodes there are, and if we are booted from BootX,
-		 * we need a pointer to the first (and hopefully only)
-		 * such node.  But we can't use find_devices here since
-		 * np->name has not been set yet.  -- paulus
-		 */
-		int n = 0;
-		char *name, *ic;
-		int iclen;
-
-		for (np = allnodes; np != NULL; np = np->allnext) {
-			ic = get_property(np, "interrupt-controller", &iclen);
-			name = get_property(np, "name", NULL);
-			/* checking iclen makes sure we don't get a false
-			   match on /chosen.interrupt_controller */
-			if ((name != NULL
-			     && strcmp(name, "interrupt-controller") == 0)
-			    || (ic != NULL && iclen == 0)) {
-				if (n == 0)
-					dflt_interrupt_controller = np;
-				++n;
-			}
-		}
-		num_interrupt_controllers = n;
-	}
-
-	mem = finish_node(allnodes, mem, NULL, 1, 1);
-	dev_tree_size = mem - (unsigned long) allnodes;
-	klimit = (char *) mem;
-}
-
-static unsigned long __init
-finish_node(struct device_node *np, unsigned long mem_start,
-	    interpret_func *ifunc, int naddrc, int nsizec)
-{
-	struct device_node *child;
-	int *ip;
-
-	np->name = get_property(np, "name", 0);
-	np->type = get_property(np, "device_type", 0);
-
-	if (!np->name)
-		np->name = "<NULL>";
-	if (!np->type)
-		np->type = "<NULL>";
-
-	/* get the device addresses and interrupts */
-	if (ifunc != NULL)
-		mem_start = ifunc(np, mem_start, naddrc, nsizec);
-
-	if (use_of_interrupt_tree)
-		mem_start = finish_node_interrupts(np, mem_start);
-
-	/* Look for #address-cells and #size-cells properties. */
-	ip = (int *) get_property(np, "#address-cells", 0);
-	if (ip != NULL)
-		naddrc = *ip;
-	ip = (int *) get_property(np, "#size-cells", 0);
-	if (ip != NULL)
-		nsizec = *ip;
-
-	if (np->parent == NULL)
-		ifunc = interpret_root_props;
-	else if (np->type == 0)
-		ifunc = NULL;
-	else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
-		ifunc = interpret_pci_props;
-	else if (!strcmp(np->type, "dbdma"))
-		ifunc = interpret_dbdma_props;
-	else if (!strcmp(np->type, "mac-io")
-		 || ifunc == interpret_macio_props)
-		ifunc = interpret_macio_props;
-	else if (!strcmp(np->type, "isa"))
-		ifunc = interpret_isa_props;
-	else if (!strcmp(np->name, "uni-n"))
-		ifunc = interpret_root_props;
-	else if (!((ifunc == interpret_dbdma_props
-		    || ifunc == interpret_macio_props)
-		   && (!strcmp(np->type, "escc")
-		       || !strcmp(np->type, "media-bay"))))
-		ifunc = NULL;
-
-	/* if we were booted from BootX, convert the full name */
-	if (boot_infos
-	    && strncmp(np->full_name, "Devices:device-tree", 19) == 0) {
-		if (np->full_name[19] == 0) {
-			strcpy(np->full_name, "/");
-		} else if (np->full_name[19] == ':') {
-			char *p = np->full_name + 19;
-			np->full_name = p;
-			for (; *p; ++p)
-				if (*p == ':')
-					*p = '/';
-		}
-	}
-
-	for (child = np->child; child != NULL; child = child->sibling)
-		mem_start = finish_node(child, mem_start, ifunc,
-					naddrc, nsizec);
-
-	return mem_start;
-}
-
-/*
- * Find the interrupt parent of a node.
- */
-static struct device_node * __init
-intr_parent(struct device_node *p)
-{
-	phandle *parp;
-
-	parp = (phandle *) get_property(p, "interrupt-parent", NULL);
-	if (parp == NULL)
-		return p->parent;
-	p = find_phandle(*parp);
-	if (p != NULL)
-		return p;
-	/*
-	 * On a powermac booted with BootX, we don't get to know the
-	 * phandles for any nodes, so find_phandle will return NULL.
-	 * Fortunately these machines only have one interrupt controller
-	 * so there isn't in fact any ambiguity.  -- paulus
-	 */
-	if (num_interrupt_controllers == 1)
-		p = dflt_interrupt_controller;
-	return p;
-}
-
-/*
- * Find out the size of each entry of the interrupts property
- * for a node.
- */
-static int __init
-prom_n_intr_cells(struct device_node *np)
-{
-	struct device_node *p;
-	unsigned int *icp;
-
-	for (p = np; (p = intr_parent(p)) != NULL; ) {
-		icp = (unsigned int *)
-			get_property(p, "#interrupt-cells", NULL);
-		if (icp != NULL)
-			return *icp;
-		if (get_property(p, "interrupt-controller", NULL) != NULL
-		    || get_property(p, "interrupt-map", NULL) != NULL) {
-			printk("oops, node %s doesn't have #interrupt-cells\n",
-			       p->full_name);
-			return 1;
-		}
-	}
-	printk("prom_n_intr_cells failed for %s\n", np->full_name);
-	return 1;
-}
-
-/*
- * Map an interrupt from a device up to the platform interrupt
- * descriptor.
- */
-static int __init
-map_interrupt(unsigned int **irq, struct device_node **ictrler,
-	      struct device_node *np, unsigned int *ints, int nintrc)
-{
-	struct device_node *p, *ipar;
-	unsigned int *imap, *imask, *ip;
-	int i, imaplen, match;
-	int newintrc, newaddrc;
-	unsigned int *reg;
-	int naddrc;
-
-	reg = (unsigned int *) get_property(np, "reg", NULL);
-	naddrc = prom_n_addr_cells(np);
-	p = intr_parent(np);
-	while (p != NULL) {
-		if (get_property(p, "interrupt-controller", NULL) != NULL)
-			/* this node is an interrupt controller, stop here */
-			break;
-		imap = (unsigned int *)
-			get_property(p, "interrupt-map", &imaplen);
-		if (imap == NULL) {
-			p = intr_parent(p);
-			continue;
-		}
-		imask = (unsigned int *)
-			get_property(p, "interrupt-map-mask", NULL);
-		if (imask == NULL) {
-			printk("oops, %s has interrupt-map but no mask\n",
-			       p->full_name);
-			return 0;
-		}
-		imaplen /= sizeof(unsigned int);
-		match = 0;
-		ipar = NULL;
-		while (imaplen > 0 && !match) {
-			/* check the child-interrupt field */
-			match = 1;
-			for (i = 0; i < naddrc && match; ++i)
-				match = ((reg[i] ^ imap[i]) & imask[i]) == 0;
-			for (; i < naddrc + nintrc && match; ++i)
-				match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0;
-			imap += naddrc + nintrc;
-			imaplen -= naddrc + nintrc;
-			/* grab the interrupt parent */
-			ipar = find_phandle((phandle) *imap++);
-			--imaplen;
-			if (ipar == NULL && num_interrupt_controllers == 1)
-				/* cope with BootX not giving us phandles */
-				ipar = dflt_interrupt_controller;
-			if (ipar == NULL) {
-				printk("oops, no int parent %x in map of %s\n",
-				       imap[-1], p->full_name);
-				return 0;
-			}
-			/* find the parent's # addr and intr cells */
-			ip = (unsigned int *)
-				get_property(ipar, "#interrupt-cells", NULL);
-			if (ip == NULL) {
-				printk("oops, no #interrupt-cells on %s\n",
-				       ipar->full_name);
-				return 0;
-			}
-			newintrc = *ip;
-			ip = (unsigned int *)
-				get_property(ipar, "#address-cells", NULL);
-			newaddrc = (ip == NULL)? 0: *ip;
-			imap += newaddrc + newintrc;
-			imaplen -= newaddrc + newintrc;
-		}
-		if (imaplen < 0) {
-			printk("oops, error decoding int-map on %s, len=%d\n",
-			       p->full_name, imaplen);
-			return 0;
-		}
-		if (!match) {
-			printk("oops, no match in %s int-map for %s\n",
-			       p->full_name, np->full_name);
-			return 0;
-		}
-		p = ipar;
-		naddrc = newaddrc;
-		nintrc = newintrc;
-		ints = imap - nintrc;
-		reg = ints - naddrc;
-	}
-	if (p == NULL)
-		printk("hmmm, int tree for %s doesn't have ctrler\n",
-		       np->full_name);
-	*irq = ints;
-	*ictrler = p;
-	return nintrc;
-}
-
-/*
- * New version of finish_node_interrupts.
- */
-static unsigned long __init
-finish_node_interrupts(struct device_node *np, unsigned long mem_start)
-{
-	unsigned int *ints;
-	int intlen, intrcells;
-	int i, j, n, offset;
-	unsigned int *irq;
-	struct device_node *ic;
-
-	ints = (unsigned int *) get_property(np, "interrupts", &intlen);
-	if (ints == NULL)
-		return mem_start;
-	intrcells = prom_n_intr_cells(np);
-	intlen /= intrcells * sizeof(unsigned int);
-	np->n_intrs = intlen;
-	np->intrs = (struct interrupt_info *) mem_start;
-	mem_start += intlen * sizeof(struct interrupt_info);
-
-	for (i = 0; i < intlen; ++i) {
-		np->intrs[i].line = 0;
-		np->intrs[i].sense = 1;
-		n = map_interrupt(&irq, &ic, np, ints, intrcells);
-		if (n <= 0)
-			continue;
-		offset = 0;
-		/*
-		 * On a CHRP we have an 8259 which is subordinate to
-		 * the openpic in the interrupt tree, but we want the
-		 * openpic's interrupt numbers offsetted, not the 8259's.
-		 * So we apply the offset if the controller is at the
-		 * root of the interrupt tree, i.e. has no interrupt-parent.
-		 * This doesn't cope with the general case of multiple
-		 * cascaded interrupt controllers, but then neither will
-		 * irq.c at the moment either.  -- paulus
-		 */
-		if (num_interrupt_controllers > 1 && ic != NULL
-		    && get_property(ic, "interrupt-parent", NULL) == NULL)
-			offset = 16;
-		np->intrs[i].line = irq[0] + offset;
-		if (n > 1)
-			np->intrs[i].sense = irq[1];
-		if (n > 2) {
-			printk("hmmm, got %d intr cells for %s:", n,
-			       np->full_name);
-			for (j = 0; j < n; ++j)
-				printk(" %d", irq[j]);
-			printk("\n");
-		}
-		ints += intrcells;
-	}
-
-	return mem_start;
-}
-
-/*
- * When BootX makes a copy of the device tree from the MacOS
- * Name Registry, it is in the format we use but all of the pointers
- * are offsets from the start of the tree.
- * This procedure updates the pointers.
- */
-void __init
-relocate_nodes(void)
-{
-	unsigned long base;
-	struct device_node *np;
-	struct property *pp;
-
-#define ADDBASE(x)	(x = (x)? ((typeof (x))((unsigned long)(x) + base)): 0)
-
-	base = (unsigned long) boot_infos + boot_infos->deviceTreeOffset;
-	allnodes = (struct device_node *)(base + 4);
-	for (np = allnodes; np != 0; np = np->allnext) {
-		ADDBASE(np->full_name);
-		ADDBASE(np->properties);
-		ADDBASE(np->parent);
-		ADDBASE(np->child);
-		ADDBASE(np->sibling);
-		ADDBASE(np->allnext);
-		for (pp = np->properties; pp != 0; pp = pp->next) {
-			ADDBASE(pp->name);
-			ADDBASE(pp->value);
-			ADDBASE(pp->next);
-		}
-	}
-}
-
-int
-prom_n_addr_cells(struct device_node* np)
-{
-	int* ip;
-	do {
-		if (np->parent)
-			np = np->parent;
-		ip = (int *) get_property(np, "#address-cells", 0);
-		if (ip != NULL)
-			return *ip;
-	} while (np->parent);
-	/* No #address-cells property for the root node, default to 1 */
-	return 1;
-}
-
-int
-prom_n_size_cells(struct device_node* np)
-{
-	int* ip;
-	do {
-		if (np->parent)
-			np = np->parent;
-		ip = (int *) get_property(np, "#size-cells", 0);
-		if (ip != NULL)
-			return *ip;
-	} while (np->parent);
-	/* No #size-cells property for the root node, default to 1 */
-	return 1;
-}
-
-static unsigned long __init
-map_addr(struct device_node *np, unsigned long space, unsigned long addr)
-{
-	int na;
-	unsigned int *ranges;
-	int rlen = 0;
-	unsigned int type;
-
-	type = (space >> 24) & 3;
-	if (type == 0)
-		return addr;
-
-	while ((np = np->parent) != NULL) {
-		if (strcmp(np->type, "pci") != 0)
-			continue;
-		/* PCI bridge: map the address through the ranges property */
-		na = prom_n_addr_cells(np);
-		ranges = (unsigned int *) get_property(np, "ranges", &rlen);
-		while ((rlen -= (na + 5) * sizeof(unsigned int)) >= 0) {
-			if (((ranges[0] >> 24) & 3) == type
-			    && ranges[2] <= addr
-			    && addr - ranges[2] < ranges[na+4]) {
-				/* ok, this matches, translate it */
-				addr += ranges[na+2] - ranges[2];
-				break;
-			}
-			ranges += na + 5;
-		}
-	}
-	return addr;
-}
-
-static unsigned long __init
-interpret_pci_props(struct device_node *np, unsigned long mem_start,
-		    int naddrc, int nsizec)
-{
-	struct address_range *adr;
-	struct pci_reg_property *pci_addrs;
-	int i, l, *ip;
-
-	pci_addrs = (struct pci_reg_property *)
-		get_property(np, "assigned-addresses", &l);
-	if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) {
-		i = 0;
-		adr = (struct address_range *) mem_start;
-		while ((l -= sizeof(struct pci_reg_property)) >= 0) {
-			adr[i].space = pci_addrs[i].addr.a_hi;
-			adr[i].address = map_addr(np, pci_addrs[i].addr.a_hi,
-						  pci_addrs[i].addr.a_lo);
-			adr[i].size = pci_addrs[i].size_lo;
-			++i;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
-	}
-
-	if (use_of_interrupt_tree)
-		return mem_start;
-
-	ip = (int *) get_property(np, "AAPL,interrupts", &l);
-	if (ip == 0 && np->parent)
-		ip = (int *) get_property(np->parent, "AAPL,interrupts", &l);
-	if (ip == 0)
-		ip = (int *) get_property(np, "interrupts", &l);
-	if (ip != 0) {
-		np->intrs = (struct interrupt_info *) mem_start;
-		np->n_intrs = l / sizeof(int);
-		mem_start += np->n_intrs * sizeof(struct interrupt_info);
-		for (i = 0; i < np->n_intrs; ++i) {
-			np->intrs[i].line = *ip++;
-			np->intrs[i].sense = 1;
-		}
-	}
-
-	return mem_start;
-}
-
-static unsigned long __init
-interpret_dbdma_props(struct device_node *np, unsigned long mem_start,
-		      int naddrc, int nsizec)
-{
-	struct reg_property *rp;
-	struct address_range *adr;
-	unsigned long base_address;
-	int i, l, *ip;
-	struct device_node *db;
-
-	base_address = 0;
-	for (db = np->parent; db != NULL; db = db->parent) {
-		if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
-			base_address = db->addrs[0].address;
-			break;
-		}
-	}
-
-	rp = (struct reg_property *) get_property(np, "reg", &l);
-	if (rp != 0 && l >= sizeof(struct reg_property)) {
-		i = 0;
-		adr = (struct address_range *) mem_start;
-		while ((l -= sizeof(struct reg_property)) >= 0) {
-			adr[i].space = 2;
-			adr[i].address = rp[i].address + base_address;
-			adr[i].size = rp[i].size;
-			++i;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
-	}
-
-	if (use_of_interrupt_tree)
-		return mem_start;
-
-	ip = (int *) get_property(np, "AAPL,interrupts", &l);
-	if (ip == 0)
-		ip = (int *) get_property(np, "interrupts", &l);
-	if (ip != 0) {
-		np->intrs = (struct interrupt_info *) mem_start;
-		np->n_intrs = l / sizeof(int);
-		mem_start += np->n_intrs * sizeof(struct interrupt_info);
-		for (i = 0; i < np->n_intrs; ++i) {
-			np->intrs[i].line = *ip++;
-			np->intrs[i].sense = 1;
-		}
-	}
-
-	return mem_start;
-}
-
-static unsigned long __init
-interpret_macio_props(struct device_node *np, unsigned long mem_start,
-		      int naddrc, int nsizec)
-{
-	struct reg_property *rp;
-	struct address_range *adr;
-	unsigned long base_address;
-	int i, l, *ip;
-	struct device_node *db;
-
-	base_address = 0;
-	for (db = np->parent; db != NULL; db = db->parent) {
-		if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
-			base_address = db->addrs[0].address;
-			break;
-		}
-	}
-
-	rp = (struct reg_property *) get_property(np, "reg", &l);
-	if (rp != 0 && l >= sizeof(struct reg_property)) {
-		i = 0;
-		adr = (struct address_range *) mem_start;
-		while ((l -= sizeof(struct reg_property)) >= 0) {
-			adr[i].space = 2;
-			adr[i].address = rp[i].address + base_address;
-			adr[i].size = rp[i].size;
-			++i;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
-	}
-
-	if (use_of_interrupt_tree)
-		return mem_start;
-
-	ip = (int *) get_property(np, "interrupts", &l);
-	if (ip == 0)
-		ip = (int *) get_property(np, "AAPL,interrupts", &l);
-	if (ip != 0) {
-		np->intrs = (struct interrupt_info *) mem_start;
-		np->n_intrs = l / sizeof(int);
-		for (i = 0; i < np->n_intrs; ++i) {
-			np->intrs[i].line = *ip++;
-			np->intrs[i].sense = 1;
-		}
-		mem_start += np->n_intrs * sizeof(struct interrupt_info);
-	}
-
-	return mem_start;
-}
-
-static unsigned long __init
-interpret_isa_props(struct device_node *np, unsigned long mem_start,
-		    int naddrc, int nsizec)
-{
-	struct isa_reg_property *rp;
-	struct address_range *adr;
-	int i, l, *ip;
-
-	rp = (struct isa_reg_property *) get_property(np, "reg", &l);
-	if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
-		i = 0;
-		adr = (struct address_range *) mem_start;
-		while ((l -= sizeof(struct reg_property)) >= 0) {
-			adr[i].space = rp[i].space;
-			adr[i].address = rp[i].address
-				+ (adr[i].space? 0: _ISA_MEM_BASE);
-			adr[i].size = rp[i].size;
-			++i;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
-	}
-
-	if (use_of_interrupt_tree)
-		return mem_start;
-
-	ip = (int *) get_property(np, "interrupts", &l);
-	if (ip != 0) {
-		np->intrs = (struct interrupt_info *) mem_start;
-		np->n_intrs = l / (2 * sizeof(int));
-		mem_start += np->n_intrs * sizeof(struct interrupt_info);
-		for (i = 0; i < np->n_intrs; ++i) {
-			np->intrs[i].line = *ip++;
-			np->intrs[i].sense = *ip++;
-		}
-	}
-
-	return mem_start;
-}
-
-static unsigned long __init
-interpret_root_props(struct device_node *np, unsigned long mem_start,
-		     int naddrc, int nsizec)
-{
-	struct address_range *adr;
-	int i, l, *ip;
-	unsigned int *rp;
-	int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
-
-	rp = (unsigned int *) get_property(np, "reg", &l);
-	if (rp != 0 && l >= rpsize) {
-		i = 0;
-		adr = (struct address_range *) mem_start;
-		while ((l -= rpsize) >= 0) {
-			adr[i].space = (naddrc >= 2? rp[naddrc-2]: 2);
-			adr[i].address = rp[naddrc - 1];
-			adr[i].size = rp[naddrc + nsizec - 1];
-			++i;
-			rp += naddrc + nsizec;
-		}
-		np->addrs = adr;
-		np->n_addrs = i;
-		mem_start += i * sizeof(struct address_range);
-	}
-
-	if (use_of_interrupt_tree)
-		return mem_start;
-
-	ip = (int *) get_property(np, "AAPL,interrupts", &l);
-	if (ip == 0)
-		ip = (int *) get_property(np, "interrupts", &l);
-	if (ip != 0) {
-		np->intrs = (struct interrupt_info *) mem_start;
-		np->n_intrs = l / sizeof(int);
-		mem_start += np->n_intrs * sizeof(struct interrupt_info);
-		for (i = 0; i < np->n_intrs; ++i) {
-			np->intrs[i].line = *ip++;
-			np->intrs[i].sense = 1;
-		}
-	}
-
-	return mem_start;
-}
-
-/*
- * Work out the sense (active-low level / active-high edge)
- * of each interrupt from the device tree.
- */
-void __init
-prom_get_irq_senses(unsigned char *senses, int off, int max)
-{
-	struct device_node *np;
-	int i, j;
-
-	/* default to level-triggered */
-	memset(senses, 1, max - off);
-	if (!use_of_interrupt_tree)
-		return;
-
-	for (np = allnodes; np != 0; np = np->allnext) {
-		for (j = 0; j < np->n_intrs; j++) {
-			i = np->intrs[j].line;
-			if (i >= off && i < max) {
-				if (np->intrs[j].sense == 1)
-					senses[i-off] = (IRQ_SENSE_LEVEL
-						| IRQ_POLARITY_NEGATIVE);
-				else
-					senses[i-off] = (IRQ_SENSE_EDGE 
-						| IRQ_POLARITY_POSITIVE);
-			}
-		}
-	}
-}
-
-/*
- * Construct and return a list of the device_nodes with a given name.
- */
-struct device_node *
-find_devices(const char *name)
-{
-	struct device_node *head, **prevp, *np;
-
-	prevp = &head;
-	for (np = allnodes; np != 0; np = np->allnext) {
-		if (np->name != 0 && strcasecmp(np->name, name) == 0) {
-			*prevp = np;
-			prevp = &np->next;
-		}
-	}
-	*prevp = 0;
-	return head;
-}
-
-/*
- * Construct and return a list of the device_nodes with a given type.
- */
-struct device_node *
-find_type_devices(const char *type)
-{
-	struct device_node *head, **prevp, *np;
-
-	prevp = &head;
-	for (np = allnodes; np != 0; np = np->allnext) {
-		if (np->type != 0 && strcasecmp(np->type, type) == 0) {
-			*prevp = np;
-			prevp = &np->next;
-		}
-	}
-	*prevp = 0;
-	return head;
-}
-
-/*
- * Returns all nodes linked together
- */
-struct device_node * __openfirmware
-find_all_nodes(void)
-{
-	struct device_node *head, **prevp, *np;
-
-	prevp = &head;
-	for (np = allnodes; np != 0; np = np->allnext) {
-		*prevp = np;
-		prevp = &np->next;
-	}
-	*prevp = 0;
-	return head;
-}
-
-/* Checks if the given "compat" string matches one of the strings in
- * the device's "compatible" property
- */
-int
-device_is_compatible(struct device_node *device, const char *compat)
-{
-	const char* cp;
-	int cplen, l;
-
-	cp = (char *) get_property(device, "compatible", &cplen);
-	if (cp == NULL)
-		return 0;
-	while (cplen > 0) {
-		if (strncasecmp(cp, compat, strlen(compat)) == 0)
-			return 1;
-		l = strlen(cp) + 1;
-		cp += l;
-		cplen -= l;
-	}
-
-	return 0;
-}
-
-
-/*
- * Indicates whether the root node has a given value in its
- * compatible property.
- */
-int
-machine_is_compatible(const char *compat)
-{
-	struct device_node *root;
-
-	root = find_path_device("/");
-	if (root == 0)
-		return 0;
-	return device_is_compatible(root, compat);
-}
-
-/*
- * Construct and return a list of the device_nodes with a given type
- * and compatible property.
- */
-struct device_node *
-find_compatible_devices(const char *type, const char *compat)
-{
-	struct device_node *head, **prevp, *np;
-
-	prevp = &head;
-	for (np = allnodes; np != 0; np = np->allnext) {
-		if (type != NULL
-		    && !(np->type != 0 && strcasecmp(np->type, type) == 0))
-			continue;
-		if (device_is_compatible(np, compat)) {
-			*prevp = np;
-			prevp = &np->next;
-		}
-	}
-	*prevp = 0;
-	return head;
-}
-
-/*
- * Find the device_node with a given full_name.
- */
-struct device_node *
-find_path_device(const char *path)
-{
-	struct device_node *np;
-
-	for (np = allnodes; np != 0; np = np->allnext)
-		if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
-			return np;
-	return NULL;
-}
-
-/*
- * Find the device_node with a given phandle.
- */
-static struct device_node * __init
-find_phandle(phandle ph)
-{
-	struct device_node *np;
-
-	for (np = allnodes; np != 0; np = np->allnext)
-		if (np->node == ph)
-			return np;
-	return NULL;
-}
-
-/*
- * Find a property with a given name for a given node
- * and return the value.
- */
-unsigned char *
-get_property(struct device_node *np, const char *name, int *lenp)
-{
-	struct property *pp;
-
-	for (pp = np->properties; pp != 0; pp = pp->next)
-		if (pp->name != NULL && strcmp(pp->name, name) == 0) {
-			if (lenp != 0)
-				*lenp = pp->length;
-			return pp->value;
-		}
-	return 0;
-}
-
-/*
- * Add a property to a node
- */
-void __openfirmware
-prom_add_property(struct device_node* np, struct property* prop)
-{
-	struct property **next = &np->properties;
-
-	prop->next = NULL;
-	while (*next)
-		next = &(*next)->next;
-	*next = prop;
-}
-
-/* I quickly hacked that one, check against spec ! */
-static inline unsigned long __openfirmware
-bus_space_to_resource_flags(unsigned int bus_space)
-{
-	u8 space = (bus_space >> 24) & 0xf;
-	if (space == 0)
-		space = 0x02;
-	if (space == 0x02)
-		return IORESOURCE_MEM;
-	else if (space == 0x01)
-		return IORESOURCE_IO;
-	else {
-		printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n",
-		    	bus_space);
-		return 0;
-	}
-}
-
-static struct resource* __openfirmware
-find_parent_pci_resource(struct pci_dev* pdev, struct address_range *range)
-{
-	unsigned long mask;
-	int i;
-	
-	/* Check this one */ 
-	mask = bus_space_to_resource_flags(range->space);
-	for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
-		if ((pdev->resource[i].flags & mask) == mask &&
-			pdev->resource[i].start <= range->address &&
-			pdev->resource[i].end > range->address) {
-				if ((range->address + range->size - 1) > pdev->resource[i].end) {
-					/* Add better message */
-					printk(KERN_WARNING "PCI/OF resource overlap !\n");
-					return NULL;
-				}
-				break;
-			}
-	}
-	if (i == DEVICE_COUNT_RESOURCE)
-		return NULL;
-	return &pdev->resource[i];
-}
-
-/*
- * Request an OF device resource. Currently handles child of PCI devices,
- * or other nodes attached to the root node. Ultimately, put some
- * link to resources in the OF node.
- * WARNING: out_resource->name should be initialized before calling this
- * function.
- */
-struct resource* __openfirmware
-request_OF_resource(struct device_node* node, int index, const char* name_postfix)
-{
-	struct pci_dev* pcidev;
-	u8 pci_bus, pci_devfn;
-	unsigned long iomask;
-	struct device_node* nd;
-	struct resource* parent;
-	struct resource *res = NULL;
-	int nlen, plen;
-
-	if (index >= node->n_addrs)
-		goto fail;
-
-	/* Sanity check on bus space */
-	iomask = bus_space_to_resource_flags(node->addrs[index].space);
-	if (iomask & IORESOURCE_MEM)
-		parent = &iomem_resource;
-	else if (iomask & IORESOURCE_IO)
-		parent = &ioport_resource;
-	else
-		goto fail;
-		
-	/* Find a PCI parent if any */
-	nd = node;
-	pcidev = NULL;
-	while(nd) {
-		if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
-			pcidev = pci_find_slot(pci_bus, pci_devfn);
-		if (pcidev) break;
-		nd = nd->parent;
-	}
-	if (pcidev)
-		parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
-	if (!parent) {
-		printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
-			node->name);
-		goto fail;
-	}
-
-	res = __request_region(parent, node->addrs[index].address, node->addrs[index].size, NULL);
-	if (!res)
-		goto fail;
-	nlen = strlen(node->name);
-	plen = name_postfix ? strlen(name_postfix) : 0;
-	res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL);
-	if (res->name) {
-		strcpy((char *)res->name, node->name);
-		if (plen)
-			strcpy((char *)res->name+nlen, name_postfix);
-	}
-	return res;
-fail:
-	return NULL;
-}
-
-int __openfirmware
-release_OF_resource(struct device_node* node, int index)
-{
-	struct pci_dev* pcidev;
-	u8 pci_bus, pci_devfn;
-	unsigned long iomask;
-	struct device_node* nd;
-	struct resource* parent;
-	struct resource *res = NULL;
-
-	if (index >= node->n_addrs)
-		return -EINVAL;
-
-	/* Sanity check on bus space */
-	iomask = bus_space_to_resource_flags(node->addrs[index].space);
-	if (iomask & IORESOURCE_MEM)
-		parent = &iomem_resource;
-	else if (iomask & IORESOURCE_IO)
-		parent = &ioport_resource;
-	else
-		return -EINVAL;
-		
-	/* Find a PCI parent if any */
-	nd = node;
-	pcidev = NULL;
-	while(nd) {
-		if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
-			pcidev = pci_find_slot(pci_bus, pci_devfn);
-		if (pcidev) break;
-		nd = nd->parent;
-	}
-	if (pcidev)
-		parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
-	if (!parent) {
-		printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
-			node->name);
-		return -ENODEV;
-	}
-
-	/* Find us in the parent */
-	res = parent->child;
-	while (res) {
-		if (res->start == node->addrs[index].address &&
-		    res->end == (res->start + node->addrs[index].size - 1))
-		    	break;
-		res = res->sibling;
-	}
-	if (!res)
-		return -ENODEV;
-
-	if (res->name) {
-		kfree(res->name);
-		res->name = NULL;
-	}
-	release_resource(res);
-	kfree(res);
-
-	return 0;
-}
-
-#if 0
-void __openfirmware
-print_properties(struct device_node *np)
-{
-	struct property *pp;
-	char *cp;
-	int i, n;
-
-	for (pp = np->properties; pp != 0; pp = pp->next) {
-		printk(KERN_INFO "%s", pp->name);
-		for (i = strlen(pp->name); i < 16; ++i)
-			printk(" ");
-		cp = (char *) pp->value;
-		for (i = pp->length; i > 0; --i, ++cp)
-			if ((i > 1 && (*cp < 0x20 || *cp > 0x7e))
-			    || (i == 1 && *cp != 0))
-				break;
-		if (i == 0 && pp->length > 1) {
-			/* looks like a string */
-			printk(" %s\n", (char *) pp->value);
-		} else {
-			/* dump it in hex */
-			n = pp->length;
-			if (n > 64)
-				n = 64;
-			if (pp->length % 4 == 0) {
-				unsigned int *p = (unsigned int *) pp->value;
-
-				n /= 4;
-				for (i = 0; i < n; ++i) {
-					if (i != 0 && (i % 4) == 0)
-						printk("\n                ");
-					printk(" %08x", *p++);
-				}
-			} else {
-				unsigned char *bp = pp->value;
-
-				for (i = 0; i < n; ++i) {
-					if (i != 0 && (i % 16) == 0)
-						printk("\n                ");
-					printk(" %02x", *bp++);
-				}
-			}
-			printk("\n");
-			if (pp->length > 64)
-				printk("                 ... (length = %d)\n",
-				       pp->length);
-		}
-	}
-}
-#endif
-
-static spinlock_t rtas_lock = SPIN_LOCK_UNLOCKED;
-
-/* this can be called after setup -- Cort */
-int __openfirmware
-call_rtas(const char *service, int nargs, int nret,
-	  unsigned long *outputs, ...)
-{
-	va_list list;
-	int i;
-	unsigned long s;
-	struct device_node *rtas;
-	int *tokp;
-	union {
-		unsigned long words[16];
-		double align;
-	} u;
-
-	rtas = find_devices("rtas");
-	if (rtas == NULL)
-		return -1;
-	tokp = (int *) get_property(rtas, service, NULL);
-	if (tokp == NULL) {
-		printk(KERN_ERR "No RTAS service called %s\n", service);
-		return -1;
-	}
-	u.words[0] = *tokp;
-	u.words[1] = nargs;
-	u.words[2] = nret;
-	va_start(list, outputs);
-	for (i = 0; i < nargs; ++i)
-		u.words[i+3] = va_arg(list, unsigned long);
-	va_end(list);
-
-	/*
-	 * RTAS doesn't use floating point.
-	 * Or at least, according to the CHRP spec we enter RTAS
-	 * with FP disabled, and it doesn't change the FP registers.
-	 *  -- paulus.
-	 */
-	spin_lock_irqsave(&rtas_lock, s);
-	enter_rtas((void *)__pa(&u));
-	spin_unlock_irqrestore(&rtas_lock, s);
-
-	if (nret > 1 && outputs != NULL)
-		for (i = 0; i < nret-1; ++i)
-			outputs[i] = u.words[i+nargs+4];
-	return u.words[nargs+3];
-}
diff -Nru a/arch/ppc/kernel/prom_init.c b/arch/ppc/kernel/prom_init.c
--- a/arch/ppc/kernel/prom_init.c	Sun Nov 10 19:28:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,900 +0,0 @@
-/*
- * Note that prom_init() and anything called from prom_init()
- * may be running at an address that is different from the address
- * that it was linked at.  References to static data items are
- * handled by compiling this file with -mrelocatable-lib.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/init.h>
-#include <linux/version.h>
-#include <linux/threads.h>
-#include <linux/spinlock.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-
-#include <asm/sections.h>
-#include <asm/prom.h>
-#include <asm/page.h>
-#include <asm/processor.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/smp.h>
-#include <asm/bootx.h>
-#include <asm/system.h>
-#include <asm/mmu.h>
-#include <asm/pgtable.h>
-#include <asm/bitops.h>
-#include <asm/bootinfo.h>
-#include <asm/btext.h>
-#include <asm/pci-bridge.h>
-#include <asm/open_pic.h>
-#include <asm/cacheflush.h>
-
-#ifdef CONFIG_FB
-#include <asm/linux_logo.h>
-#endif
-
-/*
- * Properties whose value is longer than this get excluded from our
- * copy of the device tree.  This way we don't waste space storing
- * things like "driver,AAPL,MacOS,PowerPC" properties.  But this value
- * does need to be big enough to ensure that we don't lose things
- * like the interrupt-map property on a PCI-PCI bridge.
- */
-#define MAX_PROPERTY_LENGTH	4096
-
-#ifndef FB_MAX			/* avoid pulling in all of the fb stuff */
-#define FB_MAX	8
-#endif
-
-#define ALIGNUL(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
-
-struct prom_args {
-	const char *service;
-	int nargs;
-	int nret;
-	void *args[10];
-};
-
-struct pci_address {
-	unsigned a_hi;
-	unsigned a_mid;
-	unsigned a_lo;
-};
-
-struct pci_reg_property {
-	struct pci_address addr;
-	unsigned size_hi;
-	unsigned size_lo;
-};
-
-struct pci_range {
-	struct pci_address addr;
-	unsigned phys;
-	unsigned size_hi;
-	unsigned size_lo;
-};
-
-struct isa_reg_property {
-	unsigned space;
-	unsigned address;
-	unsigned size;
-};
-
-struct pci_intr_map {
-	struct pci_address addr;
-	unsigned dunno;
-	phandle int_ctrler;
-	unsigned intr;
-};
-
-static void prom_exit(void);
-static void *call_prom(const char *service, int nargs, int nret, ...);
-static void *call_prom_ret(const char *service, int nargs, int nret,
-			   void **rets, ...);
-static void prom_print_hex(unsigned int v);
-static int  prom_set_color(ihandle ih, int i, int r, int g, int b);
-static int  prom_next_node(phandle *nodep);
-static unsigned long check_display(unsigned long mem);
-static void setup_disp_fake_bi(ihandle dp);
-static unsigned long copy_device_tree(unsigned long mem_start,
-				unsigned long mem_end);
-static unsigned long inspect_node(phandle node, struct device_node *dad,
-				unsigned long mem_start, unsigned long mem_end,
-				struct device_node ***allnextpp);
-static void prom_hold_cpus(unsigned long mem);
-static void prom_instantiate_rtas(void);
-static void * early_get_property(unsigned long base, unsigned long node,
-				char *prop);
-
-prom_entry prom __initdata = 0;
-ihandle prom_chosen __initdata = 0;
-ihandle prom_stdout __initdata = 0;
-
-char *prom_display_paths[FB_MAX] __initdata = { 0, };
-phandle prom_display_nodes[FB_MAX] __initdata;
-unsigned int prom_num_displays __initdata = 0;
-static char *of_stdout_device __initdata = 0;
-static ihandle prom_disp_node __initdata = 0;
-
-unsigned int rtas_data;   /* physical pointer */
-unsigned int rtas_entry;  /* physical pointer */
-unsigned int rtas_size;
-unsigned int old_rtas;
-
-boot_infos_t *boot_infos;
-char *bootpath;
-char *bootdevice;
-struct device_node *allnodes;
-
-extern char *klimit;
-extern char _stext;
-
-static void __init
-prom_exit(void)
-{
-	struct prom_args args;
-
-	args.service = "exit";
-	args.nargs = 0;
-	args.nret = 0;
-	prom(&args);
-	for (;;)			/* should never get here */
-		;
-}
-
-static void * __init
-call_prom(const char *service, int nargs, int nret, ...)
-{
-	va_list list;
-	int i;
-	struct prom_args prom_args;
-
-	prom_args.service = service;
-	prom_args.nargs = nargs;
-	prom_args.nret = nret;
-	va_start(list, nret);
-	for (i = 0; i < nargs; ++i)
-		prom_args.args[i] = va_arg(list, void *);
-	va_end(list);
-	for (i = 0; i < nret; ++i)
-		prom_args.args[i + nargs] = 0;
-	prom(&prom_args);
-	return prom_args.args[nargs];
-}
-
-static void * __init
-call_prom_ret(const char *service, int nargs, int nret, void **rets, ...)
-{
-	va_list list;
-	int i;
-	struct prom_args prom_args;
-
-	prom_args.service = service;
-	prom_args.nargs = nargs;
-	prom_args.nret = nret;
-	va_start(list, rets);
-	for (i = 0; i < nargs; ++i)
-		prom_args.args[i] = va_arg(list, void *);
-	va_end(list);
-	for (i = 0; i < nret; ++i)
-		prom_args.args[i + nargs] = 0;
-	prom(&prom_args);
-	for (i = 1; i < nret; ++i)
-		rets[i-1] = prom_args.args[nargs + i];
-	return prom_args.args[nargs];
-}
-
-void __init
-prom_print(const char *msg)
-{
-	const char *p, *q;
-
-	if (prom_stdout == 0)
-		return;
-
-	for (p = msg; *p != 0; p = q) {
-		for (q = p; *q != 0 && *q != '\n'; ++q)
-			;
-		if (q > p)
-			call_prom("write", 3, 1, prom_stdout, p, q - p);
-		if (*q != 0) {
-			++q;
-			call_prom("write", 3, 1, prom_stdout, "\r\n", 2);
-		}
-	}
-}
-
-static void __init
-prom_print_hex(unsigned int v)
-{
-	char buf[16];
-	int i, c;
-
-	for (i = 0; i < 8; ++i) {
-		c = (v >> ((7-i)*4)) & 0xf;
-		c += (c >= 10)? ('a' - 10): '0';
-		buf[i] = c;
-	}
-	buf[i] = ' ';
-	buf[i+1] = 0;
-	prom_print(buf);
-}
-
-static int __init
-prom_set_color(ihandle ih, int i, int r, int g, int b)
-{
-	struct prom_args prom_args;
-
-	prom_args.service = "call-method";
-	prom_args.nargs = 6;
-	prom_args.nret = 1;
-	prom_args.args[0] = "color!";
-	prom_args.args[1] = ih;
-	prom_args.args[2] = (void *) i;
-	prom_args.args[3] = (void *) b;
-	prom_args.args[4] = (void *) g;
-	prom_args.args[5] = (void *) r;
-	prom(&prom_args);
-	return (int) prom_args.args[6];
-}
-
-static int __init
-prom_next_node(phandle *nodep)
-{
-	phandle node;
-
-	if ((node = *nodep) != 0
-	    && (*nodep = call_prom("child", 1, 1, node)) != 0)
-		return 1;
-	if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
-		return 1;
-	for (;;) {
-		if ((node = call_prom("parent", 1, 1, node)) == 0)
-			return 0;
-		if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
-			return 1;
-	}
-}
-
-/*
- * If we have a display that we don't know how to drive,
- * we will want to try to execute OF's open method for it
- * later.  However, OF will probably fall over if we do that
- * we've taken over the MMU.
- * So we check whether we will need to open the display,
- * and if so, open it now.
- */
-static unsigned long __init
-check_display(unsigned long mem)
-{
-	phandle node;
-	ihandle ih;
-	int i;
-	char type[16], *path;
-	static unsigned char default_colors[] = {
-		0x00, 0x00, 0x00,
-		0x00, 0x00, 0xaa,
-		0x00, 0xaa, 0x00,
-		0x00, 0xaa, 0xaa,
-		0xaa, 0x00, 0x00,
-		0xaa, 0x00, 0xaa,
-		0xaa, 0xaa, 0x00,
-		0xaa, 0xaa, 0xaa,
-		0x55, 0x55, 0x55,
-		0x55, 0x55, 0xff,
-		0x55, 0xff, 0x55,
-		0x55, 0xff, 0xff,
-		0xff, 0x55, 0x55,
-		0xff, 0x55, 0xff,
-		0xff, 0xff, 0x55,
-		0xff, 0xff, 0xff
-	};
-
-	prom_disp_node = 0;
-
-	for (node = 0; prom_next_node(&node); ) {
-		type[0] = 0;
-		call_prom("getprop", 4, 1, node, "device_type",
-			  type, sizeof(type));
-		if (strcmp(type, "display") != 0)
-			continue;
-		/* It seems OF doesn't null-terminate the path :-( */
-		path = (char *) mem;
-		memset(path, 0, 256);
-		if ((int) call_prom("package-to-path", 3, 1,
-				    node, path, 255) < 0)
-			continue;
-
-		/*
-		 * If this display is the device that OF is using for stdout,
-		 * move it to the front of the list.
-		 */
-		mem += strlen(path) + 1;
-		i = prom_num_displays++;
-		if (of_stdout_device != 0 && i > 0
-		    && strcmp(of_stdout_device, path) == 0) {
-			for (; i > 0; --i) {
-				prom_display_paths[i]
-					= prom_display_paths[i-1];
-				prom_display_nodes[i]
-					= prom_display_nodes[i-1];
-			}
-		}
-		prom_display_paths[i] = path;
-		prom_display_nodes[i] = node;
-		if (i == 0)
-			prom_disp_node = node;
-		if (prom_num_displays >= FB_MAX)
-			break;
-	}
-
-try_again:
-	/*
-	 * Open the first display and set its colormap.
-	 */
-	if (prom_num_displays > 0) {
-		path = prom_display_paths[0];
-		prom_print("opening display ");
-		prom_print(path);
-		ih = call_prom("open", 1, 1, path);
-		if (ih == 0 || ih == (ihandle) -1) {
-			prom_print("... failed\n");
-			for (i=1; i<prom_num_displays; i++) {
-				prom_display_paths[i-1] = prom_display_paths[i];
-				prom_display_nodes[i-1] = prom_display_nodes[i];
-			}
-			if (--prom_num_displays > 0)
-				prom_disp_node = prom_display_nodes[0];
-			else
-				prom_disp_node = NULL;
-			goto try_again;
-		} else {
-			prom_print("... ok\n");
-			/*
-			 * Setup a usable color table when the appropriate
-			 * method is available.
-			 * Should update this to use set-colors.
-			 */
-			for (i = 0; i < 32; i++)
-				if (prom_set_color(ih, i, default_colors[i*3],
-						   default_colors[i*3+1],
-						   default_colors[i*3+2]) != 0)
-					break;
-
-#ifdef CONFIG_FB
-			for (i = 0; i < LINUX_LOGO_COLORS; i++)
-				if (prom_set_color(ih, i + 32,
-						   linux_logo_red[i],
-						   linux_logo_green[i],
-						   linux_logo_blue[i]) != 0)
-					break;
-#endif /* CONFIG_FB */
-		}
-	}
-
-	return ALIGNUL(mem);
-}
-
-/* This function will enable the early boot text when doing OF booting. This
- * way, xmon output should work too
- */
-static void __init
-setup_disp_fake_bi(ihandle dp)
-{
-#ifdef CONFIG_BOOTX_TEXT
-	int width = 640, height = 480, depth = 8, pitch;
-	unsigned address;
-	struct pci_reg_property addrs[8];
-	int i, naddrs;
-	char name[32];
-	char *getprop = "getprop";
-
-	prom_print("Initializing fake screen: ");
-
-	memset(name, 0, sizeof(name));
-	call_prom(getprop, 4, 1, dp, "name", name, sizeof(name));
-	name[sizeof(name)-1] = 0;
-	prom_print(name);
-	prom_print("\n");
-	call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width));
-	call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height));
-	call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth));
-	pitch = width * ((depth + 7) / 8);
-	call_prom(getprop, 4, 1, dp, "linebytes",
-		  &pitch, sizeof(pitch));
-	if (pitch == 1)
-		pitch = 0x1000;		/* for strange IBM display */
-	address = 0;
-	call_prom(getprop, 4, 1, dp, "address",
-		  &address, sizeof(address));
-	if (address == 0) {
-		/* look for an assigned address with a size of >= 1MB */
-		naddrs = (int) call_prom(getprop, 4, 1, dp,
-				"assigned-addresses",
-				addrs, sizeof(addrs));
-		naddrs /= sizeof(struct pci_reg_property);
-		for (i = 0; i < naddrs; ++i) {
-			if (addrs[i].size_lo >= (1 << 20)) {
-				address = addrs[i].addr.a_lo;
-				/* use the BE aperture if possible */
-				if (addrs[i].size_lo >= (16 << 20))
-					address += (8 << 20);
-				break;
-			}
-		}
-		if (address == 0) {
-			prom_print("Failed to get address\n");
-			return;
-		}
-	}
-	/* kludge for valkyrie */
-	if (strcmp(name, "valkyrie") == 0)
-		address += 0x1000;
-
-	btext_setup_display(width, height, depth, pitch, address);
-
-	btext_prepare_BAT();
-#endif /* CONFIG_BOOTX_TEXT */
-}
-
-/*
- * Make a copy of the device tree from the PROM.
- */
-static unsigned long __init
-copy_device_tree(unsigned long mem_start, unsigned long mem_end)
-{
-	phandle root;
-	unsigned long new_start;
-	struct device_node **allnextp;
-
-	root = call_prom("peer", 1, 1, (phandle)0);
-	if (root == (phandle)0) {
-		prom_print("couldn't get device tree root\n");
-		prom_exit();
-	}
-	allnextp = &allnodes;
-	mem_start = ALIGNUL(mem_start);
-	new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp);
-	*allnextp = 0;
-	return new_start;
-}
-
-static unsigned long __init
-inspect_node(phandle node, struct device_node *dad,
-	     unsigned long mem_start, unsigned long mem_end,
-	     struct device_node ***allnextpp)
-{
-	int l;
-	phandle child;
-	struct device_node *np;
-	struct property *pp, **prev_propp;
-	char *prev_name, *namep;
-	unsigned char *valp;
-
-	np = (struct device_node *) mem_start;
-	mem_start += sizeof(struct device_node);
-	memset(np, 0, sizeof(*np));
-	np->node = node;
-	**allnextpp = PTRUNRELOC(np);
-	*allnextpp = &np->allnext;
-	if (dad != 0) {
-		np->parent = PTRUNRELOC(dad);
-		/* we temporarily use the `next' field as `last_child'. */
-		if (dad->next == 0)
-			dad->child = PTRUNRELOC(np);
-		else
-			dad->next->sibling = PTRUNRELOC(np);
-		dad->next = np;
-	}
-
-	/* get and store all properties */
-	prev_propp = &np->properties;
-	prev_name = "";
-	for (;;) {
-		pp = (struct property *) mem_start;
-		namep = (char *) (pp + 1);
-		pp->name = PTRUNRELOC(namep);
-		if ((int) call_prom("nextprop", 3, 1, node, prev_name,
-				    namep) <= 0)
-			break;
-		mem_start = ALIGNUL((unsigned long)namep + strlen(namep) + 1);
-		prev_name = namep;
-		valp = (unsigned char *) mem_start;
-		pp->value = PTRUNRELOC(valp);
-		pp->length = (int)
-			call_prom("getprop", 4, 1, node, namep,
-				  valp, mem_end - mem_start);
-		if (pp->length < 0)
-			continue;
-#ifdef MAX_PROPERTY_LENGTH
-		if (pp->length > MAX_PROPERTY_LENGTH)
-			continue; /* ignore this property */
-#endif
-		mem_start = ALIGNUL(mem_start + pp->length);
-		*prev_propp = PTRUNRELOC(pp);
-		prev_propp = &pp->next;
-	}
-	if (np->node != NULL) {
-		/* Add a "linux,phandle" property" */
-		pp = (struct property *) mem_start;
-		*prev_propp = PTRUNRELOC(pp);
-		prev_propp = &pp->next;
-		namep = (char *) (pp + 1);
-		pp->name = PTRUNRELOC(namep);
-		strcpy(namep, "linux,phandle");
-		mem_start = ALIGNUL((unsigned long)namep + strlen(namep) + 1);
-		pp->value = (unsigned char *) PTRUNRELOC(&np->node);
-		pp->length = sizeof(np->node);
-	}
-	*prev_propp = NULL;
-
-	/* get the node's full name */
-	l = (int) call_prom("package-to-path", 3, 1, node,
-			    (char *) mem_start, mem_end - mem_start);
-	if (l >= 0) {
-		np->full_name = PTRUNRELOC((char *) mem_start);
-		*(char *)(mem_start + l) = 0;
-		mem_start = ALIGNUL(mem_start + l + 1);
-	}
-
-	/* do all our children */
-	child = call_prom("child", 1, 1, node);
-	while (child != (void *)0) {
-		mem_start = inspect_node(child, np, mem_start, mem_end,
-					 allnextpp);
-		child = call_prom("peer", 1, 1, child);
-	}
-
-	return mem_start;
-}
-
-unsigned long smp_chrp_cpu_nr __initdata = 0;
-
-/*
- * With CHRP SMP we need to use the OF to start the other
- * processors so we can't wait until smp_boot_cpus (the OF is
- * trashed by then) so we have to put the processors into
- * a holding pattern controlled by the kernel (not OF) before
- * we destroy the OF.
- *
- * This uses a chunk of high memory, puts some holding pattern
- * code there and sends the other processors off to there until
- * smp_boot_cpus tells them to do something.  We do that by using
- * physical address 0x0.  The holding pattern checks that address
- * until its cpu # is there, when it is that cpu jumps to
- * __secondary_start().  smp_boot_cpus() takes care of setting those
- * values.
- *
- * We also use physical address 0x4 here to tell when a cpu
- * is in its holding pattern code.
- *
- * -- Cort
- *
- * Note that we have to do this if we have more than one CPU,
- * even if this is a UP kernel.  Otherwise when we trash OF
- * the other CPUs will start executing some random instructions
- * and crash the system.  -- paulus
- */
-static void __init
-prom_hold_cpus(unsigned long mem)
-{
-	extern void __secondary_hold(void);
-	unsigned long i;
-	int cpu;
-	phandle node;
-	char type[16], *path;
-	unsigned int reg;
-
-	/*
-	 * XXX: hack to make sure we're chrp, assume that if we're
-	 *      chrp we have a device_type property -- Cort
-	 */
-	node = call_prom("finddevice", 1, 1, "/");
-	if ((int)call_prom("getprop", 4, 1, node,
-			   "device_type",type, sizeof(type)) <= 0)
-		return;
-
-	/* copy the holding pattern code to someplace safe (0) */
-	/* the holding pattern is now within the first 0x100
-	   bytes of the kernel image -- paulus */
-	memcpy((void *)0, &_stext, 0x100);
-	flush_icache_range(0, 0x100);
-
-	/* look for cpus */
-	*(unsigned long *)(0x0) = 0;
-	asm volatile("dcbf 0,%0": : "r" (0) : "memory");
-	for (node = 0; prom_next_node(&node); ) {
-		type[0] = 0;
-		call_prom("getprop", 4, 1, node, "device_type",
-			  type, sizeof(type));
-		if (strcmp(type, "cpu") != 0)
-			continue;
-		path = (char *) mem;
-		memset(path, 0, 256);
-		if ((int) call_prom("package-to-path", 3, 1,
-				    node, path, 255) < 0)
-			continue;
-		reg = -1;
-		call_prom("getprop", 4, 1, node, "reg", &reg, sizeof(reg));
-		cpu = smp_chrp_cpu_nr++;
-#ifdef CONFIG_SMP
-		smp_hw_index[cpu] = reg;
-#endif /* CONFIG_SMP */
-		/* XXX: hack - don't start cpu 0, this cpu -- Cort */
-		if (cpu == 0)
-			continue;
-		prom_print("starting cpu ");
-		prom_print(path);
-		*(ulong *)(0x4) = 0;
-		call_prom("start-cpu", 3, 0, node,
-			  (char *)__secondary_hold - &_stext, cpu);
-		prom_print("...");
-		for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ )
-			;
-		if (*(ulong *)(0x4) == cpu)
-			prom_print("ok\n");
-		else {
-			prom_print("failed: ");
-			prom_print_hex(*(ulong *)0x4);
-			prom_print("\n");
-		}
-	}
-}
-
-static void __init
-prom_instantiate_rtas(void)
-{
-	ihandle prom_rtas;
-	unsigned int i;
-	struct prom_args prom_args;
-
-	prom_rtas = call_prom("finddevice", 1, 1, "/rtas");
-	if (prom_rtas == (void *) -1)
-		return;
-
-	rtas_size = 0;
-	call_prom("getprop", 4, 1, prom_rtas,
-		  "rtas-size", &rtas_size, sizeof(rtas_size));
-	prom_print("instantiating rtas");
-	if (rtas_size == 0) {
-		rtas_data = 0;
-	} else {
-		/*
-		 * Ask OF for some space for RTAS.
-		 * Actually OF has bugs so we just arbitrarily
-		 * use memory at the 6MB point.
-		 */
-		rtas_data = 6 << 20;
-		prom_print(" at ");
-		prom_print_hex(rtas_data);
-	}
-
-	prom_rtas = call_prom("open", 1, 1, "/rtas");
-	prom_print("...");
-	prom_args.service = "call-method";
-	prom_args.nargs = 3;
-	prom_args.nret = 2;
-	prom_args.args[0] = "instantiate-rtas";
-	prom_args.args[1] = prom_rtas;
-	prom_args.args[2] = (void *) rtas_data;
-	prom(&prom_args);
-	i = 0;
-	if (prom_args.args[3] == 0)
-		i = (unsigned int)prom_args.args[4];
-	rtas_entry = i;
-	if ((rtas_entry == -1) || (rtas_entry == 0))
-		prom_print(" failed\n");
-	else
-		prom_print(" done\n");
-}
-
-/*
- * We enter here early on, when the Open Firmware prom is still
- * handling exceptions and the MMU hash table for us.
- */
-unsigned long __init
-prom_init(int r3, int r4, prom_entry pp)
-{
-	unsigned long mem;
-	ihandle prom_mmu;
-	unsigned long offset = reloc_offset();
-	int i, l;
-	char *p, *d;
- 	unsigned long phys;
-	void *result[3];
-
- 	/* Default */
- 	phys = (unsigned long) &_stext;
-
-	/* First get a handle for the stdout device */
-	prom = pp;
-	prom_chosen = call_prom("finddevice", 1, 1,
-				       "/chosen");
-	if (prom_chosen == (void *)-1)
-		prom_exit();
-	if ((int) call_prom("getprop", 4, 1, prom_chosen,
-			    "stdout", &prom_stdout,
-			    sizeof(prom_stdout)) <= 0)
-		prom_exit();
-
-	/* Get the full OF pathname of the stdout device */
-	mem = (unsigned long) klimit + offset;
-	p = (char *) mem;
-	memset(p, 0, 256);
-	call_prom("instance-to-path", 3, 1, prom_stdout, p, 255);
-	of_stdout_device = p;
-	mem += strlen(p) + 1;
-
-	/* Get the boot device and translate it to a full OF pathname. */
-	p = (char *) mem;
-	l = (int) call_prom("getprop", 4, 1, prom_chosen,
-			    "bootpath", p, 1<<20);
-	if (l > 0) {
-		p[l] = 0;	/* should already be null-terminated */
-		bootpath = PTRUNRELOC(p);
-		mem += l + 1;
-		d = (char *) mem;
-		*d = 0;
-		call_prom("canon", 3, 1, p, d, 1<<20);
-		bootdevice = PTRUNRELOC(d);
-		mem = ALIGNUL(mem + strlen(d) + 1);
-	}
-
-	prom_instantiate_rtas();
-
-	mem = check_display(mem);
-
-	prom_print("copying OF device tree...");
-	mem = copy_device_tree(mem, mem + (1<<20));
-	prom_print("done\n");
-
-	prom_hold_cpus(mem);
-
-	klimit = (char *) (mem - offset);
-
-	/* If we are already running at 0xc0000000, we assume we were
-	 * loaded by an OF bootloader which did set a BAT for us.
-	 * This breaks OF translate so we force phys to be 0.
-	 */
-	if (offset == 0)
-		phys = 0;
-	else if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu",
-				 &prom_mmu, sizeof(prom_mmu)) <= 0) {
-		prom_print(" no MMU found\n");
-	} else if ((int)call_prom_ret("call-method", 4, 4, result, "translate",
-				      prom_mmu, &_stext, 1) != 0) {
-		prom_print(" (translate failed)\n");
-	} else {
-		/* We assume the phys. address size is 3 cells */
-		phys = (unsigned long)result[2];
-	}
-
-	if (prom_disp_node != 0)
-		setup_disp_fake_bi(prom_disp_node);
-
-	/* Use quiesce call to get OF to shut down any devices it's using */
-	prom_print("Calling quiesce ...\n");
-	call_prom("quiesce", 0, 0);
-
-	/* Relocate various pointers which will be used once the
-	   kernel is running at the address it was linked at. */
-	for (i = 0; i < prom_num_displays; ++i)
-		prom_display_paths[i] = PTRUNRELOC(prom_display_paths[i]);
-
-	prom_print("returning 0x");
-	prom_print_hex(phys);
-	prom_print("from prom_init\n");
-	prom_stdout = 0;
-
-	return phys;
-}
-
-/*
- * early_get_property is used to access the device tree image prepared
- * by BootX very early on, before the pointers in it have been relocated.
- */
-static void * __init
-early_get_property(unsigned long base, unsigned long node, char *prop)
-{
-	struct device_node *np = (struct device_node *)(base + node);
-	struct property *pp;
-
-	for (pp = np->properties; pp != 0; pp = pp->next) {
-		pp = (struct property *) (base + (unsigned long)pp);
-		if (strcmp((char *)((unsigned long)pp->name + base),
-			   prop) == 0) {
-			return (void *)((unsigned long)pp->value + base);
-		}
-	}
-	return 0;
-}
-
-/* Is boot-info compatible ? */
-#define BOOT_INFO_IS_COMPATIBLE(bi)		((bi)->compatible_version <= BOOT_INFO_VERSION)
-#define BOOT_INFO_IS_V2_COMPATIBLE(bi)	((bi)->version >= 2)
-#define BOOT_INFO_IS_V4_COMPATIBLE(bi)	((bi)->version >= 4)
-
-void __init
-bootx_init(unsigned long r4, unsigned long phys)
-{
-	boot_infos_t *bi = (boot_infos_t *) r4;
-	unsigned long space;
-	unsigned long ptr, x;
-	char *model;
-
-	boot_infos = PTRUNRELOC(bi);
-	if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
-		bi->logicalDisplayBase = 0;
-
-#ifdef CONFIG_BOOTX_TEXT
-	btext_init(bi);
-
-	/*
-	 * Test if boot-info is compatible.  Done only in config
-	 * CONFIG_BOOTX_TEXT since there is nothing much we can do
-	 * with an incompatible version, except display a message
-	 * and eventually hang the processor...
-	 *
-	 * I'll try to keep enough of boot-info compatible in the
-	 * future to always allow display of this message;
-	 */
-	if (!BOOT_INFO_IS_COMPATIBLE(bi)) {
-		btext_drawstring(" !!! WARNING - Incompatible version of BootX !!!\n\n\n");
-		btext_flushscreen();
-	}
-#endif	/* CONFIG_BOOTX_TEXT */
-
-	/* New BootX enters kernel with MMU off, i/os are not allowed
-	   here. This hack will have been done by the boostrap anyway.
-	*/
-	if (bi->version < 4) {
-		/*
-		 * XXX If this is an iMac, turn off the USB controller.
-		 */
-		model = (char *) early_get_property
-			(r4 + bi->deviceTreeOffset, 4, "model");
-		if (model
-		    && (strcmp(model, "iMac,1") == 0
-			|| strcmp(model, "PowerMac1,1") == 0)) {
-			out_le32((unsigned *)0x80880008, 1);	/* XXX */
-		}
-	}
-
-	/* Move klimit to enclose device tree, args, ramdisk, etc... */
-	if (bi->version < 5) {
-		space = bi->deviceTreeOffset + bi->deviceTreeSize;
-		if (bi->ramDisk)
-			space = bi->ramDisk + bi->ramDiskSize;
-	} else
-		space = bi->totalParamsSize;
-	klimit = PTRUNRELOC((char *) bi + space);
-
-	/* New BootX will have flushed all TLBs and enters kernel with
-	   MMU switched OFF, so this should not be useful anymore.
-	*/
-	if (bi->version < 4) {
-		/*
-		 * Touch each page to make sure the PTEs for them
-		 * are in the hash table - the aim is to try to avoid
-		 * getting DSI exceptions while copying the kernel image.
-		 */
-		for (ptr = ((unsigned long) &_stext) & PAGE_MASK;
-		     ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
-			x = *(volatile unsigned long *)ptr;
-	}
-
-#ifdef CONFIG_BOOTX_TEXT
-	/*
-	 * Note that after we call btext_prepare_BAT, we can't do
-	 * prom_draw*, flushscreen or clearscreen until we turn the MMU
-	 * on, since btext_prepare_BAT sets disp_bi.logicalDisplayBase
-	 * to a virtual address.
-	 */
-	btext_prepare_BAT();
-#endif
-}
diff -Nru a/arch/ppc/kernel/qspan_pci.c b/arch/ppc/kernel/qspan_pci.c
--- a/arch/ppc/kernel/qspan_pci.c	Sun Nov 10 19:28:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,379 +0,0 @@
-/*
- * QSpan pci routines.
- * Most 8xx boards use the QSpan PCI bridge.  The config address register
- * is located 0x500 from the base of the bridge control/status registers.
- * The data register is located at 0x504.
- * This is a two step operation.  First, the address register is written,
- * then the data register is read/written as required.
- * I don't know what to do about interrupts (yet).
- *
- * The RPX Classic implementation shares a chip select for normal
- * PCI access and QSpan control register addresses.  The selection is
- * further selected by a bit setting in a board control register.
- * Although it should happen, we disable interrupts during this operation
- * to make sure some driver doesn't accidentally access the PCI while
- * we have switched the chip select.
- */
-
-#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 <asm/io.h>
-#include <asm/mpc8xx.h>
-#include <asm/system.h>
-#include <asm/machdep.h>
-#include <asm/pci-bridge.h>
-
-
-/*
- * This blows......
- * When reading the configuration space, if something does not respond
- * the bus times out and we get a machine check interrupt.  So, the
- * good ol' exception tables come to mind to trap it and return some
- * value.
- *
- * On an error we just return a -1, since that is what the caller wants
- * returned if nothing is present.  I copied this from __get_user_asm,
- * with the only difference of returning -1 instead of EFAULT.
- * There is an associated hack in the machine check trap code.
- *
- * The QSPAN is also a big endian device, that is it makes the PCI
- * look big endian to us.  This presents a problem for the Linux PCI
- * functions, which assume little endian.  For example, we see the
- * first 32-bit word like this:
- *	------------------------
- *	| Device ID | Vendor ID |
- *	------------------------
- * If we read/write as a double word, that's OK.  But in our world,
- * when read as a word, device ID is at location 0, not location 2 as
- * the little endian PCI would believe.  We have to switch bits in
- * the PCI addresses given to us to get the data to/from the correct
- * byte lanes.
- *
- * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5.
- * It always forces the MS bit to zero.  Therefore, dev_fn values
- * greater than 128 are returned as "no device found" errors.
- *
- * The QSPAN can only perform long word (32-bit) configuration cycles.
- * The "offset" must have the two LS bits set to zero.  Read operations
- * require we read the entire word and then sort out what should be
- * returned.  Write operations other than long word require that we
- * read the long word, update the proper word or byte, then write the
- * entire long word back.
- *
- * PCI Bridge hack.  We assume (correctly) that bus 0 is the primary
- * PCI bus from the QSPAN.  If we are called with a bus number other
- * than zero, we create a Type 1 configuration access that a downstream
- * PCI bridge will interpret.
- */
-
-#define __get_qspan_pci_config(x, addr, op)		\
-	__asm__ __volatile__(				\
-		"1:	"op" %0,0(%1)\n"		\
-		"	eieio\n"			\
-		"2:\n"					\
-		".section .fixup,\"ax\"\n"		\
-		"3:	li %0,-1\n"			\
-		"	b 2b\n"				\
-		".section __ex_table,\"a\"\n"		\
-		"	.align 2\n"			\
-		"	.long 1b,3b\n"			\
-		".text"					\
-		: "=r"(x) : "r"(addr) : " %0")
-
-#define QS_CONFIG_ADDR	((volatile uint *)(PCI_CSR_ADDR + 0x500))
-#define QS_CONFIG_DATA	((volatile uint *)(PCI_CSR_ADDR + 0x504))
-
-#define mk_config_addr(bus, dev, offset) \
-	(((bus)<<16) | ((dev)<<8) | (offset & 0xfc))
-
-#define mk_config_type1(bus, dev, offset) \
-	mk_config_addr(bus, dev, offset) | 1;
-
-int qspan_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
-				  unsigned char offset, unsigned char *val)
-{
-	uint	temp;
-	u_char	*cp;
-#ifdef CONFIG_RPXCLASSIC
-	unsigned long flags;
-#endif
-
-	if ((bus > 7) || (dev_fn > 127)) {
-		*val = 0xff;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	}
-
-#ifdef CONFIG_RPXCLASSIC
-	save_flags(flags);
-	cli();
-	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
-	eieio();
-#endif
-
-	if (bus == 0)
-		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
-	else
-		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
-	__get_qspan_pci_config(temp, QS_CONFIG_DATA, "lwz");
-
-#ifdef CONFIG_RPXCLASSIC
-	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
-	eieio();
-	restore_flags(flags);
-#endif
-
-	offset ^= 0x03;
-	cp = ((u_char *)&temp) + (offset & 0x03);
-	*val = *cp;
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int qspan_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
-				  unsigned char offset, unsigned short *val)
-{
-	uint	temp;
-	ushort	*sp;
-#ifdef CONFIG_RPXCLASSIC
-	unsigned long flags;
-#endif
-
-	if ((bus > 7) || (dev_fn > 127)) {
-		*val = 0xffff;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	}
-
-#ifdef CONFIG_RPXCLASSIC
-	save_flags(flags);
-	cli();
-	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
-	eieio();
-#endif
-
-	if (bus == 0)
-		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
-	else
-		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
-	__get_qspan_pci_config(temp, QS_CONFIG_DATA, "lwz");
-	offset ^= 0x02;
-
-#ifdef CONFIG_RPXCLASSIC
-	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
-	eieio();
-	restore_flags(flags);
-#endif
-
-	sp = ((ushort *)&temp) + ((offset >> 1) & 1);
-	*val = *sp;
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int qspan_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
-				   unsigned char offset, unsigned int *val)
-{
-#ifdef CONFIG_RPXCLASSIC
-	unsigned long flags;
-#endif
-
-	if ((bus > 7) || (dev_fn > 127)) {
-		*val = 0xffffffff;
-		return PCIBIOS_DEVICE_NOT_FOUND;
-	}
-
-#ifdef CONFIG_RPXCLASSIC
-	save_flags(flags);
-	cli();
-	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
-	eieio();
-#endif
-
-	if (bus == 0)
-		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
-	else
-		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
-	__get_qspan_pci_config(*val, QS_CONFIG_DATA, "lwz");
-
-#ifdef CONFIG_RPXCLASSIC
-	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
-	eieio();
-	restore_flags(flags);
-#endif
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int qspan_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
-				   unsigned char offset, unsigned char val)
-{
-	uint	temp;
-	u_char	*cp;
-#ifdef CONFIG_RPXCLASSIC
-	unsigned long flags;
-#endif
-
-	if ((bus > 7) || (dev_fn > 127))
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	qspan_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
-
-	offset ^= 0x03;
-	cp = ((u_char *)&temp) + (offset & 0x03);
-	*cp = val;
-
-#ifdef CONFIG_RPXCLASSIC
-	save_flags(flags);
-	cli();
-	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
-	eieio();
-#endif
-
-	if (bus == 0)
-		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
-	else
-		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
-	*QS_CONFIG_DATA = temp;
-
-#ifdef CONFIG_RPXCLASSIC
-	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
-	eieio();
-	restore_flags(flags);
-#endif
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int qspan_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
-				   unsigned char offset, unsigned short val)
-{
-	uint	temp;
-	ushort	*sp;
-#ifdef CONFIG_RPXCLASSIC
-	unsigned long flags;
-#endif
-
-	if ((bus > 7) || (dev_fn > 127))
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-	qspan_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
-
-	offset ^= 0x02;
-	sp = ((ushort *)&temp) + ((offset >> 1) & 1);
-	*sp = val;
-
-#ifdef CONFIG_RPXCLASSIC
-	save_flags(flags);
-	cli();
-	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
-	eieio();
-#endif
-
-	if (bus == 0)
-		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
-	else
-		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
-	*QS_CONFIG_DATA = temp;
-
-#ifdef CONFIG_RPXCLASSIC
-	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
-	eieio();
-	restore_flags(flags);
-#endif
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int qspan_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
-				    unsigned char offset, unsigned int val)
-{
-#ifdef CONFIG_RPXCLASSIC
-	unsigned long flags;
-#endif
-
-	if ((bus > 7) || (dev_fn > 127))
-		return PCIBIOS_DEVICE_NOT_FOUND;
-
-#ifdef CONFIG_RPXCLASSIC
-	save_flags(flags);
-	cli();
-	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
-	eieio();
-#endif
-
-	if (bus == 0)
-		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
-	else
-		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
-	*(unsigned int *)QS_CONFIG_DATA = val;
-
-#ifdef CONFIG_RPXCLASSIC
-	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
-	eieio();
-	restore_flags(flags);
-#endif
-
-	return PCIBIOS_SUCCESSFUL;
-}
-
-int qspan_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
-			     unsigned short index, unsigned char *bus_ptr,
-			     unsigned char *dev_fn_ptr)
-{
-    int num, devfn;
-    unsigned int x, vendev;
-
-    if (vendor == 0xffff)
-	return PCIBIOS_BAD_VENDOR_ID;
-    vendev = (dev_id << 16) + vendor;
-    num = 0;
-    for (devfn = 0;  devfn < 32;  devfn++) {
-	qspan_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x);
-	if (x == vendev) {
-	    if (index == num) {
-		*bus_ptr = 0;
-		*dev_fn_ptr = devfn<<3;
-		return PCIBIOS_SUCCESSFUL;
-	    }
-	    ++num;
-	}
-    }
-    return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-int qspan_pcibios_find_class(unsigned int class_code, unsigned short index,
-			    unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
-{
-    int devnr, x, num;
-
-    num = 0;
-    for (devnr = 0;  devnr < 32;  devnr++) {
-	qspan_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x);
-	if ((x>>8) == class_code) {
-	    if (index == num) {
-		*bus_ptr = 0;
-		*dev_fn_ptr = devnr<<3;
-		return PCIBIOS_SUCCESSFUL;
-	    }
-	    ++num;
-	}
-    }
-    return PCIBIOS_DEVICE_NOT_FOUND;
-}
-
-void __init
-m8xx_pcibios_fixup(void))
-{
-   /* Lots to do here, all board and configuration specific. */
-}
-
-void __init
-m8xx_setup_pci_ptrs(void))
-{
-	set_config_access_method(qspan);
-
-	ppc_md.pcibios_fixup = m8xx_pcibios_fixup;
-}
-
diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
--- a/arch/ppc/kernel/setup.c	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/kernel/setup.c	Sun Nov 10 19:28:41 2002
@@ -54,6 +54,8 @@
 extern void kgdb_map_scc(void);
 #endif
 
+extern void ppc6xx_idle(void);
+
 extern boot_infos_t *boot_infos;
 char saved_command_line[256];
 unsigned char aux_device_present;
@@ -527,6 +529,10 @@
 #ifdef CONFIG_CMDLINE
 	strcpy(cmd_line, CONFIG_CMDLINE);
 #endif /* CONFIG_CMDLINE */
+
+#if defined(CONFIG_6xx) || defined(CONFIG_ALL_PPC)
+	ppc_md.power_save = ppc6xx_idle;
+#endif
 
 	platform_init(r3, r4, r5, r6, r7);
 
diff -Nru a/arch/ppc/kernel/todc_time.c b/arch/ppc/kernel/todc_time.c
--- a/arch/ppc/kernel/todc_time.c	Sun Nov 10 19:28:40 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,456 +0,0 @@
-/*
- * arch/ppc/kernel/todc_time.c
- * 
- * Time of Day Clock support for the M48T35, M48T37, M48T59, and MC146818
- * Real Time Clocks/Timekeepers.
- *
- * Author: Mark A. Greer
- *         mgreer@mvista.com
- *
- * Copyright 2001 MontaVista Software 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.
- */
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/time.h>
-#include <linux/timex.h>
-
-#include <asm/machdep.h>
-#include <asm/io.h>
-#include <asm/time.h>
-#include <asm/todc.h>
-
-/*
- * Depending on the hardware on your board and your board design, the
- * RTC/NVRAM may be accessed either directly (like normal memory) or via
- * address/data registers.  If your board uses the direct method, set
- * 'nvram_data' to the base address of your nvram and leave 'nvram_as0' and
- * 'nvram_as1' NULL.  If your board uses address/data regs to access nvram,
- * set 'nvram_as0' to the address of the lower byte, set 'nvram_as1' to the
- * address of the upper byte (leave NULL if using mv146818), and set
- * 'nvram_data' to the address of the 8-bit data register.
- *
- * You also need to set 'ppc_md.nvram_read_val' and 'ppc_md.nvram_write_val' to
- * the proper routines.  There are standard ones defined further down in
- * this file that you can use.
- *
- * There is a built in assumption that the RTC and NVRAM are accessed by the
- * same mechanism (i.e., ppc_md.nvram_read_val, etc works for both).
- *
- * Note: Even though the documentation for the various RTC chips say that it
- * 	 take up to a second before it starts updating once the 'R' bit is
- * 	 cleared, they always seem to update even though we bang on it many
- * 	 times a second.  This is true, except for the Dallas Semi 1746/1747
- * 	 (possibly others).  Those chips seem to have a real problem whenever
- * 	 we set the 'R' bit before reading them, they basically stop counting.
- * 	 					--MAG
- */
-
-/*
- * 'todc_info' should be initialized in your *_setup.c file to
- * point to a fully initialized 'todc_info_t' structure.
- * This structure holds all the register offsets for your particular
- * TODC/RTC chip.
- * TODC_ALLOC()/TODC_INIT() will allocate and initialize this table for you.
- */
-
-#ifdef	RTC_FREQ_SELECT
-#undef	RTC_FREQ_SELECT
-#define	RTC_FREQ_SELECT		control_b	/* Register A */
-#endif
-
-#ifdef	RTC_CONTROL
-#undef	RTC_CONTROL
-#define	RTC_CONTROL		control_a	/* Register B */
-#endif
-
-#ifdef	RTC_INTR_FLAGS
-#undef	RTC_INTR_FLAGS
-#define	RTC_INTR_FLAGS		watchdog	/* Register C */
-#endif
-
-#ifdef	RTC_VALID
-#undef	RTC_VALID
-#define	RTC_VALID		interrupts	/* Register D */
-#endif
-
-/* Access routines when RTC accessed directly (like normal memory) */
-u_char
-todc_direct_read_val(int addr)
-{
-	return readb(todc_info->nvram_data + addr);
-}
-  
-void
-todc_direct_write_val(int addr, unsigned char val)
-{
-	writeb(val, todc_info->nvram_data + addr);
-	return;
-}
-
-/* Access routines for accessing m48txx type chips via addr/data regs */
-u_char
-todc_m48txx_read_val(int addr)
-{
-	outb(addr, todc_info->nvram_as0);
-	outb(addr>>todc_info->as0_bits, todc_info->nvram_as1);
-	return inb(todc_info->nvram_data);
-}
-  
-void
-todc_m48txx_write_val(int addr, unsigned char val)
-{
-	outb(addr, todc_info->nvram_as0);
-	outb(addr>>todc_info->as0_bits, todc_info->nvram_as1);
-   	outb(val, todc_info->nvram_data);
-	return;
-}
-
-/* Access routines for accessing mc146818 type chips via addr/data regs */
-u_char
-todc_mc146818_read_val(int addr)
-{
-	outb(addr, todc_info->nvram_as0);
-	return inb(todc_info->nvram_data);
-}
-  
-void
-todc_mc146818_write_val(int addr, unsigned char val)
-{
-	outb(addr, todc_info->nvram_as0);
-   	outb(val, todc_info->nvram_data);
-	return;
-}
-
-/*
- * TODC routines
- *
- * There is some ugly stuff in that there are assumptions for the mc146818.
- *
- * Assumptions:
- *	- todc_info->control_a has the offset as mc146818 Register B reg
- *	- todc_info->control_b has the offset as mc146818 Register A reg
- *	- m48txx control reg's write enable or 'W' bit is same as
- *	  mc146818 Register B 'SET' bit (i.e., 0x80)
- *
- * These assumptions were made to make the code simpler.
- */
-long __init
-todc_time_init(void)
-{
-	static u_char	not_initialized = 1;
-
-	/* Make sure clocks are running */
-	if (not_initialized) {
-		u_char	cntl_b;
-
-		cntl_b = ppc_md.nvram_read_val(todc_info->control_b);
-
-		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
-			if ((cntl_b & 0x70) != 0x20) {
-				printk(KERN_INFO "TODC %s %s\n",
-					"real-time-clock was stopped.",
-					"Now starting...");
-				cntl_b &= ~0x70;
-				cntl_b |= 0x20;
-			}
-
-			ppc_md.nvram_write_val(todc_info->control_b, cntl_b);
-		}
-		else if (todc_info->rtc_type == TODC_TYPE_DS1501) {
-			u_char	month;
-
-			todc_info->enable_read = TODC_DS1501_CNTL_B_TE;
-			todc_info->enable_write = TODC_DS1501_CNTL_B_TE;
-
-			month = ppc_md.nvram_read_val(todc_info->month);
-
-			if ((month & 0x80) == 0x80) {
-				printk(KERN_INFO "TODC %s %s\n",
-					"real-time-clock was stopped.",
-					"Now starting...");
-				month &= ~0x80;
-				ppc_md.nvram_write_val(todc_info->month, month);
-			}
-
-			cntl_b &= ~TODC_DS1501_CNTL_B_TE;
-			ppc_md.nvram_write_val(todc_info->control_b, cntl_b);
-		}
-		else { /* must be a m48txx type */
-			u_char	cntl_a;
-
-			todc_info->enable_read = TODC_MK48TXX_CNTL_A_R;
-			todc_info->enable_write = TODC_MK48TXX_CNTL_A_W;
-
-			cntl_a = ppc_md.nvram_read_val(todc_info->control_a);
-
-			/* Check & clear STOP bit in control B register */
-			if (cntl_b & TODC_MK48TXX_DAY_CB) {
-				printk(KERN_INFO "TODC %s %s\n",
-					"real-time-clock was stopped.",
-					"Now starting...");
-
-				cntl_a |= todc_info->enable_write;
-				cntl_b &= ~TODC_MK48TXX_DAY_CB;/* Start Oscil */
-
-				ppc_md.nvram_write_val(todc_info->control_a,
-						       cntl_a);
-				ppc_md.nvram_write_val(todc_info->control_b,
-						       cntl_b);
-			}
-
-			/* Make sure READ & WRITE bits are cleared. */
-			cntl_a &= ~(todc_info->enable_write |
-				    todc_info->enable_read);
-			ppc_md.nvram_write_val(todc_info->control_a, cntl_a);
-		}
-
-		not_initialized = 0;
-	}
-
-
-	return 0;
-}
-
-/*
- * There is some ugly stuff in that there are assumptions that for a mc146818,
- * the todc_info->control_a has the offset of the mc146818 Register B reg and
- * that the register'ss 'SET' bit is the same as the m48txx's write enable
- * bit in the control register of the m48txx (i.e., 0x80).
- *
- * It was done to make the code look simpler.
- */
-ulong
-todc_get_rtc_time(void)
-{
-	uint	year, mon, day, hour, min, sec;
-	uint	limit, i;
-	u_char	save_control, uip;
-
-	save_control = ppc_md.nvram_read_val(todc_info->control_a);
-
-	if (todc_info->rtc_type != TODC_TYPE_MC146818) {
-		limit = 1;
-
-		switch (todc_info->rtc_type) {
-			case TODC_TYPE_DS1557:
-			case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
-			case TODC_TYPE_DS1747:
-				break;
-			default:
-				ppc_md.nvram_write_val(todc_info->control_a,
-				       (save_control | todc_info->enable_read));
-		}
-	}
-	else {
-		limit = 100000000;
-	}
-
-	for (i=0; i<limit; i++) {
-		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
-			uip = ppc_md.nvram_read_val(todc_info->RTC_FREQ_SELECT);
-		}
-
-		sec = ppc_md.nvram_read_val(todc_info->seconds) & 0x7f;
-		min = ppc_md.nvram_read_val(todc_info->minutes) & 0x7f;
-		hour = ppc_md.nvram_read_val(todc_info->hours) & 0x3f;
-		day = ppc_md.nvram_read_val(todc_info->day_of_month) & 0x3f;
-		mon = ppc_md.nvram_read_val(todc_info->month) & 0x1f;
-		year = ppc_md.nvram_read_val(todc_info->year) & 0xff;
-
-		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
-			uip |= ppc_md.nvram_read_val(
-					todc_info->RTC_FREQ_SELECT);
-			if ((uip & RTC_UIP) == 0) break;
-		}
-	}
-
-	if (todc_info->rtc_type != TODC_TYPE_MC146818) {
-		switch (todc_info->rtc_type) {
-			case TODC_TYPE_DS1557:
-			case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
-			case TODC_TYPE_DS1747:
-				break;
-			default:
-				save_control &= ~(todc_info->enable_read);
-				ppc_md.nvram_write_val(todc_info->control_a,
-						       save_control);
-		}
-	}
-
-	if ((todc_info->rtc_type != TODC_TYPE_MC146818) ||
-	    ((save_control & RTC_DM_BINARY) == 0) ||
-	    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);
-	}
-
-	year = year + 1900;
-	if (year < 1970) {
-		year += 100;
-	}
-
-	return mktime(year, mon, day, hour, min, sec);
-}
-
-int
-todc_set_rtc_time(unsigned long nowtime)
-{
-	struct rtc_time	tm;
-	u_char		save_control, save_freq_select;
-
-	to_tm(nowtime, &tm);
-
-	save_control = ppc_md.nvram_read_val(todc_info->control_a);
-
-	/* Assuming MK48T59_RTC_CA_WRITE & RTC_SET are equal */
-	ppc_md.nvram_write_val(todc_info->control_a,
-			       (save_control | todc_info->enable_write));
-	save_control &= ~(todc_info->enable_write); /* in case it was set */
-
-	if (todc_info->rtc_type == TODC_TYPE_MC146818) {
-		save_freq_select =
-			ppc_md.nvram_read_val(todc_info->RTC_FREQ_SELECT);
-		ppc_md.nvram_write_val(todc_info->RTC_FREQ_SELECT,
-				       save_freq_select | RTC_DIV_RESET2);
-	}
-
-
-        tm.tm_year = (tm.tm_year - 1900) % 100;
-
-	if ((todc_info->rtc_type != TODC_TYPE_MC146818) ||
-	    ((save_control & RTC_DM_BINARY) == 0) ||
-	    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);
-	}
-
-	ppc_md.nvram_write_val(todc_info->seconds,      tm.tm_sec);
-	ppc_md.nvram_write_val(todc_info->minutes,      tm.tm_min);
-	ppc_md.nvram_write_val(todc_info->hours,        tm.tm_hour);
-	ppc_md.nvram_write_val(todc_info->month,        tm.tm_mon);
-	ppc_md.nvram_write_val(todc_info->day_of_month, tm.tm_mday);
-	ppc_md.nvram_write_val(todc_info->year,         tm.tm_year);
-	
-	ppc_md.nvram_write_val(todc_info->control_a, save_control);
-
-	if (todc_info->rtc_type == TODC_TYPE_MC146818) {
-		ppc_md.nvram_write_val(todc_info->RTC_FREQ_SELECT,
-				       save_freq_select);
-	}
-
-	return 0;
-}
-
-/*
- * Manipulates read bit to reliably read seconds at a high rate.
- */
-static unsigned char __init todc_read_timereg(int addr)
-{
-	unsigned char save_control, val;
-
-	switch (todc_info->rtc_type) {
-		case TODC_TYPE_DS1557:
-		case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
-		case TODC_TYPE_DS1747:
-		case TODC_TYPE_MC146818:
-			break;
-		default:
-			save_control =
-				ppc_md.nvram_read_val(todc_info->control_a);
-			ppc_md.nvram_write_val(todc_info->control_a,
-				       (save_control | todc_info->enable_read));
-	}
-	val = ppc_md.nvram_read_val(addr);
-
-	switch (todc_info->rtc_type) {
-		case TODC_TYPE_DS1557:
-		case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
-		case TODC_TYPE_DS1747:
-		case TODC_TYPE_MC146818:
-			break;
-		default:
-			save_control &= ~(todc_info->enable_read);
-			ppc_md.nvram_write_val(todc_info->control_a,
-					       save_control);
-	}
-
-	return val;
-} 
-
-/*
- * This was taken from prep_setup.c
- * Use the NVRAM RTC to time a second to calibrate the decrementer.
- */
-void __init
-todc_calibrate_decr(void)
-{
-	ulong	freq;
-	ulong	tbl, tbu;
-        long	i, loop_count;
-        u_char	sec;
- 
-	todc_time_init();
-
-	/*
-	 * 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.
-	 */
-	/*
-	 * Need to make sure the tbl doesn't roll over so if tbu increments
-	 * during this test, we need to do it again.
-	 */
-	loop_count = 0;
-
-	sec = todc_read_timereg(todc_info->seconds) & 0x7f;
-
-	do {
-		tbu = get_tbu();
-
-		for (i = 0 ; i < 10000000 ; i++) {/* may take up to 1 second */
-		   tbl = get_tbl();
-
-		   if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) {
-		      break;
-		   }
-		}
-
-		sec = todc_read_timereg(todc_info->seconds) & 0x7f;
-
-		for (i = 0 ; i < 10000000 ; i++) { /* Should take 1 second */
-		   freq = get_tbl();
-
-		   if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) {
-		      break;
-		   }
-		}
-
-		freq -= tbl;
-	} while ((get_tbu() != tbu) && (++loop_count < 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);
-
-	return;
-}
diff -Nru a/arch/ppc/mm/Makefile b/arch/ppc/mm/Makefile
--- a/arch/ppc/mm/Makefile	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc/mm/Makefile	Sun Nov 10 19:28:40 2002
@@ -6,8 +6,6 @@
 EXTRA_AFLAGS		:= -Wa,-mppc64bridge
 endif
 
-AFLAGS_hashtable.o	+= -I$(TOPDIR)/arch/$(ARCH)/kernel
-
 obj-y				:= fault.o init.o mem_pieces.o extable.o \
 					mmu_context.o pgtable.o
 
diff -Nru a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
--- a/arch/ppc/mm/init.c	Sun Nov 10 19:28:37 2002
+++ b/arch/ppc/mm/init.c	Sun Nov 10 19:28:37 2002
@@ -47,11 +47,13 @@
 #include "mem_pieces.h"
 #include "mmu_decl.h"
 
-#ifdef CONFIG_LOWMEM_SIZE_BOOL
+#if defined(CONFIG_KERNEL_START_BOOL) || defined(CONFIG_LOWMEM_SIZE_BOOL)
+/* The ammount of lowmem must be within 0xF0000000 - KERNELBASE. */
+#if (CONFIG_LOWMEM_SIZE > (0xF0000000 - KERNELBASE))
+#error "You must adjust CONFIG_LOWMEM_SIZE or CONFIG_START_KERNEL"
+#endif
+#endif
 #define MAX_LOW_MEM	CONFIG_LOWMEM_SIZE
-#else
-#define MAX_LOW_MEM	(0xF0000000UL - KERNELBASE)
-#endif /* CONFIG_LOWMEM_SIZE_BOOL */
 
 #ifdef CONFIG_PPC_ISERIES
 extern void create_virtual_bus_tce_table(void);
@@ -472,11 +474,23 @@
 	if (agp_special_page)
 		printk(KERN_INFO "AGP special page: 0x%08lx\n", agp_special_page);
 #endif /* defined(CONFIG_ALL_PPC) */
-#ifdef CONFIG_PPC_ISERIES
 
+#ifdef CONFIG_PPC_ISERIES
 	create_virtual_bus_tce_table();
-
 #endif /* CONFIG_PPC_ISERIES */
+
+	/* Make sure all our pagetable pages have page->mapping
+	   and page->index set correctly. */
+	for (addr = KERNELBASE; addr != 0; addr += PGDIR_SIZE) {
+		struct page *pg;
+		pmd_t *pmd = pmd_offset(pgd_offset_k(addr), addr);
+		if (pmd_present(*pmd)) {
+			pg = pmd_page(*pmd);
+			pg->mapping = (void *) &init_mm;
+			pg->index = addr;
+		}
+	}
+
 	mem_init_done = 1;
 }
 
@@ -556,28 +570,17 @@
 	clear_bit(PG_arch_1, &page->flags);
 }
 
-void flush_icache_page(struct vm_area_struct *vma, struct page *page)
-{
-	unsigned long phys;
-
-	if (page->mapping && !PageReserved(page)
-	    && !test_bit(PG_arch_1, &page->flags)) {
-		phys = page_to_pfn(page) << PAGE_SHIFT;
-		__flush_dcache_icache_phys(phys);
-		set_bit(PG_arch_1, &page->flags);
-	}
-}
-
 void clear_user_page(void *page, unsigned long vaddr, struct page *pg)
 {
 	clear_page(page);
+	clear_bit(PG_arch_1, &pg->flags);
 }
 
 void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
 		    struct page *pg)
 {
 	copy_page(vto, vfrom);
-	__flush_dcache_icache(vto);
+	clear_bit(PG_arch_1, &pg->flags);
 }
 
 void flush_icache_user_range(struct vm_area_struct *vma, struct page *page,
@@ -588,4 +591,39 @@
 	maddr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK);
 	flush_icache_range(maddr, maddr + len);
 	kunmap(page);
+}
+
+/*
+ * This is called at the end of handling a user page fault, when the
+ * fault has been handled by updating a PTE in the linux page tables.
+ * We use it to preload an HPTE into the hash table corresponding to
+ * the updated linux PTE.
+ */
+void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
+		      pte_t pte)
+{
+	/* handle i-cache coherency */
+	unsigned long pfn = pte_pfn(pte);
+
+	if (pfn_valid(pfn)) {
+		struct page *page = pfn_to_page(pfn);
+		if (!PageReserved(page)
+		    && !test_bit(PG_arch_1, &page->flags)) {
+			__flush_dcache_icache((void *) address);
+			set_bit(PG_arch_1, &page->flags);
+		}
+	}
+
+#ifdef CONFIG_PPC_STD_MMU
+	/* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */
+	if (Hash != 0 && pte_young(pte)) {
+		struct mm_struct *mm;
+		pmd_t *pmd;
+
+		mm = (address < TASK_SIZE)? vma->vm_mm: &init_mm;
+		pmd = pmd_offset(pgd_offset(mm, address), address);
+		if (!pmd_none(*pmd))
+			add_hash_page(mm->context, address, pmd_val(*pmd));
+	}
+#endif
 }
diff -Nru a/arch/ppc/mm/ppc_mmu.c b/arch/ppc/mm/ppc_mmu.c
--- a/arch/ppc/mm/ppc_mmu.c	Sun Nov 10 19:28:37 2002
+++ b/arch/ppc/mm/ppc_mmu.c	Sun Nov 10 19:28:37 2002
@@ -280,27 +280,3 @@
 
 	if ( ppc_md.progress ) ppc_md.progress("hash:done", 0x205);
 }
-
-/*
- * This is called at the end of handling a user page fault, when the
- * fault has been handled by updating a PTE in the linux page tables.
- * We use it to preload an HPTE into the hash table corresponding to
- * the updated linux PTE.
- */
-void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
-		      pte_t pte)
-{
-	struct mm_struct *mm;
-	pmd_t *pmd;
-	static int nopreload;
-
-	if (Hash == 0 || nopreload)
-		return;
-	/* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */
-	if (!pte_young(pte))
-		return;
-	mm = (address < TASK_SIZE)? vma->vm_mm: &init_mm;
-	pmd = pmd_offset(pgd_offset(mm, address), address);
-	if (!pmd_none(*pmd))
-		add_hash_page(mm->context, address, pmd_val(*pmd));
-}
diff -Nru a/arch/ppc/platforms/4xx/ash.h b/arch/ppc/platforms/4xx/ash.h
--- a/arch/ppc/platforms/4xx/ash.h	Sun Nov 10 19:28:37 2002
+++ b/arch/ppc/platforms/4xx/ash.h	Sun Nov 10 19:28:37 2002
@@ -17,8 +17,8 @@
 #ifdef __KERNEL__
 #ifndef __ASM_ASH_H__
 #define __ASM_ASH_H__
-#include <platforms/ibm_ocp.h>
-#include <platforms/ibmnp405h.h>
+#include <platforms/4xx/ibm_ocp.h>
+#include <platforms/4xx/ibmnp405h.h>
 
 #ifndef __ASSEMBLY__
 /*
diff -Nru a/arch/ppc/platforms/4xx/cedar.h b/arch/ppc/platforms/4xx/cedar.h
--- a/arch/ppc/platforms/4xx/cedar.h	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc/platforms/4xx/cedar.h	Sun Nov 10 19:28:40 2002
@@ -17,7 +17,7 @@
 #ifdef __KERNEL__
 #ifndef __ASM_CEDER_H__
 #define __ASM_CEDER_H__
-#include <platforms/ibmnp405l.h>
+#include <platforms/4xx/ibmnp405l.h>
 
 #ifndef __ASSEMBLY__
 /*
diff -Nru a/arch/ppc/platforms/4xx/ep405.c b/arch/ppc/platforms/4xx/ep405.c
--- a/arch/ppc/platforms/4xx/ep405.c	Sun Nov 10 19:28:37 2002
+++ b/arch/ppc/platforms/4xx/ep405.c	Sun Nov 10 19:28:37 2002
@@ -12,7 +12,7 @@
 #include <asm/pci-bridge.h>
 #include <asm/machdep.h>
 #include <asm/todc.h>
-#include <platforms/ibm_ocp.h>
+#include <platforms/4xx/ibm_ocp.h>
 
 #undef DEBUG
 #ifdef DEBUG
diff -Nru a/arch/ppc/platforms/4xx/ep405.h b/arch/ppc/platforms/4xx/ep405.h
--- a/arch/ppc/platforms/4xx/ep405.h	Sun Nov 10 19:28:36 2002
+++ b/arch/ppc/platforms/4xx/ep405.h	Sun Nov 10 19:28:36 2002
@@ -13,7 +13,7 @@
 #define __ASM_EP405_H__
 
 /* We have a 405GP core */
-#include <platforms/ibm405gp.h>
+#include <platforms/4xx/ibm405gp.h>
 
 #ifndef __ASSEMBLY__
 typedef struct board_info {
diff -Nru a/arch/ppc/platforms/4xx/ibm405gp.c b/arch/ppc/platforms/4xx/ibm405gp.c
--- a/arch/ppc/platforms/4xx/ibm405gp.c	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc/platforms/4xx/ibm405gp.c	Sun Nov 10 19:28:40 2002
@@ -39,7 +39,7 @@
 #include <linux/threads.h>
 #include <linux/param.h>
 #include <linux/string.h>
-#include <platforms/ibm405gp.h>
+#include <platforms/4xx/ibm405gp.h>
 
 const struct pcil0_regs *PCIL_ADDR[] = {
 	(struct pcil0_regs *) PCIL0_BASE,
diff -Nru a/arch/ppc/platforms/4xx/ibm405gp.h b/arch/ppc/platforms/4xx/ibm405gp.h
--- a/arch/ppc/platforms/4xx/ibm405gp.h	Sun Nov 10 19:28:36 2002
+++ b/arch/ppc/platforms/4xx/ibm405gp.h	Sun Nov 10 19:28:36 2002
@@ -50,7 +50,7 @@
 #define __ASM_IBM405GP_H__
 
 #include <linux/config.h>
-#include <platforms/ibm_ocp.h>
+#include <platforms/4xx/ibm_ocp.h>
 
 /* ibm405.h at bottom of this file */
 
@@ -189,7 +189,7 @@
 #define DCRN_UIC0_BASE		0x0C0
 #define UIC0 DCRN_UIC0_BASE
 
-#include <platforms/ibm405.h>
+#include <asm/ibm405.h>
 
 #endif				/* __ASM_IBM405GP_H__ */
 #endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/ibmnp405h.c b/arch/ppc/platforms/4xx/ibmnp405h.c
--- a/arch/ppc/platforms/4xx/ibmnp405h.c	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/platforms/4xx/ibmnp405h.c	Sun Nov 10 19:28:41 2002
@@ -39,7 +39,7 @@
 #include <linux/threads.h>
 #include <linux/param.h>
 #include <linux/string.h>
-#include <platforms/ibmnp405h.h>
+#include <platforms/4xx/ibmnp405h.h>
 
 const struct NS16550* COM_PORTS[] =
 {
diff -Nru a/arch/ppc/platforms/4xx/ibmnp405h.h b/arch/ppc/platforms/4xx/ibmnp405h.h
--- a/arch/ppc/platforms/4xx/ibmnp405h.h	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc/platforms/4xx/ibmnp405h.h	Sun Nov 10 19:28:40 2002
@@ -42,7 +42,7 @@
 #define __ASM_IBMNP405H_H__
 
 #include <linux/config.h>
-#include <platforms/ibm_ocp.h>
+#include <platforms/4xx/ibm_ocp.h>
 
 /* ibm405.h at bottom of this file */
 
@@ -166,7 +166,7 @@
 #define DCRN_UIC1_VCR	(DCRN_UIC1_BASE + 0x8)
 #endif
 
-#include <platforms/ibm405.h>
+#include <asm/ibm405.h>
 
 #endif				/* __ASM_IBMNP405H_H__ */
 #endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/ibmnp405l.c b/arch/ppc/platforms/4xx/ibmnp405l.c
--- a/arch/ppc/platforms/4xx/ibmnp405l.c	Sun Nov 10 19:28:37 2002
+++ b/arch/ppc/platforms/4xx/ibmnp405l.c	Sun Nov 10 19:28:37 2002
@@ -39,7 +39,7 @@
 #include <linux/threads.h>
 #include <linux/param.h>
 #include <linux/string.h>
-#include <platforms/ibmnp405l.h>
+#include <platforms/4xx/ibmnp405l.h>
 
 const struct NS16550* COM_PORTS[] =
 {
diff -Nru a/arch/ppc/platforms/4xx/ibmnp405l.h b/arch/ppc/platforms/4xx/ibmnp405l.h
--- a/arch/ppc/platforms/4xx/ibmnp405l.h	Sun Nov 10 19:28:38 2002
+++ b/arch/ppc/platforms/4xx/ibmnp405l.h	Sun Nov 10 19:28:38 2002
@@ -42,7 +42,7 @@
 #define __ASM_IBMNP405L_H__
 
 #include <linux/config.h>
-#include <platforms/ibm_ocp.h>
+#include <platforms/4xx/ibm_ocp.h>
 
 /* ibm405.h at bottom of this file */
 
@@ -150,7 +150,7 @@
 #define DCRN_UIC1_VCR	(DCRN_UIC1_BASE + 0x8)
 #endif
 
-#include <platforms/ibm405.h>
+#include <asm/ibm405.h>
 
 #endif				/* __ASM_IBMNP405L_H__ */
 #endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/ibmstb3.c b/arch/ppc/platforms/4xx/ibmstb3.c
--- a/arch/ppc/platforms/4xx/ibmstb3.c	Sun Nov 10 19:28:36 2002
+++ b/arch/ppc/platforms/4xx/ibmstb3.c	Sun Nov 10 19:28:36 2002
@@ -34,7 +34,7 @@
  */
 
 #include <linux/config.h>
-#include <platforms/ibmstb3.h>
+#include <platforms/4xx/ibmstb3.h>
 
 const struct NS16550* COM_PORTS[] =
 {
diff -Nru a/arch/ppc/platforms/4xx/ibmstb3.h b/arch/ppc/platforms/4xx/ibmstb3.h
--- a/arch/ppc/platforms/4xx/ibmstb3.h	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/platforms/4xx/ibmstb3.h	Sun Nov 10 19:28:41 2002
@@ -48,7 +48,7 @@
 #define __ASM_IBMSTBX_H__
 
 #include <linux/config.h>
-#include <platforms/ibm_ocp.h>
+#include <platforms/4xx/ibm_ocp.h>
 
 /* ibm405.h at bottom of this file */
 
@@ -282,7 +282,7 @@
 #define DCRN_OCMDSCR	(DCRN_OCM0_BASE + 0x3)	/* OCM Data Side Control */
 #endif
 
-#include <platforms/ibm405.h>
+#include <asm/ibm405.h>
 
 #endif				/* __ASM_IBMSTBX_H__ */
 #endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/ibmstb4.c b/arch/ppc/platforms/4xx/ibmstb4.c
--- a/arch/ppc/platforms/4xx/ibmstb4.c	Sun Nov 10 19:28:37 2002
+++ b/arch/ppc/platforms/4xx/ibmstb4.c	Sun Nov 10 19:28:37 2002
@@ -34,7 +34,7 @@
  */
 
 #include <linux/config.h>
-#include <platforms/ibmstb4.h>
+#include <platforms/4xx/ibmstb4.h>
 
 const struct NS16550* COM_PORTS[] =
 {
diff -Nru a/arch/ppc/platforms/4xx/ibmstb4.h b/arch/ppc/platforms/4xx/ibmstb4.h
--- a/arch/ppc/platforms/4xx/ibmstb4.h	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/platforms/4xx/ibmstb4.h	Sun Nov 10 19:28:41 2002
@@ -42,7 +42,7 @@
 #define __ASM_IBMSTB4_H__
 
 #include <linux/config.h>
-#include <platforms/ibm_ocp.h>
+#include <platforms/4xx/ibm_ocp.h>
 
 /* serial port defines */
 #define STB04xxx_IO_BASE	((uint)0xe0000000)
@@ -262,7 +262,7 @@
 #define DCRN_BESR0	(DCRN_EBIMC_BASE + 0x21)	/* Bus Error Status Register */
 #define DCRN_BIUCR	(DCRN_EBIMC_BASE + 0x2A)	/* Bus Interfac Unit Ctrl Reg */
 
-#include <platforms/ibm405.h>
+#include <asm/ibm405.h>
 
 #endif				/* __ASM_IBMSTB4_H__ */
 #endif				/* __KERNEL__ */
diff -Nru a/arch/ppc/platforms/4xx/redwood.h b/arch/ppc/platforms/4xx/redwood.h
--- a/arch/ppc/platforms/4xx/redwood.h	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/platforms/4xx/redwood.h	Sun Nov 10 19:28:41 2002
@@ -16,7 +16,7 @@
 #define __ASM_REDWOOD_H__
 
 /* Redwoods have an STB03xxx or STB04xxx core */
-#include <platforms/ibmstb3.h>
+#include <platforms/4xx/ibmstb3.h>
 
 #ifndef __ASSEMBLY__
 typedef struct board_info {
diff -Nru a/arch/ppc/platforms/4xx/redwood5.h b/arch/ppc/platforms/4xx/redwood5.h
--- a/arch/ppc/platforms/4xx/redwood5.h	Sun Nov 10 19:28:36 2002
+++ b/arch/ppc/platforms/4xx/redwood5.h	Sun Nov 10 19:28:36 2002
@@ -16,7 +16,7 @@
 #define __ASM_REDWOOD5_H__
 
 /* Redwood5 has an STB04xxx core */
-#include <platforms/ibmstb4.h>
+#include <platforms/4xx/ibmstb4.h>
 
 #ifndef __ASSEMBLY__
 typedef struct board_info {
diff -Nru a/arch/ppc/platforms/4xx/walnut.c b/arch/ppc/platforms/4xx/walnut.c
--- a/arch/ppc/platforms/4xx/walnut.c	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc/platforms/4xx/walnut.c	Sun Nov 10 19:28:40 2002
@@ -39,7 +39,7 @@
 #include <asm/page.h>
 #include <asm/time.h>
 #include <asm/io.h>
-#include <platforms/ibm_ocp.h>
+#include <platforms/4xx/ibm_ocp.h>
 
 #ifdef CONFIG_PPC_RTC
 #include <asm/todc.h>
diff -Nru a/arch/ppc/platforms/4xx/walnut.h b/arch/ppc/platforms/4xx/walnut.h
--- a/arch/ppc/platforms/4xx/walnut.h	Sun Nov 10 19:28:39 2002
+++ b/arch/ppc/platforms/4xx/walnut.h	Sun Nov 10 19:28:39 2002
@@ -25,7 +25,7 @@
 #define __ASM_WALNUT_H__
 
 /* We have a 405GP core */
-#include <platforms/ibm405gp.h>
+#include <platforms/4xx/ibm405gp.h>
 
 #ifndef __ASSEMBLY__
 /*
diff -Nru a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile
--- a/arch/ppc/platforms/Makefile	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/platforms/Makefile	Sun Nov 10 19:28:41 2002
@@ -37,14 +37,14 @@
 obj-$(CONFIG_MCPN765)		+= mcpn765_setup.o mcpn765_pci.o
 obj-$(CONFIG_MENF1)		+= menf1_setup.o menf1_pci.o
 obj-$(CONFIG_MVME5100)		+= mvme5100_setup.o mvme5100_pci.o
-obj-$(CONFIG_PAL4)		+= pal4_setup.o pal4_pci.o cpc700_pic.o
+obj-$(CONFIG_PAL4)		+= pal4_setup.o pal4_pci.o
 obj-$(CONFIG_PCORE)		+= pcore_setup.o pcore_pci.o
 obj-$(CONFIG_POWERPMC250)	+= powerpmc250.o
 obj-$(CONFIG_PPLUS)		+= pplus_pci.o pplus_setup.o
 obj-$(CONFIG_PRPMC750)		+= prpmc750_setup.o prpmc750_pci.o
 obj-$(CONFIG_PRPMC800)		+= prpmc800_setup.o prpmc800_pci.o
 obj-$(CONFIG_SANDPOINT)		+= sandpoint_setup.o sandpoint_pci.o
-obj-$(CONFIG_SPRUCE)		+= spruce_setup.o spruce_pci.o cpc700_pic.o
+obj-$(CONFIG_SPRUCE)		+= spruce_setup.o spruce_pci.o
 obj-$(CONFIG_ZX4500)		+= zx4500_setup.o zx4500_pci.o
 obj-$(CONFIG_PPC_ISERIES)	+= iSeries_setup.o iSeries_time.o \
 					iSeries_dma.o iSeries_pic.o
diff -Nru a/arch/ppc/platforms/adir_pci.c b/arch/ppc/platforms/adir_pci.c
--- a/arch/ppc/platforms/adir_pci.c	Sun Nov 10 19:28:38 2002
+++ b/arch/ppc/platforms/adir_pci.c	Sun Nov 10 19:28:39 2002
@@ -18,7 +18,7 @@
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
 
-#include "cpc710.h"
+#include <syslib/cpc710.h>
 #include "adir.h"
 
 #undef DEBUG
diff -Nru a/arch/ppc/platforms/cpc700.h b/arch/ppc/platforms/cpc700.h
--- a/arch/ppc/platforms/cpc700.h	Sun Nov 10 19:28:38 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,109 +0,0 @@
-/*
- * include/asm-ppc/cpc700.h
- * 
- * Header file for IBM CPC700 Host Bridge, et. al.
- *
- * Author: Mark A. Greer
- *         mgreer@mvista.com
- *
- * Copyright 2000-2002 MontaVista Software 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  SOFTWARE  IS PROVIDED   ``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  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 OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * You should have received a copy of the  GNU General Public License along
- * with this program; if not, write  to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/*
- * This file contains the defines and macros for the IBM CPC700 host bridge,
- * memory controller, PIC, UARTs, IIC, and Timers.
- */
-
-#ifndef	_ASMPPC_CPC700_H
-#define	_ASMPPC_CPC700_H
-
-#include <linux/stddef.h>
-#include <linux/types.h>
-#include <linux/init.h>
-
-#define CPC700_OUT_32(a,d)  (*(u_int *)a = d)
-#define CPC700_IN_32(a)     (*(u_int *)a)
-
-/*
- * PCI Section
- */
-#define CPC700_PCI_CONFIG_ADDR          0xfec00000
-#define CPC700_PCI_CONFIG_DATA          0xfec00004
-
-#define CPC700_PMM0_LOCAL		0xff400000
-#define CPC700_PMM0_MASK_ATTR		0xff400004
-#define CPC700_PMM0_PCI_LOW		0xff400008
-#define CPC700_PMM0_PCI_HIGH		0xff40000c
-#define CPC700_PMM1_LOCAL		0xff400010
-#define CPC700_PMM1_MASK_ATTR		0xff400014
-#define CPC700_PMM1_PCI_LOW		0xff400018
-#define CPC700_PMM1_PCI_HIGH		0xff40001c
-#define CPC700_PMM2_LOCAL		0xff400020
-#define CPC700_PMM2_MASK_ATTR		0xff400024
-#define CPC700_PMM2_PCI_LOW		0xff400028
-#define CPC700_PMM2_PCI_HIGH		0xff40002c
-#define CPC700_PTM1_MEMSIZE		0xff400030
-#define CPC700_PTM1_LOCAL		0xff400034
-#define CPC700_PTM2_MEMSIZE		0xff400038
-#define CPC700_PTM2_LOCAL		0xff40003c
-
-/*
- * PIC Section
- *
- * IBM calls the CPC700's programmable interrupt controller the Universal
- * Interrupt Controller or UIC.
- */
-
-/*
- * UIC Register Addresses.
- */
-#define	CPC700_UIC_UICSR		0xff500880	/* Status Reg (Rd/Clr)*/
-#define	CPC700_UIC_UICSRS		0xff500884	/* Status Reg (Set) */
-#define	CPC700_UIC_UICER		0xff500888	/* Enable Reg */
-#define	CPC700_UIC_UICCR		0xff50088c	/* Critical Reg */
-#define	CPC700_UIC_UICPR		0xff500890	/* Polarity Reg */
-#define	CPC700_UIC_UICTR		0xff500894	/* Trigger Reg */
-#define	CPC700_UIC_UICMSR		0xff500898	/* Masked Status Reg */
-#define	CPC700_UIC_UICVR		0xff50089c	/* Vector Reg */
-#define	CPC700_UIC_UICVCR		0xff5008a0	/* Vector Config Reg */
-
-#define	CPC700_UIC_UICER_ENABLE		0x00000001	/* Enable an IRQ */
-
-#define	CPC700_UIC_UICVCR_31_HI		0x00000000	/* IRQ 31 hi priority */
-#define	CPC700_UIC_UICVCR_0_HI		0x00000001	/* IRQ 0 hi priority */
-#define CPC700_UIC_UICVCR_BASE_MASK	0xfffffffc
-#define CPC700_UIC_UICVCR_ORDER_MASK	0x00000001
-
-/* Specify value of a bit for an IRQ. */
-#define	CPC700_UIC_IRQ_BIT(i)		((0x00000001) << (31 - (i)))
-
-/*
- * UIC Exports...
- */
-extern struct hw_interrupt_type cpc700_pic;
-extern unsigned int cpc700_irq_assigns[32][2];
- 
-extern void __init cpc700_init_IRQ(void);
-extern int cpc700_get_irq(struct pt_regs *);
-
-#endif	/* _ASMPPC_CPC700_H */
diff -Nru a/arch/ppc/platforms/cpc700_pic.c b/arch/ppc/platforms/cpc700_pic.c
--- a/arch/ppc/platforms/cpc700_pic.c	Sun Nov 10 19:28:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,205 +0,0 @@
-/*
- * arch/ppc/platforms/cpc700_pic.c
- * 
- * Interrupt controller support for IBM Spruce
- *
- * Authors: Mark Greer, Matt Porter, and Johnnie Peters
- *	    mgreer@mvista.com
- *          mporter@mvista.com
- *          jpeters@mvista.com
- *
- * Copyright 2001-2002 MontaVista Software 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  SOFTWARE  IS PROVIDED   ``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  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 OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * 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/stddef.h>
-#include <linux/init.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
-#include <linux/irq.h>
-
-#include <asm/io.h>
-#include <asm/processor.h>
-#include <asm/system.h>
-#include <asm/irq.h>
-
-#include "cpc700.h"
-
-static void
-cpc700_unmask_irq(unsigned int irq)
-{
-	unsigned int tr_bits;
-
-	/*
-	 * IRQ 31 is largest IRQ supported.
-	 * IRQs 17-19 are reserved.
-	 */
-	if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
-		tr_bits = CPC700_IN_32(CPC700_UIC_UICTR);
-
-		if ((tr_bits & (1 << (31 - irq))) == 0) {
-			/* level trigger interrupt, clear bit in status
-			 * register */
-			CPC700_OUT_32(CPC700_UIC_UICSR, 1 << (31 - irq));
-		}
-
-		/* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
-		ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq);
-		
-		CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
-	}
-	return;
-}
-
-static void
-cpc700_mask_irq(unsigned int irq)
-{
-	/*
-	 * IRQ 31 is largest IRQ supported.
-	 * IRQs 17-19 are reserved.
-	 */
-	if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
-		/* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
-		ppc_cached_irq_mask[0] &=
-			~CPC700_UIC_IRQ_BIT(irq);
-
-		CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
-	}
-	return;
-}
-
-static void
-cpc700_mask_and_ack_irq(unsigned int irq)
-{
-	u_int	bit;
-
-	/*
-	 * IRQ 31 is largest IRQ supported.
-	 * IRQs 17-19 are reserved.
-	 */
-	if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
-		/* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
-		bit = CPC700_UIC_IRQ_BIT(irq);
-
-		ppc_cached_irq_mask[0] &= ~bit;
-		CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
-		CPC700_OUT_32(CPC700_UIC_UICSR, bit); /* Write 1 clears IRQ */
-	}
-	return;
-}
-
-static struct hw_interrupt_type cpc700_pic = {
-	"CPC700 PIC",
-	NULL,
-	NULL,
-	cpc700_unmask_irq,
-	cpc700_mask_irq,
-	cpc700_mask_and_ack_irq,
-	NULL,
-	NULL
-};
-
-__init static void
-cpc700_pic_init_irq(unsigned int irq)
-{
-	unsigned int tmp;
-
-	/* Set interrupt sense */
-	tmp = CPC700_IN_32(CPC700_UIC_UICTR);
-	if (cpc700_irq_assigns[irq][0] == 0) {
-		tmp &= ~CPC700_UIC_IRQ_BIT(irq);
-	} else {
-		tmp |= CPC700_UIC_IRQ_BIT(irq);
-	}
-	CPC700_OUT_32(CPC700_UIC_UICTR, tmp);
-
-	/* Set interrupt polarity */
-	tmp = CPC700_IN_32(CPC700_UIC_UICPR);
-	if (cpc700_irq_assigns[irq][1]) {
-		tmp |= CPC700_UIC_IRQ_BIT(irq);
-	} else {
-		tmp &= ~CPC700_UIC_IRQ_BIT(irq);
-	}
-	CPC700_OUT_32(CPC700_UIC_UICPR, tmp);
-
-	/* Set interrupt critical */
-	tmp = CPC700_IN_32(CPC700_UIC_UICCR);
-	tmp |= CPC700_UIC_IRQ_BIT(irq);
-	CPC700_OUT_32(CPC700_UIC_UICCR, tmp);
-			
-	return;
-}
-	
-__init void
-cpc700_init_IRQ(void)
-{
-	int i;
-
-	ppc_cached_irq_mask[0] = 0;
-	CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000);    /* Disable all irq's */
-	CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff);    /* Clear cur intrs */
-	CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff);    /* Gen INT not MCP */
-	CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000);    /* Active low */
-	CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000);    /* Level Sensitive */
-	CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI);
-						        /* IRQ 0 is highest */
-
-	for (i = 0; i < 17; i++) {
-		irq_desc[i].handler = &cpc700_pic;
-		cpc700_pic_init_irq(i);
-	}
-
-	for (i = 20; i < 32; i++) {
-		irq_desc[i].handler = &cpc700_pic;
-		cpc700_pic_init_irq(i);
-	}
-
-	return;
-}
-
-
-
-/*
- * Find the highest IRQ that generating an interrupt, if any.
- */
-int
-cpc700_get_irq(struct pt_regs *regs)
-{
-	int irq = 0;
-	u_int irq_status, irq_test = 1;
-
-	irq_status = CPC700_IN_32(CPC700_UIC_UICMSR);
-
-	do
-	{
-		if (irq_status & irq_test)
-			break;
-		irq++;
-		irq_test <<= 1;
-	} while (irq < NR_IRQS);
-		
-
-	if (irq == NR_IRQS)
-	    irq = 33;
-
-	return (31 - irq);
-}
diff -Nru a/arch/ppc/platforms/cpc710.h b/arch/ppc/platforms/cpc710.h
--- a/arch/ppc/platforms/cpc710.h	Sun Nov 10 19:28:39 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,77 +0,0 @@
-/*
- * arch/ppc/platforms/cpc710.h
- * 
- * Definitions for the IBM CPC710 PCI Host Bridge
- *
- * Author: Matt Porter <mporter@mvista.com>
- *
- * Copyright 2001 MontaVista Software 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.
- */
-
-#ifndef __PPC_PLATFORMS_CPC710_H
-#define __PPC_PLATFORMS_CPC710_H
-
-/* General bridge and memory controller registers */
-#define PIDR	0xff000008
-#define	CNFR	0xff00000c
-#define	RSTR	0xff000010
-#define UCTL	0xff001000
-#define	MPSR	0xff001010
-#define	SIOC	0xff001020
-#define	ABCNTL	0xff001030
-#define SRST	0xff001040
-#define	ERRC	0xff001050
-#define	SESR	0xff001060
-#define	SEAR	0xff001070
-#define	PGCHP	0xff001100
-#define	GPDIR	0xff001130
-#define	ATAS	0xff001160
-#define	AVDG	0xff001170
-#define	MCCR	0xff001200
-#define	MESR	0xff001220
-#define	MEAR	0xff001230
-#define	MCER0	0xff001300
-#define	MCER1	0xff001310
-#define	MCER2	0xff001320
-#define	MCER3	0xff001330
-#define	MCER4	0xff001340
-#define	MCER5	0xff001350
-#define	MCER6	0xff001360
-#define	MCER7	0xff001370
-
-/*
- * PCI32/64 configuration registers
- * Given as offsets from their
- * respective physical segment BAR
- */
-#define PIBAR	0x000f7800
-#define PMBAR	0x000f7810
-#define MSIZE	0x000f7f40
-#define IOSIZE	0x000f7f60
-#define SMBAR	0x000f7f80
-#define SIBAR	0x000f7fc0
-#define PSSIZE	0x000f8100
-#define PPSIZE	0x000f8110
-#define BARPS	0x000f8120
-#define BARPP	0x000f8130
-#define PSBAR	0x000f8140
-#define PPBAR	0x000f8150
-
-/* System standard configuration registers space */
-#define	DCR	0xff200000
-#define	DID	0xff200004
-#define	BAR	0xff200018
-
-/* Device specific configuration space */
-#define	PCIENB	0xff201000
-
-/* Configuration space registers */
-#define CPC710_BUS_NUMBER	0x40
-#define CPC710_SUB_BUS_NUMBER	0x41
-
-#endif /* __PPC_PLATFORMS_CPC710_H */
diff -Nru a/arch/ppc/platforms/iSeries_setup.c b/arch/ppc/platforms/iSeries_setup.c
--- a/arch/ppc/platforms/iSeries_setup.c	Sun Nov 10 19:28:39 2002
+++ b/arch/ppc/platforms/iSeries_setup.c	Sun Nov 10 19:28:39 2002
@@ -57,6 +57,7 @@
 extern void iSeries_pci_Initialize(void);
 static int iSeries_show_cpuinfo(struct seq_file *m);
 static int iSeries_show_percpuinfo(struct seq_file *m, int i);
+extern void iSeries_idle(void);
 extern struct pci_ops iSeries_pci_ops;
 
 /* Global Variables */
@@ -537,6 +538,8 @@
 	mf_init();
 	viopath_init();
 */
+
+	ppc_md.idle = iSeries_idle;
 }
 
 /*
diff -Nru a/arch/ppc/platforms/k2_pci.c b/arch/ppc/platforms/k2_pci.c
--- a/arch/ppc/platforms/k2_pci.c	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/platforms/k2_pci.c	Sun Nov 10 19:28:41 2002
@@ -24,7 +24,8 @@
 #include <asm/machdep.h>
 #include <asm/pci-bridge.h>
 
-#include "cpc710.h"
+#include <syslib/cpc710.h>
+
 #include "k2.h"
 
 #undef DEBUG
diff -Nru a/arch/ppc/platforms/pal4_pci.c b/arch/ppc/platforms/pal4_pci.c
--- a/arch/ppc/platforms/pal4_pci.c	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/platforms/pal4_pci.c	Sun Nov 10 19:28:41 2002
@@ -23,7 +23,8 @@
 #include <asm/pci-bridge.h>
 #include <asm/uaccess.h>
 
-#include "cpc700.h"
+#include <syslib/cpc700.h>
+
 #include "pal4.h"
 
 /* not much to this.... */
diff -Nru a/arch/ppc/platforms/pal4_setup.c b/arch/ppc/platforms/pal4_setup.c
--- a/arch/ppc/platforms/pal4_setup.c	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/platforms/pal4_setup.c	Sun Nov 10 19:28:41 2002
@@ -31,7 +31,8 @@
 #include <asm/todc.h>
 #include <asm/bootinfo.h>
 
-#include "cpc700.h"
+#include <syslib/cpc700.h>
+
 #include "pal4.h"
 
 extern void pal4_find_bridges(void);
diff -Nru a/arch/ppc/platforms/pmac_setup.c b/arch/ppc/platforms/pmac_setup.c
--- a/arch/ppc/platforms/pmac_setup.c	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc/platforms/pmac_setup.c	Sun Nov 10 19:28:40 2002
@@ -91,8 +91,6 @@
 extern void pmac_pcibios_after_init(void);
 extern int of_show_percpuinfo(struct seq_file *m, int i);
 
-extern kdev_t sd_find_target(void *host, int tgt);
-
 struct device_node *memory_node;
 
 unsigned char drive_info;
@@ -406,13 +404,6 @@
 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 (!kdev_same(boot_dev, NODEV))
-			return;
-	}
-#endif
 #if defined(CONFIG_BLK_DEV_IDE) && defined(CONFIG_BLK_DEV_IDE_PMAC)
 	boot_dev = find_ide_boot();
 #endif
diff -Nru a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c
--- a/arch/ppc/platforms/prep_pci.c	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/platforms/prep_pci.c	Sun Nov 10 19:28:41 2002
@@ -24,6 +24,7 @@
 #include <asm/machdep.h>
 #include <asm/open_pic.h>
 
+extern void (*setup_ibm_pci)(char *irq_lo, char *irq_hi);
 
 /* Which PCI interrupt line does a given device [slot] use? */
 /* Note: This really should be two dimensional based in slot/pin used */
@@ -612,6 +613,7 @@
 #define ELCRM_INT7_LVL          0x80
 #define ELCRM_INT5_LVL          0x20
 
+#if 0
 /*
  * PCI config space access.
  */
@@ -686,6 +688,7 @@
 	prep_read_config,
 	prep_write_config
 };
+#endif
 
 #define MOTOROLA_CPUTYPE_REG	0x800
 #define MOTOROLA_BASETYPE_REG	0x803
@@ -695,7 +698,7 @@
 
 static u_char prep_openpic_initsenses[] __initdata = {
     (IRQ_SENSE_LEVEL | IRQ_POLARITY_POSITIVE), /* MVME2600_INT_SIO */
-    (IRQ_SENSE_EDGE | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_FALCON_ECC_ERR */
+    (IRQ_SENSE_EDGE  | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_FALCN_ECC_ERR */
     (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_ETHERNET */
     (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_SCSI */
     (IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE), /* MVME2600_INT_PCI_GRAPHICS */
@@ -834,32 +837,51 @@
 void __init
 ibm_prep_init(void)
 {
-	u32 addr;
 #ifdef CONFIG_PREP_RESIDUAL
+	u32 addr, real_addr, len;
 	PPC_DEVICE *mpic;
-#endif
+	PnP_TAG_PACKET *pkt;
+
+	/* Use the PReP residual data to determine if an OpenPIC is
+	 * present.  If so, get the large vendor packet which will
+	 * tell us the base address and length in memory.
+	 * If we are successful, ioremap the memory area and set
+	 * OpenPIC_Addr (this indicates that the OpenPIC was found).
+	 */
+	mpic = residual_find_device(-1, NULL, SystemPeripheral,
+			    ProgrammableInterruptController, MPIC, 0);
+	if (!mpic)
+		return;
 
-	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;
+	pkt = PnP_find_large_vendor_packet(res->DevicePnPHeap +
+			mpic->AllocatedOffset, 9, 0);
 
-			OpenPIC_InitSenses = prep_openpic_initsenses;
-			OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses);
-		}
-	}
+	if (!pkt)
+		return;
 
-#ifdef CONFIG_PREP_RESIDUAL
-	mpic = residual_find_device(-1, NULL, SystemPeripheral,
-				    ProgrammableInterruptController, MPIC, 0);
-	if (mpic != NULL)
-		printk("mpic = %p\n", mpic);
+#define p pkt->L4_Pack.L4_Data.L4_PPCPack
+	if (!((p.PPCData[0] == 2) && (p.PPCData[1] == 32)))
+		return; /* not a 32-bit memory address */
+
+	real_addr = ld_le32((unsigned int *) (p.PPCData + 4));
+	if (real_addr == 0xffffffff)
+		return;
+
+	/* Adjust address to be as seen by CPU */
+	addr = real_addr + PREP_ISA_MEM_BASE;
+
+	len = ld_le32((unsigned int *) (p.PPCData + 12));
+	if (!len)
+		return;
+#undef p
+	OpenPIC_Addr = ioremap(addr, len);
+	ppc_md.get_irq = openpic_get_irq;
+
+	OpenPIC_InitSenses = prep_openpic_initsenses;
+	OpenPIC_NumInitSenses = sizeof(prep_openpic_initsenses);
+
+	printk(KERN_INFO "MPIC at 0x%08x (0x%08x), length 0x%08x "
+	       "mapped to 0x%p\n", addr, real_addr, len, OpenPIC_Addr);
 #endif
 }
 
@@ -880,6 +902,47 @@
 }
 
 void __init
+prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+	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 */
+}
+
+void __init
+prep_thinkpad_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+	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 */
+}
+
+void __init
+prep_carolina_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+	Motherboard_map_name = "IBM 7248, PowerSeries 830/850 (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 */
+}
+
+void __init
+prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi)
+{
+	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 */
+}
+
+void __init
 prep_route_pci_interrupts(void)
 {
 	unsigned char *ibc_pirq = (unsigned char *)0x80800860;
@@ -948,52 +1011,12 @@
 			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;
-		}
+		setup_ibm_pci(&irq_edge_mask_lo, &irq_edge_mask_hi);
 
-		outb(inb(0x04d0)|irq_edge_mask_lo, 0x04d0); /* primary 8259 */
-		outb(inb(0x04d1)|irq_edge_mask_hi, 0x04d1); /* cascaded 8259 */
+		outb(inb(0x04d0)|irq_edge_mask_lo, 0x4d0); /* primary 8259 */
+		outb(inb(0x04d1)|irq_edge_mask_hi, 0x4d1); /* cascaded 8259 */
 	} else {
 		printk("No known machine pci routing!\n");
 		return;
@@ -1151,7 +1174,6 @@
         struct pci_dev *dev;
         extern unsigned char *Motherboard_map;
         extern unsigned char *Motherboard_routes;
-        unsigned char i;
 
 	prep_route_pci_interrupts();
 
@@ -1182,38 +1204,6 @@
 		 */
 		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
 	}
 }
 
@@ -1270,9 +1260,8 @@
 	prep_init_resource(&hose->io_resource, 0, 0x007fffff, IORESOURCE_IO);
 	prep_init_resource(&hose->mem_resources[0], 0xc0000000, 0xfeffffff,
 			   IORESOURCE_MEM);
-	/* XXX why can't we use the indirect config space access method? */
-	hose->cfg_data = ioremap(PREP_ISA_IO_BASE + 0x800000, 0x800000);
-	hose->ops = &prep_pci_ops;
+	setup_indirect_pci(hose, PREP_ISA_IO_BASE + 0xcf8,
+			   PREP_ISA_IO_BASE + 0xcfc);
 
 	printk("PReP architecture\n");
 #ifdef CONFIG_PREP_RESIDUAL	  
diff -Nru a/arch/ppc/platforms/prep_setup.c b/arch/ppc/platforms/prep_setup.c
--- a/arch/ppc/platforms/prep_setup.c	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/platforms/prep_setup.c	Sun Nov 10 19:28:41 2002
@@ -80,6 +80,12 @@
 
 int _prep_type;
 
+extern void prep_sandalfoot_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern void prep_thinkpad_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern void prep_carolina_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+extern void prep_tiger1_setup_pci(char *irq_edge_mask_lo, char *irq_edge_mask_hi);
+
+
 #define cached_21	(((char *)(ppc_cached_irq_mask))[3])
 #define cached_A1	(((char *)(ppc_cached_irq_mask))[2])
 
@@ -100,39 +106,305 @@
 EXPORT_SYMBOL(ppc_cs4232_dma2);
 #endif
 
-static int __prep
-prep_show_cpuinfo(struct seq_file *m)
+/* useful ISA ports */
+#define PREP_SYSCTL	0x81c
+/* present in the IBM reference design; possibly identical in Mot boxes: */
+#define PREP_IBM_SIMM_ID	0x803	/* SIMM size: 32 or 8 MiB */
+#define PREP_IBM_SIMM_PRESENCE	0x804
+#define PREP_IBM_EQUIPMENT	0x80c
+#define PREP_IBM_L2INFO	0x80d
+#define PREP_IBM_PM1	0x82a	/* power management register 1 */
+#define PREP_IBM_PLANAR	0x852	/* planar ID - identifies the motherboard */
+#define PREP_IBM_DISP	0x8c0	/* 4-digit LED display */
+
+/* Equipment Present Register masks: */
+#define PREP_IBM_EQUIPMENT_RESERVED	0x80
+#define PREP_IBM_EQUIPMENT_SCSIFUSE	0x40
+#define PREP_IBM_EQUIPMENT_L2_COPYBACK	0x08
+#define PREP_IBM_EQUIPMENT_L2_256	0x04
+#define PREP_IBM_EQUIPMENT_CPU	0x02
+#define PREP_IBM_EQUIPMENT_L2	0x01
+
+/* planar ID values: */
+/* Sandalfoot/Sandalbow (6015/7020) */
+#define PREP_IBM_SANDALFOOT	0xfc
+/* Woodfield, Thinkpad 850/860 (6042/7249) */
+#define PREP_IBM_THINKPAD	0xff /* planar ID unimplemented */
+/* PowerSeries 830/850 (6050/6070) */
+#define PREP_IBM_CAROLINA_IDE_0	0xf0
+#define PREP_IBM_CAROLINA_IDE_1	0xf1
+#define PREP_IBM_CAROLINA_IDE_2	0xf2
+/* 7248-43P */
+#define PREP_IBM_CAROLINA_SCSI_0	0xf4
+#define PREP_IBM_CAROLINA_SCSI_1	0xf5
+#define PREP_IBM_CAROLINA_SCSI_2	0xf6
+#define PREP_IBM_CAROLINA_SCSI_3	0xf7 /* missing from Carolina Tech Spec */
+/* Tiger1 (7043-140) */
+#define PREP_IBM_TIGER1_133		0xd1
+#define PREP_IBM_TIGER1_166		0xd2
+#define PREP_IBM_TIGER1_180		0xd3
+#define PREP_IBM_TIGER1_xxx		0xd4 /* unknown, but probably exists */
+#define PREP_IBM_TIGER1_333		0xd5 /* missing from Tiger Tech Spec */
+
+/* setup_ibm_pci:
+ * 	set Motherboard_map_name, Motherboard_map, Motherboard_routes.
+ * 	return 8259 edge/level masks.
+ */
+void (*setup_ibm_pci)(char *irq_lo, char *irq_hi);
+
+extern char *Motherboard_map_name; /* for use in *_cpuinfo */
+
+/*
+ * As found in the PReP reference implementation.
+ * Used by Thinkpad, Sandalfoot (6015/7020), and all Motorola PReP.
+ */
+static void __init
+prep_gen_enable_l2(void)
 {
-	extern char *Motherboard_map_name;
-	int cachew;
+	outb(inb(PREP_SYSCTL) | 0x3, PREP_SYSCTL);
+}
+
+/* Used by Carolina and Tiger1 */
+static void __init
+prep_carolina_enable_l2(void)
+{
+	outb(inb(PREP_SYSCTL) | 0xc0, PREP_SYSCTL);
+}
+
+/* cpuinfo code common to all IBM PReP */
+static void __prep
+prep_ibm_cpuinfo(struct seq_file *m)
+{
+	unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
 
 	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, "upgrade cpu\t: ");
+	if (equip_reg & PREP_IBM_EQUIPMENT_CPU) {
+		seq_printf(m, "not ");
+	}
+	seq_printf(m, "present\n");
+
+	/* print info about the SCSI fuse */
+	seq_printf(m, "scsi fuse\t: ");
+	if (equip_reg & PREP_IBM_EQUIPMENT_SCSIFUSE) 
+		seq_printf(m, "ok");
+	else
+		seq_printf(m, "bad");
+	seq_printf(m, "\n");
+
+#ifdef CONFIG_PREP_RESIDUAL
+	/* print info about SIMMs */
+	if (res->ResidualLength != 0) {
+		int i;
+		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:%ldMiB ", i,
+					(res->Memories[i].SIMMSize > 1024) ? 
+					res->Memories[i].SIMMSize>>20 : 
+					res->Memories[i].SIMMSize);
 		}
-		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) {
+		seq_printf(m, "\n");
+	}
+#endif
+}
+
+static int __prep
+prep_sandalfoot_cpuinfo(struct seq_file *m)
+{
+	unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
+
+	prep_ibm_cpuinfo(m);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "L2 cache\t: ");
+	if (equip_reg & PREP_IBM_EQUIPMENT_L2) {
+		seq_printf(m, "not present");
+	} else {
+		if (equip_reg & PREP_IBM_EQUIPMENT_L2_256)
+			seq_printf(m, "256KiB");
+		else
+			seq_printf(m, "unknown size");
+
+		if (equip_reg & PREP_IBM_EQUIPMENT_L2_COPYBACK)
+			seq_printf(m, ", copy-back");
+		else
+			seq_printf(m, ", write-through");
+	}
+	seq_printf(m, "\n");
+
+	return 0;
+}
+
+static int __prep
+prep_thinkpad_cpuinfo(struct seq_file *m)
+{
+	unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
+	char *cpubus_speed, *pci_speed;
+
+	prep_ibm_cpuinfo(m);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "l2 cache\t: ");
+	if ((equip_reg & 0x1) == 0) {
+		switch ((equip_reg & 0xc) >> 2) {
+			case 0x0:
+				seq_printf(m, "128KiB look-aside 2-way write-through\n");
+				break;
+			case 0x1:
+				seq_printf(m, "512KiB look-aside direct-mapped write-back\n");
+				break;
+			case 0x2:
+				seq_printf(m, "256KiB look-aside 2-way write-through\n");
+				break;
+			case 0x3:
+				seq_printf(m, "256KiB look-aside direct-mapped write-back\n");
+				break;
+		}
+	} else {
+		seq_printf(m, "not present\n");
+	}
+
+	/* report bus speeds because we can */
+	if ((equip_reg & 0x80) == 0) {
+		switch ((equip_reg & 0x30) >> 4) {
+			case 0x1:
+				cpubus_speed = "50";
+				pci_speed = "25";
+				break;
+			case 0x3:
+				cpubus_speed = "66";
+				pci_speed = "33";
+				break;
+			default:
+				cpubus_speed = "unknown";
+				pci_speed = "unknown";
+				break;
+		}
+	} else {
+		switch ((equip_reg & 0x30) >> 4) {
+			case 0x1:
+				cpubus_speed = "25";
+				pci_speed = "25";
+				break;
+			case 0x2:
+				cpubus_speed = "60";
+				pci_speed = "30";
+				break;
+			case 0x3:
+				cpubus_speed = "33";
+				pci_speed = "33";
+				break;
+			default:
+				cpubus_speed = "unknown";
+				pci_speed = "unknown";
+				break;
+		}
+	}
+	seq_printf(m, "60x bus\t\t: %sMHz\n", cpubus_speed);
+	seq_printf(m, "pci bus\t\t: %sMHz\n", pci_speed);
+
+	return 0;
+}
+
+static int __prep
+prep_carolina_cpuinfo(struct seq_file *m)
+{
+	unsigned int equip_reg = inb(PREP_IBM_EQUIPMENT);
+
+	prep_ibm_cpuinfo(m);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "l2 cache\t: ");
+	if ((equip_reg & 0x1) == 0) {
+		unsigned int l2_reg = inb(PREP_IBM_L2INFO);
+
+		/* L2 size */
+		if ((l2_reg & 0x60) == 0)
+			seq_printf(m, "256KiB");
+		else if ((l2_reg & 0x60) == 1)
+			seq_printf(m, "512KiB");
+		else
+			seq_printf(m, "unknown size");
+
+		/* L2 type */
+		if ((l2_reg & 0x3) == 0)
+			seq_printf(m, ", async");
+		else if ((l2_reg & 0x3) == 1)
+			seq_printf(m, ", sync");
+		else
+			seq_printf(m, ", unknown type");
+
+		seq_printf(m, "\n");
+	} else {
+		seq_printf(m, "not present\n");
+	}
+
+	return 0;
+}
+
+static int __prep
+prep_tiger1_cpuinfo(struct seq_file *m)
+{
+	unsigned int l2_reg = inb(PREP_IBM_L2INFO);
+
+	prep_ibm_cpuinfo(m);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "l2 cache\t: ");
+	if ((l2_reg & 0xf) == 0xf) {
+		seq_printf(m, "not present\n");
+	} else {
+		if (l2_reg & 0x8)
+			seq_printf(m, "async, ");
+		else
+			seq_printf(m, "sync burst, ");
+		
+		if (l2_reg & 0x4)
+			seq_printf(m, "parity, ");
+		else
+			seq_printf(m, "no parity, ");
+		
+		switch (l2_reg & 0x3) {
+			case 0x0:
+				seq_printf(m, "256KiB\n");
+				break;
+			case 0x1:
+				seq_printf(m, "512KiB\n");
+				break;
+			case 0x2:
+				seq_printf(m, "1MiB\n");
+				break;
+			default:
+				seq_printf(m, "unknown size\n");
+				break;
+		}
+	}
+
+	return 0;
+}
+
+
+/* Used by all Motorola PReP */
+static int __prep
+prep_mot_cpuinfo(struct seq_file *m)
+{
+	unsigned int cachew = *((unsigned char *)CACHECRBA);
+
+	seq_printf(m, "machine\t\t: PReP %s\n", Motherboard_map_name);
+
+	/* report amount and type of L2 cache present */
+	seq_printf(m, "l2 cache\t: ");
+	switch (cachew & L2CACHE_MASK) {
 		case L2CACHE_512KB:
-			seq_printf(m, "512Kb");
+			seq_printf(m, "512KiB");
 			break;
 		case L2CACHE_256KB:
-			seq_printf(m, "256Kb");
+			seq_printf(m, "256KiB");
 			break;
 		case L2CACHE_1MB:
-			seq_printf(m, "1MB");
+			seq_printf(m, "1MiB");
 			break;
 		case L2CACHE_NONE:
 			seq_printf(m, "none\n");
@@ -140,34 +412,29 @@
 			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;
+	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;
 	}
 
 no_l2:
 #ifdef CONFIG_PREP_RESIDUAL
+	/* print info about SIMMs */
 	if (res->ResidualLength != 0) {
 		int i;
-
-		/* 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)
@@ -183,6 +450,112 @@
 	return 0;
 }
 
+static void __prep
+prep_tiger1_progress(char *msg, unsigned short code)
+{
+	outw(code, PREP_IBM_DISP);
+}
+
+static void __prep
+prep_restart(char *cmd)
+{
+#define PREP_SP92	0x92	/* Special Port 92 */
+	local_irq_disable(); /* no interrupts */
+
+	/* set exception prefix high - to the prom */
+	_nmask_and_or_msr(0, MSR_IP);
+
+	/* make sure bit 0 (reset) is a 0 */
+	outb( inb(PREP_SP92) & ~1L , PREP_SP92);
+	/* signal a reset to system control port A - soft reset */
+	outb( inb(PREP_SP92) | 1 , PREP_SP92);
+
+	while ( 1 ) ;
+	/* not reached */
+#undef PREP_SP92
+}
+
+static void __prep
+prep_halt(void)
+{
+	local_irq_disable(); /* no interrupts */
+
+	/* set exception prefix high - to the prom */
+	_nmask_and_or_msr(0, MSR_IP);
+
+	while ( 1 ) ;
+	/* not reached */
+}
+
+/* Carrera is the power manager in the Thinkpads. Unfortunately not much is
+ * known about it, so we can't power down.
+ */
+static void __prep
+prep_carrera_poweroff(void)
+{
+	prep_halt();
+}
+
+/*
+ * On most 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;
+
+	/* 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, PREP_IBM_PM1);	/* first nibble */
+	mb();
+	udelay(100);				/* important: let controller recover */
+
+	outb(byte2, PREP_IBM_PM1);	/* second nibble */
+	mb();
+	udelay(100);				/* important: let controller recover */
+}
+
+static void __prep
+prep_sig750_poweroff(void)
+{
+	/* tweak the power manager found in most IBM PRePs (except Thinkpads) */
+
+	local_irq_disable();
+	/* set exception prefix high - to the prom */
+	_nmask_and_or_msr(0, MSR_IP);
+
+	utah_sig87c750_setbit(21, 5, 1); /* set bit 21.5, "PMEXEC_OFF" */
+
+	while (1) ;
+	/* not reached */
+}
+
 static int __prep
 prep_show_percpuinfo(struct seq_file *m, int i)
 {
@@ -314,6 +687,7 @@
 prep_setup_arch(void)
 {
 	unsigned char reg;
+	int is_ide=0;
 
 	/* init to some ~sane value until calibrate_delay() runs */
 	loops_per_jiffy = 50000000;
@@ -328,17 +702,65 @@
 	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 = Root_HDA1;
+		reg = inb(PREP_IBM_PLANAR);
+		printk(KERN_INFO "IBM planar ID: %08x", reg);
+		switch (reg) {
+			case PREP_IBM_SANDALFOOT:
+				prep_gen_enable_l2();
+				setup_ibm_pci = prep_sandalfoot_setup_pci;
+				ppc_md.power_off = prep_sig750_poweroff;
+				ppc_md.show_cpuinfo = prep_sandalfoot_cpuinfo;
+				break;
+			case PREP_IBM_THINKPAD:
+				prep_gen_enable_l2();
+				setup_ibm_pci = prep_thinkpad_setup_pci;
+				ppc_md.power_off = prep_carrera_poweroff;
+				ppc_md.show_cpuinfo = prep_thinkpad_cpuinfo;
+				break;
+			default:
+				printk(" -- unknown! Assuming Carolina");
+			case PREP_IBM_CAROLINA_IDE_0:
+			case PREP_IBM_CAROLINA_IDE_1:
+			case PREP_IBM_CAROLINA_IDE_2:
+				is_ide = 1;
+			case PREP_IBM_CAROLINA_SCSI_0:
+			case PREP_IBM_CAROLINA_SCSI_1:
+			case PREP_IBM_CAROLINA_SCSI_2:
+			case PREP_IBM_CAROLINA_SCSI_3:
+				prep_carolina_enable_l2();
+				setup_ibm_pci = prep_carolina_setup_pci;
+				ppc_md.power_off = prep_sig750_poweroff;
+				ppc_md.show_cpuinfo = prep_carolina_cpuinfo;
+				break;
+			case PREP_IBM_TIGER1_133:
+			case PREP_IBM_TIGER1_166:
+			case PREP_IBM_TIGER1_180:
+			case PREP_IBM_TIGER1_xxx:
+			case PREP_IBM_TIGER1_333:
+				prep_carolina_enable_l2();
+				setup_ibm_pci = prep_tiger1_setup_pci;
+				ppc_md.power_off = prep_sig750_poweroff;
+				ppc_md.show_cpuinfo = prep_tiger1_cpuinfo;
+				ppc_md.progress = prep_tiger1_progress;
+				break;
+		}
+		printk("\n");
+
+		/* default root device */
+		if (is_ide)
+			ROOT_DEV = MKDEV(IDE0_MAJOR, 3);
+		else
+			ROOT_DEV = MKDEV(SCSI_DISK0_MAJOR, 3);
+
 		break;
 	case _PREP_Motorola:
-		/* Enable L2.  Assume we don't need to flush -- Cort*/
-		*(unsigned char *)(0x8000081c) |= 3;
+		prep_gen_enable_l2();
+		ppc_md.power_off = prep_halt;
+		ppc_md.show_cpuinfo = prep_mot_cpuinfo;
+
 #ifdef CONFIG_BLK_DEV_INITRD
 		if (initrd_start)
 			ROOT_DEV = Root_RAM0;
@@ -552,104 +974,6 @@
 	tb_to_us = mulhwu_scale_factor(freq, 1000000);
 }
 
-static void __prep
-prep_restart(char *cmd)
-{
-	unsigned long i = 10000;
-
-	local_irq_disable();
-
-	/* 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)
-{
-	/* set exception prefix high - to the prom */
-	_nmask_and_or_msr(MSR_EE, 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) {
-		/* set exception prefix high - to the prom */
-		_nmask_and_or_msr(MSR_EE, 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)
 {
@@ -728,7 +1052,7 @@
 {
 	*(unsigned long *)KERNELBASE = nr;
 	asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory");
-	printk("CPU1 reset, waiting\n");
+	printk("CPU1 released, waiting\n");
 }
 
 static void __init
@@ -812,14 +1136,14 @@
 
 	ppc_md.setup_arch     = prep_setup_arch;
 	ppc_md.show_percpuinfo = prep_show_percpuinfo;
-	ppc_md.show_cpuinfo   = prep_show_cpuinfo;
+	ppc_md.show_cpuinfo   = NULL; /* set in prep_setup_arch() */
 	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        = i8259_irq;
 
 	ppc_md.restart        = prep_restart;
-	ppc_md.power_off      = prep_power_off;
+	ppc_md.power_off      = NULL; /* set in prep_setup_arch() */
 	ppc_md.halt           = prep_halt;
 
 	ppc_md.nvram_read_val = prep_nvram_read_val;
diff -Nru a/arch/ppc/platforms/spruce_pci.c b/arch/ppc/platforms/spruce_pci.c
--- a/arch/ppc/platforms/spruce_pci.c	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc/platforms/spruce_pci.c	Sun Nov 10 19:28:40 2002
@@ -41,7 +41,7 @@
 #include <asm/pci-bridge.h>
 #include <platforms/spruce.h>
 
-#include "cpc700.h"
+#include <syslib/cpc700.h>
 
 static inline int
 spruce_map_irq(struct pci_dev *dev, unsigned char idsel, unsigned char pin)
diff -Nru a/arch/ppc/platforms/spruce_setup.c b/arch/ppc/platforms/spruce_setup.c
--- a/arch/ppc/platforms/spruce_setup.c	Sun Nov 10 19:28:37 2002
+++ b/arch/ppc/platforms/spruce_setup.c	Sun Nov 10 19:28:37 2002
@@ -57,7 +57,7 @@
 #include <asm/todc.h>
 #include <asm/bootinfo.h>
 
-#include "cpc700.h"
+#include <syslib/cpc700.h>
 
 extern void spruce_init_IRQ(void);
 extern int spruce_get_irq(struct pt_regs *);
@@ -184,8 +184,6 @@
 {
 	spruce_restart(NULL);
 }
-
-extern int boot_mem_size;
 
 static void __init
 spruce_map_io(void)
diff -Nru a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/Makefile	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,68 @@
+#
+# Makefile for the linux kernel.
+#
+
+ifdef CONFIG_PPC64BRIDGE
+EXTRA_AFLAGS		:= -Wa,-mppc64bridge
+endif
+ifdef CONFIG_4xx
+EXTRA_AFLAGS		:= -Wa,-m405
+endif
+
+CFLAGS_prom_init.o      += -mrelocatable-lib
+CFLAGS_btext.o          += -mrelocatable-lib
+
+obj-$(CONFIG_PPCBUG_NVRAM)	+= prep_nvram.o
+ifeq ($(CONFIG_4xx),y)
+obj-$(CONFIG_4xx)		+= ppc4xx_setup.o ppc4xx_pic.o ppc4xx_serial.o
+obj-$(CONFIG_PPC_RTC)		+= todc_time.o
+obj-$(CONFIG_KGDB)		+= ppc4xx_kgdb.o
+obj-$(CONFIG_405_DMA)		+= ppc405_dma.o
+obj-$(CONFIG_PCI)		+= ppc405_pci.o indirect_pci.o pci_auto.o
+obj-$(CONFIG_PM)		+= ppc4xx_pm.o
+endif
+obj-$(CONFIG_8xx)		+= m8xx_setup.o ppc8xx_pic.o
+ifeq ($(CONFIG_8xx),y)
+obj-$(CONFIG_PCI)		+= qspan_pci.o i8259.o
+endif
+obj-$(CONFIG_ALL_PPC)		+= prom_init.o prom.o open_pic.o \
+					indirect_pci.o i8259.o
+obj-$(CONFIG_ADIR)		+= i8259.o indirect_pci.o pci_auto.o \
+					todc_time.o
+obj-$(CONFIG_EV64260)		+= gt64260_common.o gt64260_pic.o \
+					indirect_pci.o todc_time.o pci_auto.o
+obj-$(CONFIG_GEMINI)		+= open_pic.o i8259.o indirect_pci.o
+obj-$(CONFIG_K2)		+= i8259.o indirect_pci.o todc_time.o \
+					pci_auto.o
+obj-$(CONFIG_LOPEC)		+= mpc10x_common.o indirect_pci.o pci_auto.o \
+					open_pic.o i8259.o todc_time.o
+obj-$(CONFIG_MCPN765)		+= todc_time.o indirect_pci.o pci_auto.o \
+					open_pic.o i8259.o pplus_common.o
+obj-$(CONFIG_MENF1)		+= todc_time.o i8259.o mpc10x_common.o \
+					pci_auto.o indirect_pci.o
+obj-$(CONFIG_MVME5100)		+= open_pic.o todc_time.o indirect_pci.o \
+					i8259.o pci_auto.o pplus_common.o
+obj-$(CONFIG_PAL4)		+= cpc700_pic.o
+obj-$(CONFIG_PCORE)		+= mpc10x_common.o todc_time.o i8259.o \
+					indirect_pci.o pci_auto.o
+obj-$(CONFIG_POWERPMC250)	+= open_pic.o mpc10x_common.o \
+					indirect_pci.o pci_auto.o
+obj-$(CONFIG_PPLUS)		+= pplus_common.o open_pic.o i8259.o \
+				   indirect_pci.o todc_time.o pci_auto.o
+obj-$(CONFIG_PRPMC750)		+= open_pic.o indirect_pci.o pci_auto.o \
+					pplus_common.o
+obj-$(CONFIG_PRPMC800)		+= open_pic.o indirect_pci.o pci_auto.o \
+					pplus_common.o harrier.o
+obj-$(CONFIG_SANDPOINT)		+= i8259.o open_pic.o mpc10x_common.o \
+					pci_auto.o indirect_pci.o todc_time.o
+obj-$(CONFIG_SPRUCE)		+= cpc700_pic.o indirect_pci.o pci_auto.o \
+				   todc_time.o
+obj-$(CONFIG_ZX4500)		+= indirect_pci.o pci_auto.o mpc10x_common.o \
+					i8259.o open_pic.o
+obj-$(CONFIG_8260)		+= m8260_setup.o ppc8260_pic.o
+obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
+
+include $(TOPDIR)/Rules.make
+
+find_name : find_name.c
+	$(HOSTCC) $(HOSTCFLAGS) -o find_name find_name.c
diff -Nru a/arch/ppc/syslib/btext.c b/arch/ppc/syslib/btext.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/btext.c	Sun Nov 10 19:28:36 2002
@@ -0,0 +1,861 @@
+/*
+ * Procedures for drawing on the screen early on in the boot process.
+ *
+ * Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/version.h>
+
+#include <asm/sections.h>
+#include <asm/bootx.h>
+#include <asm/btext.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+
+#define NO_SCROLL
+
+#ifndef NO_SCROLL
+static void scrollscreen(void);
+#endif
+
+static void draw_byte(unsigned char c, long locX, long locY);
+static void draw_byte_32(unsigned char *bits, unsigned long *base, int rb);
+static void draw_byte_16(unsigned char *bits, unsigned long *base, int rb);
+static void draw_byte_8(unsigned char *bits, unsigned long *base, int rb);
+
+static int g_loc_X;
+static int g_loc_Y;
+static int g_max_loc_X;
+static int g_max_loc_Y;
+
+unsigned long disp_BAT[2] __initdata = {0, 0};
+
+#define cmapsz	(16*256)
+
+static unsigned char vga_font[cmapsz];
+
+int boot_text_mapped;
+int force_printk_to_btext = 0;
+
+boot_infos_t disp_bi;
+
+extern char *klimit;
+
+/*
+ * Powermac can use btext_* after boot for xmon,
+ * chrp only uses it during early boot.
+ */
+#ifdef CONFIG_XMON
+#define BTEXT	__pmac
+#define BTDATA	__pmacdata
+#else
+#define BTEXT	__init
+#define BTDATA	__initdata
+#endif /* CONFIG_XMON */
+
+/*
+ * This is called only when we are booted via BootX.
+ */
+void __init
+btext_init(boot_infos_t *bi)
+{
+	g_loc_X = 0;
+	g_loc_Y = 0;
+	g_max_loc_X = (bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) / 8;
+	g_max_loc_Y = (bi->dispDeviceRect[3] - bi->dispDeviceRect[1]) / 16;
+	disp_bi = *bi;
+	boot_text_mapped = 1;
+}
+
+void __init
+btext_welcome(void)
+{
+	unsigned long flags;
+	unsigned long pvr;
+	boot_infos_t* bi = &disp_bi;
+
+	btext_drawstring("Welcome to Linux, kernel " UTS_RELEASE "\n");
+	btext_drawstring("\nlinked at        : 0x");
+	btext_drawhex(KERNELBASE);
+	btext_drawstring("\nframe buffer at  : 0x");
+	btext_drawhex((unsigned long)bi->dispDeviceBase);
+	btext_drawstring(" (phys), 0x");
+	btext_drawhex((unsigned long)bi->logicalDisplayBase);
+	btext_drawstring(" (log)");
+	btext_drawstring("\nklimit           : 0x");
+	btext_drawhex((unsigned long)klimit);
+	btext_drawstring("\nMSR              : 0x");
+	__asm__ __volatile__ ("mfmsr %0" : "=r" (flags));
+	btext_drawhex(flags);
+	__asm__ __volatile__ ("mfspr %0, 287" : "=r" (pvr));
+	pvr >>= 16;
+	if (pvr > 1) {
+	    btext_drawstring("\nHID0             : 0x");
+	    __asm__ __volatile__ ("mfspr %0, 1008" : "=r" (flags));
+	    btext_drawhex(flags);
+	}
+	if (pvr == 8 || pvr == 12 || pvr == 0x800c) {
+	    btext_drawstring("\nICTC             : 0x");
+	    __asm__ __volatile__ ("mfspr %0, 1019" : "=r" (flags));
+	    btext_drawhex(flags);
+	}
+	btext_drawstring("\n\n");
+}
+
+/* Calc BAT values for mapping the display and store them
+ * in disp_BAT.  Those values are then used from head.S to map
+ * the display during identify_machine() and MMU_Init()
+ * 
+ * The display is mapped to virtual address 0xD0000000, rather
+ * than 1:1, because some some CHRP machines put the frame buffer
+ * in the region starting at 0xC0000000 (KERNELBASE).
+ * This mapping is temporary and will disappear as soon as the
+ * setup done by MMU_Init() is applied.
+ * 
+ * For now, we align the BAT and then map 8Mb on 601 and 16Mb
+ * on other PPCs. This may cause trouble if the framebuffer
+ * is really badly aligned, but I didn't encounter this case
+ * yet.
+ */
+void __init
+btext_prepare_BAT(void)
+{
+	boot_infos_t* bi = &disp_bi;
+	unsigned long vaddr = KERNELBASE + 0x10000000;
+	unsigned long addr;
+	unsigned long lowbits;
+
+	addr = (unsigned long)bi->dispDeviceBase;
+	if (!addr) {
+		boot_text_mapped = 0;
+		return;
+	}
+	if (PVR_VER(mfspr(PVR)) != 1) {
+		/* 603, 604, G3, G4, ... */
+		lowbits = addr & ~0xFF000000UL;
+		addr &= 0xFF000000UL;
+		disp_BAT[0] = vaddr | (BL_16M<<2) | 2;
+		disp_BAT[1] = addr | (_PAGE_NO_CACHE | _PAGE_GUARDED | BPP_RW);		
+	} else {
+		/* 601 */
+		lowbits = addr & ~0xFF800000UL;
+		addr &= 0xFF800000UL;
+		disp_BAT[0] = vaddr | (_PAGE_NO_CACHE | PP_RWXX) | 4;
+		disp_BAT[1] = addr | BL_8M | 0x40;
+	}
+	bi->logicalDisplayBase = (void *) (vaddr + lowbits);
+}
+
+/* This function will enable the early boot text when doing OF booting. This
+ * way, xmon output should work too
+ */
+void __init
+btext_setup_display(int width, int height, int depth, int pitch,
+		    unsigned long address)
+{
+	boot_infos_t* bi = &disp_bi;
+
+	g_loc_X = 0;
+	g_loc_Y = 0;
+	g_max_loc_X = width / 8;
+	g_max_loc_Y = height / 16;
+	bi->logicalDisplayBase = (unsigned char *)address;
+	bi->dispDeviceBase = (unsigned char *)address;
+	bi->dispDeviceRowBytes = pitch;
+	bi->dispDeviceDepth = depth;
+	bi->dispDeviceRect[0] = bi->dispDeviceRect[1] = 0;
+	bi->dispDeviceRect[2] = width;
+	bi->dispDeviceRect[3] = height;
+	boot_text_mapped = 1;
+}
+
+/* Here's a small text engine to use during early boot
+ * or for debugging purposes
+ * 
+ * todo:
+ * 
+ *  - build some kind of vgacon with it to enable early printk
+ *  - move to a separate file
+ *  - add a few video driver hooks to keep in sync with display
+ *    changes.
+ */
+
+void __openfirmware
+map_boot_text(void)
+{
+	unsigned long base, offset, size;
+	boot_infos_t *bi = &disp_bi;
+	unsigned char *vbase;
+
+	/* By default, we are no longer mapped */
+	boot_text_mapped = 0;
+	if (bi->dispDeviceBase == 0)
+		return;
+	base = ((unsigned long) bi->dispDeviceBase) & 0xFFFFF000UL;
+	offset = ((unsigned long) bi->dispDeviceBase) - base;
+	size = bi->dispDeviceRowBytes * bi->dispDeviceRect[3] + offset
+		+ bi->dispDeviceRect[0];
+	vbase = ioremap(base, size);
+	if (vbase == 0)
+		return;
+	bi->logicalDisplayBase = vbase + offset;
+	boot_text_mapped = 1;
+}
+
+/* Calc the base address of a given point (x,y) */
+static unsigned char * BTEXT
+calc_base(boot_infos_t *bi, int x, int y)
+{
+	unsigned char *base;
+
+	base = bi->logicalDisplayBase;
+	if (base == 0)
+		base = bi->dispDeviceBase;
+	base += (x + bi->dispDeviceRect[0]) * (bi->dispDeviceDepth >> 3);
+	base += (y + bi->dispDeviceRect[1]) * bi->dispDeviceRowBytes;
+	return base;
+}
+
+/* Adjust the display to a new resolution */
+void
+btext_update_display(unsigned long phys, int width, int height,
+		     int depth, int pitch)
+{
+	boot_infos_t *bi = &disp_bi;
+
+	if (bi->dispDeviceBase == 0)
+		return;
+
+	/* check it's the same frame buffer (within 256MB) */
+	if ((phys ^ (unsigned long)bi->dispDeviceBase) & 0xf0000000)
+		return;
+
+	bi->dispDeviceBase = (__u8 *) phys;
+	bi->dispDeviceRect[0] = 0;
+	bi->dispDeviceRect[1] = 0;
+	bi->dispDeviceRect[2] = width;
+	bi->dispDeviceRect[3] = height;
+	bi->dispDeviceDepth = depth;
+	bi->dispDeviceRowBytes = pitch;
+	if (boot_text_mapped) {
+		iounmap(bi->logicalDisplayBase);
+		boot_text_mapped = 0;
+	}
+	map_boot_text();
+	g_loc_X = 0;
+	g_loc_Y = 0;
+	g_max_loc_X = width / 8;
+	g_max_loc_Y = height / 16;
+}
+
+void BTEXT btext_clearscreen(void)
+{
+	boot_infos_t* bi	= &disp_bi;
+	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
+	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+					(bi->dispDeviceDepth >> 3)) >> 2;
+	int i,j;
+	
+	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
+	{
+		unsigned long *ptr = base;
+		for(j=width; j; --j)
+			*(ptr++) = 0;
+		base += (bi->dispDeviceRowBytes >> 2);
+	}
+}
+
+__inline__ void dcbst(const void* addr)
+{
+	__asm__ __volatile__ ("dcbst 0,%0" :: "r" (addr));
+}
+
+void BTEXT btext_flushscreen(void)
+{
+	boot_infos_t* bi	= &disp_bi;
+	unsigned long *base	= (unsigned long *)calc_base(bi, 0, 0);
+	unsigned long width 	= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+					(bi->dispDeviceDepth >> 3)) >> 2;
+	int i,j;
+	
+	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1]); i++)
+	{
+		unsigned long *ptr = base;
+		for(j=width; j>0; j-=8) {
+			dcbst(ptr);
+			ptr += 8;
+		}
+		base += (bi->dispDeviceRowBytes >> 2);
+	}
+}
+
+#ifndef NO_SCROLL
+static BTEXT void
+scrollscreen(void)
+{
+	boot_infos_t* bi		= &disp_bi;
+	unsigned long *src		= (unsigned long *)calc_base(bi,0,16);
+	unsigned long *dst		= (unsigned long *)calc_base(bi,0,0);
+	unsigned long width		= ((bi->dispDeviceRect[2] - bi->dispDeviceRect[0]) *
+						(bi->dispDeviceDepth >> 3)) >> 2;
+	int i,j;
+	
+#ifdef CONFIG_ADB_PMU
+	pmu_suspend();	/* PMU will not shut us down ! */
+#endif
+	for (i=0; i<(bi->dispDeviceRect[3] - bi->dispDeviceRect[1] - 16); i++)
+	{
+		unsigned long *src_ptr = src;
+		unsigned long *dst_ptr = dst;
+		for(j=width; j; --j)
+			*(dst_ptr++) = *(src_ptr++);
+		src += (bi->dispDeviceRowBytes >> 2);
+		dst += (bi->dispDeviceRowBytes >> 2);
+	}
+	for (i=0; i<16; i++)
+	{
+		unsigned long *dst_ptr = dst;
+		for(j=width; j; --j)
+			*(dst_ptr++) = 0;
+		dst += (bi->dispDeviceRowBytes >> 2);
+	}
+#ifdef CONFIG_ADB_PMU
+	pmu_resume();	/* PMU will not shut us down ! */
+#endif
+}
+#endif /* ndef NO_SCROLL */
+
+void BTEXT btext_drawchar(char c)
+{
+	int cline = 0, x;
+
+	if (!boot_text_mapped)
+		return;
+
+	switch (c) {
+	case '\b':
+		if (g_loc_X > 0)
+			--g_loc_X;
+		break;
+	case '\t':
+		g_loc_X = (g_loc_X & -8) + 8;
+		break;
+	case '\r':
+		g_loc_X = 0;
+		break;
+	case '\n':
+		g_loc_X = 0;
+		g_loc_Y++;
+		cline = 1;
+		break;
+	default:
+		draw_byte(c, g_loc_X++, g_loc_Y);
+	}
+	if (g_loc_X >= g_max_loc_X) {
+		g_loc_X = 0;
+		g_loc_Y++;
+		cline = 1;
+	}
+#ifndef NO_SCROLL
+	while (g_loc_Y >= g_max_loc_Y) {
+		scrollscreen();
+		g_loc_Y--;
+	}
+#else
+	/* wrap around from bottom to top of screen so we don't
+	   waste time scrolling each line.  -- paulus. */
+	if (g_loc_Y >= g_max_loc_Y)
+		g_loc_Y = 0;
+	if (cline) {
+		for (x = 0; x < g_max_loc_X; ++x)
+			draw_byte(' ', x, g_loc_Y);
+	}
+#endif
+}
+
+void BTEXT
+btext_drawstring(const char *c)
+{
+	if (!boot_text_mapped)
+		return;
+	while (*c)
+		btext_drawchar(*c++);
+}
+
+void BTEXT
+btext_drawhex(unsigned long v)
+{
+	static char hex_table[] = "0123456789abcdef";
+	
+	if (!boot_text_mapped)
+		return;
+	btext_drawchar(hex_table[(v >> 28) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 24) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 20) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 16) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >> 12) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >>  8) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >>  4) & 0x0000000FUL]);
+	btext_drawchar(hex_table[(v >>  0) & 0x0000000FUL]);
+	btext_drawchar(' ');
+}
+
+static void BTEXT
+draw_byte(unsigned char c, long locX, long locY)
+{
+	boot_infos_t* bi	= &disp_bi;
+	unsigned char *base	= calc_base(bi, locX << 3, locY << 4);
+	unsigned char *font	= &vga_font[((unsigned long)c) * 16];
+	int rb			= bi->dispDeviceRowBytes;
+	
+	switch(bi->dispDeviceDepth) {
+	case 24:
+	case 32:
+		draw_byte_32(font, (unsigned long *)base, rb);
+		break;
+	case 15:
+	case 16:
+		draw_byte_16(font, (unsigned long *)base, rb);
+		break;
+	case 8:
+		draw_byte_8(font, (unsigned long *)base, rb);
+		break;
+	}
+}
+
+static unsigned long expand_bits_8[16] BTDATA = {
+	0x00000000,
+	0x000000ff,
+	0x0000ff00,
+	0x0000ffff,
+	0x00ff0000,
+	0x00ff00ff,
+	0x00ffff00,
+	0x00ffffff,
+	0xff000000,
+	0xff0000ff,
+	0xff00ff00,
+	0xff00ffff,
+	0xffff0000,
+	0xffff00ff,
+	0xffffff00,
+	0xffffffff
+};
+
+static unsigned long expand_bits_16[4] BTDATA = {
+	0x00000000,
+	0x0000ffff,
+	0xffff0000,
+	0xffffffff
+};
+
+
+static void BTEXT
+draw_byte_32(unsigned char *font, unsigned long *base, int rb)
+{
+	int l, bits;	
+	int fg = 0xFFFFFFFFUL;
+	int bg = 0x00000000UL;
+	
+	for (l = 0; l < 16; ++l)
+	{
+		bits = *font++;
+		base[0] = (-(bits >> 7) & fg) ^ bg;
+		base[1] = (-((bits >> 6) & 1) & fg) ^ bg;
+		base[2] = (-((bits >> 5) & 1) & fg) ^ bg;
+		base[3] = (-((bits >> 4) & 1) & fg) ^ bg;
+		base[4] = (-((bits >> 3) & 1) & fg) ^ bg;
+		base[5] = (-((bits >> 2) & 1) & fg) ^ bg;
+		base[6] = (-((bits >> 1) & 1) & fg) ^ bg;
+		base[7] = (-(bits & 1) & fg) ^ bg;
+		base = (unsigned long *) ((char *)base + rb);
+	}
+}
+
+static void BTEXT
+draw_byte_16(unsigned char *font, unsigned long *base, int rb)
+{
+	int l, bits;	
+	int fg = 0xFFFFFFFFUL;
+	int bg = 0x00000000UL;
+	unsigned long *eb = expand_bits_16;
+
+	for (l = 0; l < 16; ++l)
+	{
+		bits = *font++;
+		base[0] = (eb[bits >> 6] & fg) ^ bg;
+		base[1] = (eb[(bits >> 4) & 3] & fg) ^ bg;
+		base[2] = (eb[(bits >> 2) & 3] & fg) ^ bg;
+		base[3] = (eb[bits & 3] & fg) ^ bg;
+		base = (unsigned long *) ((char *)base + rb);
+	}
+}
+
+static void BTEXT
+draw_byte_8(unsigned char *font, unsigned long *base, int rb)
+{
+	int l, bits;	
+	int fg = 0x0F0F0F0FUL;
+	int bg = 0x00000000UL;
+	unsigned long *eb = expand_bits_8;
+
+	for (l = 0; l < 16; ++l)
+	{
+		bits = *font++;
+		base[0] = (eb[bits >> 4] & fg) ^ bg;
+		base[1] = (eb[bits & 0xf] & fg) ^ bg;
+		base = (unsigned long *) ((char *)base + rb);
+	}
+}
+
+static unsigned char vga_font[cmapsz] BTDATA = {
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0x81, 0xbd, 
+0x99, 0x81, 0x81, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xff, 
+0xdb, 0xff, 0xff, 0xc3, 0xe7, 0xff, 0xff, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x6c, 0xfe, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x7c, 0xfe, 
+0x7c, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 
+0x3c, 0x3c, 0xe7, 0xe7, 0xe7, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x3c, 0x7e, 0xff, 0xff, 0x7e, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc3, 0x99, 0xbd, 
+0xbd, 0x99, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x1e, 0x0e, 
+0x1a, 0x32, 0x78, 0xcc, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x66, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x33, 0x3f, 0x30, 0x30, 0x30, 
+0x30, 0x70, 0xf0, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x63, 
+0x7f, 0x63, 0x63, 0x63, 0x63, 0x67, 0xe7, 0xe6, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x18, 0x18, 0xdb, 0x3c, 0xe7, 0x3c, 0xdb, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfe, 0xf8, 
+0xf0, 0xe0, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x06, 0x0e, 
+0x1e, 0x3e, 0xfe, 0x3e, 0x1e, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 
+0x66, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xdb, 
+0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0x60, 0x38, 0x6c, 0xc6, 0xc6, 0x6c, 0x38, 0x0c, 0xc6, 
+0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0xfe, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 
+0x7e, 0x18, 0x18, 0x18, 0x7e, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x7e, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 
+0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x24, 0x66, 0xff, 0x66, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x38, 0x7c, 0x7c, 0xfe, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x7c, 
+0x38, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66, 0x24, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 
+0x6c, 0xfe, 0x6c, 0x6c, 0x6c, 0xfe, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x7c, 0xc6, 0xc2, 0xc0, 0x7c, 0x06, 0x06, 0x86, 0xc6, 0x7c, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xc6, 0x0c, 0x18, 
+0x30, 0x60, 0xc6, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 
+0x6c, 0x38, 0x76, 0xdc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x30, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x18, 
+0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xce, 0xde, 0xf6, 0xe6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0x06, 0x06, 0x3c, 0x06, 0x06, 0x06, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 
+0x0c, 0x0c, 0x0c, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xfc, 0x06, 0x06, 0x06, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x60, 0xc0, 0xc0, 0xfc, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0x06, 0x06, 0x0c, 0x18, 
+0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x06, 0x06, 0x0c, 0x78, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 
+0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x18, 0x00, 0x00, 0x00, 0x18, 0x18, 0x30, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x06, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 
+0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 
+0x30, 0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0x0c, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xde, 0xde, 
+0xde, 0xdc, 0xc0, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x66, 0x66, 0x66, 0x66, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0xc2, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc2, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x6c, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x6c, 0xf8, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 0x60, 0x62, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x66, 0x62, 0x68, 0x78, 0x68, 
+0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xde, 0xc6, 0xc6, 0x66, 0x3a, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x0c, 
+0x0c, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0xcc, 0x78, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xe6, 0x66, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0x66, 0xe6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x60, 0x60, 0x60, 0x60, 0x60, 
+0x60, 0x62, 0x66, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xe7, 
+0xff, 0xff, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 
+0x66, 0x66, 0x7c, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 
+0x0c, 0x0e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 0x66, 0x7c, 0x6c, 
+0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 
+0xc6, 0x60, 0x38, 0x0c, 0x06, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xdb, 0x99, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x66, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0x66, 0x3c, 0x18, 0x18, 
+0x3c, 0x66, 0xc3, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xff, 0xc3, 0x86, 0x0c, 0x18, 0x30, 0x60, 0xc1, 0xc3, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x30, 0x30, 0x30, 0x30, 0x30, 
+0x30, 0x30, 0x30, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
+0xc0, 0xe0, 0x70, 0x38, 0x1c, 0x0e, 0x06, 0x02, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x3c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 
+0x30, 0x30, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x78, 0x6c, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x0c, 0x0c, 0x3c, 0x6c, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xcc, 0x78, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x6c, 0x76, 0x66, 0x66, 0x66, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x0e, 0x06, 0x06, 
+0x06, 0x06, 0x06, 0x06, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0xe0, 0x60, 
+0x60, 0x66, 0x6c, 0x78, 0x78, 0x6c, 0x66, 0xe6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0xff, 0xdb, 
+0xdb, 0xdb, 0xdb, 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x66, 0x66, 
+0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0x0c, 0x1e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x76, 0x66, 0x60, 0x60, 0x60, 0xf0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0x60, 
+0x38, 0x0c, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x30, 
+0x30, 0xfc, 0x30, 0x30, 0x30, 0x30, 0x36, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0xc3, 0xc3, 
+0xc3, 0x66, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc3, 0xc3, 0xc3, 0xdb, 0xdb, 0xff, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0x3c, 0x66, 0xc3, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xfe, 0xcc, 0x18, 0x30, 0x60, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x0e, 0x18, 0x18, 0x18, 0x70, 0x18, 0x18, 0x18, 0x18, 0x0e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x18, 
+0x18, 0x18, 0x0e, 0x18, 0x18, 0x18, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 
+0xc6, 0xc6, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 
+0xc2, 0xc0, 0xc0, 0xc0, 0xc2, 0x66, 0x3c, 0x0c, 0x06, 0x7c, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xcc, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 
+0x00, 0x78, 0x0c, 0x7c, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x3c, 0x66, 0x60, 0x60, 0x66, 0x3c, 0x0c, 0x06, 
+0x3c, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xfe, 
+0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0xc0, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x38, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x66, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x60, 0x30, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 
+0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x38, 0x00, 
+0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x30, 0x60, 0x00, 0xfe, 0x66, 0x60, 0x7c, 0x60, 0x60, 0x66, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x3b, 0x1b, 
+0x7e, 0xd8, 0xdc, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x6c, 
+0xcc, 0xcc, 0xfe, 0xcc, 0xcc, 0xcc, 0xcc, 0xce, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x10, 0x38, 0x6c, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 
+0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x30, 0x78, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 
+0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7e, 0x06, 0x0c, 0x78, 0x00, 
+0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 
+0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 
+0xc3, 0xc0, 0xc0, 0xc0, 0xc3, 0x7e, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x38, 0x6c, 0x64, 0x60, 0xf0, 0x60, 0x60, 0x60, 0x60, 0xe6, 0xfc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc3, 0x66, 0x3c, 0x18, 0xff, 0x18, 
+0xff, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x66, 0x66, 
+0x7c, 0x62, 0x66, 0x6f, 0x66, 0x66, 0x66, 0xf3, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x0e, 0x1b, 0x18, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xd8, 0x70, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0x78, 0x0c, 0x7c, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 
+0x00, 0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x18, 0x30, 0x60, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x30, 0x60, 0x00, 0xcc, 0xcc, 0xcc, 
+0xcc, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 
+0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 
+0x76, 0xdc, 0x00, 0xc6, 0xe6, 0xf6, 0xfe, 0xde, 0xce, 0xc6, 0xc6, 0xc6, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x6c, 0x6c, 0x3e, 0x00, 0x7e, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x30, 0x30, 0x00, 0x30, 0x30, 0x60, 0xc0, 0xc6, 0xc6, 0x7c, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc0, 
+0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0xfe, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 0x60, 0xce, 0x9b, 0x06, 
+0x0c, 0x1f, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc2, 0xc6, 0xcc, 0x18, 0x30, 
+0x66, 0xce, 0x96, 0x3e, 0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 
+0x00, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x3c, 0x18, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 
+0x6c, 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x44, 0x11, 0x44, 
+0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 0x11, 0x44, 
+0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 
+0x55, 0xaa, 0x55, 0xaa, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 
+0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0xdd, 0x77, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0xf8, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x06, 0xf6, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xf7, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 
+0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 
+0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 
+0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 
+0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 
+0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x76, 0xdc, 0xd8, 0xd8, 0xd8, 0xdc, 0x76, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x78, 0xcc, 0xcc, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xc6, 0xcc, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xc6, 0xc6, 0xc0, 0xc0, 0xc0, 
+0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0xfe, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0xfe, 0xc6, 0x60, 0x30, 0x18, 0x30, 0x60, 0xc6, 0xfe, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0xd8, 0xd8, 
+0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x66, 0x66, 0x66, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xc0, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x18, 0x3c, 0x66, 0x66, 
+0x66, 0x3c, 0x18, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 
+0x6c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x38, 0x6c, 0xc6, 0xc6, 0xc6, 0x6c, 0x6c, 0x6c, 0x6c, 0xee, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x18, 0x0c, 0x3e, 0x66, 
+0x66, 0x66, 0x66, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x7e, 0xdb, 0xdb, 0xdb, 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x03, 0x06, 0x7e, 0xdb, 0xdb, 0xf3, 0x7e, 0x60, 0xc0, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x30, 0x60, 0x60, 0x7c, 0x60, 
+0x60, 0x60, 0x30, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 
+0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 0x00, 0xfe, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 
+0x18, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 
+0x18, 0x0c, 0x06, 0x0c, 0x18, 0x30, 0x00, 0x7e, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x7e, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x1b, 0x1b, 0x1b, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 
+0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0xd8, 0x70, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x18, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 
+0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x6c, 0x6c, 
+0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 
+0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x6c, 0x3c, 0x1c, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0xd8, 0x6c, 0x6c, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0xd8, 0x30, 0x60, 0xc8, 0xf8, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
+0x00, 0x00, 0x00, 0x00, 
+};
diff -Nru a/arch/ppc/syslib/cpc700.h b/arch/ppc/syslib/cpc700.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/cpc700.h	Sun Nov 10 19:28:38 2002
@@ -0,0 +1,109 @@
+/*
+ * include/asm-ppc/cpc700.h
+ * 
+ * Header file for IBM CPC700 Host Bridge, et. al.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2000-2002 MontaVista Software 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  SOFTWARE  IS PROVIDED   ``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  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 OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This file contains the defines and macros for the IBM CPC700 host bridge,
+ * memory controller, PIC, UARTs, IIC, and Timers.
+ */
+
+#ifndef	_ASMPPC_CPC700_H
+#define	_ASMPPC_CPC700_H
+
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <linux/init.h>
+
+#define CPC700_OUT_32(a,d)  (*(u_int *)a = d)
+#define CPC700_IN_32(a)     (*(u_int *)a)
+
+/*
+ * PCI Section
+ */
+#define CPC700_PCI_CONFIG_ADDR          0xfec00000
+#define CPC700_PCI_CONFIG_DATA          0xfec00004
+
+#define CPC700_PMM0_LOCAL		0xff400000
+#define CPC700_PMM0_MASK_ATTR		0xff400004
+#define CPC700_PMM0_PCI_LOW		0xff400008
+#define CPC700_PMM0_PCI_HIGH		0xff40000c
+#define CPC700_PMM1_LOCAL		0xff400010
+#define CPC700_PMM1_MASK_ATTR		0xff400014
+#define CPC700_PMM1_PCI_LOW		0xff400018
+#define CPC700_PMM1_PCI_HIGH		0xff40001c
+#define CPC700_PMM2_LOCAL		0xff400020
+#define CPC700_PMM2_MASK_ATTR		0xff400024
+#define CPC700_PMM2_PCI_LOW		0xff400028
+#define CPC700_PMM2_PCI_HIGH		0xff40002c
+#define CPC700_PTM1_MEMSIZE		0xff400030
+#define CPC700_PTM1_LOCAL		0xff400034
+#define CPC700_PTM2_MEMSIZE		0xff400038
+#define CPC700_PTM2_LOCAL		0xff40003c
+
+/*
+ * PIC Section
+ *
+ * IBM calls the CPC700's programmable interrupt controller the Universal
+ * Interrupt Controller or UIC.
+ */
+
+/*
+ * UIC Register Addresses.
+ */
+#define	CPC700_UIC_UICSR		0xff500880	/* Status Reg (Rd/Clr)*/
+#define	CPC700_UIC_UICSRS		0xff500884	/* Status Reg (Set) */
+#define	CPC700_UIC_UICER		0xff500888	/* Enable Reg */
+#define	CPC700_UIC_UICCR		0xff50088c	/* Critical Reg */
+#define	CPC700_UIC_UICPR		0xff500890	/* Polarity Reg */
+#define	CPC700_UIC_UICTR		0xff500894	/* Trigger Reg */
+#define	CPC700_UIC_UICMSR		0xff500898	/* Masked Status Reg */
+#define	CPC700_UIC_UICVR		0xff50089c	/* Vector Reg */
+#define	CPC700_UIC_UICVCR		0xff5008a0	/* Vector Config Reg */
+
+#define	CPC700_UIC_UICER_ENABLE		0x00000001	/* Enable an IRQ */
+
+#define	CPC700_UIC_UICVCR_31_HI		0x00000000	/* IRQ 31 hi priority */
+#define	CPC700_UIC_UICVCR_0_HI		0x00000001	/* IRQ 0 hi priority */
+#define CPC700_UIC_UICVCR_BASE_MASK	0xfffffffc
+#define CPC700_UIC_UICVCR_ORDER_MASK	0x00000001
+
+/* Specify value of a bit for an IRQ. */
+#define	CPC700_UIC_IRQ_BIT(i)		((0x00000001) << (31 - (i)))
+
+/*
+ * UIC Exports...
+ */
+extern struct hw_interrupt_type cpc700_pic;
+extern unsigned int cpc700_irq_assigns[32][2];
+ 
+extern void __init cpc700_init_IRQ(void);
+extern int cpc700_get_irq(struct pt_regs *);
+
+#endif	/* _ASMPPC_CPC700_H */
diff -Nru a/arch/ppc/syslib/cpc700_pic.c b/arch/ppc/syslib/cpc700_pic.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/cpc700_pic.c	Sun Nov 10 19:28:37 2002
@@ -0,0 +1,205 @@
+/*
+ * arch/ppc/platforms/cpc700_pic.c
+ * 
+ * Interrupt controller support for IBM Spruce
+ *
+ * Authors: Mark Greer, Matt Porter, and Johnnie Peters
+ *	    mgreer@mvista.com
+ *          mporter@mvista.com
+ *          jpeters@mvista.com
+ *
+ * Copyright 2001-2002 MontaVista Software 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  SOFTWARE  IS PROVIDED   ``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  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 OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+
+#include "cpc700.h"
+
+static void
+cpc700_unmask_irq(unsigned int irq)
+{
+	unsigned int tr_bits;
+
+	/*
+	 * IRQ 31 is largest IRQ supported.
+	 * IRQs 17-19 are reserved.
+	 */
+	if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
+		tr_bits = CPC700_IN_32(CPC700_UIC_UICTR);
+
+		if ((tr_bits & (1 << (31 - irq))) == 0) {
+			/* level trigger interrupt, clear bit in status
+			 * register */
+			CPC700_OUT_32(CPC700_UIC_UICSR, 1 << (31 - irq));
+		}
+
+		/* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
+		ppc_cached_irq_mask[0] |= CPC700_UIC_IRQ_BIT(irq);
+		
+		CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
+	}
+	return;
+}
+
+static void
+cpc700_mask_irq(unsigned int irq)
+{
+	/*
+	 * IRQ 31 is largest IRQ supported.
+	 * IRQs 17-19 are reserved.
+	 */
+	if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
+		/* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
+		ppc_cached_irq_mask[0] &=
+			~CPC700_UIC_IRQ_BIT(irq);
+
+		CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
+	}
+	return;
+}
+
+static void
+cpc700_mask_and_ack_irq(unsigned int irq)
+{
+	u_int	bit;
+
+	/*
+	 * IRQ 31 is largest IRQ supported.
+	 * IRQs 17-19 are reserved.
+	 */
+	if ((irq <= 31) && ((irq < 17) || (irq > 19))) {
+		/* Know IRQ fits in entry 0 of ppc_cached_irq_mask[] */
+		bit = CPC700_UIC_IRQ_BIT(irq);
+
+		ppc_cached_irq_mask[0] &= ~bit;
+		CPC700_OUT_32(CPC700_UIC_UICER, ppc_cached_irq_mask[0]);
+		CPC700_OUT_32(CPC700_UIC_UICSR, bit); /* Write 1 clears IRQ */
+	}
+	return;
+}
+
+static struct hw_interrupt_type cpc700_pic = {
+	"CPC700 PIC",
+	NULL,
+	NULL,
+	cpc700_unmask_irq,
+	cpc700_mask_irq,
+	cpc700_mask_and_ack_irq,
+	NULL,
+	NULL
+};
+
+__init static void
+cpc700_pic_init_irq(unsigned int irq)
+{
+	unsigned int tmp;
+
+	/* Set interrupt sense */
+	tmp = CPC700_IN_32(CPC700_UIC_UICTR);
+	if (cpc700_irq_assigns[irq][0] == 0) {
+		tmp &= ~CPC700_UIC_IRQ_BIT(irq);
+	} else {
+		tmp |= CPC700_UIC_IRQ_BIT(irq);
+	}
+	CPC700_OUT_32(CPC700_UIC_UICTR, tmp);
+
+	/* Set interrupt polarity */
+	tmp = CPC700_IN_32(CPC700_UIC_UICPR);
+	if (cpc700_irq_assigns[irq][1]) {
+		tmp |= CPC700_UIC_IRQ_BIT(irq);
+	} else {
+		tmp &= ~CPC700_UIC_IRQ_BIT(irq);
+	}
+	CPC700_OUT_32(CPC700_UIC_UICPR, tmp);
+
+	/* Set interrupt critical */
+	tmp = CPC700_IN_32(CPC700_UIC_UICCR);
+	tmp |= CPC700_UIC_IRQ_BIT(irq);
+	CPC700_OUT_32(CPC700_UIC_UICCR, tmp);
+			
+	return;
+}
+	
+__init void
+cpc700_init_IRQ(void)
+{
+	int i;
+
+	ppc_cached_irq_mask[0] = 0;
+	CPC700_OUT_32(CPC700_UIC_UICER, 0x00000000);    /* Disable all irq's */
+	CPC700_OUT_32(CPC700_UIC_UICSR, 0xffffffff);    /* Clear cur intrs */
+	CPC700_OUT_32(CPC700_UIC_UICCR, 0xffffffff);    /* Gen INT not MCP */
+	CPC700_OUT_32(CPC700_UIC_UICPR, 0x00000000);    /* Active low */
+	CPC700_OUT_32(CPC700_UIC_UICTR, 0x00000000);    /* Level Sensitive */
+	CPC700_OUT_32(CPC700_UIC_UICVR, CPC700_UIC_UICVCR_0_HI);
+						        /* IRQ 0 is highest */
+
+	for (i = 0; i < 17; i++) {
+		irq_desc[i].handler = &cpc700_pic;
+		cpc700_pic_init_irq(i);
+	}
+
+	for (i = 20; i < 32; i++) {
+		irq_desc[i].handler = &cpc700_pic;
+		cpc700_pic_init_irq(i);
+	}
+
+	return;
+}
+
+
+
+/*
+ * Find the highest IRQ that generating an interrupt, if any.
+ */
+int
+cpc700_get_irq(struct pt_regs *regs)
+{
+	int irq = 0;
+	u_int irq_status, irq_test = 1;
+
+	irq_status = CPC700_IN_32(CPC700_UIC_UICMSR);
+
+	do
+	{
+		if (irq_status & irq_test)
+			break;
+		irq++;
+		irq_test <<= 1;
+	} while (irq < NR_IRQS);
+		
+
+	if (irq == NR_IRQS)
+	    irq = 33;
+
+	return (31 - irq);
+}
diff -Nru a/arch/ppc/syslib/cpc710.h b/arch/ppc/syslib/cpc710.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/cpc710.h	Sun Nov 10 19:28:39 2002
@@ -0,0 +1,77 @@
+/*
+ * arch/ppc/platforms/cpc710.h
+ * 
+ * Definitions for the IBM CPC710 PCI Host Bridge
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2001 MontaVista Software 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.
+ */
+
+#ifndef __PPC_PLATFORMS_CPC710_H
+#define __PPC_PLATFORMS_CPC710_H
+
+/* General bridge and memory controller registers */
+#define PIDR	0xff000008
+#define	CNFR	0xff00000c
+#define	RSTR	0xff000010
+#define UCTL	0xff001000
+#define	MPSR	0xff001010
+#define	SIOC	0xff001020
+#define	ABCNTL	0xff001030
+#define SRST	0xff001040
+#define	ERRC	0xff001050
+#define	SESR	0xff001060
+#define	SEAR	0xff001070
+#define	PGCHP	0xff001100
+#define	GPDIR	0xff001130
+#define	ATAS	0xff001160
+#define	AVDG	0xff001170
+#define	MCCR	0xff001200
+#define	MESR	0xff001220
+#define	MEAR	0xff001230
+#define	MCER0	0xff001300
+#define	MCER1	0xff001310
+#define	MCER2	0xff001320
+#define	MCER3	0xff001330
+#define	MCER4	0xff001340
+#define	MCER5	0xff001350
+#define	MCER6	0xff001360
+#define	MCER7	0xff001370
+
+/*
+ * PCI32/64 configuration registers
+ * Given as offsets from their
+ * respective physical segment BAR
+ */
+#define PIBAR	0x000f7800
+#define PMBAR	0x000f7810
+#define MSIZE	0x000f7f40
+#define IOSIZE	0x000f7f60
+#define SMBAR	0x000f7f80
+#define SIBAR	0x000f7fc0
+#define PSSIZE	0x000f8100
+#define PPSIZE	0x000f8110
+#define BARPS	0x000f8120
+#define BARPP	0x000f8130
+#define PSBAR	0x000f8140
+#define PPBAR	0x000f8150
+
+/* System standard configuration registers space */
+#define	DCR	0xff200000
+#define	DID	0xff200004
+#define	BAR	0xff200018
+
+/* Device specific configuration space */
+#define	PCIENB	0xff201000
+
+/* Configuration space registers */
+#define CPC710_BUS_NUMBER	0x40
+#define CPC710_SUB_BUS_NUMBER	0x41
+
+#endif /* __PPC_PLATFORMS_CPC710_H */
diff -Nru a/arch/ppc/syslib/gt64260_common.c b/arch/ppc/syslib/gt64260_common.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/gt64260_common.c	Sun Nov 10 19:28:36 2002
@@ -0,0 +1,1666 @@
+/*
+ * arch/ppc/kernel/gt64260_common.c
+ * 
+ * Common routines for the Marvell/Galileo GT64260 (Discovery) host bridge,
+ * interrupt controller, memory controller, serial controller, enet controller,
+ * etc.
+ *
+ * Author: Mark A. Greer <mgreer@mvista.com>
+ *
+ * Copyright 2001 MontaVista Software 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.
+ */
+
+/*
+ * The GT64260 port is the result of hard work from many people from
+ * many companies.  In particular, employees of Marvell/Galileo, Mission
+ * Critical Linux, Xyterra, and MontaVista Software were heavily involved.
+ */
+
+/*
+ * At last count, the 64260-B-0 has 65 errata and 24 restrictions.  The odds of
+ * you getting it to work well, under stress, for a long period of time are
+ * low.  If nothing else, you will likely run into an interrupt controller
+ * bug.
+ *
+ * The newer 64260A-B-0 is much improved but has its own problems.
+ * Dave Wilhardt <dwilhardt@zyterra.com> has discovered that you must set
+ * up your PCI snoop regions to be prefetchable with 4-word bursts AND set the
+ * "Memory Write and Invalidate bit" (bit 4) in the cmd reg of each PCI device
+ * before coherency works between PCI and other devices.  Many thanks to Dave.
+ *
+ * So far this code has been tested on Marvell/Galileo EV-64260-BP and
+ * an EV-64260A-BP uni-processor boards with 750 and 7400 processors.
+ * It has not yet been tested with a 7410 or 7450, or on an smp system.
+ *
+ * Note: I have not had any luck moving the base register address of the bridge
+ * 	 with the gt64260_set_base() routine.  I move it in the bootloader
+ * 	 before starting the kernel.  I haven't really looked into it so it
+ * 	 may be an easy fix. -- MAG
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/gt64260.h>
+#include <asm/delay.h>
+
+
+u32	gt64260_base; /* Virtual base address of 64260's regs */
+u32	gt64260_revision; /* Revision of the chip */
+u8	gt64260_pci_exclude_bridge = TRUE;
+
+
+/*
+ *****************************************************************************
+ *
+ *	Bridge Initialization Routines
+ *
+ *****************************************************************************
+ */
+static void gt64260_check_errata(struct pci_controller *hose_a,
+				 struct pci_controller *hose_b);
+
+/*
+ * Typical '_find_bridges()' routine for boards with a GT64260 bridge.
+ */
+int __init
+gt64260_find_bridges(u32 phys_base_addr, gt64260_bridge_info_t *info,
+	int ((*map_irq)(struct pci_dev *, unsigned char, unsigned char)))
+{
+	struct pci_controller		*hose_a, *hose_b;
+	u32				io_base_a, io_base_b;
+	int				rc;
+
+
+	gt64260_base = (u32)ioremap(phys_base_addr,GT64260_INTERNAL_SPACE_SIZE);
+
+	hose_a = pcibios_alloc_controller();
+	if (!hose_a)
+		return -1;
+
+	hose_b = pcibios_alloc_controller();
+	if (!hose_b)
+		return -1;
+
+	info->hose_a = hose_a;
+	info->hose_b = hose_b;
+
+	/* Ends up mapping PCI Config addr/data pairs twice */
+	setup_indirect_pci(hose_a,
+			   phys_base_addr + GT64260_PCI_0_CONFIG_ADDR,
+			   phys_base_addr + GT64260_PCI_0_CONFIG_DATA);
+
+	setup_indirect_pci(hose_b,
+			   phys_base_addr + GT64260_PCI_1_CONFIG_ADDR,
+			   phys_base_addr + GT64260_PCI_1_CONFIG_DATA);
+
+	if ((rc = gt64260_bridge_init(info)) != 0) {
+		iounmap((void *)hose_a->cfg_addr);
+		iounmap((void *)hose_a->cfg_data);
+		iounmap((void *)hose_b->cfg_addr);
+		iounmap((void *)hose_b->cfg_data);
+		iounmap((void *)gt64260_base);
+		return rc;
+	}
+
+	/* ioremap PCI I/O regions */
+	io_base_b = (u32)ioremap(info->pci_1_io_start_proc,info->pci_1_io_size);
+	io_base_a = (u32)ioremap(info->pci_0_io_start_proc,info->pci_0_io_size);
+	isa_io_base = io_base_a;
+
+	hose_a->first_busno = 0;
+	hose_a->last_busno  = 0xff;
+
+	pci_init_resource(&hose_a->io_resource,
+			  0,	/* really: io_base_a - isa_io_base */
+			  info->pci_0_io_size - 1,
+			  IORESOURCE_IO,
+			  "host bridge PCI bus 0");
+	hose_a->io_space.start = info->pci_0_io_start_pci;
+	hose_a->io_space.end   = info->pci_0_io_start_pci +
+					info->pci_0_io_size - 1;
+	hose_a->io_base_virt = (void *)isa_io_base;
+
+	pci_init_resource(&hose_a->mem_resources[0],
+			  info->pci_0_mem_start_proc,
+			  info->pci_0_mem_start_proc + info->pci_0_mem_size - 1,
+			  IORESOURCE_MEM,
+			  "host bridge PCI bus 0");
+	hose_a->mem_space.start = info->pci_0_mem_start_pci_lo;
+	hose_a->mem_space.end   = info->pci_0_mem_start_pci_lo +
+					info->pci_0_mem_size - 1;
+	hose_a->pci_mem_offset = (info->pci_0_mem_start_proc -
+					info->pci_0_mem_start_pci_lo);
+
+	hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
+
+
+	hose_b->first_busno = hose_a->last_busno + 1;
+	hose_b->bus_offset  = hose_b->first_busno;
+	hose_b->last_busno  = 0xff;
+
+	pci_init_resource(&hose_b->io_resource,
+			  io_base_b - isa_io_base,
+			  io_base_b - isa_io_base + info->pci_1_io_size - 1,
+			  IORESOURCE_IO,
+			  "host bridge PCI bus 1");
+	hose_b->io_space.start = info->pci_1_io_start_pci;
+	hose_b->io_space.end   = info->pci_1_io_start_pci +
+					info->pci_1_io_size - 1;
+	hose_b->io_base_virt = (void *)isa_io_base;
+
+	pci_init_resource(&hose_b->mem_resources[0],
+			  info->pci_1_mem_start_proc,
+			  info->pci_1_mem_start_proc + info->pci_1_mem_size - 1,
+			  IORESOURCE_MEM,
+			  "host bridge PCI bus 1");
+	hose_b->mem_space.start = info->pci_1_mem_start_pci_lo;
+	hose_b->mem_space.end   = info->pci_1_mem_start_pci_lo +
+					info->pci_1_mem_size - 1;
+	hose_b->pci_mem_offset = (info->pci_1_mem_start_proc -
+					info->pci_1_mem_start_pci_lo);
+
+	hose_b->last_busno = pciauto_bus_scan(hose_b, hose_b->first_busno);
+
+
+	ppc_md.pci_exclude_device = gt64260_pci_exclude_device;
+	ppc_md.pci_swizzle        = common_swizzle;
+	ppc_md.pci_map_irq        = map_irq;
+
+	return 0;
+} /* gt64260_find_bridges() */
+
+/*
+ * gt64260_bridge_init()
+ *
+ * Perform bridge initialization for a "typical" setup for a PPC system.
+ */
+int __init
+gt64260_bridge_init(gt64260_bridge_info_t *info)
+{
+	int	window;
+	u16	u16_val;
+	u32	u32_val;
+	int	rc = 0;
+	u8	save_exclude;
+
+	/*
+	 * Count on firmware to set/clear other bits in this register.
+	 *
+	 * Set CPU CONFIG Reg bit:
+	 *	bit 13 - Pipeline
+	 *	bit 16 - RdOOO
+	 *
+	 * Clear CPU Config Reg bit:
+	 * 	bit 12 - endianess
+	 *	bit 27 - RemapWrDis
+	 */
+	u32_val = gt_read(GT64260_CPU_CONFIG);
+	u32_val |= ((1<<13) | (1<<16));
+	u32_val &= ~((1<<8) | (1<<12) | (1<<27));
+	gt_write(GT64260_CPU_CONFIG, u32_val);
+
+	/* PCI 0/1 Timeout and Retry limits */
+	u32_val = gt_read(GT64260_PCI_0_TO_RETRY);
+	u32_val |= 0x0000ffff;
+	gt_write(GT64260_PCI_0_TO_RETRY, u32_val);
+
+	u32_val = gt_read(GT64260_PCI_1_TO_RETRY);
+	u32_val |= 0x0000ffff;
+	gt_write(GT64260_PCI_1_TO_RETRY, u32_val);
+
+	save_exclude = gt64260_pci_exclude_bridge;
+	gt64260_pci_exclude_bridge = FALSE;
+
+	/* Set class code to indicate host bridge */
+	early_read_config_dword(info->hose_a,
+			        info->hose_a->first_busno,
+			        PCI_DEVFN(0,0),
+			        PCI_CLASS_REVISION,
+			        &u32_val);
+	u32_val &= 0x000000ff;
+	gt64260_revision = u32_val;	/* a 64260 or 64260A? */
+	u32_val |= (PCI_CLASS_BRIDGE_HOST << 16);
+	early_write_config_dword(info->hose_a,
+				 info->hose_a->first_busno,
+				 PCI_DEVFN(0,0),
+				 PCI_CLASS_REVISION,
+				 u32_val);
+
+	early_read_config_dword(info->hose_b,
+			        info->hose_b->first_busno,
+			        PCI_DEVFN(0,0),
+			        PCI_CLASS_REVISION,
+			        &u32_val);
+	u32_val &= 0x000000ff;
+	u32_val |= (PCI_CLASS_BRIDGE_HOST << 16);
+	early_write_config_dword(info->hose_b,
+				 info->hose_b->first_busno,
+				 PCI_DEVFN(0,0),
+				 PCI_CLASS_REVISION,
+				 u32_val);
+
+	/* Enable 64260 to be PCI master & respond to PCI MEM cycles */
+	early_read_config_word(info->hose_a,
+			       info->hose_a->first_busno,
+			       PCI_DEVFN(0,0),
+			       PCI_COMMAND,
+			       &u16_val);
+	u16_val |= (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+	early_write_config_word(info->hose_a,
+				info->hose_a->first_busno,
+				PCI_DEVFN(0,0),
+				PCI_COMMAND,
+				u16_val);
+
+	early_read_config_word(info->hose_b,
+			       info->hose_b->first_busno,
+			       PCI_DEVFN(0,0),
+			       PCI_COMMAND,
+			       &u16_val);
+	u16_val |= (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
+	early_write_config_word(info->hose_b,
+				info->hose_b->first_busno,
+				PCI_DEVFN(0,0),
+				PCI_COMMAND,
+				u16_val);
+
+	gt64260_pci_exclude_bridge = save_exclude;
+
+	/*
+	 * Disable all CPU windows on the bridge except for SCS 0 which
+	 * is covering all of system memory.:
+	 */
+	gt64260_cpu_disable_all_windows();
+
+	/*
+	 * Set CPU snoop window to indicate all of system memory
+	 * is covered with wirte-back cache.
+	 */
+	gt64260_cpu_snoop_set_window(0,
+				     0x00000000,
+				     info->mem_size,
+				     GT64260_CPU_SNOOP_WB);
+
+	/*
+	 * Set up CPU->PCI mappings (so CPU can get at PCI dev regs/mem).
+	 * Will only use one of the four CPU->PCI MEM windows on each bus.
+	 */
+	gt64260_cpu_set_pci_io_window(0,
+				      info->pci_0_io_start_proc,
+				      info->pci_0_io_start_pci,
+				      info->pci_0_io_size,
+				      info->pci_0_io_swap);
+
+	gt64260_cpu_set_pci_mem_window(0,
+				       0,
+				       info->pci_0_mem_start_proc,
+				       info->pci_0_mem_start_pci_hi,
+				       info->pci_0_mem_start_pci_lo,
+				       info->pci_0_mem_size,
+				       info->pci_0_mem_swap);
+
+	gt64260_cpu_set_pci_io_window(1,
+				      info->pci_1_io_start_proc,
+				      info->pci_1_io_start_pci,
+				      info->pci_1_io_size,
+				      info->pci_1_io_swap);
+
+	gt64260_cpu_set_pci_mem_window(1,
+				       0,
+				       info->pci_1_mem_start_proc,
+				       info->pci_1_mem_start_pci_hi,
+				       info->pci_1_mem_start_pci_lo,
+				       info->pci_1_mem_size,
+				       info->pci_1_mem_swap);
+
+	/*
+	 * Set up PCI MEM->system memory mapping (bridge slave PCI window).
+	 *
+	 * Set BAR enables to allow only the SCS0 slave window to respond
+	 * to PCI read/write cycles.
+	 */
+	gt64260_pci_bar_enable(0, GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_0);
+	gt64260_pci_bar_enable(1, GT64260_PCI_SLAVE_BAR_REG_ENABLES_SCS_0);
+
+	/*
+	 * For virt_to_bus & bus_to_virt to work correctly, this mapping
+	 * must be the same on both PCI buses.
+	 */
+	gt64260_pci_slave_scs_set_window(info->hose_a,
+					 0,
+					 0x00000000,
+					 0x00000000,
+					 info->mem_size);
+
+	gt64260_pci_slave_scs_set_window(info->hose_b,
+					 0,
+					 0x00000000,
+					 0x00000000,
+					 info->mem_size);
+	pci_dram_offset = 0; /* System mem at same addr on PCI & cpu bus */
+
+	/* Disable all the access control windows */
+	for (window=0; window<GT64260_PCI_ACC_CNTL_WINDOWS; window++) {
+		gt64260_pci_acc_cntl_set_window(0, window, 0, 0, 0, 0); 
+		gt64260_pci_acc_cntl_set_window(1, window, 0, 0, 0, 0); 
+	}
+
+	/* Disable all the PCI snoop regions */
+	for (window=0; window<GT64260_PCI_SNOOP_WINDOWS; window++) {
+		gt64260_pci_snoop_set_window(0, window, 0, 0, 0, 0); 
+		gt64260_pci_snoop_set_window(1, window, 0, 0, 0, 0); 
+	}
+
+	gt64260_pci_acc_cntl_set_window(0,
+					0,
+					0x00000000,
+					0x00000000,
+					info->mem_size,
+					(GT64260_PCI_ACC_CNTL_PREFETCHEN |
+					 GT64260_PCI_ACC_CNTL_MBURST_4_WORDS |
+					 GT64260_PCI_ACC_CNTL_SWAP_BYTE));
+
+	gt64260_pci_acc_cntl_set_window(1,
+					0,
+					0x00000000,
+					0x00000000,
+					info->mem_size,
+					(GT64260_PCI_ACC_CNTL_PREFETCHEN |
+					 GT64260_PCI_ACC_CNTL_MBURST_4_WORDS |
+					 GT64260_PCI_ACC_CNTL_SWAP_BYTE));
+
+	gt64260_pci_snoop_set_window(0,
+				     0,
+				     0x00000000,
+				     0x00000000,
+				     info->mem_size,
+				     GT64260_PCI_SNOOP_WB);
+					
+	gt64260_pci_snoop_set_window(1,
+				     0,
+				     0x00000000,
+				     0x00000000,
+				     info->mem_size,
+				     GT64260_PCI_SNOOP_WB);
+
+	gt64260_check_errata(info->hose_a, info->hose_b);
+
+
+	/* Set latency timer (to 64) & cacheline size; clear BIST */
+	gt64260_pci_exclude_bridge = FALSE;
+	u32_val = ((0x04 << 8) | (L1_CACHE_LINE_SIZE / 4));
+
+	early_write_config_dword(info->hose_a,
+				 info->hose_a->first_busno,
+				 PCI_DEVFN(0,0),
+				 PCI_CACHE_LINE_SIZE,
+				 u32_val);
+	early_write_config_dword(info->hose_b,
+				 info->hose_b->first_busno,
+				 PCI_DEVFN(0,0),
+				 PCI_CACHE_LINE_SIZE,
+				 u32_val);
+	gt64260_pci_exclude_bridge = TRUE;
+
+	return rc;
+} /* gt64260_bridge_init() */
+
+/*
+ * gt64260_check_errata()
+ *
+ * Apply applicable errata and restrictions from 0.5 of the
+ * Errata and Restrictions document from Marvell/Galileo.
+ */
+static void __init
+gt64260_check_errata(struct pci_controller *hose_a,
+		     struct pci_controller *hose_b)
+{
+	u32	val;
+	u8	save_exclude;
+
+	/* Currently 2 versions, 64260 and 64260A */
+	if (gt64260_revision == GT64260) {
+		save_exclude = gt64260_pci_exclude_bridge;
+		gt64260_pci_exclude_bridge = FALSE;
+
+		/* FEr#5, FEr#12 */
+		early_read_config_dword(hose_a,
+					hose_a->first_busno,
+					PCI_DEVFN(0,0),
+					PCI_COMMAND,
+					&val);
+		val &= ~(PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY);
+		early_write_config_dword(hose_a,
+					 hose_a->first_busno,
+					 PCI_DEVFN(0,0),
+					 PCI_COMMAND,
+					 val);
+
+		early_read_config_dword(hose_b,
+					hose_b->first_busno,
+					PCI_DEVFN(0,0),
+					PCI_COMMAND,
+					&val);
+		val &= ~(PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY);
+		early_write_config_dword(hose_b,
+					 hose_b->first_busno,
+					 PCI_DEVFN(0,0),
+					 PCI_COMMAND,
+					 val);
+		gt64260_pci_exclude_bridge = save_exclude;
+
+		/* FEr#12, FEr#13 */
+		gt_clr_bits(GT64260_PCI_0_CMD, ((1<<4) | (1<<5) | (1<<9)));
+		gt_clr_bits(GT64260_PCI_1_CMD, ((1<<4) | (1<<5) | (1<<9)));
+
+		/* FEr#54 */
+		gt_clr_bits(GT64260_CPU_SNOOP_BASE_0, 0xfffcf000);
+		gt_clr_bits(GT64260_CPU_SNOOP_BASE_1, 0xfffcf000);
+		gt_clr_bits(GT64260_CPU_SNOOP_BASE_2, 0xfffcf000);
+		gt_clr_bits(GT64260_CPU_SNOOP_BASE_3, 0xfffcf000);
+
+		/* R#18 */
+		gt_set_bits(GT64260_SDRAM_CONFIG, (1<<26));
+
+	} else if (gt64260_revision == GT64260A) {
+		/* R#18 */
+		gt_set_bits(GT64260_SDRAM_CONFIG, (1<<26));
+
+		/* No longer errata so turn on */
+		gt_set_bits(GT64260_PCI_0_CMD, ((1<<4) | (1<<5) | (1<<9)));
+		gt_set_bits(GT64260_PCI_1_CMD, ((1<<4) | (1<<5) | (1<<9)));
+	}
+} /* gt64260_check_errata() */
+
+
+/*
+ *****************************************************************************
+ *
+ *	General Window Setting Routines
+ *
+ *****************************************************************************
+ */
+
+static int
+gt64260_set_32bit_window(u32 base_addr,
+			 u32 size,
+			 u32 other_bits,
+			 u32 bot_reg,
+			 u32 top_reg)
+{
+	u32	val;
+
+	if (size > 0) {
+		/* Set up the window on the CPU side */
+		gt_write(bot_reg, (base_addr >> 20) | other_bits);
+		gt_write(top_reg, (base_addr + size - 1) >> 20);
+	} else { /* Disable window */
+		gt_write(top_reg, 0x00000000);
+		gt_write(bot_reg, 0x00000fff | other_bits);
+	}
+
+	val = gt_read(bot_reg); /* Flush FIFO */
+	return 0;
+} /* gt64260_set_32bit_window() */
+
+static int
+gt64260_set_64bit_window(u32 base_addr_hi,
+			 u32 base_addr_lo,
+			 u32 size,
+			 u32 other_bits,
+			 u32 bot_reg_hi,
+			 u32 bot_reg_lo,
+			 u32 top_reg)
+{
+	int	rc;
+
+	if ((rc = gt64260_set_32bit_window(base_addr_lo,
+					   size,
+					   other_bits,
+					   bot_reg_lo,
+					   top_reg)) == 0) {
+
+		gt_write(bot_reg_hi, base_addr_hi);
+		base_addr_hi = gt_read(bot_reg_hi); /* Flush FIFO */
+	}
+
+	return rc;
+} /* gt64260_set_64bit_window() */
+
+
+/*
+ *****************************************************************************
+ *
+ *	CPU Configuration Routines
+ *
+ *****************************************************************************
+ */
+
+int
+gt64260_cpu_scs_set_window(u32 window,
+			   u32 base_addr,
+			   u32 size)
+{
+	static u32
+	cpu_scs_windows[GT64260_CPU_SCS_DECODE_WINDOWS][2] = {
+		{ GT64260_CPU_SCS_DECODE_0_BOT, GT64260_CPU_SCS_DECODE_0_TOP },
+		{ GT64260_CPU_SCS_DECODE_1_BOT, GT64260_CPU_SCS_DECODE_1_TOP },
+		{ GT64260_CPU_SCS_DECODE_2_BOT, GT64260_CPU_SCS_DECODE_2_TOP },
+		{ GT64260_CPU_SCS_DECODE_3_BOT, GT64260_CPU_SCS_DECODE_3_TOP },
+	}; /* cpu_scs_windows[][] */
+	int	rc = -1;
+
+	if (window < GT64260_CPU_SCS_DECODE_WINDOWS) {
+		rc = gt64260_set_32bit_window(base_addr,
+					      size,
+					      0,
+					      cpu_scs_windows[window][0],
+					      cpu_scs_windows[window][1]);
+	}
+
+	return rc;
+} /* gt64260_cpu_scs_set_window() */
+
+int
+gt64260_cpu_cs_set_window(u32 window,
+			  u32 base_addr,
+			  u32 size)
+{
+	static u32
+	cpu_cs_windows[GT64260_CPU_CS_DECODE_WINDOWS][2] = {
+		{ GT64260_CPU_CS_DECODE_0_BOT, GT64260_CPU_CS_DECODE_0_TOP },
+		{ GT64260_CPU_CS_DECODE_1_BOT, GT64260_CPU_CS_DECODE_1_TOP },
+		{ GT64260_CPU_CS_DECODE_2_BOT, GT64260_CPU_CS_DECODE_2_TOP },
+		{ GT64260_CPU_CS_DECODE_3_BOT, GT64260_CPU_CS_DECODE_3_TOP },
+	}; /* cpu_cs_windows[][] */
+	int	rc = -1;
+
+	if (window < GT64260_CPU_CS_DECODE_WINDOWS) {
+		rc = gt64260_set_32bit_window(base_addr,
+					      size,
+					      0,
+					      cpu_cs_windows[window][0],
+					      cpu_cs_windows[window][1]);
+	}
+
+	return rc;
+} /* gt64260_cpu_cs_set_window() */
+
+int
+gt64260_cpu_boot_set_window(u32 base_addr,
+			    u32 size)
+{
+	int	rc;
+
+	rc = gt64260_set_32bit_window(base_addr,
+				      size,
+				      0,
+				      GT64260_CPU_BOOT_CS_DECODE_0_BOT,
+				      GT64260_CPU_BOOT_CS_DECODE_0_TOP);
+
+	return rc;
+} /* gt64260_cpu_boot_set_window() */
+
+/*
+ * gt64260_cpu_set_pci_io_window()
+ *
+ * Set up a CPU window into PCI I/O or MEM space.
+ * Always do Read/Modify/Write to window regs.
+ */
+static int
+gt64260_cpu_pci_set_window(u32 cpu_base_addr,
+			   u32 pci_base_addr,
+			   u32 size,
+			   u32 other_bits,
+			   u32 bot_reg,
+			   u32 top_reg,
+			   u32 remap_reg)
+{
+	u32	val;
+	int	rc;
+
+	if ((rc = gt64260_set_32bit_window(cpu_base_addr,
+					   size,
+					   other_bits,
+					   bot_reg,
+					   top_reg)) == 0) {
+
+		/* Set up CPU->PCI remapping (on lower 32 bits) */
+		gt_write(remap_reg, pci_base_addr >> 20);
+		val = gt_read(bot_reg); /* Flush FIFO */
+	}
+
+	return rc;
+} /* gt64260_cpu_pci_set_window() */
+
+
+/*
+ * gt64260_cpu_set_pci_io_window()
+ *
+ * Set up a CPU window into PCI I/O space.
+ * Always do Read/Modify/Write to window regs.
+ */
+int
+gt64260_cpu_set_pci_io_window(u32 pci_bus,
+			      u32 cpu_base_addr,
+			      u32 pci_base_addr,
+			      u32 size,
+			      u32 swap)
+{
+	/* 2 PCI buses with 1 I/O window each (from CPU point of view) */
+	static u32
+	cpu_pci_io_windows[GT64260_PCI_BUSES][3] = {
+		{ GT64260_CPU_PCI_0_IO_DECODE_BOT,
+		  GT64260_CPU_PCI_0_IO_DECODE_TOP,
+		  GT64260_CPU_PCI_0_IO_REMAP },
+
+		{ GT64260_CPU_PCI_1_IO_DECODE_BOT,
+		  GT64260_CPU_PCI_1_IO_DECODE_TOP,
+		  GT64260_CPU_PCI_1_IO_REMAP },
+	}; /* cpu_pci_io_windows[][] */
+	int	rc = -1;
+
+	if (pci_bus < GT64260_PCI_BUSES) {
+		rc =  gt64260_cpu_pci_set_window(cpu_base_addr,
+					  pci_base_addr,
+					  size,
+					  swap,
+					  cpu_pci_io_windows[pci_bus][0],
+					  cpu_pci_io_windows[pci_bus][1],
+					  cpu_pci_io_windows[pci_bus][2]);
+	}
+
+	return rc;
+} /* gt64260_cpu_set_pci_io_window() */
+
+/*
+ * gt64260_cpu_set_pci_mem_window()
+ *
+ * Set up a CPU window into PCI MEM space (4 PCI MEM windows per PCI bus).
+ * Always do Read/Modify/Write to window regs.
+ */
+int
+gt64260_cpu_set_pci_mem_window(u32 pci_bus,
+			       u32 window,
+			       u32 cpu_base_addr,
+			       u32 pci_base_addr_hi,
+			       u32 pci_base_addr_lo,
+			       u32 size,
+			       u32 swap_64bit)
+{
+	/* 2 PCI buses with 4 memory windows each (from CPU point of view) */
+	static u32
+	cpu_pci_mem_windows[GT64260_PCI_BUSES][GT64260_PCI_MEM_WINDOWS_PER_BUS][4] = {
+		{ /* PCI 0 */
+			{ GT64260_CPU_PCI_0_MEM_0_DECODE_BOT,
+			  GT64260_CPU_PCI_0_MEM_0_DECODE_TOP,
+			  GT64260_CPU_PCI_0_MEM_0_REMAP_HI,
+			  GT64260_CPU_PCI_0_MEM_0_REMAP_LO },
+
+			{ GT64260_CPU_PCI_0_MEM_1_DECODE_BOT,
+			  GT64260_CPU_PCI_0_MEM_1_DECODE_TOP,
+			  GT64260_CPU_PCI_0_MEM_1_REMAP_HI,
+			  GT64260_CPU_PCI_0_MEM_1_REMAP_LO },
+
+			{ GT64260_CPU_PCI_0_MEM_2_DECODE_BOT,
+			  GT64260_CPU_PCI_0_MEM_2_DECODE_TOP,
+			  GT64260_CPU_PCI_0_MEM_2_REMAP_HI,
+			  GT64260_CPU_PCI_0_MEM_2_REMAP_LO },
+
+			{ GT64260_CPU_PCI_0_MEM_3_DECODE_BOT,
+			  GT64260_CPU_PCI_0_MEM_3_DECODE_TOP,
+			  GT64260_CPU_PCI_0_MEM_3_REMAP_HI,
+			  GT64260_CPU_PCI_0_MEM_3_REMAP_LO }
+		},
+
+		{ /* PCI 1 */
+			{ GT64260_CPU_PCI_1_MEM_0_DECODE_BOT,
+			  GT64260_CPU_PCI_1_MEM_0_DECODE_TOP,
+			  GT64260_CPU_PCI_1_MEM_0_REMAP_HI,
+			  GT64260_CPU_PCI_1_MEM_0_REMAP_LO },
+
+			{ GT64260_CPU_PCI_1_MEM_1_DECODE_BOT,
+			  GT64260_CPU_PCI_1_MEM_1_DECODE_TOP,
+			  GT64260_CPU_PCI_1_MEM_1_REMAP_HI,
+			  GT64260_CPU_PCI_1_MEM_1_REMAP_LO },
+
+			{ GT64260_CPU_PCI_1_MEM_2_DECODE_BOT,
+			  GT64260_CPU_PCI_1_MEM_2_DECODE_TOP,
+			  GT64260_CPU_PCI_1_MEM_2_REMAP_HI,
+			  GT64260_CPU_PCI_1_MEM_2_REMAP_LO },
+
+			{ GT64260_CPU_PCI_1_MEM_3_DECODE_BOT,
+			  GT64260_CPU_PCI_1_MEM_3_DECODE_TOP,
+			  GT64260_CPU_PCI_1_MEM_3_REMAP_HI,
+			  GT64260_CPU_PCI_1_MEM_3_REMAP_LO },
+		}
+	}; /* cpu_pci_mem_windows[][][] */
+	u32		remap_reg, remap;
+	int		rc = -1;
+
+	if ((pci_bus < GT64260_PCI_BUSES) &&
+	    (window < GT64260_PCI_MEM_WINDOWS_PER_BUS)) {
+
+		if (gt64260_cpu_pci_set_window(
+			cpu_base_addr,
+			pci_base_addr_lo,
+			size,
+			swap_64bit,
+			cpu_pci_mem_windows[pci_bus][window][0],
+			cpu_pci_mem_windows[pci_bus][window][1],
+			cpu_pci_mem_windows[pci_bus][window][3]) == 0) {
+
+			remap_reg = cpu_pci_mem_windows[pci_bus][window][2];
+			gt_write(remap_reg, pci_base_addr_hi);
+
+			remap = gt_read(remap_reg); /* Flush FIFO */
+
+			rc = 0;
+		}
+	}
+
+	return rc;
+} /* gt64260_cpu_set_pci_mem_window() */
+
+int
+gt64260_cpu_prot_set_window(u32 window,
+			    u32 base_addr,
+			    u32 size,
+			    u32 access_bits)
+{
+	static u32
+	cpu_prot_windows[GT64260_CPU_PROT_WINDOWS][2] = {
+		{ GT64260_CPU_PROT_BASE_0, GT64260_CPU_PROT_TOP_0 },
+		{ GT64260_CPU_PROT_BASE_1, GT64260_CPU_PROT_TOP_1 },
+		{ GT64260_CPU_PROT_BASE_2, GT64260_CPU_PROT_TOP_2 },
+		{ GT64260_CPU_PROT_BASE_3, GT64260_CPU_PROT_TOP_3 },
+		{ GT64260_CPU_PROT_BASE_4, GT64260_CPU_PROT_TOP_4 },
+		{ GT64260_CPU_PROT_BASE_5, GT64260_CPU_PROT_TOP_5 },
+		{ GT64260_CPU_PROT_BASE_6, GT64260_CPU_PROT_TOP_6 },
+		{ GT64260_CPU_PROT_BASE_7, GT64260_CPU_PROT_TOP_7 },
+	}; /* cpu_prot_windows[][] */
+	int	rc = -1;
+
+	if (window < GT64260_CPU_PROT_WINDOWS) {
+		rc = gt64260_set_32bit_window(base_addr,
+					      size,
+					      access_bits,
+					      cpu_prot_windows[window][0],
+					      cpu_prot_windows[window][1]);
+	}
+
+	return rc;
+} /* gt64260_cpu_prot_set_window() */
+
+int
+gt64260_cpu_snoop_set_window(u32 window,
+			     u32 base_addr,
+			     u32 size,
+			     u32  snoop_type)
+{
+	static u32
+	cpu_snoop_windows[GT64260_CPU_SNOOP_WINDOWS][2] = {
+		{ GT64260_CPU_SNOOP_BASE_0, GT64260_CPU_SNOOP_TOP_0 },
+		{ GT64260_CPU_SNOOP_BASE_1, GT64260_CPU_SNOOP_TOP_1 },
+		{ GT64260_CPU_SNOOP_BASE_2, GT64260_CPU_SNOOP_TOP_2 },
+		{ GT64260_CPU_SNOOP_BASE_3, GT64260_CPU_SNOOP_TOP_3 },
+	}; /* cpu_snoop_windows[][] */
+	int	rc = -1;
+
+	if ((window < GT64260_CPU_SNOOP_WINDOWS) &&
+	    (snoop_type <= GT64260_CPU_SNOOP_WB)) {
+
+		rc = gt64260_set_32bit_window(base_addr,
+					      size,
+					      snoop_type,
+					      cpu_snoop_windows[window][0],
+					      cpu_snoop_windows[window][1]);
+	}
+
+	return rc;
+} /* gt64260_cpu_snoop_set_window() */
+
+void
+gt64260_cpu_disable_all_windows(void)
+{
+	int	pci_bus, window;
+
+	/* Don't disable SCS windows b/c we need to access system memory */
+
+	for (window=0; window<GT64260_CPU_CS_DECODE_WINDOWS; window++) {
+		gt64260_cpu_cs_set_window(window, 0, 0);
+	}
+
+	gt64260_cpu_boot_set_window(0, 0);
+
+	for (pci_bus=0; pci_bus<GT64260_PCI_BUSES; pci_bus++) {
+		gt64260_cpu_set_pci_io_window(pci_bus, 0, 0, 0, 0);
+
+		for (window=0;window<GT64260_PCI_MEM_WINDOWS_PER_BUS;window++) {
+			gt64260_cpu_set_pci_mem_window(pci_bus,
+						       window,
+						       0, 0, 0, 0, 0);
+		}
+	}
+
+	for (window=0; window<GT64260_CPU_PROT_WINDOWS; window++) {
+		gt64260_cpu_prot_set_window(window, 0, 0, 0);
+	}
+
+	for (window=0; window<GT64260_CPU_SNOOP_WINDOWS; window++) {
+		gt64260_cpu_snoop_set_window(window, 0, 0, 0);
+	}
+
+	return;
+} /* gt64260_cpu_disable_all_windows() */
+
+
+/*
+ *****************************************************************************
+ *
+ *	PCI Slave Window Configuration Routines
+ *
+ *****************************************************************************
+ */
+
+int
+gt64260_pci_bar_enable(u32 pci_bus,
+		       u32 enable_bits)
+{
+	u32	reg, val;
+	int	rc = -1;
+
+	if (pci_bus < GT64260_PCI_BUSES) {
+		reg = (pci_bus == 0) ? GT64260_PCI_0_SLAVE_BAR_REG_ENABLES :
+				       GT64260_PCI_1_SLAVE_BAR_REG_ENABLES;
+
+
+		/* Note: '0' enables, '1' disables */
+		val = gt_read(reg);
+		val |= 0xffffffff;	/* Disable everything by default */
+		val &= ~enable_bits;
+		gt_write(reg, val);
+
+		gt_read(reg); /* Flush FIFO */
+
+		rc = 0;
+	}
+
+	return rc;
+} /* gt64260_pci_bar_enable() */
+
+static int
+gt64260_pci_slave_set_window(struct pci_controller *hose,
+			     u32 pci_base_addr,
+			     u32 cpu_base_addr,
+			     u32 bar_size,
+			     u32 pci_cfg_fcn,
+			     u32 pci_cfg_hdr_offset,
+			     u32 bar_size_reg,
+			     u32 remap_reg)
+{
+	u32	val;
+	int	devfn;
+	u8	save_exclude;
+
+	pci_base_addr &= 0xfffff000;
+	cpu_base_addr &= 0xfffff000;
+	bar_size &= 0xfffff000;
+	devfn = PCI_DEVFN(0, pci_cfg_fcn);
+
+	gt_write(bar_size_reg, (bar_size - 1) & 0xfffff000);
+	gt_write(remap_reg, cpu_base_addr);
+	gt_read(remap_reg); /* Flush FIFO */
+
+	save_exclude = gt64260_pci_exclude_bridge;
+	gt64260_pci_exclude_bridge = FALSE;
+	early_read_config_dword(hose,
+				hose->first_busno,
+				devfn,
+				pci_cfg_hdr_offset,
+				&val);
+	val &= 0x0000000f;
+	early_write_config_dword(hose,
+				 hose->first_busno,
+				 devfn,
+				 pci_cfg_hdr_offset,
+				 pci_base_addr | val);
+	gt64260_pci_exclude_bridge = save_exclude;
+
+	return 0;
+} /* gt64260_pci_slave_set_window() */
+
+int
+gt64260_pci_slave_scs_set_window(struct pci_controller *hose,
+				 u32 window,
+				 u32 pci_base_addr,
+				 u32 cpu_base_addr,
+				 u32 size)
+{
+	static u32
+	pci_scs_windows[GT64260_PCI_BUSES][GT64260_PCI_SCS_WINDOWS][4] = {
+		{ /* PCI 0 */
+			{ 0, 0x10,
+			  GT64260_PCI_0_SLAVE_SCS_0_SIZE,
+			  GT64260_PCI_0_SLAVE_SCS_0_REMAP },
+			{ 0, 0x14,
+			  GT64260_PCI_0_SLAVE_SCS_1_SIZE,
+			  GT64260_PCI_0_SLAVE_SCS_1_REMAP },
+			{ 0, 0x18,
+			  GT64260_PCI_0_SLAVE_SCS_2_SIZE,
+			  GT64260_PCI_0_SLAVE_SCS_2_REMAP },
+			{ 0, 0x1c,
+			  GT64260_PCI_0_SLAVE_SCS_3_SIZE,
+			  GT64260_PCI_0_SLAVE_SCS_3_REMAP },
+		},
+		{ /* PCI 1 */
+			{ 0, 0x10,
+			  GT64260_PCI_1_SLAVE_SCS_0_SIZE,
+			  GT64260_PCI_1_SLAVE_SCS_0_REMAP },
+			{ 0, 0x14,
+			  GT64260_PCI_1_SLAVE_SCS_1_SIZE,
+			  GT64260_PCI_1_SLAVE_SCS_1_REMAP },
+			{ 0, 0x18,
+			  GT64260_PCI_1_SLAVE_SCS_2_SIZE,
+			  GT64260_PCI_1_SLAVE_SCS_2_REMAP },
+			{ 0, 0x1c,
+			  GT64260_PCI_1_SLAVE_SCS_3_SIZE,
+			  GT64260_PCI_1_SLAVE_SCS_3_REMAP },
+		}
+	}; /* pci_scs_windows[][][] */
+	int	pci_bus;
+	int	rc = -1;
+
+	if (window < GT64260_PCI_SCS_WINDOWS) {
+		pci_bus = (hose->first_busno == 0) ? 0 : 1;
+
+		rc = gt64260_pci_slave_set_window(
+				hose,
+				pci_base_addr,
+				cpu_base_addr,
+				size,
+				pci_scs_windows[pci_bus][window][0],
+				pci_scs_windows[pci_bus][window][1],
+				pci_scs_windows[pci_bus][window][2],
+				pci_scs_windows[pci_bus][window][3]);
+	}
+
+	return rc;
+} /* gt64260_pci_slave_scs_set_window() */
+
+int
+gt64260_pci_slave_cs_set_window(struct pci_controller *hose,
+				u32 window,
+				u32 pci_base_addr,
+				u32 cpu_base_addr,
+				u32 size)
+{
+	static u32
+	pci_cs_windows[GT64260_PCI_BUSES][GT64260_PCI_CS_WINDOWS][4] = {
+		{ /* PCI 0 */
+			{ 1, 0x10,
+			  GT64260_PCI_0_SLAVE_CS_0_SIZE,
+			  GT64260_PCI_0_SLAVE_CS_0_REMAP },
+			{ 1, 0x14,
+			  GT64260_PCI_0_SLAVE_CS_1_SIZE,
+			  GT64260_PCI_0_SLAVE_CS_1_REMAP },
+			{ 1, 0x18,
+			  GT64260_PCI_0_SLAVE_CS_2_SIZE,
+			  GT64260_PCI_0_SLAVE_CS_2_REMAP },
+			{ 1, 0x1c,
+			  GT64260_PCI_0_SLAVE_CS_3_SIZE,
+			  GT64260_PCI_0_SLAVE_CS_3_REMAP },
+		},
+		{ /* PCI 1 */
+			{ 1, 0x10,
+			  GT64260_PCI_1_SLAVE_CS_0_SIZE,
+			  GT64260_PCI_1_SLAVE_CS_0_REMAP },
+			{ 1, 0x14,
+			  GT64260_PCI_1_SLAVE_CS_1_SIZE,
+			  GT64260_PCI_1_SLAVE_CS_1_REMAP },
+			{ 1, 0x18,
+			  GT64260_PCI_1_SLAVE_CS_2_SIZE,
+			  GT64260_PCI_1_SLAVE_CS_2_REMAP },
+			{ 1, 0x1c,
+			  GT64260_PCI_1_SLAVE_CS_3_SIZE,
+			  GT64260_PCI_1_SLAVE_CS_3_REMAP },
+		}
+	}; /* pci_cs_windows[][][] */
+	int	pci_bus;
+	int	rc = -1;
+
+	if (window < GT64260_PCI_CS_WINDOWS) {
+		pci_bus = (hose->first_busno == 0) ? 0 : 1;
+
+		rc = gt64260_pci_slave_set_window(
+				hose,
+				pci_base_addr,
+				cpu_base_addr,
+				size,
+				pci_cs_windows[pci_bus][window][0],
+				pci_cs_windows[pci_bus][window][1],
+				pci_cs_windows[pci_bus][window][2],
+				pci_cs_windows[pci_bus][window][3]);
+	}
+
+	return rc;
+} /* gt64260_pci_slave_cs_set_window() */
+
+int
+gt64260_pci_slave_boot_set_window(struct pci_controller *hose,
+				  u32 pci_base_addr,
+				  u32 cpu_base_addr,
+				  u32 size)
+{
+	int	rc;
+
+	rc = gt64260_pci_slave_set_window(hose,
+					  pci_base_addr,
+					  cpu_base_addr,
+					  size,
+					  1,
+					  0x20,
+					  GT64260_PCI_1_SLAVE_BOOT_SIZE,
+					  GT64260_PCI_1_SLAVE_BOOT_REMAP);
+
+	return rc;
+} /* gt64260_pci_slave_boot_set_window() */
+
+int
+gt64260_pci_slave_p2p_mem_set_window(struct pci_controller *hose,
+				     u32 window,
+				     u32 pci_base_addr,
+				     u32 other_bus_base_addr,
+				     u32 size)
+{
+	static u32 
+	pci_p2p_mem_windows[GT64260_PCI_BUSES][GT64260_PCI_P2P_MEM_WINDOWS][4]={
+		{ /* PCI 0 */
+			{ 2, 0x10,
+			  GT64260_PCI_0_SLAVE_P2P_MEM_0_SIZE,
+			  GT64260_PCI_0_SLAVE_P2P_MEM_0_REMAP_LO },
+			{ 2, 0x14,
+			  GT64260_PCI_0_SLAVE_P2P_MEM_1_SIZE,
+			  GT64260_PCI_0_SLAVE_P2P_MEM_1_REMAP_LO },
+		},
+		{ /* PCI 1 */
+			{ 2, 0x10,
+			  GT64260_PCI_1_SLAVE_P2P_MEM_0_SIZE,
+			  GT64260_PCI_1_SLAVE_P2P_MEM_0_REMAP_LO },
+			{ 2, 0x14,
+			  GT64260_PCI_1_SLAVE_P2P_MEM_1_SIZE,
+			  GT64260_PCI_1_SLAVE_P2P_MEM_1_REMAP_LO },
+		}
+	}; /* pci_p2p_mem_windows[][][] */
+	int	pci_bus;
+	int	rc = -1;
+
+	if (window < GT64260_PCI_P2P_MEM_WINDOWS) {
+		pci_bus = (hose->first_busno == 0) ? 0 : 1;
+
+		rc = gt64260_pci_slave_set_window(
+				hose,
+				pci_base_addr,
+				other_bus_base_addr,
+				size,
+				pci_p2p_mem_windows[pci_bus][window][0],
+				pci_p2p_mem_windows[pci_bus][window][1],
+				pci_p2p_mem_windows[pci_bus][window][2],
+				pci_p2p_mem_windows[pci_bus][window][3]);
+	}
+
+	return rc;
+} /* gt64260_pci_slave_p2p_mem_set_window() */
+
+int
+gt64260_pci_slave_p2p_io_set_window(struct pci_controller *hose,
+				    u32 pci_base_addr,
+				    u32 other_bus_base_addr,
+				    u32 size)
+{
+	int	rc;
+
+	rc = gt64260_pci_slave_set_window(hose,
+					  pci_base_addr,
+					  other_bus_base_addr,
+					  size,
+					  2,
+					  0x18,
+					  GT64260_PCI_1_SLAVE_P2P_IO_SIZE,
+					  GT64260_PCI_1_SLAVE_P2P_IO_REMAP);
+
+	return rc;
+} /* gt64260_pci_slave_p2p_io_set_window() */
+
+int
+gt64260_pci_slave_dac_scs_set_window(struct pci_controller *hose,
+				     u32 window,
+				     u32 pci_base_addr_hi,
+				     u32 pci_base_addr_lo,
+				     u32 cpu_base_addr,
+				     u32 size)
+{
+	static u32 
+	pci_dac_scs_windows[GT64260_PCI_BUSES][GT64260_PCI_DAC_SCS_WINDOWS][5]={
+		{ /* PCI 0 */
+			{ 4, 0x10, 0x14,
+			  GT64260_PCI_0_SLAVE_DAC_SCS_0_SIZE,
+			  GT64260_PCI_0_SLAVE_DAC_SCS_0_REMAP },
+			{ 4, 0x18, 0x1c,
+			  GT64260_PCI_0_SLAVE_DAC_SCS_1_SIZE,
+			  GT64260_PCI_0_SLAVE_DAC_SCS_1_REMAP },
+			{ 5, 0x10, 0x14,
+			  GT64260_PCI_0_SLAVE_DAC_SCS_2_SIZE,
+			  GT64260_PCI_0_SLAVE_DAC_SCS_2_REMAP },
+			{ 5, 0x18, 0x1c,
+			  GT64260_PCI_0_SLAVE_DAC_SCS_3_SIZE,
+			  GT64260_PCI_0_SLAVE_DAC_SCS_3_REMAP },
+		},
+		{ /* PCI 1 */
+			{ 4, 0x10, 0x14,
+			  GT64260_PCI_1_SLAVE_DAC_SCS_0_SIZE,
+			  GT64260_PCI_1_SLAVE_DAC_SCS_0_REMAP },
+			{ 4, 0x18, 0x1c,
+			  GT64260_PCI_1_SLAVE_DAC_SCS_1_SIZE,
+			  GT64260_PCI_1_SLAVE_DAC_SCS_1_REMAP },
+			{ 5, 0x10, 0x14,
+			  GT64260_PCI_1_SLAVE_DAC_SCS_2_SIZE,
+			  GT64260_PCI_1_SLAVE_DAC_SCS_2_REMAP },
+			{ 5, 0x18, 0x1c,
+			  GT64260_PCI_1_SLAVE_DAC_SCS_3_SIZE,
+			  GT64260_PCI_1_SLAVE_DAC_SCS_3_REMAP },
+		}
+	}; /* pci_dac_scs_windows[][][] */
+	int	pci_bus;
+	int	rc = -1;
+
+	if (window < GT64260_PCI_DAC_SCS_WINDOWS) {
+		pci_bus = (hose->first_busno == 0) ? 0 : 1;
+
+		rc = gt64260_pci_slave_set_window(
+				hose,
+				pci_base_addr_lo,
+				cpu_base_addr,
+				size,
+				pci_dac_scs_windows[pci_bus][window][0],
+				pci_dac_scs_windows[pci_bus][window][1],
+				pci_dac_scs_windows[pci_bus][window][3],
+				pci_dac_scs_windows[pci_bus][window][4]);
+
+		early_write_config_dword(
+			hose,
+			hose->first_busno,
+			PCI_DEVFN(0, pci_dac_scs_windows[pci_bus][window][0]),
+			pci_dac_scs_windows[pci_bus][window][2],
+			pci_base_addr_hi);
+	}
+
+	return rc;
+} /* gt64260_pci_slave_dac_scs_set_window() */
+
+int
+gt64260_pci_slave_dac_cs_set_window(struct pci_controller *hose,
+				    u32 window,
+				    u32 pci_base_addr_hi,
+				    u32 pci_base_addr_lo,
+				    u32 cpu_base_addr,
+				    u32 size)
+{
+	static u32 
+	pci_dac_cs_windows[GT64260_PCI_BUSES][GT64260_PCI_DAC_CS_WINDOWS][5] = {
+		{ /* PCI 0 */
+			{ 6, 0x10, 0x14,
+			  GT64260_PCI_0_SLAVE_DAC_CS_0_SIZE,
+			  GT64260_PCI_0_SLAVE_DAC_CS_0_REMAP },
+			{ 6, 0x18, 0x1c,
+			  GT64260_PCI_0_SLAVE_DAC_CS_1_SIZE,
+			  GT64260_PCI_0_SLAVE_DAC_CS_1_REMAP },
+			{ 6, 0x20, 0x24,
+			  GT64260_PCI_0_SLAVE_DAC_CS_2_SIZE,
+			  GT64260_PCI_0_SLAVE_DAC_CS_2_REMAP },
+			{ 7, 0x10, 0x14,
+			  GT64260_PCI_0_SLAVE_DAC_CS_3_SIZE,
+			  GT64260_PCI_0_SLAVE_DAC_CS_3_REMAP },
+		},
+		{ /* PCI 1 */
+			{ 6, 0x10, 0x14,
+			  GT64260_PCI_1_SLAVE_DAC_CS_0_SIZE,
+			  GT64260_PCI_1_SLAVE_DAC_CS_0_REMAP },
+			{ 6, 0x18, 0x1c,
+			  GT64260_PCI_1_SLAVE_DAC_CS_1_SIZE,
+			  GT64260_PCI_1_SLAVE_DAC_CS_1_REMAP },
+			{ 6, 0x20, 0x24,
+			  GT64260_PCI_1_SLAVE_DAC_CS_2_SIZE,
+			  GT64260_PCI_1_SLAVE_DAC_CS_2_REMAP },
+			{ 7, 0x10, 0x14,
+			  GT64260_PCI_1_SLAVE_DAC_CS_3_SIZE,
+			  GT64260_PCI_1_SLAVE_DAC_CS_3_REMAP },
+		}
+	}; /* pci_dac_cs_windows[][][] */
+	int	pci_bus;
+	int	rc = -1;
+
+	if (window < GT64260_PCI_CS_WINDOWS) {
+		pci_bus = (hose->first_busno == 0) ? 0 : 1;
+
+		rc = gt64260_pci_slave_set_window(
+				hose,
+				pci_base_addr_lo,
+				cpu_base_addr,
+				size,
+				pci_dac_cs_windows[pci_bus][window][0],
+				pci_dac_cs_windows[pci_bus][window][1],
+				pci_dac_cs_windows[pci_bus][window][3],
+				pci_dac_cs_windows[pci_bus][window][4]);
+
+		early_write_config_dword(
+			hose,
+			hose->first_busno,
+			PCI_DEVFN(0, pci_dac_cs_windows[pci_bus][window][0]),
+			pci_dac_cs_windows[pci_bus][window][2],
+			pci_base_addr_hi);
+	}
+
+	return rc;
+} /* gt64260_pci_slave_dac_cs_set_window() */
+
+int
+gt64260_pci_slave_dac_boot_set_window(struct pci_controller *hose,
+				      u32 pci_base_addr_hi,
+				      u32 pci_base_addr_lo,
+				      u32 cpu_base_addr,
+				      u32 size)
+{
+	int	rc;
+
+	rc = gt64260_pci_slave_set_window(hose,
+					  pci_base_addr_lo,
+					  cpu_base_addr,
+					  size,
+					  7,
+					  0x18,
+					  GT64260_PCI_1_SLAVE_BOOT_SIZE,
+					  GT64260_PCI_1_SLAVE_BOOT_REMAP);
+
+	early_write_config_dword(hose,
+				 hose->first_busno,
+				 PCI_DEVFN(0, 7),
+				 0x1c,
+				 pci_base_addr_hi);
+
+	return rc;
+} /* gt64260_pci_slave_dac_boot_set_window() */
+
+int
+gt64260_pci_slave_dac_p2p_mem_set_window(struct pci_controller *hose,
+				         u32 window,
+				         u32 pci_base_addr_hi,
+				         u32 pci_base_addr_lo,
+				         u32 other_bus_base_addr,
+				         u32 size)
+{
+	static u32 
+	pci_dac_p2p_mem_windows[GT64260_PCI_BUSES][GT64260_PCI_DAC_P2P_MEM_WINDOWS][5] = {
+		{ /* PCI 0 */
+			{ 4, 0x20, 0x24,
+			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_SIZE,
+			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_REMAP_LO },
+			{ 5, 0x20, 0x24,
+			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_SIZE,
+			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_REMAP_LO },
+		},
+		{ /* PCI 1 */
+			{ 4, 0xa0, 0xa4,
+			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_SIZE,
+			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_0_REMAP_LO },
+			{ 5, 0xa0, 0xa4,
+			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_SIZE,
+			  GT64260_PCI_0_SLAVE_DAC_P2P_MEM_1_REMAP_LO },
+		}
+	}; /* pci_dac_p2p_windows[][][] */
+	int	pci_bus;
+	int	rc = -1;
+
+	if (window < GT64260_PCI_P2P_MEM_WINDOWS) {
+		pci_bus = (hose->first_busno == 0) ? 0 : 1;
+
+		rc = gt64260_pci_slave_set_window(
+				hose,
+				pci_base_addr_lo,
+				other_bus_base_addr,
+				size,
+				pci_dac_p2p_mem_windows[pci_bus][window][0],
+				pci_dac_p2p_mem_windows[pci_bus][window][1],
+				pci_dac_p2p_mem_windows[pci_bus][window][3],
+				pci_dac_p2p_mem_windows[pci_bus][window][4]);
+
+		early_write_config_dword(
+		    hose,
+		    hose->first_busno,
+		    PCI_DEVFN(0, pci_dac_p2p_mem_windows[pci_bus][window][0]),
+		    pci_dac_p2p_mem_windows[pci_bus][window][2],
+		    pci_base_addr_hi);
+	}
+
+	return rc;
+} /* gt64260_pci_slave_dac_p2p_mem_set_window() */
+
+
+/*
+ *****************************************************************************
+ *
+ *	PCI Control Configuration Routines
+ *
+ *****************************************************************************
+ */
+
+
+int
+gt64260_pci_acc_cntl_set_window(u32 pci_bus,
+			        u32 window,
+			        u32 base_addr_hi,
+			        u32 base_addr_lo,
+			        u32 size,
+			        u32 features)
+{
+	static u32
+	pci_acc_cntl_windows[GT64260_PCI_BUSES][GT64260_PCI_ACC_CNTL_WINDOWS][3] = {
+		{ /* PCI 0 */
+			{ GT64260_PCI_0_ACC_CNTL_0_BASE_HI,
+			  GT64260_PCI_0_ACC_CNTL_0_BASE_LO,
+			  GT64260_PCI_0_ACC_CNTL_0_TOP },
+
+			{ GT64260_PCI_0_ACC_CNTL_1_BASE_HI,
+			  GT64260_PCI_0_ACC_CNTL_1_BASE_LO,
+			  GT64260_PCI_0_ACC_CNTL_1_TOP },
+
+			{ GT64260_PCI_0_ACC_CNTL_2_BASE_HI,
+			  GT64260_PCI_0_ACC_CNTL_2_BASE_LO,
+			  GT64260_PCI_0_ACC_CNTL_2_TOP },
+
+			{ GT64260_PCI_0_ACC_CNTL_3_BASE_HI,
+			  GT64260_PCI_0_ACC_CNTL_3_BASE_LO,
+			  GT64260_PCI_0_ACC_CNTL_3_TOP },
+
+			{ GT64260_PCI_0_ACC_CNTL_4_BASE_HI,
+			  GT64260_PCI_0_ACC_CNTL_4_BASE_LO,
+			  GT64260_PCI_0_ACC_CNTL_4_TOP },
+
+			{ GT64260_PCI_0_ACC_CNTL_5_BASE_HI,
+			  GT64260_PCI_0_ACC_CNTL_5_BASE_LO,
+			  GT64260_PCI_0_ACC_CNTL_5_TOP },
+
+			{ GT64260_PCI_0_ACC_CNTL_6_BASE_HI,
+			  GT64260_PCI_0_ACC_CNTL_6_BASE_LO,
+			  GT64260_PCI_0_ACC_CNTL_6_TOP },
+
+			{ GT64260_PCI_0_ACC_CNTL_7_BASE_HI,
+			  GT64260_PCI_0_ACC_CNTL_7_BASE_LO,
+			  GT64260_PCI_0_ACC_CNTL_7_TOP },
+		},
+		{ /* PCI 1 */
+			{ GT64260_PCI_1_ACC_CNTL_0_BASE_HI,
+			  GT64260_PCI_1_ACC_CNTL_0_BASE_LO,
+			  GT64260_PCI_1_ACC_CNTL_0_TOP },
+
+			{ GT64260_PCI_1_ACC_CNTL_1_BASE_HI,
+			  GT64260_PCI_1_ACC_CNTL_1_BASE_LO,
+			  GT64260_PCI_1_ACC_CNTL_1_TOP },
+
+			{ GT64260_PCI_1_ACC_CNTL_2_BASE_HI,
+			  GT64260_PCI_1_ACC_CNTL_2_BASE_LO,
+			  GT64260_PCI_1_ACC_CNTL_2_TOP },
+
+			{ GT64260_PCI_1_ACC_CNTL_3_BASE_HI,
+			  GT64260_PCI_1_ACC_CNTL_3_BASE_LO,
+			  GT64260_PCI_1_ACC_CNTL_3_TOP },
+
+			{ GT64260_PCI_1_ACC_CNTL_4_BASE_HI,
+			  GT64260_PCI_1_ACC_CNTL_4_BASE_LO,
+			  GT64260_PCI_1_ACC_CNTL_4_TOP },
+
+			{ GT64260_PCI_1_ACC_CNTL_5_BASE_HI,
+			  GT64260_PCI_1_ACC_CNTL_5_BASE_LO,
+			  GT64260_PCI_1_ACC_CNTL_5_TOP },
+
+			{ GT64260_PCI_1_ACC_CNTL_6_BASE_HI,
+			  GT64260_PCI_1_ACC_CNTL_6_BASE_LO,
+			  GT64260_PCI_1_ACC_CNTL_6_TOP },
+
+			{ GT64260_PCI_1_ACC_CNTL_7_BASE_HI,
+			  GT64260_PCI_1_ACC_CNTL_7_BASE_LO,
+			  GT64260_PCI_1_ACC_CNTL_7_TOP },
+		}
+	}; /* pci_acc_cntl_windows[][][] */
+	int	rc = -1;
+
+	if ((pci_bus < GT64260_PCI_BUSES) &&
+	    (window < GT64260_PCI_ACC_CNTL_WINDOWS)) {
+
+		rc = gt64260_set_64bit_window(
+			      base_addr_hi,
+			      base_addr_lo,
+			      size,
+			      features,
+			      pci_acc_cntl_windows[pci_bus][window][0],
+			      pci_acc_cntl_windows[pci_bus][window][1],
+			      pci_acc_cntl_windows[pci_bus][window][2]);
+	}
+
+	return rc;
+} /* gt64260_pci_acc_cntl_set_window() */
+
+int
+gt64260_pci_snoop_set_window(u32 pci_bus,
+			     u32 window,
+			     u32 base_addr_hi,
+			     u32 base_addr_lo,
+			     u32 size,
+			     u32 snoop_type)
+{
+	static u32
+	pci_snoop_windows[GT64260_PCI_BUSES][GT64260_PCI_SNOOP_WINDOWS][3] = {
+		{ /* PCI 0 */
+			{ GT64260_PCI_0_SNOOP_0_BASE_HI,
+			  GT64260_PCI_0_SNOOP_0_BASE_LO,
+			  GT64260_PCI_0_SNOOP_0_TOP },
+
+			{ GT64260_PCI_0_SNOOP_1_BASE_HI,
+			  GT64260_PCI_0_SNOOP_1_BASE_LO,
+			  GT64260_PCI_0_SNOOP_1_TOP },
+
+			{ GT64260_PCI_0_SNOOP_2_BASE_HI,
+			  GT64260_PCI_0_SNOOP_2_BASE_LO,
+			  GT64260_PCI_0_SNOOP_2_TOP },
+
+			{ GT64260_PCI_0_SNOOP_3_BASE_HI,
+			  GT64260_PCI_0_SNOOP_3_BASE_LO,
+			  GT64260_PCI_0_SNOOP_3_TOP },
+		},
+		{ /* PCI 1 */
+			{ GT64260_PCI_1_SNOOP_0_BASE_HI,
+			  GT64260_PCI_1_SNOOP_0_BASE_LO,
+			  GT64260_PCI_1_SNOOP_0_TOP },
+
+			{ GT64260_PCI_1_SNOOP_1_BASE_HI,
+			  GT64260_PCI_1_SNOOP_1_BASE_LO,
+			  GT64260_PCI_1_SNOOP_1_TOP },
+
+			{ GT64260_PCI_1_SNOOP_2_BASE_HI,
+			  GT64260_PCI_1_SNOOP_2_BASE_LO,
+			  GT64260_PCI_1_SNOOP_2_TOP },
+
+			{ GT64260_PCI_1_SNOOP_3_BASE_HI,
+			  GT64260_PCI_1_SNOOP_3_BASE_LO,
+			  GT64260_PCI_1_SNOOP_3_TOP },
+		},
+	}; /* pci_snoop_windows[][][] */
+	int	rc = -1;
+
+	if ((pci_bus < GT64260_PCI_BUSES) &&
+	    (window < GT64260_PCI_SNOOP_WINDOWS)) {
+
+		rc = gt64260_set_64bit_window(
+			      base_addr_hi,
+			      base_addr_lo,
+			      size,
+			      snoop_type,
+			      pci_snoop_windows[pci_bus][window][0],
+			      pci_snoop_windows[pci_bus][window][1],
+			      pci_snoop_windows[pci_bus][window][2]);
+	}
+
+	return rc;
+} /* gt64260_pci_snoop_set_window() */
+
+/*
+ *****************************************************************************
+ *
+ *	64260's Register Base Address Routines
+ *
+ *****************************************************************************
+ */
+
+/*
+ * gt64260_remap_bridge_regs()
+ *
+ * Move the bridge's register to the specified base address.
+ * Assume that there are no other windows overlapping this area and that
+ * all but the highest 3 nibbles are 0.
+ */
+int
+gt64260_set_base(u32 new_base)
+{
+	u32	val;
+	int	limit = 100000;
+	int	rc = 0;
+
+	val = gt_read(GT64260_INTERNAL_SPACE_DECODE);
+	val = (new_base >> 20) | (val & 0xffff0000);
+	gt_write(GT64260_INTERNAL_SPACE_DECODE, val);
+
+	iounmap((void *)gt64260_base);
+	gt64260_base = (u32)ioremap((new_base & 0xfff00000),
+				    GT64260_INTERNAL_SPACE_SIZE);
+
+	do { /* Wait for bridge to move its regs */
+		val = gt_read(GT64260_INTERNAL_SPACE_DECODE);
+	} while ((val != 0xffffffff) && (limit-- > 0));
+
+	if (limit <= 0) {
+		rc = -1;
+	}
+
+	return rc;
+} /* gt64260_remap_bridge_regs() */
+
+/*
+ * gt64260_get_base()
+ *
+ * Return the current virtual base address of the 64260's registers.
+ */
+int
+gt64260_get_base(u32 *base)
+{
+	*base = gt64260_base;
+	return 0;
+} /* gt64260_remap_bridge_regs() */
+
+/*
+ *****************************************************************************
+ *
+ *	Exclude PCI config space access to bridge itself
+ *
+ *****************************************************************************
+ */
+
+/*
+ * gt64260_exclude_pci_device()
+ *
+ * This routine causes the PCI subsystem to skip the PCI device in slot 0
+ * (which is the 64260 itself) unless explicitly allowed.
+ */
+int
+gt64260_pci_exclude_device(u8 bus, u8 devfn)
+{
+	struct pci_controller	*hose;
+
+	hose = pci_bus_to_hose(bus);
+
+	/* Skip slot 0 and 1 on both hoses */
+	if ((gt64260_pci_exclude_bridge == TRUE) &&
+	    (PCI_SLOT(devfn) == 0) &&
+	    (hose->first_busno == bus)) {
+
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+	else {
+		return PCIBIOS_SUCCESSFUL;
+	}
+} /* gt64260_pci_exclude_device() */
+
+#if defined(CONFIG_SERIAL_TEXT_DEBUG)
+
+/*
+ * gt64260_putc()
+ *
+ * Dump a character out the MPSC port for gt64260_mpsc_progress
+ * this assumes the baud rate has already been set up and the 
+ * MPSC initialized by the bootloader or firmware.
+ */
+
+static inline void
+gt_putc(char c){
+	mb();
+	gt_write(GT64260_MPSC_0_CHR_1, c);
+	mb();
+	gt_write(GT64260_MPSC_0_CHR_2, 0x200);
+	mb();
+
+	udelay(10000);
+}
+
+void
+puthex(unsigned long val){
+
+        int i;
+
+        for (i = 7;  i >= 0;  i--) {
+		gt_putc("0123456789ABCDEF"[(val>>28) & 0x0f]);
+		val <<= 4;
+	}
+	gt_putc('\r');
+	gt_putc('\n');	
+	
+}
+
+
+void
+gt64260_mpsc_progress(char *s, unsigned short hex){
+	/* spit stuff out the 64260 mpsc */
+	
+	volatile char	c;
+	while ((c = *s++) != 0){
+		gt_putc(c);
+		if ( c == '\n' ) gt_putc('\r');	
+	}
+	gt_putc('\n');
+	gt_putc('\r');
+
+	return;
+}
+
+#endif /* CONFIG_DEBUG_TEXT */
diff -Nru a/arch/ppc/syslib/gt64260_pic.c b/arch/ppc/syslib/gt64260_pic.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/gt64260_pic.c	Sun Nov 10 19:28:40 2002
@@ -0,0 +1,245 @@
+/*
+ * arch/ppc/kernel/gt64260_pic.c
+ * 
+ * Interrupt controller support for Galileo's GT64260.
+ *
+ * Author: Chris Zankel <chris@mvista.com>
+ * Modified by: Mark A. Greer <mgreer@mvista.com>
+ *
+ * Based on sources from Rabeeh Khoury / Galileo Technology
+ *
+ * Copyright 2001 MontaVista Software 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 file contains the specific functions to support the GT64260
+ * interrupt controller.
+ *
+ * The GT64260 has two main interrupt registers (high and low) that
+ * summarizes the interrupts generated by the units of the GT64260.
+ * Each bit is assigned to an interrupt number, where the low register
+ * are assigned from IRQ0 to IRQ31 and the high cause register
+ * from IRQ32 to IRQ63 
+ * The GPP (General Purpose Port) interrupts are assigned from IRQ64 (GPP0) 
+ * to IRQ95 (GPP31). 
+ * get_irq() returns the lowest interrupt number that is currently asserted.
+ *
+ * Note: 
+ *  - This driver does not initialize the GPP when used as an interrupt 
+ *    input.
+ */
+
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/gt64260.h>
+
+
+/* ========================== forward declaration ========================== */
+
+static void gt64260_unmask_irq(unsigned int);
+static void gt64260_mask_irq(unsigned int);
+
+/* ========================== local declarations =========================== */
+
+struct hw_interrupt_type gt64260_pic = {
+	" GT64260_PIC ",		/* typename */
+	NULL,				/* startup */
+	NULL,				/* shutdown */
+	gt64260_unmask_irq,		/* enable */
+	gt64260_mask_irq,		/* disable */
+	gt64260_mask_irq,		/* ack */
+	NULL,				/* end */
+	NULL				/* set_affinity */
+};
+
+u32 gt64260_irq_base = 0;      /* GT64260 handles the next 96 IRQs from here */
+
+/* gt64260_init_irq()
+ *
+ *  This function initializes the interrupt controller. It assigns
+ *  all interrupts from IRQ0 to IRQ95 to the gt64260 interrupt controller.
+ *
+ * Input Variable(s):
+ *  None.
+ *
+ * Outpu. Variable(s):
+ *  None.
+ *
+ * Returns:
+ *  void
+ *
+ * Note:
+ *  We register all GPP inputs as interrupt source, but disable them.
+ */
+
+__init void
+gt64260_init_irq(void)
+{
+	int i;
+
+	if ( ppc_md.progress ) ppc_md.progress("gt64260_init_irq: enter", 0x0);
+
+	ppc_cached_irq_mask[0] = 0;
+	ppc_cached_irq_mask[1] = 0x0f000000; /* Enable GPP intrs */
+	ppc_cached_irq_mask[2] = 0;
+
+	/* disable all interrupts and clear current interrupts */
+	gt_write(GT64260_GPP_INTR_MASK, ppc_cached_irq_mask[2]);
+	gt_write(GT64260_GPP_INTR_CAUSE,0);
+	gt_write(GT64260_IC_CPU_INTR_MASK_LO, ppc_cached_irq_mask[0]);
+	gt_write(GT64260_IC_CPU_INTR_MASK_HI, ppc_cached_irq_mask[1]);
+
+	/* use the gt64260 for all (possible) interrupt sources */
+	for( i = gt64260_irq_base;  i < (gt64260_irq_base + 96);  i++ )  {
+		irq_desc[i].handler = &gt64260_pic;
+	}
+
+	if ( ppc_md.progress ) ppc_md.progress("gt64260_init_irq: exit", 0x0);
+}
+
+
+/* gt64260_get_irq()
+ *
+ *  This function returns the lowest interrupt number of all interrupts that
+ *  are currently asserted. 
+ *
+ * Input Variable(s):
+ *  struct pt_regs*	not used
+ *
+ * Output Variable(s):
+ *  None.
+ *
+ * Returns:
+ *  int	<interrupt number> or -2 (bogus interrupt)
+ * 
+ */
+int
+gt64260_get_irq(struct pt_regs *regs)
+{
+	int irq;
+	int irq_gpp;
+
+	irq = gt_read(GT64260_IC_MAIN_CAUSE_LO);
+	irq = __ilog2((irq & 0x3dfffffe) & ppc_cached_irq_mask[0]);
+
+	if (irq == -1) {
+		irq = gt_read(GT64260_IC_MAIN_CAUSE_HI);
+		irq = __ilog2((irq & 0x0f000db7) & ppc_cached_irq_mask[1]);
+
+		if (irq == -1) {
+			irq = -2;   /* bogus interrupt, should never happen */
+		} else {
+			if (irq >= 24) {
+				irq_gpp = gt_read(GT64260_GPP_INTR_CAUSE);
+				irq_gpp = __ilog2(irq_gpp &
+						  ppc_cached_irq_mask[2]);
+
+				if (irq_gpp == -1) {
+					irq = -2;
+				} else {
+					irq = irq_gpp + 64;
+					gt_write(GT64260_GPP_INTR_CAUSE, ~(1<<(irq-64)));
+				}
+			} else {
+				irq += 32;
+			}
+		}
+	}
+
+	if( irq < 0 )  {
+		return( irq );
+	} else  {
+		return( gt64260_irq_base + irq );
+	}
+}
+
+/* gt64260_unmask_irq()
+ *
+ *  This function enables an interrupt.
+ *
+ * Input Variable(s):
+ *  unsigned int	interrupt number (IRQ0...IRQ95).
+ *
+ * Output Variable(s):
+ *  None.
+ *
+ * Returns:
+ *  void
+ */
+
+static void
+gt64260_unmask_irq(unsigned int irq)
+{
+	irq -= gt64260_irq_base;
+	if (irq > 31) {
+		if (irq > 63) {
+			/* unmask GPP irq */
+			gt_write(GT64260_GPP_INTR_MASK,  
+				     ppc_cached_irq_mask[2] |= (1<<(irq-64)));
+		} else {
+			/* mask high interrupt register */
+			gt_write(GT64260_IC_CPU_INTR_MASK_HI, 
+				     ppc_cached_irq_mask[1] |= (1<<(irq-32)));
+		}
+	} else {
+		/* mask low interrupt register */
+		gt_write(GT64260_IC_CPU_INTR_MASK_LO, 
+			     ppc_cached_irq_mask[0] |= (1<<irq));
+	}
+}
+
+
+/* gt64260_mask_irq()
+ *
+ *  This funktion disables the requested interrupt.
+ *
+ * Input Variable(s):
+ *  unsigned int	interrupt number (IRQ0...IRQ95).
+ *
+ * Output Variable(s):
+ *  None.
+ *
+ * Returns:
+ *  void
+ */
+
+static void
+gt64260_mask_irq(unsigned int irq)
+{
+	irq -= gt64260_irq_base;
+	if (irq > 31) {
+		if (irq > 63) {
+			/* mask GPP irq */
+			gt_write(GT64260_GPP_INTR_MASK,  
+				     ppc_cached_irq_mask[2] &= ~(1<<(irq-64)));
+		} else {
+			/* mask high interrupt register */
+			gt_write(GT64260_IC_CPU_INTR_MASK_HI, 
+				     ppc_cached_irq_mask[1] &= ~(1<<(irq-32)));
+		}
+	} else {
+		/* mask low interrupt register */
+		gt_write(GT64260_IC_CPU_INTR_MASK_LO, 
+			     ppc_cached_irq_mask[0] &= ~(1<<irq));
+	}
+
+	if (irq == 36) { /* Seems necessary for SDMA interrupts */
+		udelay(1);
+	}
+}
+
diff -Nru a/arch/ppc/syslib/harrier.c b/arch/ppc/syslib/harrier.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/harrier.c	Sun Nov 10 19:28:39 2002
@@ -0,0 +1,214 @@
+/*
+ * arch/ppc/kernel/harrier.c
+ * 
+ * Motorola MCG Harrier northbridge/memory controller support
+ *
+ * Author: Dale Farnsworth
+ *         dale.farnsworth@mvista.com
+ *
+ * Copyright 2001 MontaVista Software 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.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pci.h>
+#include <asm/pci-bridge.h>
+#include <asm/open_pic.h>
+#include <asm/harrier.h>
+
+/*
+ * Initialize the Motorola MCG Harrier host bridge.
+ *
+ * This means setting up the PPC bus to PCI memory and I/O space mappings,
+ * setting the PCI memory space address of the MPIC (mapped straight
+ * through), and ioremap'ing the mpic registers.
+ * 'OpenPIC_Addr' will be set correctly by this routine.
+ * This routine will not change the PCI_CONFIG_ADDR or PCI_CONFIG_DATA
+ * addresses and assumes that the mapping of PCI memory space back to system
+ * memory is set up correctly by PPCBug.
+ */
+int __init
+harrier_init(struct pci_controller *hose,
+	     uint ppc_reg_base,
+	     ulong processor_pci_mem_start,
+	     ulong processor_pci_mem_end,
+	     ulong processor_pci_io_start,
+	     ulong processor_pci_io_end,
+	     ulong processor_mpic_base)
+{
+	uint		addr, offset;
+
+	/*
+	 * Some sanity checks...
+	 */
+	if (((processor_pci_mem_start&0xffff0000) != processor_pci_mem_start) ||
+	    ((processor_pci_io_start &0xffff0000) != processor_pci_io_start)) {
+		printk("harrier_init: %s\n",
+			"PPC to PCI mappings must start on 64 KB boundaries");
+		return -1;
+	}
+
+	if (((processor_pci_mem_end  &0x0000ffff) != 0x0000ffff) ||
+	    ((processor_pci_io_end   &0x0000ffff) != 0x0000ffff)) {
+		printk("harrier_init: PPC to PCI mappings %s\n",
+			"must end just before a 64 KB boundaries");
+		return -1;
+	}
+
+	if (((processor_pci_mem_end - processor_pci_mem_start) !=
+	     (hose->mem_space.end - hose->mem_space.start)) ||
+	    ((processor_pci_io_end - processor_pci_io_start) !=
+	     (hose->io_space.end - hose->io_space.start))) {
+		printk("harrier_init: %s\n",
+			"PPC and PCI memory or I/O space sizes don't match");
+		return -1;
+	}
+
+	if ((processor_mpic_base & 0xfffc0000) != processor_mpic_base) {
+		printk("harrier_init: %s\n",
+			"MPIC address must start on 256 KB boundary");
+		return -1;
+	}
+
+	if ((pci_dram_offset & 0xffff0000) != pci_dram_offset) {
+		printk("harrier_init: %s\n",
+			"pci_dram_offset must be multiple of 64 KB");
+		return -1;
+	}
+
+	/*
+	 * Program the OTAD/OTOF registers to set up the PCI Mem & I/O
+	 * space mappings.  These are the mappings going from the processor to
+	 * the PCI bus.
+	 *
+	 * Note: Don't need to 'AND' start/end addresses with 0xffff0000
+	 *	 because sanity check above ensures that they are properly
+	 *	 aligned.
+	 */
+
+	/* Set up PPC->PCI Mem mapping */
+	addr = processor_pci_mem_start | (processor_pci_mem_end >> 16);
+	offset = (hose->mem_space.start - processor_pci_mem_start) | 0x92;
+	out_be32((uint *)(ppc_reg_base + HARRIER_OTAD0_OFF), addr);
+	out_be32((uint *)(ppc_reg_base + HARRIER_OTOF0_OFF), offset);
+
+	/* Set up PPC->PCI I/O mapping -- Contiguous I/O space */
+	addr = processor_pci_io_start | (processor_pci_io_end >> 16);
+	offset = (hose->io_space.start - processor_pci_io_start) | 0x80;
+	out_be32((uint *)(ppc_reg_base + HARRIER_OTAD1_OFF), addr);
+	out_be32((uint *)(ppc_reg_base + HARRIER_OTOF1_OFF), offset);
+
+	/* Enable MPIC */
+	OpenPIC_Addr = (void *)processor_mpic_base;
+	addr = (processor_mpic_base >> 16) | 1;
+	out_be16((ushort *)(ppc_reg_base + HARRIER_MBAR_OFF), addr);
+	out_8((u_char *)(ppc_reg_base + HARRIER_MPIC_CSR_OFF),
+		HARRIER_MPIC_OPI_ENABLE);
+
+	return 0;
+}
+
+/*
+ * Find the amount of RAM present.
+ * This assumes that PPCBug has initialized the memory controller (SMC)
+ * on the Harrier correctly (i.e., it does no sanity checking).
+ * It also assumes that the memory base registers are set to configure the
+ * memory as contigous starting with "RAM A BASE", "RAM B BASE", etc.
+ * however, RAM base registers can be skipped (e.g. A, B, C are set,
+ * D is skipped but E is set is okay).
+ */
+#define	MB	(1024*1024UL)
+
+static uint harrier_size_table[] __initdata = {
+	   0 * MB, /* 0 ==>    0 MB */
+	  32 * MB, /* 1 ==>   32 MB */
+	  64 * MB, /* 2 ==>   64 MB */
+	  64 * MB, /* 3 ==>   64 MB */
+	 128 * MB, /* 4 ==>  128 MB */
+	 128 * MB, /* 5 ==>  128 MB */
+	 128 * MB, /* 6 ==>  128 MB */
+	 256 * MB, /* 7 ==>  256 MB */
+	 256 * MB, /* 8 ==>  256 MB */
+	 256 * MB, /* 9 ==>  256 MB */
+	 512 * MB, /* a ==>  512 MB */
+	 512 * MB, /* b ==>  512 MB */
+	 512 * MB, /* c ==>  512 MB */
+	1024 * MB, /* d ==> 1024 MB */
+	1024 * MB, /* e ==> 1024 MB */
+	2048 * MB, /* f ==> 2048 MB */
+};
+
+/*
+ * *** WARNING: You MUST have a BAT set up to map in the XCSR regs ***
+ *
+ * Read the memory controller's registers to determine the amount of system
+ * memory.  Assumes that the memory controller registers are already mapped
+ * into virtual memory--too early to use ioremap().
+ */
+unsigned long __init
+harrier_get_mem_size(uint xcsr_base)
+{
+	ulong		last_addr;
+	int		i;
+	uint		vend_dev_id;
+	uint		*size_table;
+	uint		val;
+	uint		*csrp;
+	uint		size;
+	int		size_table_entries;
+
+	vend_dev_id = in_be32((uint *)xcsr_base + PCI_VENDOR_ID);
+
+	if (((vend_dev_id & 0xffff0000) >> 16) != PCI_VENDOR_ID_MOTOROLA) {
+		printk("harrier_get_mem_size: %s (0x%x)\n",
+			"Not a Motorola Memory Controller", vend_dev_id);
+		return 0;
+	}
+
+	vend_dev_id &= 0x0000ffff;
+
+	if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_HARRIER) {
+		size_table = harrier_size_table;
+		size_table_entries = sizeof(harrier_size_table) /
+				     sizeof(harrier_size_table[0]);
+	}
+	else {
+		printk("harrier_get_mem_size: %s (0x%x)\n",
+			"Not a Harrier", vend_dev_id);
+		return 0;
+	}
+
+	last_addr = 0;
+
+	csrp = (uint *)(xcsr_base + HARRIER_SDBA_OFF);
+	for (i=0; i<8; i++) {
+		val = in_be32(csrp++);
+
+		if (val & 0x100) {	/* If enabled */
+			size = val >> HARRIER_SDB_SIZE_SHIFT;
+			size &= HARRIER_SDB_SIZE_MASK;
+			if (size >= size_table_entries) {
+				break;	/* Register not set correctly */
+			}
+			size = size_table[size];
+			
+			val &= ~(size-1);
+			val += size;
+
+			if (val > last_addr) {
+				last_addr = val;
+			}
+		}
+	}
+
+	return last_addr;
+}
diff -Nru a/arch/ppc/syslib/i8259.c b/arch/ppc/syslib/i8259.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/i8259.c	Sun Nov 10 19:28:39 2002
@@ -0,0 +1,199 @@
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/io.h>
+#include <asm/i8259.h>
+
+static volatile unsigned char *pci_intack; /* RO, gives us the irq vector */
+
+unsigned char cached_8259[2] = { 0xff, 0xff };
+#define cached_A1 (cached_8259[0])
+#define cached_21 (cached_8259[1])
+
+static spinlock_t i8259_lock = SPIN_LOCK_UNLOCKED;
+
+int i8259_pic_irq_offset;
+
+/*
+ * Acknowledge the IRQ using either the PCI host bridge's interrupt
+ * acknowledge feature or poll.  How i8259_init() is called determines
+ * which is called.  It should be noted that polling is broken on some
+ * IBM and Motorola PReP boxes so we must use the int-ack feature on them.
+ */
+int
+i8259_irq(struct pt_regs *regs)
+{
+	int irq;
+
+	spin_lock(&i8259_lock);
+
+	/* Either int-ack or poll for the IRQ */
+	if (pci_intack)
+		irq = *pci_intack;
+	else {
+		/* Perform an interrupt acknowledge cycle on controller 1. */
+		outb(0x0C, 0x20);		/* prepare for poll */
+		irq = inb(0x20) & 7;
+		if (irq == 2 ) {
+			/*
+			 * Interrupt is cascaded so perform interrupt
+			 * acknowledge on controller 2.
+			 */
+			outb(0x0C, 0xA0);	/* prepare for poll */
+			irq = (inb(0xA0) & 7) + 8;
+		}
+	}
+
+	if (irq == 7) {
+		/*
+		 * This may be a spurious interrupt.
+		 *
+		 * Read the interrupt status register (ISR). If the most
+		 * significant bit is not set then there is no valid
+		 * interrupt.
+		 */
+		if (!pci_intack)
+			outb(0x0B, 0x20);	/* ISR register */
+		if(~inb(0x20) & 0x80)
+			irq = -1;
+	}
+
+	spin_unlock(&i8259_lock);
+	return irq;
+}
+
+static void i8259_mask_and_ack_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259_lock, flags);
+	if ( irq_nr >= i8259_pic_irq_offset )
+		irq_nr -= i8259_pic_irq_offset;
+
+	if (irq_nr > 7) {
+		cached_A1 |= 1 << (irq_nr-8);
+		inb(0xA1); /* DUMMY */
+		outb(cached_A1,0xA1);
+		outb(0x20,0xA0); /* Non-specific EOI */
+		outb(0x20,0x20); /* Non-specific EOI to cascade */
+	} else {
+		cached_21 |= 1 << irq_nr;
+		inb(0x21); /* DUMMY */
+		outb(cached_21,0x21);
+		outb(0x20,0x20); /* Non-specific EOI */
+	}
+	spin_unlock_irqrestore(&i8259_lock, flags);
+}
+
+static void i8259_set_irq_mask(int irq_nr)
+{
+	outb(cached_A1,0xA1);
+	outb(cached_21,0x21);
+}
+ 
+static void i8259_mask_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259_lock, flags);
+	if ( irq_nr >= i8259_pic_irq_offset )
+		irq_nr -= i8259_pic_irq_offset;
+	if ( irq_nr < 8 )
+		cached_21 |= 1 << irq_nr;
+	else
+		cached_A1 |= 1 << (irq_nr-8);
+	i8259_set_irq_mask(irq_nr);
+	spin_unlock_irqrestore(&i8259_lock, flags);
+}
+
+static void i8259_unmask_irq(unsigned int irq_nr)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259_lock, flags);
+	if ( irq_nr >= i8259_pic_irq_offset )
+		irq_nr -= i8259_pic_irq_offset;
+	if ( irq_nr < 8 )
+		cached_21 &= ~(1 << irq_nr);
+	else
+		cached_A1 &= ~(1 << (irq_nr-8));
+	i8259_set_irq_mask(irq_nr);
+	spin_unlock_irqrestore(&i8259_lock, flags);
+}
+
+static void i8259_end_irq(unsigned int irq)
+{
+	if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS))
+	    && irq_desc[irq].action)
+		i8259_unmask_irq(irq);
+}
+
+struct hw_interrupt_type i8259_pic = {
+	" i8259    ",
+	NULL,
+	NULL,
+	i8259_unmask_irq,
+	i8259_mask_irq,
+	i8259_mask_and_ack_irq,
+	i8259_end_irq,
+	NULL
+};
+
+static struct resource pic1_iores = {
+	"8259 (master)", 0x20, 0x21, IORESOURCE_BUSY
+};
+
+static struct resource pic2_iores = {
+	"8259 (slave)", 0xa0, 0xa1, IORESOURCE_BUSY
+};
+
+static struct resource pic_edgectrl_iores = {
+	"8259 edge control", 0x4d0, 0x4d1, IORESOURCE_BUSY
+};
+
+/*
+ * i8259_init()
+ * intack_addr - PCI interrupt acknowledge (real) address which will return
+ *               the active irq from the 8259
+ */
+void __init
+i8259_init(long intack_addr)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8259_lock, flags);
+	/* init master interrupt controller */
+	outb(0x11, 0x20); /* Start init sequence */
+	outb(0x00, 0x21); /* Vector base */
+	outb(0x04, 0x21); /* edge tiggered, Cascade (slave) on IRQ2 */
+	outb(0x01, 0x21); /* Select 8086 mode */
+
+	/* init slave interrupt controller */
+	outb(0x11, 0xA0); /* Start init sequence */
+	outb(0x08, 0xA1); /* Vector base */
+	outb(0x02, 0xA1); /* edge triggered, Cascade (slave) on IRQ2 */
+	outb(0x01, 0xA1); /* Select 8086 mode */
+
+	/* always read ISR */
+	outb(0x0B, 0x20);
+	outb(0x0B, 0xA0);
+
+	/* Mask all interrupts */
+	outb(cached_A1, 0xA1);
+	outb(cached_21, 0x21);
+
+	spin_unlock_irqrestore(&i8259_lock, flags);
+
+	/* reserve our resources */
+	request_irq( i8259_pic_irq_offset + 2, no_action, SA_INTERRUPT,
+				"82c59 secondary cascade", NULL );
+	request_resource(&ioport_resource, &pic1_iores);
+	request_resource(&ioport_resource, &pic2_iores);
+	request_resource(&ioport_resource, &pic_edgectrl_iores);
+
+	if (intack_addr != 0)
+		pci_intack = ioremap(intack_addr, 1);
+}
diff -Nru a/arch/ppc/syslib/indirect_pci.c b/arch/ppc/syslib/indirect_pci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/indirect_pci.c	Sun Nov 10 19:28:37 2002
@@ -0,0 +1,118 @@
+/*
+ * Support for indirect PCI bridges.
+ *
+ * Copyright (C) 1998 Gabriel Paubert.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/bootmem.h>
+
+#include <asm/io.h>
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#include <asm/machdep.h>
+
+static int
+indirect_read_config(struct pci_bus *bus, unsigned int devfn, int offset,
+		     int len, u32 *val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	volatile unsigned char *cfg_data;
+	u8 cfg_type = 0;
+
+	if (ppc_md.pci_exclude_device)
+		if (ppc_md.pci_exclude_device(bus->number, devfn))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+	
+	if (hose->set_cfg_type)
+		if (bus->number != hose->first_busno)
+			cfg_type = 1;
+
+	out_be32(hose->cfg_addr,
+		 (((offset & 0xfc) | cfg_type) << 24) | (devfn << 16)
+		 | ((bus->number - hose->bus_offset) << 8) | 0x80);
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	cfg_data = hose->cfg_data + (offset & 3);
+	switch (len) {
+	case 1:
+		*val = in_8((u8 *)cfg_data);
+		break;
+	case 2:
+		*val = in_le16((u16 *)cfg_data);
+		break;
+	default:
+		*val = in_le32((u32 *)cfg_data);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int
+indirect_write_config(struct pci_bus *bus, unsigned int devfn, int offset,
+		      int len, u32 val)
+{
+	struct pci_controller *hose = bus->sysdata;
+	volatile unsigned char *cfg_data;
+	u8 cfg_type = 0;
+
+	if (ppc_md.pci_exclude_device)
+		if (ppc_md.pci_exclude_device(bus->number, devfn))
+			return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (hose->set_cfg_type)
+		if (bus->number != hose->first_busno)
+			cfg_type = 1;
+
+	out_be32(hose->cfg_addr,
+		 (((offset & 0xfc) | cfg_type) << 24) | (devfn << 16)
+		 | ((bus->number - hose->bus_offset) << 8) | 0x80);
+	/*
+	 * Note: the caller has already checked that offset is
+	 * suitably aligned and that len is 1, 2 or 4.
+	 */
+	cfg_data = hose->cfg_data + (offset & 3);
+	switch (len) {
+	case 1:
+		out_8((u8 *)cfg_data, val);
+		break;
+	case 2:
+		out_le16((u16 *)cfg_data, val);
+		break;
+	default:
+		out_le32((u32 *)cfg_data, val);
+		break;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static struct pci_ops indirect_pci_ops =
+{
+	indirect_read_config,
+	indirect_write_config
+};
+
+void __init
+setup_indirect_pci(struct pci_controller* hose, u32 cfg_addr, u32 cfg_data)
+{
+	unsigned long base = cfg_addr & PAGE_MASK;
+	char *mbase;
+
+	mbase = ioremap(base, PAGE_SIZE);
+	hose->cfg_addr = (unsigned int *)(mbase + (cfg_addr & ~PAGE_MASK));
+	if ((cfg_data & PAGE_MASK) != base)
+		mbase = ioremap(cfg_data & PAGE_MASK, PAGE_SIZE);
+	hose->cfg_data = (unsigned char *)(mbase + (cfg_data & ~PAGE_MASK));
+	hose->ops = &indirect_pci_ops;
+}
diff -Nru a/arch/ppc/syslib/m8260_setup.c b/arch/ppc/syslib/m8260_setup.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/m8260_setup.c	Sun Nov 10 19:28:39 2002
@@ -0,0 +1,275 @@
+/*
+ *  arch/ppc/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
+ *  Further modified for generic 8xx and 8260 by Dan.
+ */
+
+/*
+ * 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/ide.h>
+#include <linux/seq_file.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/ide.h>
+#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);
+static unsigned long m8260_get_rtc_time(void);
+static void m8260_calibrate_decr(void);
+
+unsigned char __res[sizeof(bd_t)];
+
+extern void m8260_cpm_reset(void);
+
+static void __init
+m8260_setup_arch(void)
+{
+	/* Reset the Communication Processor Module.
+	*/
+	m8260_cpm_reset();
+}
+
+static void
+abort(void)
+{
+#ifdef CONFIG_XMON
+	extern void xmon(void *);
+	xmon(0);
+#endif
+	machine_restart(NULL);
+}
+
+/* The decrementer counts at the system (internal) clock frequency
+ * divided by four.
+ */
+static void __init
+m8260_calibrate_decr(void)
+{
+	bd_t	*binfo = (bd_t *)__res;
+	int freq, divisor;
+
+	freq = binfo->bi_busfreq;
+        divisor = 4;
+        tb_ticks_per_jiffy = freq / HZ / divisor;
+	tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
+}
+
+/* The 8260 has an internal 1-second timer update register that
+ * we should use for this purpose.
+ */
+static uint rtc_time;
+
+static static int
+m8260_set_rtc_time(unsigned long time)
+{
+#ifdef CONFIG_TQM8260
+	((immap_t *)IMAP_ADDR)->im_sit.sit_tmcnt = time;
+	((immap_t *)IMAP_ADDR)->im_sit.sit_tmcntsc = 0x3;
+#else
+	rtc_time = time;
+#endif
+	return(0);
+}
+
+static unsigned long
+m8260_get_rtc_time(void)
+{
+#ifdef CONFIG_TQM8260
+	return ((immap_t *)IMAP_ADDR)->im_sit.sit_tmcnt;
+#else
+	/* Get time from the RTC.
+	*/
+	return((unsigned long)rtc_time);
+#endif
+}
+
+static void
+m8260_restart(char *cmd)
+{
+	extern void m8260_gorom(bd_t *bi, uint addr);
+	uint	startaddr;
+
+	/* Most boot roms have a warmstart as the second instruction
+	 * of the reset vector.  If that doesn't work for you, change this
+	 * or the reboot program to send a proper address.
+	 */
+#ifdef CONFIG_TQM8260
+	startaddr = 0x40000104;
+#else
+	startaddr = 0xff000104;
+#endif
+	if (cmd != NULL) {
+		if (!strncmp(cmd, "startaddr=", 10))
+			startaddr = simple_strtoul(&cmd[10], NULL, 0);
+	}
+
+	m8260_gorom((unsigned int)__pa(__res), startaddr);
+}
+
+static void
+m8260_power_off(void)
+{
+   m8260_restart(NULL);
+}
+
+static void
+m8260_halt(void)
+{
+   m8260_restart(NULL);
+}
+
+
+static int
+m8260_show_percpuinfo(struct seq_file *m, int i)
+{
+	bd_t	*bp;
+
+	bp = (bd_t *)__res;
+
+	seq_printf(m, "core clock\t: %d MHz\n"
+		   "CPM  clock\t: %d MHz\n"
+		   "bus  clock\t: %d MHz\n",
+		   bp->bi_intfreq / 1000000,
+		   bp->bi_cpmfreq / 1000000,
+		   bp->bi_busfreq / 1000000);
+	return 0;
+}
+
+/* Initialize the internal interrupt controller.  The number of
+ * interrupts supported can vary with the processor type, and the
+ * 8260 family can have up to 64.
+ * External interrupts can be either edge or level triggered, and
+ * need to be initialized by the appropriate driver.
+ */
+static void __init
+m8260_init_IRQ(void)
+{
+	int i;
+	void cpm_interrupt_init(void);
+
+#if 0
+        ppc8260_pic.irq_offset = 0;
+#endif
+        for ( i = 0 ; i < NR_SIU_INTS ; i++ )
+                irq_desc[i].handler = &ppc8260_pic;
+
+	/* Initialize the default interrupt mapping priorities,
+	 * in case the boot rom changed something on us.
+	 */
+	immr->im_intctl.ic_sicr = 0;
+	immr->im_intctl.ic_siprr = 0x05309770;
+	immr->im_intctl.ic_scprrh = 0x05309770;
+	immr->im_intctl.ic_scprrl = 0x05309770;
+
+}
+
+/*
+ * Same hack as 8xx
+ */
+static unsigned long __init
+m8260_find_end_of_memory(void)
+{
+	bd_t	*binfo;
+	extern unsigned char __res[];
+
+	binfo = (bd_t *)__res;
+
+	return binfo->bi_memsize;
+}
+
+/* Map the IMMR, plus anything else we can cover
+ * in that upper space according to the memory controller
+ * chip select mapping.  Grab another bunch of space
+ * below that for stuff we can't cover in the upper.
+ */
+static void __init
+m8260_map_io(void)
+{
+	io_block_mapping(0xf0000000, 0xf0000000, 0x10000000, _PAGE_IO);
+	io_block_mapping(0xe0000000, 0xe0000000, 0x10000000, _PAGE_IO);
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+
+	if ( r3 )
+		memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r4 ) {
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+	/* take care of cmd line */
+	if ( r6 ) {
+		*(char *)(r7+KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6+KERNELBASE));
+	}
+
+	ppc_md.setup_arch		= m8260_setup_arch;
+	ppc_md.show_percpuinfo		= m8260_show_percpuinfo;
+	ppc_md.irq_cannonicalize	= NULL;
+	ppc_md.init_IRQ			= m8260_init_IRQ;
+	ppc_md.get_irq			= m8260_get_irq;
+	ppc_md.init			= NULL;
+
+	ppc_md.restart			= m8260_restart;
+	ppc_md.power_off		= m8260_power_off;
+	ppc_md.halt			= m8260_halt;
+
+	ppc_md.time_init		= NULL;
+	ppc_md.set_rtc_time		= m8260_set_rtc_time;
+	ppc_md.get_rtc_time		= m8260_get_rtc_time;
+	ppc_md.calibrate_decr		= m8260_calibrate_decr;
+
+	ppc_md.find_end_of_memory	= m8260_find_end_of_memory;
+	ppc_md.setup_io_mappings	= m8260_map_io;
+}
+
+/* Mainly for ksyms.
+*/
+int
+request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+		       unsigned long flag, const char *naem, void *dev)
+{
+	panic("request IRQ\n");
+}
diff -Nru a/arch/ppc/syslib/m8xx_setup.c b/arch/ppc/syslib/m8xx_setup.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/m8xx_setup.c	Sun Nov 10 19:28:39 2002
@@ -0,0 +1,400 @@
+/*
+ *  arch/ppc/kernel/setup.c
+ *
+ *  Copyright (C) 1995  Linus Torvalds
+ *  Adapted from 'alpha' version by Gary Thomas
+ *  Modified by Cort Dougan (cort@cs.nmt.edu)
+ *  Modified for MBX using prep/chrp/pmac functions by Dan (dmalek@jlc.net)
+ *  Further modified for generic 8xx by Dan.
+ */
+
+/*
+ * 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/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/root_dev.h>
+
+#include <asm/mmu.h>
+#include <asm/processor.h>
+#include <asm/residual.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#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);
+static unsigned long m8xx_get_rtc_time(void);
+void m8xx_calibrate_decr(void);
+
+unsigned char __res[sizeof(bd_t)];
+
+extern void m8xx_ide_init(void);
+
+extern unsigned long find_available_memory(void);
+extern void m8xx_cpm_reset(uint);
+extern void rpxfb_alloc_pages(void);
+
+void __init
+m8xx_setup_arch(void)
+{
+	int	cpm_page;
+
+	cpm_page = (int) alloc_bootmem_pages(PAGE_SIZE);
+
+	/* Reset the Communication Processor Module.
+	*/
+	m8xx_cpm_reset(cpm_page);
+
+#ifdef CONFIG_FB_RPX
+	rpxfb_alloc_pages();
+#endif
+
+#ifdef notdef
+	ROOT_DEV = Root_HDA1; /* hda1 */
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+#if 0
+	ROOT_DEV = Root_FD0; /* floppy */
+	rd_prompt = 1;
+	rd_doload = 1;
+	rd_image_start = 0;
+#endif
+#if 0	/* XXX this may need to be updated for the new bootmem stuff,
+	   or possibly just deleted (see set_phys_avail() in init.c).
+	   - paulus. */
+	/* initrd_start and size are setup by boot/head.S and kernel/head.S */
+	if ( initrd_start )
+	{
+		if (initrd_end > *memory_end_p)
+		{
+			printk("initrd extends beyond end of memory "
+			       "(0x%08lx > 0x%08lx)\ndisabling initrd\n",
+			       initrd_end,*memory_end_p);
+			initrd_start = 0;
+		}
+	}
+#endif
+#endif
+}
+
+void
+abort(void)
+{
+#ifdef CONFIG_XMON
+	xmon(0);
+#endif
+	machine_restart(NULL);
+
+	/* not reached */
+	for (;;);
+}
+
+/* A place holder for time base interrupts, if they are ever enabled. */
+void timebase_interrupt(int irq, void * dev, struct pt_regs * regs)
+{
+	printk ("timebase_interrupt()\n");
+}
+
+/* The decrementer counts at the system (internal) clock frequency divided by
+ * sixteen, or external oscillator divided by four.  We force the processor
+ * to use system clock divided by sixteen.
+ */
+void __init m8xx_calibrate_decr(void)
+{
+	bd_t	*binfo = (bd_t *)__res;
+	int freq, fp, divisor;
+
+	/* Unlock the SCCR. */
+	((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = ~KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_clkrstk.cark_sccrk = KAPWR_KEY;
+
+	/* Force all 8xx processors to use divide by 16 processor clock. */
+	((volatile immap_t *)IMAP_ADDR)->im_clkrst.car_sccr |= 0x02000000;
+
+	/* Processor frequency is MHz.
+	 * The value 'fp' is the number of decrementer ticks per second.
+	 */
+	fp = binfo->bi_intfreq / 16;
+	freq = fp*60;	/* try to make freq/1e6 an integer */
+        divisor = 60;
+        printk("Decrementer Frequency = %d/%d\n", freq, divisor);
+        tb_ticks_per_jiffy = freq / HZ / divisor;
+	tb_to_us = mulhwu_scale_factor(freq / divisor, 1000000);
+
+	/* Perform some more timer/timebase initialization.  This used
+	 * to be done elsewhere, but other changes caused it to get
+	 * called more than once....that is a bad thing.
+	 *
+	 * First, unlock all of the registers we are going to modify.
+	 * To protect them from corruption during power down, registers
+	 * that are maintained by keep alive power are "locked".  To
+	 * modify these registers we have to write the key value to
+	 * the key location associated with the register.
+	 * Some boards power up with these unlocked, while others
+	 * are locked.  Writing anything (including the unlock code?)
+	 * to the unlocked registers will lock them again.  So, here
+	 * we guarantee the registers are locked, then we unlock them
+	 * for our use.
+	 */
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk = ~KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck = ~KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk    = ~KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbscrk =  KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtcsck =  KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_tbk    =  KAPWR_KEY;
+
+	/* Disable the RTC one second and alarm interrupts. */
+	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc &=
+						~(RTCSC_SIE | RTCSC_ALE);
+	/* Enable the RTC */
+	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtcsc |=
+						(RTCSC_RTF | RTCSC_RTE);
+
+	/* Enabling the decrementer also enables the timebase interrupts
+	 * (or from the other point of view, to get decrementer interrupts
+	 * we have to enable the timebase).  The decrementer interrupt
+	 * is wired into the vector table, nothing to do here for that.
+	 */
+	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_tbscr =
+				((mk_int_int_mask(DEC_INTERRUPT) << 8) |
+					 (TBSCR_TBF | TBSCR_TBE));
+
+	if (request_8xxirq(DEC_INTERRUPT, timebase_interrupt, 0, "tbint", NULL) != 0)
+		panic("Could not allocate timer IRQ!");
+}
+
+/* The RTC on the MPC8xx is an internal register.
+ * We want to protect this during power down, so we need to unlock,
+ * modify, and re-lock.
+ */
+static int
+m8xx_set_rtc_time(unsigned long time)
+{
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = KAPWR_KEY;
+	((volatile immap_t *)IMAP_ADDR)->im_sit.sit_rtc = time;
+	((volatile immap_t *)IMAP_ADDR)->im_sitk.sitk_rtck = ~KAPWR_KEY;
+	return(0);
+}
+
+static unsigned long
+m8xx_get_rtc_time(void)
+{
+	/* Get time from the RTC. */
+	return((unsigned long)(((immap_t *)IMAP_ADDR)->im_sit.sit_rtc));
+}
+
+static void
+m8xx_restart(char *cmd)
+{
+	__volatile__ unsigned char dummy;
+	uint	msr;
+
+	cli();
+	((immap_t *)IMAP_ADDR)->im_clkrst.car_plprcr |= 0x00000080;
+
+	/* Clear the ME bit in MSR to cause checkstop on machine check
+	*/
+	__asm__("mfmsr %0" : "=r" (msr) );
+	msr &= ~0x1000;
+	__asm__("mtmsr %0" : : "r" (msr) );
+
+	dummy = ((immap_t *)IMAP_ADDR)->im_clkrst.res[0];
+	printk("Restart failed\n");
+	while(1);
+}
+
+static void
+m8xx_power_off(void)
+{
+   m8xx_restart(NULL);
+}
+
+static void
+m8xx_halt(void)
+{
+   m8xx_restart(NULL);
+}
+
+
+static int
+m8xx_show_percpuinfo(struct seq_file *m, int i)
+{
+	bd_t	*bp;
+
+	bp = (bd_t *)__res;
+
+	seq_printf(m, "clock\t\t: %dMHz\n"
+		   "bus clock\t: %dMHz\n",
+		   bp->bi_intfreq / 1000000,
+		   bp->bi_busfreq / 1000000);
+
+	return 0;
+}
+
+/* Initialize the internal interrupt controller.  The number of
+ * interrupts supported can vary with the processor type, and the
+ * 82xx family can have up to 64.
+ * External interrupts can be either edge or level triggered, and
+ * need to be initialized by the appropriate driver.
+ */
+static void __init
+m8xx_init_IRQ(void)
+{
+	int i;
+	void cpm_interrupt_init(void);
+
+        for ( i = 0 ; i < NR_SIU_INTS ; i++ )
+                irq_desc[i].handler = &ppc8xx_pic;
+
+	/* We could probably incorporate the CPM into the multilevel
+	 * interrupt structure.
+	 */
+	cpm_interrupt_init();
+        unmask_irq(CPM_INTERRUPT);
+
+#if defined(CONFIG_PCI)
+        for ( i = NR_SIU_INTS ; i < (NR_SIU_INTS + NR_8259_INTS) ; i++ )
+                irq_desc[i].handler = &i8259_pic;
+        i8259_pic.irq_offset = NR_SIU_INTS;
+        i8259_init();
+        request_8xxirq(ISA_BRIDGE_INT, mbx_i8259_action, 0, "8259 cascade", NULL);
+        enable_irq(ISA_BRIDGE_INT);
+#endif
+}
+
+/* -------------------------------------------------------------------- */
+
+/*
+ * This is a big hack right now, but it may turn into something real
+ * someday.
+ *
+ * For the 8xx boards (at this time anyway), there is nothing to initialize
+ * associated the PROM.  Rather than include all of the prom.c
+ * functions in the image just to get prom_init, all we really need right
+ * now is the initialization of the physical memory region.
+ */
+static unsigned long __init
+m8xx_find_end_of_memory(void)
+{
+	bd_t	*binfo;
+	extern unsigned char __res[];
+
+	binfo = (bd_t *)__res;
+
+	return binfo->bi_memsize;
+}
+
+/*
+ * Now map in some of the I/O space that is generically needed
+ * or shared with multiple devices.
+ * All of this fits into the same 4Mbyte region, so it only
+ * requires one page table page.  (or at least it used to  -- paulus)
+ */
+static void __init
+m8xx_map_io(void)
+{
+        io_block_mapping(IMAP_ADDR, IMAP_ADDR, IMAP_SIZE, _PAGE_IO);
+#ifdef CONFIG_MBX
+        io_block_mapping(NVRAM_ADDR, NVRAM_ADDR, NVRAM_SIZE, _PAGE_IO);
+        io_block_mapping(MBX_CSR_ADDR, MBX_CSR_ADDR, MBX_CSR_SIZE, _PAGE_IO);
+        io_block_mapping(PCI_CSR_ADDR, PCI_CSR_ADDR, PCI_CSR_SIZE, _PAGE_IO);
+
+	/* Map some of the PCI/ISA I/O space to get the IDE interface.
+	*/
+        io_block_mapping(PCI_ISA_IO_ADDR, PCI_ISA_IO_ADDR, 0x4000, _PAGE_IO);
+        io_block_mapping(PCI_IDE_ADDR, PCI_IDE_ADDR, 0x4000, _PAGE_IO);
+#endif
+#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
+	io_block_mapping(RPX_CSR_ADDR, RPX_CSR_ADDR, RPX_CSR_SIZE, _PAGE_IO);
+#if !defined(CONFIG_PCI)
+	io_block_mapping(_IO_BASE,_IO_BASE,_IO_BASE_SIZE, _PAGE_IO);
+#endif
+#endif
+#ifdef CONFIG_HTDMSOUND
+	io_block_mapping(HIOX_CSR_ADDR, HIOX_CSR_ADDR, HIOX_CSR_SIZE, _PAGE_IO);
+#endif
+#ifdef CONFIG_FADS
+	io_block_mapping(BCSR_ADDR, BCSR_ADDR, BCSR_SIZE, _PAGE_IO);
+#endif
+#ifdef CONFIG_PCI
+        io_block_mapping(PCI_CSR_ADDR, PCI_CSR_ADDR, PCI_CSR_SIZE, _PAGE_IO);
+#endif
+}
+
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+
+	if ( r3 )
+		memcpy( (void *)__res,(void *)(r3+KERNELBASE), sizeof(bd_t) );
+
+#ifdef CONFIG_PCI
+	m8xx_setup_pci_ptrs();
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+	/* take care of initrd if we have one */
+	if ( r4 )
+	{
+		initrd_start = r4 + KERNELBASE;
+		initrd_end = r5 + KERNELBASE;
+	}
+#endif /* CONFIG_BLK_DEV_INITRD */
+	/* take care of cmd line */
+	if ( r6 )
+	{
+		*(char *)(r7+KERNELBASE) = 0;
+		strcpy(cmd_line, (char *)(r6+KERNELBASE));
+	}
+
+	ppc_md.setup_arch		= m8xx_setup_arch;
+	ppc_md.show_percpuinfo		= m8xx_show_percpuinfo;
+	ppc_md.irq_cannonicalize	= NULL;
+	ppc_md.init_IRQ			= m8xx_init_IRQ;
+	ppc_md.get_irq			= m8xx_get_irq;
+	ppc_md.init			= NULL;
+
+	ppc_md.restart			= m8xx_restart;
+	ppc_md.power_off		= m8xx_power_off;
+	ppc_md.halt			= m8xx_halt;
+
+	ppc_md.time_init		= NULL;
+	ppc_md.set_rtc_time		= m8xx_set_rtc_time;
+	ppc_md.get_rtc_time		= m8xx_get_rtc_time;
+	ppc_md.calibrate_decr		= m8xx_calibrate_decr;
+
+	ppc_md.find_end_of_memory	= m8xx_find_end_of_memory;
+	ppc_md.setup_io_mappings	= m8xx_map_io;
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+	m8xx_ide_init();
+#endif
+}
diff -Nru a/arch/ppc/syslib/mpc10x_common.c b/arch/ppc/syslib/mpc10x_common.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/mpc10x_common.c	Sun Nov 10 19:28:37 2002
@@ -0,0 +1,378 @@
+
+/*
+ * arch/ppc/kernel/mpc10x_common.c
+ * 
+ * Common routines for the Motorola SPS MPC106, MPC107 and MPC8240 Host bridge,
+ * Mem ctlr, EPIC, etc.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001 MontaVista Software 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.
+ */
+
+/*
+ * *** WARNING - A BAT MUST be set to access the PCI config addr/data regs ***
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/open_pic.h>
+#include <asm/mpc10x.h>
+
+
+/* Set resources to match bridge memory map */
+void __init
+mpc10x_bridge_set_resources(int map, struct pci_controller *hose)
+{
+
+	switch (map) {
+		case MPC10X_MEM_MAP_A:
+			pci_init_resource(&hose->io_resource,
+					0x00000000,
+					0x3f7fffff,
+					IORESOURCE_IO,
+					"PCI host bridge");
+
+			pci_init_resource (&hose->mem_resources[0],
+					0xc0000000,
+					0xfeffffff,
+					IORESOURCE_MEM,
+					"PCI host bridge");
+			break;
+		case MPC10X_MEM_MAP_B:
+			pci_init_resource(&hose->io_resource,
+					0x00000000,
+					0x00bfffff,
+					IORESOURCE_IO,
+					"PCI host bridge");
+
+			pci_init_resource (&hose->mem_resources[0],
+					0x80000000,
+					0xfcffffff,
+					IORESOURCE_MEM,
+					"PCI host bridge");
+			break;
+		default:
+			printk("mpc10x_bridge_set_resources: "
+					"Invalid map specified\n");
+			if (ppc_md.progress)
+				ppc_md.progress("mpc10x:exit1", 0x100);
+	}
+}
+/*
+ * Do some initialization and put the EUMB registers at the specified address
+ * (also map the EPIC registers into virtual space--OpenPIC_Addr will be set).
+ *
+ * The EPIC is not on the 106, only the 8240 and 107.
+ */
+int __init
+mpc10x_bridge_init(struct pci_controller *hose,
+		   uint current_map,
+		   uint new_map,
+		   uint phys_eumb_base)
+{
+	int	host_bridge, picr1, picr1_bit;
+	ulong	pci_config_addr, pci_config_data;
+	u_char	pir, byte;
+
+	if (ppc_md.progress) ppc_md.progress("mpc10x:enter", 0x100);
+
+	/* Set up for current map so we can get at config regs */
+	switch (current_map) {
+		case MPC10X_MEM_MAP_A:
+			setup_indirect_pci(hose,
+					   MPC10X_MAPA_CNFG_ADDR,
+					   MPC10X_MAPA_CNFG_DATA);
+			break;
+		case MPC10X_MEM_MAP_B:
+			setup_indirect_pci(hose,
+					   MPC10X_MAPB_CNFG_ADDR,
+					   MPC10X_MAPB_CNFG_DATA);
+			break;
+		default:
+			printk("mpc10x_bridge_init: %s\n",
+				"Invalid current map specified");
+			if (ppc_md.progress)
+				ppc_md.progress("mpc10x:exit1", 0x100);
+			return -1;
+	}
+
+	/* Make sure its a supported bridge */
+	early_read_config_dword(hose,
+			        0,
+			        PCI_DEVFN(0,0),
+			        PCI_VENDOR_ID,
+			        &host_bridge);
+
+	switch (host_bridge) {
+		case MPC10X_BRIDGE_106:
+		case MPC10X_BRIDGE_8240:
+		case MPC10X_BRIDGE_107:
+		case MPC10X_BRIDGE_8245:
+			break;
+		default:
+			if (ppc_md.progress)
+				ppc_md.progress("mpc10x:exit2", 0x100);
+			return -1;
+	}
+
+	switch (new_map) {
+		case MPC10X_MEM_MAP_A:
+			MPC10X_SETUP_HOSE(hose, A);
+			pci_config_addr = MPC10X_MAPA_CNFG_ADDR;
+			pci_config_data = MPC10X_MAPA_CNFG_DATA;
+			picr1_bit = MPC10X_CFG_PICR1_ADDR_MAP_A;
+			break;
+		case MPC10X_MEM_MAP_B:
+			MPC10X_SETUP_HOSE(hose, B);
+			pci_config_addr = MPC10X_MAPB_CNFG_ADDR;
+			pci_config_data = MPC10X_MAPB_CNFG_DATA;
+			picr1_bit = MPC10X_CFG_PICR1_ADDR_MAP_B;
+			break;
+		default:
+			printk("mpc10x_bridge_init: %s\n",
+				"Invalid new map specified");
+			if (ppc_md.progress)
+				ppc_md.progress("mpc10x:exit3", 0x100);
+			return -1;
+	}
+
+	/* Make bridge use the 'new_map', if not already usng it */
+	if (current_map != new_map) {
+		early_read_config_dword(hose,
+					0,
+					PCI_DEVFN(0,0),
+					MPC10X_CFG_PICR1_REG,
+					&picr1);
+
+		picr1 = (picr1 & ~MPC10X_CFG_PICR1_ADDR_MAP_MASK) |
+			 picr1_bit;
+
+		early_write_config_dword(hose,
+					 0,
+					 PCI_DEVFN(0,0),
+					 MPC10X_CFG_PICR1_REG,
+					 picr1);
+
+		asm volatile("sync");
+
+		/* Undo old mappings & map in new cfg data/addr regs */
+		iounmap((void *)hose->cfg_addr);
+		iounmap((void *)hose->cfg_data);
+
+		setup_indirect_pci(hose,
+				   pci_config_addr,
+				   pci_config_data);
+	}
+
+	/* Setup resources to match map */
+	mpc10x_bridge_set_resources(new_map, hose);
+
+	/*
+	 * Want processor accesses of 0xFDxxxxxx to be mapped
+	 * to PCI memory space at 0x00000000.  Do not want
+	 * host bridge to respond to PCI memory accesses of
+	 * 0xFDxxxxxx.  Do not want host bridge to respond
+	 * to PCI memory addresses 0xFD000000-0xFDFFFFFF;
+	 * want processor accesses from 0x000A0000-0x000BFFFF
+	 * to be forwarded to system memory.
+	 *
+	 * Only valid if not in agent mode and using MAP B.
+	 */
+	if (new_map == MPC10X_MEM_MAP_B) {
+		early_read_config_byte(hose,
+				       0,
+				       PCI_DEVFN(0,0),
+				       MPC10X_CFG_MAPB_OPTIONS_REG,
+				       &byte);
+
+		byte &= ~(MPC10X_CFG_MAPB_OPTIONS_PFAE  |
+			  MPC10X_CFG_MAPB_OPTIONS_PCICH |
+			  MPC10X_CFG_MAPB_OPTIONS_PROCCH);
+
+		if (host_bridge != MPC10X_BRIDGE_106) {
+			byte |= MPC10X_CFG_MAPB_OPTIONS_CFAE;
+		}
+
+		early_write_config_byte(hose,
+					0,
+					PCI_DEVFN(0,0),
+					MPC10X_CFG_MAPB_OPTIONS_REG,
+					byte);
+	}
+
+	if (host_bridge != MPC10X_BRIDGE_106) {
+		early_read_config_byte(hose,
+				       0,
+				       PCI_DEVFN(0,0),
+				       MPC10X_CFG_PIR_REG,
+				       &pir);
+
+		if (pir != MPC10X_CFG_PIR_HOST_BRIDGE) {
+			printk("Host bridge in Agent mode\n");
+			/* Read or Set LMBAR & PCSRBAR? */
+		}
+		       
+		/* Set base addr of the 8240/107 EUMB.  */
+		early_write_config_dword(hose,
+					 0,
+					 PCI_DEVFN(0,0),
+					 MPC10X_CFG_EUMBBAR,
+					 phys_eumb_base);
+
+		/* Map EPIC register part of EUMB into vitual memory */
+		OpenPIC_Addr = 
+			ioremap(phys_eumb_base + MPC10X_EUMB_EPIC_OFFSET,
+				MPC10X_EUMB_EPIC_SIZE);
+	}
+
+#ifdef CONFIG_MPC10X_STORE_GATHERING
+	mpc10x_enable_store_gathering(hose);
+#endif
+
+	if (ppc_md.progress) ppc_md.progress("mpc10x:exit", 0x100);
+	return 0;
+}
+
+/*
+ * Need to make our own PCI config space access macros because
+ * mpc10x_get_mem_size() is called before the data structures are set up for
+ * the 'early_xxx' and 'indirect_xxx' routines to work.
+ * Assumes bus 0.
+ */
+#define MPC10X_CFG_read(val, addr, type, op)	*val = op((type)(addr))
+#define MPC10X_CFG_write(val, addr, type, op)	op((type *)(addr), (val))
+
+#define MPC10X_PCI_OP(rw, size, type, op, mask)			 	\
+static void								\
+mpc10x_##rw##_config_##size(uint *cfg_addr, uint *cfg_data, int devfn, int offset, type val) \
+{									\
+	out_be32(cfg_addr, 						\
+		 ((offset & 0xfc) << 24) | (devfn << 16)		\
+		 | (0 << 8) | 0x80);					\
+	MPC10X_CFG_##rw(val, cfg_data + (offset & mask), type, op);	\
+	return;    					 		\
+}
+
+MPC10X_PCI_OP(read,  byte,  u8 *, in_8, 3)
+MPC10X_PCI_OP(read,  dword, u32 *, in_le32, 0)
+#if 0	/* Not used */
+MPC10X_PCI_OP(write, byte,  u8, out_8, 3)
+MPC10X_PCI_OP(read,  word,  u16 *, in_le16, 2)
+MPC10X_PCI_OP(write, word,  u16, out_le16, 2)
+MPC10X_PCI_OP(write, dword, u32, out_le32, 0)
+#endif
+
+/*
+ * Read the memory controller registers to determine the amount of memory in
+ * the system.  This assumes that the firmware has correctly set up the memory
+ * controller registers.
+ */
+unsigned long __init
+mpc10x_get_mem_size(uint mem_map)
+{
+	uint			*config_addr, *config_data, val;
+	ulong			start, end, total, offset;
+	int			i;
+	u_char			bank_enables;
+
+	switch (mem_map) {
+		case MPC10X_MEM_MAP_A:
+			config_addr = (uint *)MPC10X_MAPA_CNFG_ADDR;
+			config_data = (uint *)MPC10X_MAPA_CNFG_DATA;
+			break;
+		case MPC10X_MEM_MAP_B:
+			config_addr = (uint *)MPC10X_MAPB_CNFG_ADDR;
+			config_data = (uint *)MPC10X_MAPB_CNFG_DATA;
+			break;
+		default:
+			return 0;
+	}
+
+	mpc10x_read_config_byte(config_addr,
+				config_data,
+				PCI_DEVFN(0,0),
+			        MPC10X_MCTLR_MEM_BANK_ENABLES,
+			        &bank_enables);
+
+	total = 0;
+
+	for (i=0; i<8; i++) {
+		if (bank_enables & (1 << i)) {
+			offset = MPC10X_MCTLR_MEM_START_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr,
+						 config_data,
+						 PCI_DEVFN(0,0),
+						 offset,
+						 &val);
+			start = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_START_1 + ((i>3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr,
+						 config_data,
+						 PCI_DEVFN(0,0),
+						 offset,
+						 &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			start = (val << 28) | (start << 20);
+
+			offset = MPC10X_MCTLR_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr,
+						 config_data,
+						 PCI_DEVFN(0,0),
+						 offset,
+						 &val);
+			end = (val >> ((i & 3) << 3)) & 0xff;
+
+			offset = MPC10X_MCTLR_EXT_MEM_END_1 + ((i > 3) ? 4 : 0);
+			mpc10x_read_config_dword(config_addr,
+						 config_data,
+						 PCI_DEVFN(0,0),
+						 offset,
+						 &val);
+			val = (val >> ((i & 3) << 3)) & 0x03;
+			end = (val << 28) | (end << 20) | 0xfffff;
+
+			total += (end - start + 1);
+		}
+	}
+
+	return total;
+}
+
+int __init
+mpc10x_enable_store_gathering(struct pci_controller *hose)
+{
+	uint picr1;
+
+	early_read_config_dword(hose,
+				0,
+				PCI_DEVFN(0,0),
+			        MPC10X_CFG_PICR1_REG,
+			        &picr1);
+
+	picr1 |= MPC10X_CFG_PICR1_ST_GATH_EN;
+
+	early_write_config_dword(hose,
+				0,
+				PCI_DEVFN(0,0),
+				MPC10X_CFG_PICR1_REG,
+				picr1);
+
+	return 0;
+}
diff -Nru a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/open_pic.c	Sun Nov 10 19:28:40 2002
@@ -0,0 +1,927 @@
+/*
+ *  arch/ppc/kernel/open_pic.c -- OpenPIC Interrupt Handling
+ *
+ *  Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive
+ *  for more details.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <asm/ptrace.h>
+#include <asm/signal.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/prom.h>
+#include <asm/sections.h>
+#include <asm/open_pic.h>
+#include <asm/i8259.h>
+#include <asm/hardirq.h>
+
+#include "open_pic_defs.h"
+
+#ifdef CONFIG_PRPMC800
+#define OPENPIC_BIG_ENDIAN
+#endif
+
+void* OpenPIC_Addr;
+static volatile struct OpenPIC *OpenPIC = NULL;
+/*
+ * We define OpenPIC_InitSenses table thusly:
+ * bit 0x1: sense, 0 for edge and 1 for level.
+ * bit 0x2: polarity, 0 for negative, 1 for positive.
+ */
+u_int OpenPIC_NumInitSenses __initdata = 0;
+u_char *OpenPIC_InitSenses __initdata = NULL;
+extern int use_of_interrupt_tree;
+
+static u_int NumProcessors;
+static u_int NumSources;
+static int open_pic_irq_offset;
+static volatile OpenPIC_Source *ISR[NR_IRQS];
+
+/* Global Operations */
+static void openpic_disable_8259_pass_through(void);
+static void openpic_set_priority(u_int pri);
+static void openpic_set_spurious(u_int vector);
+
+#ifdef CONFIG_SMP
+/* Interprocessor Interrupts */
+static void openpic_initipi(u_int ipi, u_int pri, u_int vector);
+static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs);
+#endif
+
+/* Timer Interrupts */
+static void openpic_inittimer(u_int timer, u_int pri, u_int vector);
+static void openpic_maptimer(u_int timer, u_int cpumask);
+
+/* Interrupt Sources */
+static void openpic_enable_irq(u_int irq);
+static void openpic_disable_irq(u_int irq);
+static void openpic_initirq(u_int irq, u_int pri, u_int vector, int polarity,
+			    int is_level);
+static void openpic_mapirq(u_int irq, u_int cpumask, u_int keepmask);
+
+/*
+ * These functions are not used but the code is kept here
+ * for completeness and future reference.
+ */
+#ifdef notused
+static void openpic_enable_8259_pass_through(void);
+static u_int openpic_get_priority(void);
+static u_int openpic_get_spurious(void);
+static void openpic_set_sense(u_int irq, int sense);
+#endif /* notused */
+
+/*
+ * Description of the openpic for the higher-level irq code
+ */
+static void openpic_end_irq(unsigned int irq_nr);
+static void openpic_ack_irq(unsigned int irq_nr);
+static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask);
+
+struct hw_interrupt_type open_pic = {
+	" OpenPIC  ",
+	NULL,
+	NULL,
+	openpic_enable_irq,
+	openpic_disable_irq,
+	openpic_ack_irq,
+	openpic_end_irq,
+	openpic_set_affinity
+};
+
+#ifdef CONFIG_SMP
+static void openpic_end_ipi(unsigned int irq_nr);
+static void openpic_ack_ipi(unsigned int irq_nr);
+static void openpic_enable_ipi(unsigned int irq_nr);
+static void openpic_disable_ipi(unsigned int irq_nr);
+
+struct hw_interrupt_type open_pic_ipi = {
+	" OpenPIC  ",
+	NULL,
+	NULL,
+	openpic_enable_ipi,
+	openpic_disable_ipi,
+	openpic_ack_ipi,
+	openpic_end_ipi,
+	0
+};
+#endif /* CONFIG_SMP */
+
+/*
+ *  Accesses to the current processor's openpic registers
+ */
+#ifdef CONFIG_SMP
+#define THIS_CPU		Processor[cpu]
+#define DECL_THIS_CPU		int cpu = smp_hw_index[smp_processor_id()]
+#define CHECK_THIS_CPU		check_arg_cpu(cpu)
+#else
+#define THIS_CPU		Processor[0]
+#define DECL_THIS_CPU
+#define CHECK_THIS_CPU
+#endif /* CONFIG_SMP */
+
+#if 1
+#define check_arg_ipi(ipi) \
+    if (ipi < 0 || ipi >= OPENPIC_NUM_IPI) \
+	printk("open_pic.c:%d: illegal ipi %d\n", __LINE__, ipi);
+#define check_arg_timer(timer) \
+    if (timer < 0 || timer >= OPENPIC_NUM_TIMERS) \
+	printk("open_pic.c:%d: illegal timer %d\n", __LINE__, timer);
+#define check_arg_vec(vec) \
+    if (vec < 0 || vec >= OPENPIC_NUM_VECTORS) \
+	printk("open_pic.c:%d: illegal vector %d\n", __LINE__, vec);
+#define check_arg_pri(pri) \
+    if (pri < 0 || pri >= OPENPIC_NUM_PRI) \
+	printk("open_pic.c:%d: illegal priority %d\n", __LINE__, pri);
+/*
+ * Print out a backtrace if it's out of range, since if it's larger than NR_IRQ's
+ * data has probably been corrupted and we're going to panic or deadlock later
+ * anyway --Troy
+ */
+#define check_arg_irq(irq) \
+    if (irq < open_pic_irq_offset || irq >= NumSources+open_pic_irq_offset \
+	|| ISR[irq - open_pic_irq_offset] == 0) { \
+      printk("open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
+      dump_stack(); }
+#define check_arg_cpu(cpu) \
+    if (cpu < 0 || cpu >= NumProcessors){ \
+	printk("open_pic.c:%d: illegal cpu %d\n", __LINE__, cpu); \
+	dump_stack(); }
+#else
+#define check_arg_ipi(ipi)	do {} while (0)
+#define check_arg_timer(timer)	do {} while (0)
+#define check_arg_vec(vec)	do {} while (0)
+#define check_arg_pri(pri)	do {} while (0)
+#define check_arg_irq(irq)	do {} while (0)
+#define check_arg_cpu(cpu)	do {} while (0)
+#endif
+
+u_int openpic_read(volatile u_int *addr)
+{
+	u_int val;
+
+#ifdef OPENPIC_BIG_ENDIAN
+	val = in_be32(addr);
+#else
+	val = in_le32(addr);
+#endif
+	return val;
+}
+
+static inline void openpic_write(volatile u_int *addr, u_int val)
+{
+#ifdef OPENPIC_BIG_ENDIAN
+	out_be32(addr, val);
+#else
+	out_le32(addr, val);
+#endif
+}
+
+static inline u_int openpic_readfield(volatile u_int *addr, u_int mask)
+{
+	u_int val = openpic_read(addr);
+	return val & mask;
+}
+
+inline void openpic_writefield(volatile u_int *addr, u_int mask,
+			       u_int field)
+{
+	u_int val = openpic_read(addr);
+	openpic_write(addr, (val & ~mask) | (field & mask));
+}
+
+static inline void openpic_clearfield(volatile u_int *addr, u_int mask)
+{
+	openpic_writefield(addr, mask, 0);
+}
+
+static inline void openpic_setfield(volatile u_int *addr, u_int mask)
+{
+	openpic_writefield(addr, mask, mask);
+}
+
+static void openpic_safe_writefield(volatile u_int *addr, u_int mask,
+				    u_int field)
+{
+	openpic_setfield(addr, OPENPIC_MASK);
+	while (openpic_read(addr) & OPENPIC_ACTIVITY);
+	openpic_writefield(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
+}
+
+#ifdef CONFIG_SMP
+/* yes this is right ... bug, feature, you decide! -- tgall */
+u_int openpic_read_IPI(volatile u_int* addr)
+{
+         u_int val = 0;
+#if defined(OPENPIC_BIG_ENDIAN) || defined(CONFIG_POWER3)
+        val = in_be32(addr);
+#else
+        val = in_le32(addr);
+#endif
+        return val;
+}
+
+/* because of the power3 be / le above, this is needed */
+inline void openpic_writefield_IPI(volatile u_int* addr, u_int mask, u_int field)
+{
+        u_int  val = openpic_read_IPI(addr);
+        openpic_write(addr, (val & ~mask) | (field & mask));
+}
+
+static inline void openpic_clearfield_IPI(volatile u_int *addr, u_int mask)
+{
+        openpic_writefield_IPI(addr, mask, 0);
+}
+
+static inline void openpic_setfield_IPI(volatile u_int *addr, u_int mask)
+{
+        openpic_writefield_IPI(addr, mask, mask);
+}
+
+static void openpic_safe_writefield_IPI(volatile u_int *addr, u_int mask, u_int field)
+{
+        openpic_setfield_IPI(addr, OPENPIC_MASK);
+
+        /* wait until it's not in use */
+        /* BenH: Is this code really enough ? I would rather check the result
+         *       and eventually retry ...
+         */
+        while(openpic_read_IPI(addr) & OPENPIC_ACTIVITY);
+
+        openpic_writefield_IPI(addr, mask | OPENPIC_MASK, field | OPENPIC_MASK);
+}
+#endif /* CONFIG_SMP */
+
+#if defined(CONFIG_EPIC_SERIAL_MODE) || defined(CONFIG_PMAC_PBOOK)
+static void openpic_reset(void)
+{
+	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
+			 OPENPIC_CONFIG_RESET);
+	while (openpic_readfield(&OpenPIC->Global.Global_Configuration0,
+				 OPENPIC_CONFIG_RESET))
+		mb();
+}
+#endif
+
+#ifdef CONFIG_EPIC_SERIAL_MODE
+static void openpic_enable_sie(void)
+{
+	openpic_setfield(&OpenPIC->Global.Global_Configuration1,
+			 OPENPIC_EICR_SIE);
+}
+
+static void openpic_eicr_set_clk(u_int clkval)
+{
+	openpic_writefield(&OpenPIC->Global.Global_Configuration1,
+			 OPENPIC_EICR_S_CLK_MASK, (clkval << 28));
+}
+#endif
+
+void openpic_set_sources(int first_irq, int num_irqs, void *first_ISR)
+{
+	volatile OpenPIC_Source *src = first_ISR;
+	int i, last_irq;
+
+	last_irq = first_irq + num_irqs;
+	if (last_irq > NumSources)
+		NumSources = last_irq;
+	if (src == 0)
+		src = &((struct OpenPIC *)OpenPIC_Addr)->Source[first_irq];
+	for (i = first_irq; i < last_irq; ++i, ++src)
+		ISR[i] = src;
+}
+
+void __init openpic_init(int linux_irq_offset)
+{
+	u_int t, i;
+	u_int timerfreq;
+	const char *version;
+
+	if (!OpenPIC_Addr) {
+		printk("No OpenPIC found !\n");
+		return;
+	}
+	OpenPIC = (volatile struct OpenPIC *)OpenPIC_Addr;
+
+#ifdef CONFIG_EPIC_SERIAL_MODE
+	/* Have to start from ground zero.
+	*/
+	openpic_reset();
+#endif
+
+	if (ppc_md.progress) ppc_md.progress("openpic: enter", 0x122);
+
+	t = openpic_read(&OpenPIC->Global.Feature_Reporting0);
+	switch (t & OPENPIC_FEATURE_VERSION_MASK) {
+	case 1:
+		version = "1.0";
+		break;
+	case 2:
+		version = "1.2";
+		break;
+	case 3:
+		version = "1.3";
+		break;
+	default:
+		version = "?";
+		break;
+	}
+	NumProcessors = ((t & OPENPIC_FEATURE_LAST_PROCESSOR_MASK) >>
+			 OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT) + 1;
+	if (NumSources == 0)
+		openpic_set_sources(0,
+				    ((t & OPENPIC_FEATURE_LAST_SOURCE_MASK) >>
+				     OPENPIC_FEATURE_LAST_SOURCE_SHIFT) + 1,
+				    NULL);
+	printk("OpenPIC Version %s (%d CPUs and %d IRQ sources) at %p\n",
+	       version, NumProcessors, NumSources, OpenPIC);
+	timerfreq = openpic_read(&OpenPIC->Global.Timer_Frequency);
+	if (timerfreq)
+		printk("OpenPIC timer frequency is %d.%06d MHz\n",
+		       timerfreq / 1000000, timerfreq % 1000000);
+
+	open_pic_irq_offset = linux_irq_offset;
+
+	/* Initialize timer interrupts */
+	if ( ppc_md.progress ) ppc_md.progress("openpic: timer",0x3ba);
+	for (i = 0; i < OPENPIC_NUM_TIMERS; i++) {
+		/* Disabled, Priority 0 */
+		openpic_inittimer(i, 0, OPENPIC_VEC_TIMER+i+linux_irq_offset);
+		/* No processor */
+		openpic_maptimer(i, 0);
+	}
+
+#ifdef CONFIG_SMP
+	/* Initialize IPI interrupts */
+	if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb);
+	for (i = 0; i < OPENPIC_NUM_IPI; i++) {
+		/* Disabled, Priority 10..13 */
+		openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+linux_irq_offset);
+		/* IPIs are per-CPU */
+		irq_desc[OPENPIC_VEC_IPI+i+linux_irq_offset].status |=
+			IRQ_PER_CPU;
+		irq_desc[OPENPIC_VEC_IPI+i+linux_irq_offset].handler =
+			&open_pic_ipi;
+	}
+#endif
+
+	/* Initialize external interrupts */
+	if (ppc_md.progress) ppc_md.progress("openpic: external",0x3bc);
+
+	openpic_set_priority(0xf);
+
+	/* Init all external sources, including possibly the cascade. */
+	for (i = 0; i < NumSources; i++) {
+		int sense;
+
+		if (ISR[i] == 0)
+			continue;
+
+		/* the bootloader may have left it enabled (bad !) */
+		openpic_disable_irq(i+linux_irq_offset);
+
+		/*
+		 * We find the value from either the InitSenses table
+		 * or assume a negative polarity level interrupt.
+		 */
+		sense = (i < OpenPIC_NumInitSenses)? OpenPIC_InitSenses[i]: 1;
+
+		if ((sense & IRQ_SENSE_MASK) == 1)
+			irq_desc[i+linux_irq_offset].status = IRQ_LEVEL;
+
+		/* Enabled, Priority 8 */
+		openpic_initirq(i, 8, i + linux_irq_offset,
+				(sense & IRQ_POLARITY_MASK),
+				(sense & IRQ_SENSE_MASK));
+		/* Processor 0 */
+		openpic_mapirq(i, 1<<0, 0);
+	}
+
+	/* Init descriptors */
+	for (i = linux_irq_offset; i < NumSources + linux_irq_offset; i++)
+		irq_desc[i].handler = &open_pic;
+
+	/* Initialize the spurious interrupt */
+	if (ppc_md.progress) ppc_md.progress("openpic: spurious",0x3bd);
+	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+linux_irq_offset);
+
+	/* Initialize the cascade */
+	if (linux_irq_offset) {
+		if (request_irq(linux_irq_offset, no_action, SA_INTERRUPT,
+				"82c59 cascade", NULL))
+			printk("Unable to get OpenPIC IRQ 0 for cascade\n");
+	}
+ 	openpic_disable_8259_pass_through();
+#ifdef CONFIG_EPIC_SERIAL_MODE
+	openpic_eicr_set_clk(7);	/* Slowest value until we know better */
+	openpic_enable_sie();
+#endif
+	openpic_set_priority(0);
+
+	if (ppc_md.progress) ppc_md.progress("openpic: exit",0x222);
+}
+
+#ifdef notused
+static void openpic_enable_8259_pass_through(void)
+{
+	openpic_clearfield(&OpenPIC->Global.Global_Configuration0,
+			   OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
+}
+#endif /* notused */
+
+static void openpic_disable_8259_pass_through(void)
+{
+	openpic_setfield(&OpenPIC->Global.Global_Configuration0,
+			 OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE);
+}
+
+/*
+ *  Find out the current interrupt
+ */
+u_int openpic_irq(void)
+{
+	u_int vec;
+	DECL_THIS_CPU;
+
+	CHECK_THIS_CPU;
+	vec = openpic_readfield(&OpenPIC->THIS_CPU.Interrupt_Acknowledge,
+				OPENPIC_VECTOR_MASK);
+	return vec;
+}
+
+void openpic_eoi(void)
+{
+	DECL_THIS_CPU;
+
+	CHECK_THIS_CPU;
+	openpic_write(&OpenPIC->THIS_CPU.EOI, 0);
+	/* Handle PCI write posting */
+	(void)openpic_read(&OpenPIC->THIS_CPU.EOI);
+}
+
+#ifdef notused
+static u_int openpic_get_priority(void)
+{
+	DECL_THIS_CPU;
+
+	CHECK_THIS_CPU;
+	return openpic_readfield(&OpenPIC->THIS_CPU.Current_Task_Priority,
+				 OPENPIC_CURRENT_TASK_PRIORITY_MASK);
+}
+#endif /* notused */
+
+static void openpic_set_priority(u_int pri)
+{
+	DECL_THIS_CPU;
+
+	CHECK_THIS_CPU;
+	check_arg_pri(pri);
+	openpic_writefield(&OpenPIC->THIS_CPU.Current_Task_Priority,
+			   OPENPIC_CURRENT_TASK_PRIORITY_MASK, pri);
+}
+
+/*
+ *  Get/set the spurious vector
+ */
+#ifdef notused
+static u_int openpic_get_spurious(void)
+{
+	return openpic_readfield(&OpenPIC->Global.Spurious_Vector,
+				 OPENPIC_VECTOR_MASK);
+}
+#endif /* notused */
+
+static void openpic_set_spurious(u_int vec)
+{
+	check_arg_vec(vec);
+	openpic_writefield(&OpenPIC->Global.Spurious_Vector, OPENPIC_VECTOR_MASK,
+			   vec);
+}
+
+#ifdef CONFIG_SMP
+/*
+ * Convert a cpu mask from logical to physical cpu numbers.
+ */
+static inline u32 physmask(u32 cpumask)
+{
+	int i;
+	u32 mask = 0;
+
+	for (i = 0; i < NR_CPUS; ++i, cpumask >>= 1)
+		if (cpu_online(i))
+			mask |= (cpumask & 1) << smp_hw_index[i];
+	return mask;
+}
+#else
+#define physmask(cpumask)	(cpumask)
+#endif
+
+void openpic_reset_processor_phys(u_int mask)
+{
+	openpic_write(&OpenPIC->Global.Processor_Initialization, mask);
+}
+
+#if defined(CONFIG_SMP) || defined(CONFIG_PMAC_PBOOK)
+static spinlock_t openpic_setup_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+#ifdef CONFIG_SMP
+/*
+ *  Initialize an interprocessor interrupt (and disable it)
+ *
+ *  ipi: OpenPIC interprocessor interrupt number
+ *  pri: interrupt source priority
+ *  vec: the vector it will produce
+ */
+static void __init openpic_initipi(u_int ipi, u_int pri, u_int vec)
+{
+	check_arg_ipi(ipi);
+	check_arg_pri(pri);
+	check_arg_vec(vec);
+	openpic_safe_writefield_IPI(&OpenPIC->Global.IPI_Vector_Priority(ipi),
+				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
+				(pri << OPENPIC_PRIORITY_SHIFT) | vec);
+}
+
+/*
+ *  Send an IPI to one or more CPUs
+ *  
+ *  Externally called, however, it takes an IPI number (0...OPENPIC_NUM_IPI)
+ *  and not a system-wide interrupt number
+ */
+void openpic_cause_IPI(u_int ipi, u_int cpumask)
+{
+	DECL_THIS_CPU;
+
+	CHECK_THIS_CPU;
+	check_arg_ipi(ipi);
+	openpic_write(&OpenPIC->THIS_CPU.IPI_Dispatch(ipi),
+		      physmask(cpumask));
+}
+
+void openpic_request_IPIs(void)
+{
+	int i;
+	
+	/*
+	 * Make sure this matches what is defined in smp.c for 
+	 * smp_message_{pass|recv}() or what shows up in 
+	 * /proc/interrupts will be wrong!!! --Troy */
+	
+	if (OpenPIC == NULL)
+		return;
+
+	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset,
+		    openpic_ipi_action, 0, "IPI0 (call function)", 0);
+	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+1,
+		    openpic_ipi_action, 0, "IPI1 (reschedule)", 0);
+	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+2,
+		    openpic_ipi_action, 0, "IPI2 (invalidate tlb)", 0);
+	request_irq(OPENPIC_VEC_IPI+open_pic_irq_offset+3,
+		    openpic_ipi_action, 0, "IPI3 (xmon break)", 0);
+
+	for ( i = 0; i < OPENPIC_NUM_IPI ; i++ )
+		openpic_enable_ipi(OPENPIC_VEC_IPI+open_pic_irq_offset+i);
+}
+
+/*
+ * Do per-cpu setup for SMP systems.
+ *
+ * Get IPI's working and start taking interrupts.
+ *   -- Cort
+ */
+
+void __devinit do_openpic_setup_cpu(void)
+{
+ 	int i;
+	u32 msk = 1 << smp_hw_index[smp_processor_id()];
+
+	spin_lock(&openpic_setup_lock);
+
+#ifdef CONFIG_IRQ_ALL_CPUS
+ 	/* let the openpic know we want intrs. default affinity
+ 	 * is 0xffffffff until changed via /proc
+ 	 * That's how it's done on x86. If we want it differently, then
+ 	 * we should make sure we also change the default values of irq_affinity
+ 	 * in irq.c.
+ 	 */
+ 	for (i = 0; i < NumSources; i++)
+		openpic_mapirq(i, msk, ~0U);
+#endif /* CONFIG_IRQ_ALL_CPUS */
+ 	openpic_set_priority(0);
+
+	spin_unlock(&openpic_setup_lock);
+}
+#endif /* CONFIG_SMP */
+
+/*
+ *  Initialize a timer interrupt (and disable it)
+ *
+ *  timer: OpenPIC timer number
+ *  pri: interrupt source priority
+ *  vec: the vector it will produce
+ */
+static void __init openpic_inittimer(u_int timer, u_int pri, u_int vec)
+{
+	check_arg_timer(timer);
+	check_arg_pri(pri);
+	check_arg_vec(vec);
+	openpic_safe_writefield(&OpenPIC->Global.Timer[timer].Vector_Priority,
+				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK,
+				(pri << OPENPIC_PRIORITY_SHIFT) | vec);
+}
+
+/*
+ *  Map a timer interrupt to one or more CPUs
+ */
+static void __init openpic_maptimer(u_int timer, u_int cpumask)
+{
+	check_arg_timer(timer);
+	openpic_write(&OpenPIC->Global.Timer[timer].Destination,
+		      physmask(cpumask));
+}
+
+/*
+ * Initalize the interrupt source which will generate an NMI (and disable it).
+ *
+ * irq: The logical IRQ which generates an NMI.
+ */
+void __init
+openpic_init_nmi_irq(u_int irq)
+{
+	int sense;
+
+	/* If this wasn't given, assume a level, negative polarity interrupt. */
+	sense = (irq < OpenPIC_NumInitSenses) ? OpenPIC_InitSenses[irq] :
+		(IRQ_SENSE_LEVEL | IRQ_POLARITY_NEGATIVE);
+
+	openpic_safe_writefield(&ISR[irq]->Vector_Priority,
+				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
+				OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
+				(9 << OPENPIC_PRIORITY_SHIFT) |
+				(irq + open_pic_irq_offset) |
+				((sense & IRQ_POLARITY_MASK) ?
+				 OPENPIC_POLARITY_POSITIVE :
+				 OPENPIC_POLARITY_NEGATIVE) |
+				((sense & IRQ_SENSE_MASK) ? OPENPIC_SENSE_LEVEL
+				 : OPENPIC_SENSE_EDGE));
+}
+
+/*
+ *
+ * All functions below take an offset'ed irq argument
+ *
+ */
+
+
+/*
+ *  Enable/disable an external interrupt source
+ *
+ *  Externally called, irq is an offseted system-wide interrupt number
+ */
+static void openpic_enable_irq(u_int irq)
+{
+	volatile u_int *vpp;
+
+	check_arg_irq(irq);
+	vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority;
+	openpic_clearfield(vpp, OPENPIC_MASK);
+	/* make sure mask gets to controller before we return to user */
+	do {
+		mb(); /* sync is probably useless here */
+	} while (openpic_readfield(vpp, OPENPIC_MASK));
+}
+
+static void openpic_disable_irq(u_int irq)
+{
+	volatile u_int *vpp;
+	u32 vp;
+	
+	check_arg_irq(irq);
+	vpp = &ISR[irq - open_pic_irq_offset]->Vector_Priority;
+	openpic_setfield(vpp, OPENPIC_MASK);
+	/* make sure mask gets to controller before we return to user */
+	do {
+		mb();  /* sync is probably useless here */
+		vp = openpic_readfield(vpp, OPENPIC_MASK | OPENPIC_ACTIVITY);
+	} while((vp & OPENPIC_ACTIVITY) && !(vp & OPENPIC_MASK));
+}
+
+#ifdef CONFIG_SMP
+/*
+ *  Enable/disable an IPI interrupt source
+ *  
+ *  Externally called, irq is an offseted system-wide interrupt number
+ */
+void openpic_enable_ipi(u_int irq)
+{
+	irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
+	check_arg_ipi(irq);
+	openpic_clearfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
+
+}
+
+void openpic_disable_ipi(u_int irq)
+{
+	irq -= (OPENPIC_VEC_IPI+open_pic_irq_offset);
+	check_arg_ipi(irq);
+	openpic_setfield_IPI(&OpenPIC->Global.IPI_Vector_Priority(irq), OPENPIC_MASK);
+}
+#endif
+
+/*
+ *  Initialize an interrupt source (and disable it!)
+ *
+ *  irq: OpenPIC interrupt number
+ *  pri: interrupt source priority
+ *  vec: the vector it will produce
+ *  pol: polarity (1 for positive, 0 for negative)
+ *  sense: 1 for level, 0 for edge
+ */
+static void openpic_initirq(u_int irq, u_int pri, u_int vec, int pol, int sense)
+{
+	openpic_safe_writefield(&ISR[irq]->Vector_Priority,
+				OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK |
+				OPENPIC_SENSE_MASK | OPENPIC_POLARITY_MASK,
+				(pri << OPENPIC_PRIORITY_SHIFT) | vec |
+				(pol ? OPENPIC_POLARITY_POSITIVE :
+			    		OPENPIC_POLARITY_NEGATIVE) |
+				(sense ? OPENPIC_SENSE_LEVEL : OPENPIC_SENSE_EDGE));
+}
+
+/*
+ *  Map an interrupt source to one or more CPUs
+ */
+static void openpic_mapirq(u_int irq, u_int physmask, u_int keepmask)
+{
+	if (ISR[irq] == 0)
+		return;
+	if (keepmask != 0)
+		physmask |= openpic_read(&ISR[irq]->Destination) & keepmask;
+	openpic_write(&ISR[irq]->Destination, physmask);
+}
+
+#ifdef notused
+/*
+ *  Set the sense for an interrupt source (and disable it!)
+ *
+ *  sense: 1 for level, 0 for edge
+ */
+static void openpic_set_sense(u_int irq, int sense)
+{
+	if (ISR[irq] != 0)
+		openpic_safe_writefield(&ISR[irq]->Vector_Priority,
+					OPENPIC_SENSE_LEVEL,
+					(sense ? OPENPIC_SENSE_LEVEL : 0));
+}
+#endif /* notused */
+
+/* No spinlocks, should not be necessary with the OpenPIC
+ * (1 register = 1 interrupt and we have the desc lock).
+ */
+static void openpic_ack_irq(unsigned int irq_nr)
+{
+	openpic_disable_irq(irq_nr);
+	openpic_eoi();
+}
+
+static void openpic_end_irq(unsigned int irq_nr)
+{
+	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
+	    && irq_desc[irq_nr].action)
+		openpic_enable_irq(irq_nr);
+}
+
+static void openpic_set_affinity(unsigned int irq_nr, unsigned long cpumask)
+{
+	openpic_mapirq(irq_nr - open_pic_irq_offset, physmask(cpumask), 0);
+}
+
+#ifdef CONFIG_SMP
+static void openpic_ack_ipi(unsigned int irq_nr)
+{
+	openpic_eoi();
+}
+
+static void openpic_end_ipi(unsigned int irq_nr)
+{
+}
+
+static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	smp_message_recv(cpl-OPENPIC_VEC_IPI-open_pic_irq_offset, regs);
+}
+
+#endif /* CONFIG_SMP */
+
+int
+openpic_get_irq(struct pt_regs *regs)
+{
+	int irq = openpic_irq();
+
+	/*
+	 * This needs to be cleaned up.  We don't necessarily have
+	 * an i8259 cascaded or even a cascade.
+	 */
+	if (open_pic_irq_offset && irq == open_pic_irq_offset) {
+		/* Get the IRQ from the cascade. */
+		irq = i8259_irq(regs);
+		openpic_eoi();
+	} else if (irq == OPENPIC_VEC_SPURIOUS + open_pic_irq_offset)
+		irq = -1;
+	return irq;
+}
+
+#ifdef CONFIG_SMP
+void
+smp_openpic_message_pass(int target, int msg, unsigned long data, int wait)
+{
+	/* make sure we're sending something that translates to an IPI */
+	if (msg > 0x3) {
+		printk("SMP %d: smp_message_pass: unknown msg %d\n",
+		       smp_processor_id(), msg);
+		return;
+	}
+	switch (target) {
+	case MSG_ALL:
+		openpic_cause_IPI(msg, 0xffffffff);
+		break;
+	case MSG_ALL_BUT_SELF:
+		openpic_cause_IPI(msg,
+				  0xffffffff & ~(1 << smp_processor_id()));
+		break;
+	default:
+		openpic_cause_IPI(msg, 1<<target);
+		break;
+	}
+}
+#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_PMAC_PBOOK
+static u32 save_ipi_vp[OPENPIC_NUM_IPI];
+static u32 save_irq_src_vp[OPENPIC_MAX_SOURCES];
+static u32 save_irq_src_dest[OPENPIC_MAX_SOURCES];
+static u32 save_cpu_task_pri[OPENPIC_MAX_PROCESSORS];
+
+void __pmac
+openpic_sleep_save_intrs(void)
+{
+	int	i;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&openpic_setup_lock, flags);
+
+	for (i=0; i<NumProcessors; i++) {
+		save_cpu_task_pri[i] = openpic_read(&OpenPIC->Processor[i].Current_Task_Priority);
+		openpic_writefield(&OpenPIC->Processor[i].Current_Task_Priority,
+				   OPENPIC_CURRENT_TASK_PRIORITY_MASK, 0xf);
+	}
+
+	for (i=0; i<OPENPIC_NUM_IPI; i++)
+		save_ipi_vp[i] = openpic_read(&OpenPIC->Global.IPI_Vector_Priority(i));
+	for (i=0; i<NumSources; i++) {
+		if (ISR[i] == 0)
+			continue;
+		save_irq_src_vp[i] = openpic_read(&ISR[i]->Vector_Priority)
+			& ~OPENPIC_ACTIVITY;
+		save_irq_src_dest[i] = openpic_read(&ISR[i]->Destination);
+	}
+	spin_unlock_irqrestore(&openpic_setup_lock, flags);
+}
+
+void __pmac
+openpic_sleep_restore_intrs(void)
+{
+	int		i;
+	unsigned long	flags;
+
+	spin_lock_irqsave(&openpic_setup_lock, flags);
+	
+	openpic_reset();
+
+	for (i=0; i<OPENPIC_NUM_IPI; i++)
+		openpic_write(&OpenPIC->Global.IPI_Vector_Priority(i),
+			      save_ipi_vp[i]);
+	for (i=0; i<NumSources; i++) {
+		if (ISR[i] == 0)
+			continue;
+		openpic_write(&ISR[i]->Vector_Priority, save_irq_src_vp[i]);
+		openpic_write(&ISR[i]->Destination, save_irq_src_dest[i]);
+	}
+	openpic_set_spurious(OPENPIC_VEC_SPURIOUS+open_pic_irq_offset);
+	openpic_disable_8259_pass_through();
+	for (i=0; i<NumProcessors; i++)
+		openpic_write(&OpenPIC->Processor[i].Current_Task_Priority,
+			      save_cpu_task_pri[i]);
+
+	spin_unlock_irqrestore(&openpic_setup_lock, flags);
+}
+#endif /* CONFIG_PMAC_PBOOK */
diff -Nru a/arch/ppc/syslib/open_pic_defs.h b/arch/ppc/syslib/open_pic_defs.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/open_pic_defs.h	Sun Nov 10 19:28:40 2002
@@ -0,0 +1,292 @@
+/*
+ *  arch/ppc/kernel/open_pic_defs.h -- OpenPIC definitions
+ *
+ *  Copyright (C) 1997 Geert Uytterhoeven
+ *
+ *  This file is based on the following documentation:
+ *
+ *	The Open Programmable Interrupt Controller (PIC)
+ *	Register Interface Specification Revision 1.2
+ *
+ *	Issue Date: October 1995
+ *
+ *	Issued jointly by Advanced Micro Devices and Cyrix Corporation
+ *
+ *	AMD is a registered trademark of Advanced Micro Devices, Inc.
+ *	Copyright (C) 1995, Advanced Micro Devices, Inc. and Cyrix, Inc.
+ *	All Rights Reserved.
+ *
+ *  To receive a copy of this documentation, send an email to openpic@amd.com.
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive
+ *  for more details.
+ */
+
+#ifndef _LINUX_OPENPIC_H
+#define _LINUX_OPENPIC_H
+
+#ifdef __KERNEL__
+
+    /*
+     *  OpenPIC supports up to 2048 interrupt sources and up to 32 processors
+     */
+
+#define OPENPIC_MAX_SOURCES	2048
+#define OPENPIC_MAX_PROCESSORS	32
+#define OPENPIC_MAX_ISU		16
+
+#define OPENPIC_NUM_TIMERS	4
+#define OPENPIC_NUM_IPI		4
+#define OPENPIC_NUM_PRI		16
+#define OPENPIC_NUM_VECTORS	256
+
+
+
+    /*
+     *  OpenPIC Registers are 32 bits and aligned on 128 bit boundaries
+     */
+
+typedef struct _OpenPIC_Reg {
+    u_int Reg;					/* Little endian! */
+    char Pad[0xc];
+} OpenPIC_Reg;
+
+
+    /*
+     *  Per Processor Registers
+     */
+
+typedef struct _OpenPIC_Processor {
+    /*
+     *  Private Shadow Registers (for SLiC backwards compatibility)
+     */
+    u_int IPI0_Dispatch_Shadow;			/* Write Only */
+    char Pad1[0x4];
+    u_int IPI0_Vector_Priority_Shadow;		/* Read/Write */
+    char Pad2[0x34];
+    /*
+     *  Interprocessor Interrupt Command Ports
+     */
+    OpenPIC_Reg _IPI_Dispatch[OPENPIC_NUM_IPI];	/* Write Only */
+    /*
+     *  Current Task Priority Register
+     */
+    OpenPIC_Reg _Current_Task_Priority;		/* Read/Write */
+    char Pad3[0x10];
+    /*
+     *  Interrupt Acknowledge Register
+     */
+    OpenPIC_Reg _Interrupt_Acknowledge;		/* Read Only */
+    /*
+     *  End of Interrupt (EOI) Register
+     */
+    OpenPIC_Reg _EOI;				/* Read/Write */
+    char Pad5[0xf40];
+} OpenPIC_Processor;
+
+
+    /*
+     *  Timer Registers
+     */
+
+typedef struct _OpenPIC_Timer {
+    OpenPIC_Reg _Current_Count;			/* Read Only */
+    OpenPIC_Reg _Base_Count;			/* Read/Write */
+    OpenPIC_Reg _Vector_Priority;		/* Read/Write */
+    OpenPIC_Reg _Destination;			/* Read/Write */
+} OpenPIC_Timer;
+
+
+    /*
+     *  Global Registers
+     */
+
+typedef struct _OpenPIC_Global {
+    /*
+     *  Feature Reporting Registers
+     */
+    OpenPIC_Reg _Feature_Reporting0;		/* Read Only */
+    OpenPIC_Reg _Feature_Reporting1;		/* Future Expansion */
+    /*
+     *  Global Configuration Registers
+     */
+    OpenPIC_Reg _Global_Configuration0;		/* Read/Write */
+    OpenPIC_Reg _Global_Configuration1;		/* Future Expansion */
+    /*
+     *  Vendor Specific Registers
+     */
+    OpenPIC_Reg _Vendor_Specific[4];
+    /*
+     *  Vendor Identification Register
+     */
+    OpenPIC_Reg _Vendor_Identification;		/* Read Only */
+    /*
+     *  Processor Initialization Register
+     */
+    OpenPIC_Reg _Processor_Initialization;	/* Read/Write */
+    /*
+     *  IPI Vector/Priority Registers
+     */
+    OpenPIC_Reg _IPI_Vector_Priority[OPENPIC_NUM_IPI];	/* Read/Write */
+    /*
+     *  Spurious Vector Register
+     */
+    OpenPIC_Reg _Spurious_Vector;		/* Read/Write */
+    /*
+     *  Global Timer Registers
+     */
+    OpenPIC_Reg _Timer_Frequency;		/* Read/Write */
+    OpenPIC_Timer Timer[OPENPIC_NUM_TIMERS];
+    char Pad1[0xee00];
+} OpenPIC_Global;
+
+
+    /*
+     *  Interrupt Source Registers
+     */
+
+typedef struct _OpenPIC_Source {
+    OpenPIC_Reg _Vector_Priority;		/* Read/Write */
+    OpenPIC_Reg _Destination;			/* Read/Write */
+} OpenPIC_Source, *OpenPIC_SourcePtr;
+
+
+    /*
+     *  OpenPIC Register Map
+     */
+
+struct OpenPIC {
+    char Pad1[0x1000];
+    /*
+     *  Global Registers
+     */
+    OpenPIC_Global Global;
+    /*
+     *  Interrupt Source Configuration Registers
+     */
+    OpenPIC_Source Source[OPENPIC_MAX_SOURCES];
+    /*
+     *  Per Processor Registers
+     */
+    OpenPIC_Processor Processor[OPENPIC_MAX_PROCESSORS];
+};
+
+extern volatile struct OpenPIC *OpenPIC;
+
+
+    /*
+     *  Current Task Priority Register
+     */
+
+#define OPENPIC_CURRENT_TASK_PRIORITY_MASK	0x0000000f
+
+    /*
+     *  Who Am I Register
+     */
+
+#define OPENPIC_WHO_AM_I_ID_MASK		0x0000001f
+
+    /*
+     *  Feature Reporting Register 0
+     */
+
+#define OPENPIC_FEATURE_LAST_SOURCE_MASK	0x07ff0000
+#define OPENPIC_FEATURE_LAST_SOURCE_SHIFT	16
+#define OPENPIC_FEATURE_LAST_PROCESSOR_MASK	0x00001f00
+#define OPENPIC_FEATURE_LAST_PROCESSOR_SHIFT	8
+#define OPENPIC_FEATURE_VERSION_MASK		0x000000ff
+
+    /*
+     *  Global Configuration Register 0
+     */
+
+#define OPENPIC_CONFIG_RESET			0x80000000
+#define OPENPIC_CONFIG_8259_PASSTHROUGH_DISABLE	0x20000000
+#define OPENPIC_CONFIG_BASE_MASK		0x000fffff
+
+    /*
+     *  Global Configuration Register 1
+     *  This is the EICR on EPICs.
+     */
+
+#define OPENPIC_EICR_S_CLK_MASK			0x70000000
+#define OPENPIC_EICR_SIE			0x08000000
+
+    /*
+     *  Vendor Identification Register
+     */
+
+#define OPENPIC_VENDOR_ID_STEPPING_MASK		0x00ff0000
+#define OPENPIC_VENDOR_ID_STEPPING_SHIFT	16
+#define OPENPIC_VENDOR_ID_DEVICE_ID_MASK	0x0000ff00
+#define OPENPIC_VENDOR_ID_DEVICE_ID_SHIFT	8
+#define OPENPIC_VENDOR_ID_VENDOR_ID_MASK	0x000000ff
+
+    /*
+     *  Vector/Priority Registers
+     */
+
+#define OPENPIC_MASK				0x80000000
+#define OPENPIC_ACTIVITY			0x40000000	/* Read Only */
+#define OPENPIC_PRIORITY_MASK			0x000f0000
+#define OPENPIC_PRIORITY_SHIFT			16
+#define OPENPIC_VECTOR_MASK			0x000000ff
+
+
+    /*
+     *  Interrupt Source Registers
+     */
+
+#define OPENPIC_POLARITY_POSITIVE		0x00800000
+#define OPENPIC_POLARITY_NEGATIVE		0x00000000
+#define OPENPIC_POLARITY_MASK			0x00800000
+#define OPENPIC_SENSE_LEVEL			0x00400000
+#define OPENPIC_SENSE_EDGE			0x00000000
+#define OPENPIC_SENSE_MASK			0x00400000
+
+
+    /*
+     *  Timer Registers
+     */
+
+#define OPENPIC_COUNT_MASK			0x7fffffff
+#define OPENPIC_TIMER_TOGGLE			0x80000000
+#define OPENPIC_TIMER_COUNT_INHIBIT		0x80000000
+
+
+    /*
+     *  Aliases to make life simpler
+     */
+
+/* Per Processor Registers */
+#define IPI_Dispatch(i)			_IPI_Dispatch[i].Reg
+#define Current_Task_Priority		_Current_Task_Priority.Reg
+#define Interrupt_Acknowledge		_Interrupt_Acknowledge.Reg
+#define EOI				_EOI.Reg
+
+/* Global Registers */
+#define Feature_Reporting0		_Feature_Reporting0.Reg
+#define Feature_Reporting1		_Feature_Reporting1.Reg
+#define Global_Configuration0		_Global_Configuration0.Reg
+#define Global_Configuration1		_Global_Configuration1.Reg
+#define Vendor_Specific(i)		_Vendor_Specific[i].Reg
+#define Vendor_Identification		_Vendor_Identification.Reg
+#define Processor_Initialization	_Processor_Initialization.Reg
+#define IPI_Vector_Priority(i)		_IPI_Vector_Priority[i].Reg
+#define Spurious_Vector			_Spurious_Vector.Reg
+#define Timer_Frequency			_Timer_Frequency.Reg
+
+/* Timer Registers */
+#define Current_Count			_Current_Count.Reg
+#define Base_Count			_Base_Count.Reg
+#define Vector_Priority			_Vector_Priority.Reg
+#define Destination			_Destination.Reg
+
+/* Interrupt Source Registers */
+#define Vector_Priority			_Vector_Priority.Reg
+#define Destination			_Destination.Reg
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_OPENPIC_H */
diff -Nru a/arch/ppc/syslib/pci_auto.c b/arch/ppc/syslib/pci_auto.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/pci_auto.c	Sun Nov 10 19:28:40 2002
@@ -0,0 +1,519 @@
+/*
+ * arch/ppc/kernel/pci_auto.c
+ * 
+ * PCI autoconfiguration library
+ *
+ * Author: Matt Porter <mporter@mvista.com>
+ *
+ * Copyright 2001 MontaVista Software 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.
+ */
+
+/*
+ * The CardBus support is very preliminary.  Preallocating space is
+ * the way to go but will require some change in card services to
+ * make it useful.  Eventually this will ensure that we can put
+ * multiple CB bridges behind multiple P2P bridges.  For now, at
+ * least it ensures that we place the CB bridge BAR and assigned
+ * initial bus numbers.  I definitely need to do something about
+ * the lack of 16-bit I/O support. -MDP
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/pci-bridge.h>
+
+#define	PCIAUTO_IDE_MODE_MASK		0x05
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif /* DEBUG */
+
+static int pciauto_upper_iospc;
+static int pciauto_upper_memspc;
+
+void __init pciauto_setup_bars(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int bar_limit)
+{
+	int bar_response, bar_size, bar_value;
+	int bar, addr_mask;
+	int * upper_limit;
+	int found_mem64 = 0;
+
+	DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n",
+		current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) );
+
+	for (bar = PCI_BASE_ADDRESS_0; bar <= bar_limit; bar+=4) {
+		/* Tickle the BAR and get the response */
+		early_write_config_dword(hose,
+				current_bus,
+				pci_devfn,
+				bar,
+				0xffffffff);
+		early_read_config_dword(hose,
+				current_bus,
+				pci_devfn,
+				bar,
+				&bar_response);
+
+		/* If BAR is not implemented go to the next BAR */
+		if (!bar_response)
+			continue;
+
+		/* Check the BAR type and set our address mask */
+		if (bar_response & PCI_BASE_ADDRESS_SPACE) {
+			addr_mask = PCI_BASE_ADDRESS_IO_MASK;
+			upper_limit = &pciauto_upper_iospc;
+			DBG("PCI Autoconfig: BAR 0x%x, I/O, ", bar);
+		} else {
+			if ( (bar_response & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+			PCI_BASE_ADDRESS_MEM_TYPE_64)
+				found_mem64 = 1;
+
+			addr_mask = PCI_BASE_ADDRESS_MEM_MASK;		
+			upper_limit = &pciauto_upper_memspc;
+			DBG("PCI Autoconfig: BAR 0x%x, Mem ", bar);
+		}
+
+		/* Calculate requested size */
+		bar_size = ~(bar_response & addr_mask) + 1;
+
+		/* Allocate a base address */
+		bar_value = (*upper_limit - bar_size) & ~(bar_size - 1);
+
+		/* Write it out and update our limit */
+		early_write_config_dword(hose,
+				current_bus,
+				pci_devfn,
+				bar,
+				bar_value);
+
+		*upper_limit = bar_value;
+
+		/*
+		 * If we are a 64-bit decoder then increment to the
+		 * upper 32 bits of the bar and force it to locate
+		 * in the lower 4GB of memory.
+		 */ 
+		if (found_mem64) {
+			bar += 4;
+			early_write_config_dword(hose,
+					current_bus,
+					pci_devfn,
+					bar,
+					0x00000000);
+			found_mem64 = 0;
+		}
+
+		DBG("size=0x%x, address=0x%x\n",
+			bar_size, bar_value);
+	}
+
+}
+
+void __init pciauto_prescan_setup_bridge(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int sub_bus,
+		int *iosave,
+		int *memsave)
+{
+	/* Configure bus number registers */
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PRIMARY_BUS,
+			current_bus);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SECONDARY_BUS,
+			sub_bus + 1);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SUBORDINATE_BUS,
+			0xff);
+
+	/* Round memory allocator to 1MB boundary */
+	pciauto_upper_memspc &= ~(0x100000 - 1);
+	*memsave = pciauto_upper_memspc;
+
+	/* Round I/O allocator to 4KB boundary */
+	pciauto_upper_iospc &= ~(0x1000 - 1);
+	*iosave = pciauto_upper_iospc;
+
+	/* Set up memory and I/O filter limits, assume 32-bit I/O space */
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_MEMORY_LIMIT,
+			((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_IO_LIMIT,
+			((pciauto_upper_iospc - 1) & 0x0000f000) >> 8);
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_IO_LIMIT_UPPER16,
+			((pciauto_upper_iospc - 1) & 0xffff0000) >> 16);
+
+	/* Zero upper 32 bits of prefetchable base/limit */
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PREF_BASE_UPPER32,
+			0);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PREF_LIMIT_UPPER32,
+			0);
+}
+
+void __init pciauto_postscan_setup_bridge(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int sub_bus,
+		int *iosave,
+		int *memsave)
+{
+	int cmdstat;
+
+	/* Configure bus number registers */
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SUBORDINATE_BUS,
+			sub_bus);
+
+	/*
+	 * Round memory allocator to 1MB boundary.
+	 * If no space used, allocate minimum.
+	 */
+	pciauto_upper_memspc &= ~(0x100000 - 1);
+	if (*memsave == pciauto_upper_memspc)
+		pciauto_upper_memspc -= 0x00100000;
+
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_MEMORY_BASE,
+			pciauto_upper_memspc >> 16);
+
+	/* Allocate 1MB for pre-fretch */
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PREF_MEMORY_LIMIT,
+			((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
+
+	pciauto_upper_memspc -= 0x100000;
+
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PREF_MEMORY_BASE,
+			pciauto_upper_memspc >> 16);
+
+	/* Round I/O allocator to 4KB boundary */
+	pciauto_upper_iospc &= ~(0x1000 - 1);
+	if (*iosave == pciauto_upper_iospc)
+		pciauto_upper_iospc -= 0x1000;
+
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_IO_BASE,
+			(pciauto_upper_iospc & 0x0000f000) >> 8);
+	early_write_config_word(hose,
+			current_bus,
+			pci_devfn,
+			PCI_IO_BASE_UPPER16,
+			pciauto_upper_iospc >> 16);
+	
+	/* Enable memory and I/O accesses, enable bus master */
+	early_read_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_COMMAND,
+			&cmdstat);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_COMMAND,
+			cmdstat |
+			PCI_COMMAND_IO |
+			PCI_COMMAND_MEMORY |
+			PCI_COMMAND_MASTER);
+}
+
+void __init pciauto_prescan_setup_cardbus_bridge(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int sub_bus,
+		int *iosave,
+		int *memsave)
+{
+	/* Configure bus number registers */
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_PRIMARY_BUS,
+			current_bus);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SECONDARY_BUS,
+			sub_bus + 1);
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SUBORDINATE_BUS,
+			0xff);
+
+	/* Round memory allocator to 4KB boundary */
+	pciauto_upper_memspc &= ~(0x1000 - 1);
+	*memsave = pciauto_upper_memspc;
+
+	/* Round I/O allocator to 4 byte boundary */
+	pciauto_upper_iospc &= ~(0x4 - 1);
+	*iosave = pciauto_upper_iospc;
+
+	/* Set up memory and I/O filter limits, assume 32-bit I/O space */
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			0x20,
+			pciauto_upper_memspc - 1);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			0x30,
+			pciauto_upper_iospc - 1);
+}
+
+void __init pciauto_postscan_setup_cardbus_bridge(struct pci_controller *hose,
+		int current_bus,
+		int pci_devfn,
+		int sub_bus,
+		int *iosave,
+		int *memsave)
+{
+	int cmdstat;
+
+	/*
+	 * Configure subordinate bus number.  The PCI subsystem
+	 * bus scan will renumber buses (reserving three additional
+	 * for this PCI<->CardBus bridge for the case where a CardBus
+	 * adapter contains a P2P or CB2CB bridge.
+	 */
+	early_write_config_byte(hose,
+			current_bus,
+			pci_devfn,
+			PCI_SUBORDINATE_BUS,
+			sub_bus);
+
+	/*
+	 * Reserve an additional 4MB for mem space and 16KB for
+	 * I/O space.  This should cover any additional space
+	 * requirement of unusual CardBus devices with 
+	 * additional bridges that can consume more address space.
+	 * 
+	 * Although pcmcia-cs currently will reprogram bridge
+	 * windows, the goal is to add an option to leave them
+	 * alone and use the bridge window ranges as the regions
+	 * that are searched for free resources upon hot-insertion
+	 * of a device.  This will allow a PCI<->CardBus bridge
+	 * configured by this routine to happily live behind a
+	 * P2P bridge in a system.
+	 */
+	pciauto_upper_memspc -= 0x00400000;
+	pciauto_upper_iospc -= 0x00004000;
+
+	/* Round memory allocator to 4KB boundary */
+	pciauto_upper_memspc &= ~(0x1000 - 1);
+
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			0x1c,
+			pciauto_upper_memspc);
+
+	/* Round I/O allocator to 4 byte boundary */
+	pciauto_upper_iospc &= ~(0x4 - 1);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			0x2c,
+			pciauto_upper_iospc);
+	
+	/* Enable memory and I/O accesses, enable bus master */
+	early_read_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_COMMAND,
+			&cmdstat);
+	early_write_config_dword(hose,
+			current_bus,
+			pci_devfn,
+			PCI_COMMAND,
+			cmdstat |
+			PCI_COMMAND_IO |
+			PCI_COMMAND_MEMORY |
+			PCI_COMMAND_MASTER);
+}
+
+int __init pciauto_bus_scan(struct pci_controller *hose, int current_bus)
+{
+	int sub_bus, pci_devfn, pci_class, cmdstat, found_multi = 0;
+	unsigned short vid;
+	unsigned char header_type;
+
+	/*
+	 * Fetch our I/O and memory space upper boundaries used
+	 * to allocated base addresses on this hose.
+	 */
+	if (current_bus == hose->first_busno) {
+		pciauto_upper_iospc = hose->io_space.end + 1;
+		pciauto_upper_memspc = hose->mem_space.end + 1;
+	}
+
+	sub_bus = current_bus;
+
+	for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++) {
+		/* Skip our host bridge */
+		if ( (current_bus == hose->first_busno) && (pci_devfn == 0) )
+			continue;
+
+		if (PCI_FUNC(pci_devfn) && !found_multi)
+			continue;
+
+		/* If config space read fails from this device, move on */
+		if (early_read_config_byte(hose,
+				current_bus,
+				pci_devfn,
+				PCI_HEADER_TYPE,
+				&header_type))
+			continue;
+
+		if (!PCI_FUNC(pci_devfn))
+			found_multi = header_type & 0x80;
+
+		early_read_config_word(hose,
+				current_bus,
+				pci_devfn,
+				PCI_VENDOR_ID,
+				&vid);
+
+		if (vid != 0xffff) {
+			early_read_config_dword(hose,
+					current_bus,
+					pci_devfn,
+					PCI_CLASS_REVISION, &pci_class);
+			if ( (pci_class >> 16) == PCI_CLASS_BRIDGE_PCI ) {
+				int iosave, memsave;
+
+				DBG("PCI Autoconfig: Found P2P bridge, device %d\n", PCI_SLOT(pci_devfn));
+				/* Allocate PCI I/O and/or memory space */
+				pciauto_setup_bars(hose,
+						current_bus,
+						pci_devfn,
+						PCI_BASE_ADDRESS_1);
+
+				pciauto_prescan_setup_bridge(hose,
+						current_bus,
+						pci_devfn,
+						sub_bus,
+						&iosave,
+						&memsave);
+				sub_bus = pciauto_bus_scan(hose, sub_bus+1);
+				pciauto_postscan_setup_bridge(hose,
+						current_bus,
+						pci_devfn,
+						sub_bus,
+						&iosave,
+						&memsave);
+			} else if ((pci_class >> 16) == PCI_CLASS_BRIDGE_CARDBUS) {
+				int iosave, memsave;
+
+				DBG("PCI Autoconfig: Found CardBus bridge, device %d function %d\n", PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn));
+				/* Place CardBus Socket/ExCA registers */
+				pciauto_setup_bars(hose,
+						current_bus,
+						pci_devfn,
+						PCI_BASE_ADDRESS_0);
+
+				pciauto_prescan_setup_cardbus_bridge(hose,
+						current_bus,
+						pci_devfn,
+						sub_bus,
+						&iosave,
+						&memsave);
+				sub_bus = pciauto_bus_scan(hose, sub_bus+1);
+				pciauto_postscan_setup_cardbus_bridge(hose,
+						current_bus,
+						pci_devfn,
+						sub_bus,
+						&iosave,
+						&memsave);
+			} else {
+				if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) {
+					unsigned char prg_iface;
+
+					early_read_config_byte(hose,
+							current_bus,
+							pci_devfn,
+							PCI_CLASS_PROG,
+							&prg_iface);
+					if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
+						DBG("PCI Autoconfig: Skipping legacy mode IDE controller\n");
+						continue;
+					}
+				}
+				/* Allocate PCI I/O and/or memory space */
+				pciauto_setup_bars(hose,
+						current_bus,
+						pci_devfn,
+						PCI_BASE_ADDRESS_5);
+
+				/*
+				 * Enable some standard settings
+				 */
+				early_read_config_dword(hose,
+						current_bus,
+						pci_devfn,
+						PCI_COMMAND,
+						&cmdstat);
+				early_write_config_dword(hose,
+						current_bus,
+						pci_devfn,
+						PCI_COMMAND,
+						cmdstat |
+						PCI_COMMAND_IO |
+						PCI_COMMAND_MEMORY |
+						PCI_COMMAND_MASTER);
+				early_write_config_byte(hose,
+						current_bus,
+						pci_devfn,
+						PCI_LATENCY_TIMER,
+						0x80);
+			}
+		}
+	}
+	return sub_bus;
+}
diff -Nru a/arch/ppc/syslib/ppc405_dma.c b/arch/ppc/syslib/ppc405_dma.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/ppc405_dma.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,511 @@
+/*
+ * linux/arch/ppc/kernel/ppc405_dma.c
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	IBM 405 DMA Controller Functions
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	ppopov@mvista.com or source@mvista.com
+ *
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``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  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 OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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/kernel.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/mm.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/module.h>
+
+#include <asm/ppc405_dma.h>
+
+
+/*
+ * Function prototypes
+ */
+
+int hw_init_dma_channel(unsigned int,  ppc_dma_ch_t *);
+int init_dma_channel(unsigned int);
+int get_channel_config(unsigned int, ppc_dma_ch_t *);
+int set_channel_priority(unsigned int, unsigned int);
+unsigned int get_peripheral_width(unsigned int);
+int alloc_dma_handle(sgl_handle_t *, unsigned int, unsigned int);
+void free_dma_handle(sgl_handle_t);
+
+
+ppc_dma_ch_t dma_channels[MAX_405GP_DMA_CHANNELS];
+
+/*
+ * Configures a DMA channel, including the peripheral bus width, if a
+ * peripheral is attached to the channel, the polarity of the DMAReq and
+ * DMAAck signals, etc.  This information should really be setup by the boot 
+ * code, since most likely the configuration won't change dynamically.
+ * If the kernel has to call this function, it's recommended that it's
+ * called from platform specific init code.  The driver should not need to 
+ * call this function.
+ */
+int hw_init_dma_channel(unsigned int dmanr,  ppc_dma_ch_t *p_init)
+{
+    unsigned int polarity;
+    uint32_t control = 0;
+    ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+
+#ifdef DEBUG_405DMA
+    if (!p_init) {
+        printk("hw_init_dma_channel: NULL p_init\n");
+        return DMA_STATUS_NULL_POINTER;
+    }
+    if (dmanr >= MAX_405GP_DMA_CHANNELS) {
+        printk("hw_init_dma_channel: bad channel %d\n", dmanr);
+        return DMA_STATUS_BAD_CHANNEL;
+    }
+#endif
+
+#if DCRN_POL > 0
+    polarity = mfdcr(DCRN_POL);
+#else
+    polarity = 0;
+#endif
+
+    /* Setup the control register based on the values passed to
+     * us in p_init.  Then, over-write the control register with this
+     * new value.
+     */
+
+    control |= ( 
+                SET_DMA_CIE_ENABLE(p_init->int_enable) | /* interrupt enable         */
+                SET_DMA_BEN(p_init->buffer_enable)     | /* buffer enable            */ 
+                SET_DMA_ETD(p_init->etd_output)        | /* end of transfer pin      */
+                SET_DMA_TCE(p_init->tce_enable)        | /* terminal count enable    */
+                SET_DMA_PL(p_init->pl)                 | /* peripheral location      */
+                SET_DMA_DAI(p_init->dai)               | /* dest addr increment      */
+                SET_DMA_SAI(p_init->sai)               | /* src addr increment       */
+                SET_DMA_PRIORITY(p_init->cp)           |  /* channel priority        */
+                SET_DMA_PW(p_init->pwidth)             |  /* peripheral/bus width    */
+                SET_DMA_PSC(p_init->psc)               |  /* peripheral setup cycles */
+                SET_DMA_PWC(p_init->pwc)               |  /* peripheral wait cycles  */
+                SET_DMA_PHC(p_init->phc)               |  /* peripheral hold cycles  */
+                SET_DMA_PREFETCH(p_init->pf)              /* read prefetch           */
+                );
+
+    switch (dmanr) {
+        case 0:
+            /* clear all polarity signals and then "or" in new signal levels */
+            polarity &= ~(DMAReq0_ActiveLow | DMAAck0_ActiveLow | EOT0_ActiveLow);
+            polarity |= p_dma_ch->polarity;
+#if DCRN_POL > 0
+            mtdcr(DCRN_POL, polarity);
+#endif
+            mtdcr(DCRN_DMACR0, control);
+            break;
+        case 1:
+            polarity &= ~(DMAReq1_ActiveLow | DMAAck1_ActiveLow | EOT1_ActiveLow);
+            polarity |= p_dma_ch->polarity;
+#if DCRN_POL > 0
+            mtdcr(DCRN_POL, polarity);
+#endif
+            mtdcr(DCRN_DMACR1, control);
+            break;
+        case 2:
+            polarity &= ~(DMAReq2_ActiveLow | DMAAck2_ActiveLow | EOT2_ActiveLow);
+            polarity |= p_dma_ch->polarity;
+#if DCRN_POL > 0
+            mtdcr(DCRN_POL, polarity);
+#endif
+            mtdcr(DCRN_DMACR2, control);
+            break;
+        case 3:
+            polarity &= ~(DMAReq3_ActiveLow | DMAAck3_ActiveLow | EOT3_ActiveLow);
+            polarity |= p_dma_ch->polarity;
+#if DCRN_POL > 0
+            mtdcr(DCRN_POL, polarity);
+#endif
+            mtdcr(DCRN_DMACR3, control);
+            break;
+        default:
+            return DMA_STATUS_BAD_CHANNEL;
+    }
+    
+    /* save these values in our dma channel structure */
+    memcpy(p_dma_ch, p_init, sizeof(ppc_dma_ch_t));
+
+    /*
+     * The peripheral width values written in the control register are:
+     *   PW_8                 0
+     *   PW_16                1
+     *   PW_32                2
+     *   PW_64                3
+     *
+     *   Since the DMA count register takes the number of "transfers",
+     *   we need to divide the count sent to us in certain
+     *   functions by the appropriate number.  It so happens that our
+     *   right shift value is equal to the peripheral width value.
+     */
+    p_dma_ch->shift = p_init->pwidth;
+
+    /*
+     * Save the control word for easy access.
+     */
+    p_dma_ch->control = control;
+
+    mtdcr(DCRN_DMASR, 0xffffffff); /* clear status register */
+    return DMA_STATUS_GOOD;
+}
+
+
+
+
+/*
+ * This function returns the channel configuration.
+ */
+int get_channel_config(unsigned int dmanr, ppc_dma_ch_t *p_dma_ch)
+{
+    unsigned int polarity;
+    unsigned int control;
+
+#if DCRN_POL > 0
+    polarity = mfdcr(DCRN_POL);
+#else
+    polarity = 0;
+#endif
+
+    switch (dmanr) {
+        case 0:
+            p_dma_ch->polarity = 
+                polarity & (DMAReq0_ActiveLow | DMAAck0_ActiveLow | EOT0_ActiveLow);
+            control = mfdcr(DCRN_DMACR0);
+            break;
+        case 1:
+            p_dma_ch->polarity = 
+                polarity & (DMAReq1_ActiveLow | DMAAck1_ActiveLow | EOT1_ActiveLow);
+            control = mfdcr(DCRN_DMACR1);
+            break;
+        case 2:
+            p_dma_ch->polarity = 
+                polarity & (DMAReq2_ActiveLow | DMAAck2_ActiveLow | EOT2_ActiveLow);
+            control = mfdcr(DCRN_DMACR2);
+            break;
+        case 3:
+            p_dma_ch->polarity = 
+                polarity & (DMAReq3_ActiveLow | DMAAck3_ActiveLow | EOT3_ActiveLow);
+            control = mfdcr(DCRN_DMACR3);
+            break;
+        default:
+            return DMA_STATUS_BAD_CHANNEL;
+    }
+
+    p_dma_ch->cp = GET_DMA_PRIORITY(control);
+    p_dma_ch->pwidth = GET_DMA_PW(control);
+    p_dma_ch->psc = GET_DMA_PSC(control);
+    p_dma_ch->pwc = GET_DMA_PWC(control);
+    p_dma_ch->phc = GET_DMA_PHC(control);
+    p_dma_ch->pf = GET_DMA_PREFETCH(control);
+    p_dma_ch->int_enable = GET_DMA_CIE_ENABLE(control);
+    p_dma_ch->shift = GET_DMA_PW(control);
+
+    return DMA_STATUS_GOOD;
+}
+
+/*
+ * Sets the priority for the DMA channel dmanr.
+ * Since this is setup by the hardware init function, this function 
+ * can be used to dynamically change the priority of a channel.
+ *
+ * Acceptable priorities:
+ *
+ * PRIORITY_LOW
+ * PRIORITY_MID_LOW
+ * PRIORITY_MID_HIGH
+ * PRIORITY_HIGH
+ *
+ */
+int set_channel_priority(unsigned int dmanr, unsigned int priority)
+{
+    unsigned int control;
+
+#ifdef DEBUG_405DMA
+    if ( (priority != PRIORITY_LOW) &&
+            (priority != PRIORITY_MID_LOW) &&
+            (priority != PRIORITY_MID_HIGH) &&
+            (priority != PRIORITY_HIGH)) {
+        printk("set_channel_priority: bad priority: 0x%x\n", priority);
+    }
+#endif
+
+    switch (dmanr) {
+        case 0:
+            control = mfdcr(DCRN_DMACR0);
+            control|= SET_DMA_PRIORITY(priority);
+            mtdcr(DCRN_DMACR0, control);
+            break;
+        case 1:
+            control = mfdcr(DCRN_DMACR1);
+            control|= SET_DMA_PRIORITY(priority);
+            mtdcr(DCRN_DMACR1, control);
+            break;
+        case 2:
+            control = mfdcr(DCRN_DMACR2);
+            control|= SET_DMA_PRIORITY(priority);
+            mtdcr(DCRN_DMACR2, control);
+            break;
+        case 3:
+            control = mfdcr(DCRN_DMACR3);
+            control|= SET_DMA_PRIORITY(priority);
+            mtdcr(DCRN_DMACR3, control);
+            break;
+        default:
+#ifdef DEBUG_405DMA
+            printk("set_channel_priority: bad channel: %d\n", dmanr);
+#endif
+            return DMA_STATUS_BAD_CHANNEL;
+    }
+    return DMA_STATUS_GOOD;
+}
+
+
+
+/*
+ * Returns the width of the peripheral attached to this channel. This assumes
+ * that someone who knows the hardware configuration, boot code or some other 
+ * init code, already set the width.
+ *
+ * The return value is one of:
+ *   PW_8
+ *   PW_16
+ *   PW_32
+ *   PW_64
+ *
+ *   The function returns 0 on error.
+ */
+unsigned int get_peripheral_width(unsigned int dmanr)
+{
+    unsigned int control;
+
+    switch (dmanr) {
+        case 0:
+            control = mfdcr(DCRN_DMACR0);
+            break;
+        case 1:
+            control = mfdcr(DCRN_DMACR1);
+            break;
+        case 2:
+            control = mfdcr(DCRN_DMACR2);
+            break;
+        case 3:
+            control = mfdcr(DCRN_DMACR3);
+            break;
+        default:
+#ifdef DEBUG_405DMA
+            printk("get_peripheral_width: bad channel: %d\n", dmanr);
+#endif
+            return 0;
+    }
+    return(GET_DMA_PW(control));
+}
+
+
+
+
+/*
+ *   Create a scatter/gather list handle.  This is simply a structure which
+ *   describes a scatter/gather list.
+ *
+ *   A handle is returned in "handle" which the driver should save in order to 
+ *   be able to access this list later.  A chunk of memory will be allocated 
+ *   to be used by the API for internal management purposes, including managing 
+ *   the sg list and allocating memory for the sgl descriptors.  One page should 
+ *   be more than enough for that purpose.  Perhaps it's a bit wasteful to use 
+ *   a whole page for a single sg list, but most likely there will be only one 
+ *   sg list per channel.
+ *
+ *   Interrupt notes:
+ *   Each sgl descriptor has a copy of the DMA control word which the DMA engine
+ *   loads in the control register.  The control word has a "global" interrupt 
+ *   enable bit for that channel. Interrupts are further qualified by a few bits
+ *   in the sgl descriptor count register.  In order to setup an sgl, we have to
+ *   know ahead of time whether or not interrupts will be enabled at the completion
+ *   of the transfers.  Thus, enable_dma_interrupt()/disable_dma_interrupt() MUST
+ *   be called before calling alloc_dma_handle().  If the interrupt mode will never
+ *   change after powerup, then enable_dma_interrupt()/disable_dma_interrupt() 
+ *   do not have to be called -- interrupts will be enabled or disabled based
+ *   on how the channel was configured after powerup by the hw_init_dma_channel()
+ *   function.  Each sgl descriptor will be setup to interrupt if an error occurs;
+ *   however, only the last descriptor will be setup to interrupt. Thus, an 
+ *   interrupt will occur (if interrupts are enabled) only after the complete
+ *   sgl transfer is done.
+ */
+int alloc_dma_handle(sgl_handle_t *phandle, unsigned int mode, unsigned int dmanr)
+{
+    sgl_list_info_t *psgl;
+    dma_addr_t dma_addr;
+    ppc_dma_ch_t *p_dma_ch = &dma_channels[dmanr];
+    uint32_t sg_command;
+    void *ret;
+
+#ifdef DEBUG_405DMA
+    if (!phandle) {
+            printk("alloc_dma_handle: null handle pointer\n");
+            return DMA_STATUS_NULL_POINTER;
+    }
+    switch (mode) {
+        case DMA_MODE_READ:
+        case DMA_MODE_WRITE:
+        case DMA_MODE_MM:
+        case DMA_MODE_MM_DEVATSRC:
+        case DMA_MODE_MM_DEVATDST:
+            break;
+        default:
+            printk("alloc_dma_handle: bad mode 0x%x\n", mode);
+            return DMA_STATUS_BAD_MODE;
+    }
+    if (dmanr >= MAX_405GP_DMA_CHANNELS) {
+        printk("alloc_dma_handle: invalid channel 0x%x\n", dmanr);
+        return DMA_STATUS_BAD_CHANNEL;
+    }
+#endif
+
+    /* Get a page of memory, which is zeroed out by pci_alloc_consistent() */
+
+/* wrong not a pci device - armin */
+    /* psgl = (sgl_list_info_t *) pci_alloc_consistent(NULL, SGL_LIST_SIZE, &dma_addr);
+*/
+
+	ret = consistent_alloc(GFP_ATOMIC |GFP_DMA, SGL_LIST_SIZE, &dma_addr);
+	if (ret != NULL) {
+		memset(ret, 0,SGL_LIST_SIZE );
+		psgl = (sgl_list_info_t *) ret;
+	}
+
+
+    if (psgl == NULL) {
+        *phandle = (sgl_handle_t)NULL;
+        return DMA_STATUS_OUT_OF_MEMORY;
+    }
+
+    psgl->dma_addr = dma_addr;
+    psgl->dmanr = dmanr;
+
+    /*
+     * Modify and save the control word. These word will get written to each sgl
+     * descriptor.  The DMA engine then loads this control word into the control
+     * register every time it reads a new descriptor.
+     */
+    psgl->control = p_dma_ch->control;
+    psgl->control &= ~(DMA_TM_MASK | DMA_TD);  /* clear all "mode" bits first               */
+    psgl->control |= (mode | DMA_CH_ENABLE);   /* save the control word along with the mode */
+
+    if (p_dma_ch->int_enable) {
+        psgl->control |= DMA_CIE_ENABLE;       /* channel interrupt enabled                 */
+    }
+    else {
+        psgl->control &= ~DMA_CIE_ENABLE;
+    }
+
+#if DCRN_ASGC > 0
+    sg_command = mfdcr(DCRN_ASGC);
+    switch (dmanr) {
+        case 0:
+            sg_command |= SSG0_MASK_ENABLE;
+            break;
+        case 1:
+            sg_command |= SSG1_MASK_ENABLE;
+            break;
+        case 2:
+            sg_command |= SSG2_MASK_ENABLE;
+            break;
+        case 3:
+            sg_command |= SSG3_MASK_ENABLE;
+            break;
+        default:
+#ifdef DEBUG_405DMA
+            printk("alloc_dma_handle: bad channel: %d\n", dmanr);
+#endif
+            free_dma_handle((sgl_handle_t)psgl);
+            *phandle = (sgl_handle_t)NULL;
+            return DMA_STATUS_BAD_CHANNEL;
+    }
+
+    mtdcr(DCRN_ASGC, sg_command);  /* enable writing to this channel's sgl control bits */
+#else
+   (void)sg_command;
+#endif
+    psgl->sgl_control = SG_ERI_ENABLE | SG_LINK;   /* sgl descriptor control bits */
+
+    if (p_dma_ch->int_enable) {
+        if (p_dma_ch->tce_enable)
+            psgl->sgl_control |= SG_TCI_ENABLE;
+        else
+            psgl->sgl_control |= SG_ETI_ENABLE;
+    }
+
+    *phandle = (sgl_handle_t)psgl;
+    return DMA_STATUS_GOOD;
+}
+
+
+
+/*
+ * Destroy a scatter/gather list handle that was created by alloc_dma_handle().
+ * The list must be empty (contain no elements).
+ */
+void free_dma_handle(sgl_handle_t handle)
+{
+    sgl_list_info_t *psgl = (sgl_list_info_t *)handle;
+
+    if (!handle) {
+#ifdef DEBUG_405DMA
+        printk("free_dma_handle: got NULL\n");
+#endif
+        return;
+    }
+    else if (psgl->phead) {
+#ifdef DEBUG_405DMA
+        printk("free_dma_handle: list not empty\n");
+#endif
+        return;
+    }
+    else if (!psgl->dma_addr) { /* should never happen */
+#ifdef DEBUG_405DMA
+        printk("free_dma_handle: no dma address\n");
+#endif
+        return;
+    }
+
+  /* wrong not a PCI device -armin */
+  /*  pci_free_consistent(NULL, SGL_LIST_SIZE, (void *)psgl, psgl->dma_addr); */
+	//	free_pages((unsigned long)psgl, get_order(SGL_LIST_SIZE));
+    	consistent_free((void *)psgl);
+
+
+}
+
+
+EXPORT_SYMBOL(hw_init_dma_channel);
+EXPORT_SYMBOL(get_channel_config);
+EXPORT_SYMBOL(set_channel_priority);
+EXPORT_SYMBOL(get_peripheral_width);
+EXPORT_SYMBOL(alloc_dma_handle);
+EXPORT_SYMBOL(free_dma_handle);
+EXPORT_SYMBOL(dma_channels);
diff -Nru a/arch/ppc/syslib/ppc405_pci.c b/arch/ppc/syslib/ppc405_pci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/ppc405_pci.c	Sun Nov 10 19:28:40 2002
@@ -0,0 +1,207 @@
+/*
+ * FILE NAME: ppc405_pci.c
+ *
+ * BRIEF MODULE DESCRIPTION: 
+ * Based on arch/ppc/kernel/indirect.c, Copyright (C) 1998 Gabriel Paubert.
+ *
+ * Author: MontaVista Software, Inc.  <source@mvista.com>
+ *         Frank Rowand <frank_rowand@mvista.com>
+ *         Debbie Chu   <debbie_chu@mvista.com>
+ *
+ * Copyright 2000 MontaVista Software 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  SOFTWARE  IS PROVIDED   ``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  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 OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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/pci.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <linux/init.h>
+#include <asm/ibm4xx.h>
+#include <asm/pci-bridge.h>
+#include <platforms/4xx/ibm_ocp.h>
+
+#ifdef  CONFIG_DEBUG_BRINGUP
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+extern void bios_fixup(struct pci_controller *, void *);
+extern int ppc405_map_irq(struct pci_dev *dev, unsigned char idsel,
+			  unsigned char pin);
+extern struct pcil0_regs *PCIL_ADDR[];
+
+void
+ppc405_pcibios_fixup_resources(struct pci_dev *dev)
+{
+	int i;
+	unsigned long max_host_addr;
+	unsigned long min_host_addr;
+	struct resource *res;
+
+	/*
+	 * openbios puts some graphics cards in the same range as the host
+	 * controller uses to map to SDRAM.  Fix it.
+	 */
+
+	min_host_addr = 0;
+	max_host_addr = PPC405_PCI_MEM_BASE - 1;
+
+	for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+		res = dev->resource + i;
+		if (!res->start)
+			continue;
+		if ((res->flags & IORESOURCE_MEM) &&
+		    (((res->start >= min_host_addr)
+		      && (res->start <= max_host_addr))
+		     || ((res->end >= min_host_addr)
+			 && (res->end <= max_host_addr))
+		     || ((res->start < min_host_addr)
+			 && (res->end > max_host_addr))
+		    )
+		    ) {
+
+			DBG(KERN_ERR "PCI: 0x%lx <= resource[%d] <= 0x%lx"
+			    ", bus 0x%x dev 0x%2.2x.%1.1x,\n"
+			    KERN_ERR "  %s\n"
+			    KERN_ERR "  fixup will be attempted later\n",
+			    min_host_addr, i, max_host_addr,
+			    dev->bus->number, PCI_SLOT(dev->devfn),
+			    PCI_FUNC(dev->devfn), dev->name);
+
+			/* force pcibios_assign_resources() to assign a new address */
+			res->end -= res->start;
+			res->start = 0;
+		}
+	}
+}
+
+static int
+ppc4xx_exclude_device(unsigned char bus, unsigned char devfn)
+{
+	/* We prevent us from seeing ourselves to avoid having
+	 * the kernel try to remap our BAR #1 and fuck up bus
+	 * master from external PCI devices
+	 */
+	return (bus == 0 && devfn == 0);
+}
+
+void
+ppc4xx_find_bridges(void)
+{
+	struct pci_controller *hose_a;
+	struct pcil0_regs *pcip;
+	unsigned int tmp_addr;
+	unsigned int tmp_size;
+	unsigned int reg_index;
+	unsigned int new_pmm_max;
+	unsigned int new_pmm_min;
+
+	isa_io_base = 0;
+	isa_mem_base = 0;
+	pci_dram_offset = 0;
+	
+	/* Check if running in slave mode */
+	if ((mfdcr(DCRN_CHPSR) & PSR_PCI_ARBIT_EN) == 0) {
+		printk("Running as PCI slave, kernel PCI disabled !\n");
+		return;
+	}
+	/* Setup PCI32 hose */
+	hose_a = pcibios_alloc_controller();
+	if (!hose_a)
+		return;
+	setup_indirect_pci(hose_a, PPC405_PCI_CONFIG_ADDR,
+			   PPC405_PCI_CONFIG_DATA);
+	pcip = ioremap((unsigned long) PCIL_ADDR[0], PAGE_SIZE);
+	if (pcip != NULL) {
+
+#if defined(CONFIG_BIOS_FIXUP)
+		bios_fixup(hose_a, pcip);
+#endif
+		new_pmm_min = 0xffffffff;
+		for (reg_index = 0; reg_index < 3; reg_index++) {
+			tmp_size = in_le32((void *) &(pcip->pmm[reg_index].ma));	// *_PMM0MA
+			if (tmp_size & 0x1) {
+				tmp_addr = in_le32((void *) &(pcip->pmm[reg_index].pcila));	// *_PMM0PCILA
+				if (tmp_addr < PPC405_PCI_PHY_MEM_BASE) {
+					printk(KERN_DEBUG
+					       "Disabling mapping to PCI mem addr 0x%8.8x\n",
+					       tmp_addr);
+					out_le32((void *) &(pcip->pmm[reg_index].ma), tmp_size & ~1);	// *_PMMOMA
+				} else {
+					tmp_addr = in_le32((void *) &(pcip->pmm[reg_index].la));	// *_PMMOLA
+					if (tmp_addr < new_pmm_min)
+						new_pmm_min = tmp_addr;
+					tmp_addr =
+					    tmp_addr + (0xffffffff -
+							(tmp_size &
+							 0xffffc000));
+					if (tmp_addr > PPC405_PCI_UPPER_MEM) {
+						new_pmm_max = tmp_addr;	// PPC405_PCI_UPPER_MEM 
+					} else {
+						new_pmm_max =
+						    PPC405_PCI_UPPER_MEM;
+					}
+				}
+			}
+
+		}		// for
+
+		iounmap(pcip);
+	}
+	hose_a->first_busno      = 0;
+	hose_a->last_busno       = 0xff;
+	hose_a->pci_mem_offset   = 0;
+
+	/* Setup bridge memory/IO ranges & resources
+	 * TODO: Handle firmwares setting up a legacy ISA mem base
+	 */
+	hose_a->io_space.start		= PPC405_PCI_LOWER_IO;
+	hose_a->io_space.end		= PPC405_PCI_UPPER_IO;
+	hose_a->mem_space.start		= new_pmm_min;
+	hose_a->mem_space.end		= new_pmm_max;
+	hose_a->io_base_phys		= PPC405_PCI_PHY_IO_BASE;
+	hose_a->io_base_virt		= ioremap(hose_a->io_base_phys, 0x10000);
+	hose_a->io_resource.start	= 0;
+	hose_a->io_resource.end		= PPC405_PCI_UPPER_IO-PPC405_PCI_LOWER_IO;
+	hose_a->io_resource.flags	= IORESOURCE_IO;
+	hose_a->io_resource.name	= "PCI I/O";
+	hose_a->mem_resources[0].start	= new_pmm_min;
+	hose_a->mem_resources[0].end	= new_pmm_max;
+	hose_a->mem_resources[0].flags	= IORESOURCE_MEM;
+	hose_a->mem_resources[0].name	= "PCI Memory";
+	isa_io_base			= (int)hose_a->io_base_virt;
+	isa_mem_base			= 0;	      /*     ISA not implemented */
+	ISA_DMA_THRESHOLD		= 0x00ffffff; /* ??? ISA not implemented */
+
+	/* Scan busses & initial setup by pci_auto */
+	hose_a->last_busno = pciauto_bus_scan(hose_a, hose_a->first_busno);
+	hose_a->last_busno = 0;
+
+	/* Setup ppc_md */
+	ppc_md.pcibios_fixup     	= NULL;
+	ppc_md.pci_exclude_device	= ppc4xx_exclude_device;
+	ppc_md.pcibios_fixup_resources	= ppc405_pcibios_fixup_resources;
+	ppc_md.pci_swizzle		= common_swizzle;
+	ppc_md.pci_map_irq		= ppc405_map_irq;
+}
diff -Nru a/arch/ppc/syslib/ppc4xx_kgdb.c b/arch/ppc/syslib/ppc4xx_kgdb.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/ppc4xx_kgdb.c	Sun Nov 10 19:28:40 2002
@@ -0,0 +1,124 @@
+#include <linux/config.h>
+#include <linux/types.h>
+#include <asm/ibm4xx.h>
+#include <linux/kernel.h>
+
+
+
+#define LSR_DR		0x01 /* Data ready */
+#define LSR_OE		0x02 /* Overrun */
+#define LSR_PE		0x04 /* Parity error */
+#define LSR_FE		0x08 /* Framing error */
+#define LSR_BI		0x10 /* Break */
+#define LSR_THRE	0x20 /* Xmit holding register empty */
+#define LSR_TEMT	0x40 /* Xmitter empty */
+#define LSR_ERR		0x80 /* Error */
+
+#include <platforms/4xx/ibm_ocp.h>
+
+extern struct NS16550* COM_PORTS[];
+#ifndef NULL
+#define NULL 0x00
+#endif
+
+static volatile struct NS16550 *kgdb_debugport = NULL;
+
+volatile struct NS16550 *
+NS16550_init(int chan)
+{
+	volatile struct NS16550 *com_port;
+	int quot;
+#ifdef BASE_BAUD
+	quot = BASE_BAUD / 9600;
+#else
+	quot = 0x000c; /* 0xc = 9600 baud (on a pc) */
+#endif
+
+	com_port = (struct NS16550 *) COM_PORTS[chan];
+
+	com_port->lcr = 0x00;
+	com_port->ier = 0xFF;
+	com_port->ier = 0x00;
+	com_port->lcr = com_port->lcr | 0x80; /* Access baud rate */
+	com_port->dll = ( quot & 0x00ff ); /* 0xc = 9600 baud */
+	com_port->dlm = ( quot & 0xff00 ) >> 8;
+	com_port->lcr = 0x03; /* 8 data, 1 stop, no parity */
+	com_port->mcr = 0x00; /* RTS/DTR */
+	com_port->fcr = 0x07; /* Clear & enable FIFOs */
+
+	return( com_port );
+}
+
+
+void
+NS16550_putc(volatile struct NS16550 *com_port, unsigned char c)
+{
+	while ((com_port->lsr & LSR_THRE) == 0)
+		;
+	com_port->thr = c;
+	return;
+}
+
+unsigned char
+NS16550_getc(volatile struct NS16550 *com_port)
+{
+	while ((com_port->lsr & LSR_DR) == 0)
+		;
+	return (com_port->rbr);
+}
+
+unsigned char
+NS16550_tstc(volatile struct NS16550 *com_port)
+{
+	return ((com_port->lsr & LSR_DR) != 0);
+}
+
+
+#if defined(CONFIG_KGDB_TTYS0)
+#define KGDB_PORT 0
+#elif defined(CONFIG_KGDB_TTYS1)
+#define KGDB_PORT 1
+#elif defined(CONFIG_KGDB_TTYS2)
+#define KGDB_PORT 2
+#elif defined(CONFIG_KGDB_TTYS3)
+#define KGDB_PORT 3
+#else
+#error "invalid kgdb_tty port"
+#endif
+
+void putDebugChar( unsigned char c )
+{
+	if ( kgdb_debugport == NULL )
+		kgdb_debugport = NS16550_init(KGDB_PORT);
+	NS16550_putc( kgdb_debugport, c );
+}
+
+int getDebugChar( void )
+{
+	if (kgdb_debugport == NULL)
+		kgdb_debugport = NS16550_init(KGDB_PORT);
+
+	return(NS16550_getc(kgdb_debugport));
+}
+
+void kgdb_interruptible(int enable)
+{
+	return;
+}
+
+void putDebugString(char* str)
+{
+	while (*str != '\0') {
+		putDebugChar(*str);
+		str++;
+	}
+	putDebugChar('\r');
+	return;
+}
+
+void
+kgdb_map_scc(void)
+{
+	printk("kgdb init \n");
+	kgdb_debugport = NS16550_init(KGDB_PORT);
+}
diff -Nru a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/ppc4xx_pic.c	Sun Nov 10 19:28:36 2002
@@ -0,0 +1,348 @@
+/*
+ *
+ *    Copyright (c) 1999 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Module name: ppc4xx_pic.c
+ *
+ *    Description:
+ *      Interrupt controller driver for PowerPC 4xx-based processors.
+ */
+
+/*
+ * The PowerPC 403 cores' Asynchronous Interrupt Controller (AIC) has
+ * 32 possible interrupts, a majority of which are not implemented on
+ * all cores. There are six configurable, external interrupt pins and
+ * there are eight internal interrupts for the on-chip serial port
+ * (SPU), DMA controller, and JTAG controller.
+ *
+ * The PowerPC 405/440 cores' Universal Interrupt Controller (UIC) has
+ * 32 possible interrupts as well.  Depending on the core and SoC
+ * implementation, a portion of the interrrupts are used for on-chip
+ * peripherals and a portion of the interrupts are available to be
+ * configured for external devices generating interrupts.
+ *
+ * The PowerNP and 440GP (and most likely future implementations) have
+ * cascaded UICs.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/stddef.h>
+
+#include <asm/processor.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/ppc4xx_pic.h>
+
+/* Global Variables */
+struct hw_interrupt_type *ppc4xx_pic;
+
+/* Six of one, half dozen of the other....#ifdefs, separate files,
+ * other tricks.....
+ *
+ * There are basically two types of interrupt controllers, the 403 AIC
+ * and the "others" with UIC.  I just kept them both here separated
+ * with #ifdefs, but it seems to change depending upon how supporting
+ * files (like ppc4xx.h) change.		-- Dan.
+ */
+
+#ifdef CONFIG_403
+
+/* Function Prototypes */
+
+static void ppc403_aic_enable(unsigned int irq);
+static void ppc403_aic_disable(unsigned int irq);
+static void ppc403_aic_disable_and_ack(unsigned int irq);
+
+static struct hw_interrupt_type ppc403_aic = {
+	"403GC AIC",
+	NULL,
+	NULL,
+	ppc403_aic_enable,
+	ppc403_aic_disable,
+	ppc403_aic_disable_and_ack,
+	0
+};
+
+int
+ppc403_pic_get_irq(struct pt_regs *regs)
+{
+	int irq;
+	unsigned long bits;
+
+	/*
+	 * Only report the status of those interrupts that are actually
+	 * enabled.
+	 */
+
+	bits = mfdcr(DCRN_EXISR) & mfdcr(DCRN_EXIER);
+
+	/*
+	 * Walk through the interrupts from highest priority to lowest, and
+	 * report the first pending interrupt found.
+	 * We want PPC, not C bit numbering, so just subtract the ffs()
+	 * result from 32.
+	 */
+	irq = 32 - ffs(bits);
+
+	if (irq == NR_AIC_IRQS)
+		irq = -1;
+
+	return (irq);
+}
+
+static void
+ppc403_aic_enable(unsigned int irq)
+{
+	int bit, word;
+
+	bit = irq & 0x1f;
+	word = irq >> 5;
+
+	ppc_cached_irq_mask[word] |= (1 << (31 - bit));
+	mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
+}
+
+static void
+ppc403_aic_disable(unsigned int irq)
+{
+	int bit, word;
+
+	bit = irq & 0x1f;
+	word = irq >> 5;
+
+	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
+}
+
+static void
+ppc403_aic_disable_and_ack(unsigned int irq)
+{
+	int bit, word;
+
+	bit = irq & 0x1f;
+	word = irq >> 5;
+
+	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	mtdcr(DCRN_EXIER, ppc_cached_irq_mask[word]);
+	mtdcr(DCRN_EXISR, (1 << (31 - bit)));
+}
+
+#else
+
+#ifndef UIC1
+#define UIC1 UIC0
+#endif
+
+static void
+ppc405_uic_enable(unsigned int irq)
+{
+	int bit, word;
+
+	bit = irq & 0x1f;
+	word = irq >> 5;
+#ifdef UIC_DEBUG	
+	printk("ppc405_uic_enable - irq %d word %d bit 0x%x\n",irq, word , bit);
+#endif
+	ppc_cached_irq_mask[word] |= 1 << (31 - bit);
+	switch (word){
+		case 0:
+			mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
+		break;
+		case 1:
+			mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
+		break;
+	}
+}
+
+static void
+ppc405_uic_disable(unsigned int irq)
+{
+	int bit, word;
+
+	bit = irq & 0x1f;
+	word = irq >> 5;
+#ifdef UIC_DEBUG	
+	printk("ppc405_uic_disable - irq %d word %d bit 0x%x\n",irq, word , bit);
+#endif
+	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	switch (word){
+		case 0:
+			mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
+		break;
+		case 1:
+			mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
+		break;
+	}
+}
+
+static void
+ppc405_uic_disable_and_ack(unsigned int irq)
+{
+	int bit, word;
+
+	bit = irq & 0x1f;
+	word = irq >> 5;
+
+#ifdef UIC_DEBUG	
+printk("ppc405_uic_disable_and_ack - irq %d word %d bit 0x%x\n",irq, word , bit);
+#endif
+	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	switch (word){
+		case 0:
+			mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
+			mtdcr(DCRN_UIC_SR(UIC0), (1 << (31 - bit)));
+		break;
+		case 1:	
+			mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
+			mtdcr(DCRN_UIC_SR(UIC1), (1 << (31 - bit)));
+		break;
+	}
+}
+
+static void
+ppc405_uic_end(unsigned int irq)
+{
+	int bit, word;
+	unsigned int tr_bits;
+
+	bit = irq & 0x1f;
+	word = irq >> 5;
+
+#ifdef UIC_DEBUG	
+	printk("ppc405_uic_end - irq %d word %d bit 0x%x\n",irq, word , bit);
+#endif
+
+	switch (word){
+		case 0:
+			tr_bits = mfdcr(DCRN_UIC_TR(UIC0));
+		break;
+		case 1:
+			tr_bits = mfdcr(DCRN_UIC_TR(UIC1));
+		break;
+	}
+
+	if ((tr_bits & (1 << (31 - bit))) == 0) {
+		/* level trigger */
+		switch (word){
+			case 0:
+				mtdcr(DCRN_UIC_SR(UIC0), 1 << (31 - bit));
+			break;
+			case 1:
+				mtdcr(DCRN_UIC_SR(UIC1), 1 << (31 - bit));
+			break;
+		}
+	}
+
+	if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS))
+	    && irq_desc[irq].action) {
+		ppc_cached_irq_mask[word] |= 1 << (31 - bit);
+		switch (word){
+			case 0:
+				mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[word]);
+			break;
+			case 1:
+				mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[word]);
+			break;
+		}
+	}
+}
+
+static struct hw_interrupt_type ppc405_uic = {
+#if (NR_UICS == 1)
+	"IBM UIC",
+#else
+	"IBM UIC Cascade",
+#endif
+	NULL,
+	NULL,
+	ppc405_uic_enable,
+	ppc405_uic_disable,
+	ppc405_uic_disable_and_ack,
+	ppc405_uic_end,
+	0
+};
+
+int
+ppc405_pic_get_irq(struct pt_regs *regs)
+{
+	int irq, cas_irq;
+	unsigned long bits;
+	cas_irq = 0;
+	/*
+	 * Only report the status of those interrupts that are actually
+	 * enabled.
+	 */
+
+	bits = mfdcr(DCRN_UIC_MSR(UIC0));
+
+#if (NR_UICS > 1) 
+	if (bits & UIC_CASCADE_MASK){
+		bits = mfdcr(DCRN_UIC_MSR(UIC1));
+		cas_irq = 32 - ffs(bits);
+		irq = 32 + cas_irq;
+	} else {
+		irq = 32 - ffs(bits);
+		if (irq == 32)
+			irq= -1;
+	}
+#else
+	/*
+	 * Walk through the interrupts from highest priority to lowest, and
+	 * report the first pending interrupt found.
+	 * We want PPC, not C bit numbering, so just subtract the ffs()
+	 * result from 32.
+	 */
+	irq = 32 - ffs(bits);
+#endif
+	if (irq == (NR_UIC_IRQS * NR_UICS))
+		irq = -1;
+
+#ifdef UIC_DEBUG
+printk("ppc405_pic_get_irq - irq %d bit 0x%x\n",irq, bits);
+#endif
+
+	return (irq);
+}
+#endif
+
+void __init
+ppc4xx_pic_init(void)
+{
+	/*
+	 * Disable all external interrupts until they are
+	 * explicity requested.
+	 */
+	ppc_cached_irq_mask[0] = 0;
+	ppc_cached_irq_mask[1] = 0;
+
+#if defined CONFIG_403
+	mtdcr(DCRN_EXIER, ppc_cached_irq_mask[0]);
+
+	ppc4xx_pic = &ppc403_aic;
+	ppc_md.get_irq = ppc403_pic_get_irq;
+#else
+#if  (NR_UICS > 1) 
+	ppc_cached_irq_mask[0] |= 1 << (31 - UIC0_UIC1NC ); /* enable cascading interrupt */
+	mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
+	mtdcr(DCRN_UIC_ER(UIC1), ppc_cached_irq_mask[1]);
+
+	/* Set all interrupts to non-critical.
+	 */
+	mtdcr(DCRN_UIC_CR(UIC0), 0);
+	mtdcr(DCRN_UIC_CR(UIC1), 0);
+
+#else	
+	mtdcr(DCRN_UIC_ER(UIC0), ppc_cached_irq_mask[0]);
+
+	/* Set all interrupts to non-critical.
+	 */
+	mtdcr(DCRN_UIC_CR(UIC0), 0);
+#endif
+
+	ppc4xx_pic = &ppc405_uic;
+	ppc_md.get_irq = ppc405_pic_get_irq;
+#endif
+}
diff -Nru a/arch/ppc/syslib/ppc4xx_pm.c b/arch/ppc/syslib/ppc4xx_pm.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/ppc4xx_pm.c	Sun Nov 10 19:28:37 2002
@@ -0,0 +1,75 @@
+/*
+ *	file: ppc4xx_pm.c
+ *
+ *	This an attempt to get Power Management going for the IBM 4xx processor.
+ *	This was derived from the ppc4xx._setup.c file
+ *
+ *      Armin Kuster akuster@mvista.com
+ *      Jan  2002
+ *
+ *
+ * Copyright 2002 MontaVista Softare 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  SOFTWARE  IS PROVIDED   ``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  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 OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ *
+ *	Version 1.0 (02/14/01) - A. Kuster
+ *	Initial version	 - moved pm code from ppc4xx_setup.c
+ *
+ *	1.1 02/21/01 - A. Kuster
+ *		minor fixes, init value to 0 & += to &=
+ *		added stb03 ifdef for 2nd i2c device
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+
+#include <asm/ibm4xx.h>
+
+void __init
+ppc4xx_pm_init(void)
+{
+
+	unsigned int value = 0;
+
+	/* turn off unused hardware to save power */
+#ifdef CONFIG_405GP
+	value |= CPM_DCP;	/* CodePack */
+#endif
+
+#if !defined(CONFIG_IBM_OCP_GPIO)
+	value |= CPM_GPIO0;
+#endif
+
+#if !defined(CONFIG_PPC405_I2C_ADAP)
+	value |= CPM_IIC0;
+#ifdef CONFIG_STB03xxx
+	value |= CPM_IIC1;
+#endif
+#endif
+
+
+#if !defined(CONFIG_405_DMA)
+	value |= CPM_DMA;
+#endif
+
+	mtdcr(DCRN_CPMFR, value);
+
+}
diff -Nru a/arch/ppc/syslib/ppc4xx_serial.c b/arch/ppc/syslib/ppc4xx_serial.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/ppc4xx_serial.c	Sun Nov 10 19:28:36 2002
@@ -0,0 +1,190 @@
+
+/*
+ * linux/arch/ppc/kernel/ppc405_serial.c
+ *
+ * This is a fairly standard 165xx type device that will eventually
+ * be merged with other similar processor/boards.	-- Dan
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Console I/O support for Early kernel bringup. 
+ *
+ * Copyright 2000 MontaVista Software Inc.
+ * Author: MontaVista Software, Inc.
+ *         	frank_rowand@mvista.com or source@mvista.com
+ * 	   	debbie_chu@mvista.com
+ *
+ *
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``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  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 OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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>
+
+#if defined(CONFIG_IBM405GP) || defined(CONFIG_IBM405CR)
+
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#include <linux/init.h>
+#endif
+
+#ifdef CONFIG_DEBUG_BRINGUP
+
+#include <linux/console.h>
+
+extern void ftr_reset_preferred_console(void);
+
+
+static int ppc405_sercons_setup(struct console *co, char *options)
+{
+#ifdef CONFIG_UART0_DEBUG_CONSOLE
+    volatile unsigned char *uart_dll  = (char *)0xef600300;
+    volatile unsigned char *uart_fcr  = (char *)0xef600302;
+    volatile unsigned char *uart_lcr  = (char *)0xef600303;
+#endif
+
+#ifdef CONFIG_UART1_DEBUG_CONSOLE
+    volatile unsigned char *uart_dll  = (char *)0xef600400;
+    volatile unsigned char *uart_fcr  = (char *)0xef600402;
+    volatile unsigned char *uart_lcr  = (char *)0xef600403;
+#endif
+
+    *uart_lcr = *uart_lcr | 0x80;   /* DLAB on  */
+
+/* ftr revisit - there is no config option for this
+**  also see include/asm-ppc/ppc405_serial.h
+**
+** #define CONFIG_IBM405GP_INTERNAL_CLOCK
+*/
+
+
+#ifdef  CONFIG_IBM405GP_INTERNAL_CLOCK 
+    /* ftr revisit
+    ** why is bit 19 of chcr0 (0x1000) being set?
+    */
+    /* 0x2a results in data corruption, kgdb works with 0x28 */
+    *uart_dll = 0x28;		    /* 9600 baud */
+    _put_CHCR0((_get_CHCR0() & 0xffffe000) | 0x103e);
+#else
+    *uart_dll = 0x48;		    /* 9600 baud */
+#endif
+    *uart_lcr = *uart_lcr & 0x7f;   /* DLAB off */
+
+    return 0;
+}
+
+
+/*
+ * This is a bringup hack, writing directly to uart0 or uart1
+ */
+
+static void
+ppc405_sercons_write(struct console *co, const char *ptr,
+            unsigned nb)
+{ 
+    int i;
+
+#ifdef CONFIG_UART0_DEBUG_CONSOLE
+    volatile unsigned char *uart_xmit = (char *)0xef600300;
+    volatile unsigned char *uart_lsr  = (char *)0xef600305;
+#endif
+
+#ifdef CONFIG_UART1_DEBUG_CONSOLE
+    volatile unsigned char *uart_xmit = (char *)0xef600400;
+    volatile unsigned char *uart_lsr  = (char *)0xef600405;
+#endif
+
+    for (i = 0; i < nb; ++i) {
+
+	/* wait for transmit reg (possibly fifo) to empty */
+	while ((*uart_lsr & 0x40) == 0)
+	    ;
+
+	*uart_xmit = (ptr[i] & 0xff);
+
+	if (ptr[i] == '\n') {
+
+	    /* add a carriage return */
+	
+	    /* wait for transmit reg (possibly fifo) to empty */
+	    while ((*uart_lsr & 0x40) == 0)
+		;
+
+	    *uart_xmit = '\r';
+	}
+    }
+
+    return;
+}
+
+
+static int
+ppc405_sercons_read(struct console *co, char *ptr, unsigned nb)
+{ 
+#ifdef CONFIG_UART0_DEBUG_CONSOLE
+    volatile unsigned char *uart_rcv  = (char *)0xef600300;
+    volatile unsigned char *uart_lsr  = (char *)0xef600305;
+#endif
+
+#ifdef CONFIG_UART1_DEBUG_CONSOLE
+    volatile unsigned char *uart_rcv  = (char *)0xef600400;
+    volatile unsigned char *uart_lsr  = (char *)0xef600405;
+#endif
+
+
+    /* ftr revisit: not tested */
+
+    if (nb == 0)
+	return(0);
+
+    if (!ptr)
+	return(-1);
+
+    /* wait for receive reg (possibly fifo) to contain data */
+    while ((*uart_lsr & 0x01) == 0)
+	;
+
+    *ptr = *uart_rcv;
+
+    return(1);
+}
+
+static struct console ppc405_sercons = {
+	.name =		"dbg_cons",
+	.write =	ppc405_console_write,
+	.setup =	ppc405_console_setup,
+	.flags =	CON_PRINTBUFFER,
+	.index =	-1,
+};
+
+void
+register_debug_console(void)
+{
+	register_console(&ppc405_sercons); 
+}
+
+void
+unregister_debug_console(void)
+{
+	unregister_console(&ppc405_sercons);
+}
+
+#endif	/* CONFIG_DEBUG_BRINGUP */
+
+#endif	/* #if defined(CONFIG_IBM405GP) || defined(CONFIG_IBM405CR) */
diff -Nru a/arch/ppc/syslib/ppc4xx_setup.c b/arch/ppc/syslib/ppc4xx_setup.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/ppc4xx_setup.c	Sun Nov 10 19:28:36 2002
@@ -0,0 +1,360 @@
+/*
+ *
+ *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
+ *
+ *    Copyright 2000-2001 MontaVista Software Inc.
+ *      Completed implementation.
+ *      Author: MontaVista Software, Inc.  <source@mvista.com>
+ *              Frank Rowand <frank_rowand@mvista.com>
+ *              Debbie Chu   <debbie_chu@mvista.com>
+ *
+ *    Module name: ppc4xx_setup.c
+ *
+ *    Description:
+ *      Architecture- / platform-specific boot-time initialization code for
+ *      IBM PowerPC 4xx based boards. Adapted from original
+ *      code by Gary Thomas, Cort Dougan <cort@fsmlabs.com>, and Dan Malek
+ *      <dan@net4x.com>.
+ *
+ * 	History: 11/09/2001 - armin
+ *	rename board_setup_nvram_access to board_init. board_init is
+ *	used for all other board specific instructions needed during
+ *	platform_init.
+ *	moved RTC to board.c files
+ *	moved VT/FB to board.c files
+ *	moved r/w4 ide to redwood.c
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/threads.h>
+#include <linux/spinlock.h>
+#include <linux/irq.h>
+#include <linux/reboot.h>
+#include <linux/param.h>
+#include <linux/string.h>
+#include <linux/blk.h>
+#include <linux/pci.h>
+#include <linux/rtc.h>
+#include <linux/console.h>
+#include <linux/ide.h>
+#include <linux/serial_reg.h>
+#include <linux/seq_file.h>
+
+#include <asm/system.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/page.h>
+#include <asm/kgdb.h>
+#include <asm/ibm4xx.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+#include <asm/ppc4xx_pic.h>
+#include <asm/pci-bridge.h>
+#include <asm/bootinfo.h>
+
+/* Function Prototypes */
+extern void abort(void);
+extern void ppc4xx_find_bridges(void);
+
+extern void ppc4xx_wdt_heartbeat(void);
+extern int wdt_enable;
+extern unsigned long wdt_period;
+
+/* Board specific functions */
+extern void board_setup_arch(void);
+extern void board_io_mapping(void);
+extern void board_setup_irq(void);
+extern void board_init(void);
+
+/* Global Variables */
+unsigned char __res[sizeof (bd_t)];
+
+static void __init
+ppc4xx_setup_arch(void)
+{
+
+	/* Setup PCI host bridges */
+
+#ifdef CONFIG_PCI
+	ppc4xx_find_bridges();
+#endif
+
+#if defined(CONFIG_FB)
+	conswitchp = &dummy_con;
+#endif
+
+	board_setup_arch();
+}
+
+/*
+ *   This routine pretty-prints the platform's internal CPU clock
+ *   frequencies into the buffer for usage in /proc/cpuinfo.
+ */
+
+static int
+ppc4xx_show_percpuinfo(struct seq_file *m, int i)
+{
+	bd_t *bip = (bd_t *) __res;
+
+	seq_printf(m, "clock\t\t: %ldMHz\n", (long) bip->bi_intfreq / 1000000);
+
+	return 0;
+}
+
+/*
+ *   This routine pretty-prints the platform's internal bus clock
+ *   frequencies into the buffer for usage in /proc/cpuinfo.
+ */
+static int
+ppc4xx_show_cpuinfo(struct seq_file *m)
+{
+	bd_t *bip = (bd_t *) __res;
+
+	seq_printf(m, "machine\t\t: %s\n", PPC4xx_MACHINE_NAME);
+	seq_printf(m, "plb bus clock\t: %ldMHz\n",
+		   (long) bip->bi_busfreq / 1000000);
+#ifdef CONFIG_PCI
+	seq_printf(m, "pci bus clock\t: %dMHz\n",
+		   bip->bi_pci_busfreq / 1000000);
+#endif
+
+	return 0;
+}
+
+/*
+ * Return the virtual address representing the top of physical RAM.
+ */
+static unsigned long __init
+ppc4xx_find_end_of_memory(void)
+{
+	bd_t *bip = (bd_t *) __res;
+
+	return ((unsigned long) bip->bi_memsize);
+}
+
+static void __init
+m4xx_map_io(void)
+{
+	io_block_mapping(PPC4xx_ONB_IO_VADDR,
+			 PPC4xx_ONB_IO_PADDR, PPC4xx_ONB_IO_SIZE, _PAGE_IO);
+#ifdef CONFIG_PCI
+	io_block_mapping(PPC4xx_PCI_IO_VADDR,
+			 PPC4xx_PCI_IO_PADDR, PPC4xx_PCI_IO_SIZE, _PAGE_IO);
+	io_block_mapping(PPC4xx_PCI_CFG_VADDR,
+			 PPC4xx_PCI_CFG_PADDR, PPC4xx_PCI_CFG_SIZE, _PAGE_IO);
+	io_block_mapping(PPC4xx_PCI_LCFG_VADDR,
+			 PPC4xx_PCI_LCFG_PADDR, PPC4xx_PCI_LCFG_SIZE, _PAGE_IO);
+#endif
+	board_io_mapping();
+}
+
+static void __init
+ppc4xx_init_IRQ(void)
+{
+	int i;
+
+	ppc4xx_pic_init();
+
+	for (i = 0; i < NR_IRQS; i++)
+		irq_desc[i].handler = ppc4xx_pic;
+
+	/* give board specific code a chance to setup things */
+	board_setup_irq();
+	return;
+}
+
+static void
+ppc4xx_restart(char *cmd)
+{
+	printk("%s\n", cmd);
+	abort();
+}
+
+static void
+ppc4xx_power_off(void)
+{
+	printk("System Halted\n");
+	local_irq_disable();
+	while (1) ;
+}
+
+static void
+ppc4xx_halt(void)
+{
+	printk("System Halted\n");
+	local_irq_disable();
+	while (1) ;
+}
+
+/*
+ * This routine retrieves the internal processor frequency from the board
+ * information structure, sets up the kernel timer decrementer based on
+ * that value, enables the 4xx programmable interval timer (PIT) and sets
+ * it up for auto-reload.
+ */
+static void __init
+ppc4xx_calibrate_decr(void)
+{
+	unsigned int freq;
+	bd_t *bip = (bd_t *) __res;
+
+#if defined(CONFIG_WALNUT) || defined(CONFIG_CEDER)
+	/* Walnut boot rom sets DCR CHCR1 (aka CPC0_CR1) bit CETE to 1 */
+	mtdcr(DCRN_CHCR1, mfdcr(DCRN_CHCR1) & ~CHR1_CETE);
+#endif
+#ifdef CONFIG_REDWOOD_5
+	freq = bip->bi_tbfreq;
+#else
+	freq = bip->bi_intfreq;
+
+#endif
+
+	tb_ticks_per_jiffy = freq / HZ;
+	tb_to_us = mulhwu_scale_factor(freq, 1000000);
+
+	/* Set the time base to zero.
+	   ** At 200 Mhz, time base will rollover in ~2925 years.
+	 */
+
+	mtspr(SPRN_TBWL, 0);
+	mtspr(SPRN_TBWU, 0);
+
+	/* Clear any pending timer interrupts */
+
+	mtspr(SPRN_TSR, TSR_ENW | TSR_WIS | TSR_PIS | TSR_FIS);
+	mtspr(SPRN_TCR, TCR_PIE | TCR_ARE);
+
+	/* Set the PIT reload value and just let it run. */
+	mtspr(SPRN_PIT, tb_ticks_per_jiffy);
+}
+
+#ifdef CONFIG_DEBUG_TEXT
+static void
+ppc4xx_progress(char *s, unsigned short hex)
+{
+	printk("%s\n\r", s);
+}
+#endif
+
+/*
+ * IDE stuff.
+ * should be generic for every IDE PCI chipset
+ */
+#ifdef  CONFIG_PCI
+static void
+ppc4xx_ide_init_hwif_ports(hw_regs_t * hw, ide_ioreg_t data_port,
+			   ide_ioreg_t ctrl_port, int *irq)
+{
+	int i;
+
+	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; ++i)
+		hw->io_ports[i] = data_port + i - IDE_DATA_OFFSET;
+
+	hw->io_ports[IDE_CONTROL_OFFSET] = ctrl_port;
+}
+#endif
+
+TODC_ALLOC();
+
+/*
+ * 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.
+ */
+void __init
+platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+	      unsigned long r6, unsigned long r7)
+{
+	parse_bootinfo(find_bootinfo());
+
+	/*
+	 * 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));
+	}
+#if defined(CONFIG_PPC405_WDT)
+/* Look for wdt= option on command line */
+	if (strstr(cmd_line, "wdt=")) {
+		int valid_wdt = 0;
+		char *p, *q;
+		for (q = cmd_line; (p = strstr(q, "wdt=")) != 0;) {
+			q = p + 4;
+			if (p > cmd_line && p[-1] != ' ')
+				continue;
+			wdt_period = simple_strtoul(q, &q, 0);
+			valid_wdt = 1;
+			++q;
+		}
+		wdt_enable = valid_wdt;
+	}
+#endif
+
+	/* Initialize machine-dependency vectors */
+
+	ppc_md.setup_arch = ppc4xx_setup_arch;
+	ppc_md.show_percpuinfo = ppc4xx_show_percpuinfo;
+	ppc_md.show_cpuinfo = ppc4xx_show_cpuinfo;
+	ppc_md.init_IRQ = ppc4xx_init_IRQ;
+
+	ppc_md.restart = ppc4xx_restart;
+	ppc_md.power_off = ppc4xx_power_off;
+	ppc_md.halt = ppc4xx_halt;
+
+	ppc_md.calibrate_decr = ppc4xx_calibrate_decr;
+
+#ifdef CONFIG_PPC405_WDT
+	ppc_md.heartbeat = ppc4xx_wdt_heartbeat;
+#endif
+	ppc_md.heartbeat_count = 0;
+
+	ppc_md.find_end_of_memory = ppc4xx_find_end_of_memory;
+	ppc_md.setup_io_mappings = m4xx_map_io;
+
+#ifdef CONFIG_DEBUG_TEXT
+	ppc_md.progress = ppc4xx_progress;
+#endif
+
+/*
+**   m8xx_setup.c, prep_setup.c use
+**     defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+*/
+#ifdef CONFIG_IDE
+# ifdef CONFIG_PCI
+	ppc_ide_md.ide_init_hwif = ppc4xx_ide_init_hwif_ports;
+# endif
+#endif
+	board_init();
+
+	return;
+}
diff -Nru a/arch/ppc/syslib/ppc8260_pic.c b/arch/ppc/syslib/ppc8260_pic.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/ppc8260_pic.c	Sun Nov 10 19:28:40 2002
@@ -0,0 +1,131 @@
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/irq.h>
+#include <asm/immap_8260.h>
+#include <asm/mpc8260.h>
+#include "ppc8260_pic.h"
+
+/* The 8260 internal interrupt controller.  It is usually
+ * the only interrupt controller.
+ * There are two 32-bit registers (high/low) for up to 64
+ * possible interrupts.
+ *
+ * Now, the fun starts.....Interrupt Numbers DO NOT MAP
+ * in a simple arithmetic fashion to mask or pending registers.
+ * That is, interrupt 4 does not map to bit position 4.
+ * We create two tables, indexed by vector number, to indicate
+ * which register to use and which bit in the register to use.
+ */
+static	u_char	irq_to_siureg[] = {
+	1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static	u_char	irq_to_siubit[] = {
+	31, 16, 17, 18, 19, 20, 21, 22,
+	23, 24, 25, 26, 27, 28, 29, 30,
+	29, 30, 16, 17, 18, 19, 20, 21,
+	22, 23, 24, 25, 26, 27, 28, 31,
+	 0,  1,  2,  3,  4,  5,  6,  7,
+	 8,  9, 10, 11, 12, 13, 14, 15,
+	15, 14, 13, 12, 11, 10,  9,  8,
+	 7,  6,  5,  4,  3,  2,  1,  0
+};
+
+static void m8260_mask_irq(unsigned int irq_nr)
+{
+	int	bit, word;
+	volatile uint	*simr;
+
+	bit = irq_to_siubit[irq_nr];
+	word = irq_to_siureg[irq_nr];
+
+	simr = &(immr->im_intctl.ic_simrh);
+	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void m8260_unmask_irq(unsigned int irq_nr)
+{
+	int	bit, word;
+	volatile uint	*simr;
+
+	bit = irq_to_siubit[irq_nr];
+	word = irq_to_siureg[irq_nr];
+
+	simr = &(immr->im_intctl.ic_simrh);
+	ppc_cached_irq_mask[word] |= (1 << (31 - bit));
+	simr[word] = ppc_cached_irq_mask[word];
+}
+
+static void m8260_mask_and_ack(unsigned int irq_nr)
+{
+	int	bit, word;
+	volatile uint	*simr, *sipnr;
+
+	bit = irq_to_siubit[irq_nr];
+	word = irq_to_siureg[irq_nr];
+
+	simr = &(immr->im_intctl.ic_simrh);
+	sipnr = &(immr->im_intctl.ic_sipnrh);
+	ppc_cached_irq_mask[word] &= ~(1 << (31 - bit));
+	simr[word] = ppc_cached_irq_mask[word];
+	sipnr[word] = 1 << (31 - bit);
+}
+
+static void m8260_end_irq(unsigned int irq_nr)
+{
+	int	bit, word;
+	volatile uint	*simr;
+
+	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
+			&& irq_desc[irq_nr].action) {
+
+		bit = irq_to_siubit[irq_nr];
+		word = irq_to_siureg[irq_nr];
+
+		simr = &(immr->im_intctl.ic_simrh);
+		ppc_cached_irq_mask[word] |= (1 << (31 - bit));
+		simr[word] = ppc_cached_irq_mask[word];
+	}
+}
+
+struct hw_interrupt_type ppc8260_pic = {
+	" 8260 SIU  ",
+	NULL,
+	NULL,
+	m8260_unmask_irq,
+	m8260_mask_irq,
+	m8260_mask_and_ack,
+	m8260_end_irq,
+	0
+};
+
+
+int
+m8260_get_irq(struct pt_regs *regs)
+{
+	int irq;
+        unsigned long bits;
+
+        /* For MPC8260, read the SIVEC register and shift the bits down
+         * to get the irq number.         */
+        bits = immr->im_intctl.ic_sivec;
+        irq = bits >> 26;
+
+	if (irq == 0)
+		return(-1);
+#if 0
+        irq += ppc8260_pic.irq_offset;
+#endif
+	return irq;
+}
+
diff -Nru a/arch/ppc/syslib/ppc8260_pic.h b/arch/ppc/syslib/ppc8260_pic.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/ppc8260_pic.h	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,13 @@
+#ifndef _PPC_KERNEL_PPC8260_H
+#define _PPC_KERNEL_PPC8260_H
+
+#include <linux/irq.h>
+
+extern struct hw_interrupt_type ppc8260_pic;
+
+void m8260_pic_init(void);
+void m8260_do_IRQ(struct pt_regs *regs,
+                 int            cpu);
+int m8260_get_irq(struct pt_regs *regs);
+
+#endif /* _PPC_KERNEL_PPC8260_H */
diff -Nru a/arch/ppc/syslib/ppc8xx_pic.c b/arch/ppc/syslib/ppc8xx_pic.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/ppc8xx_pic.c	Sun Nov 10 19:28:38 2002
@@ -0,0 +1,197 @@
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <asm/irq.h>
+#include <asm/8xx_immap.h>
+#include <asm/mpc8xx.h>
+#include "ppc8xx_pic.h"
+
+/* The 8xx internal interrupt controller.  It is usually
+ * the only interrupt controller.  Some boards, like the MBX and
+ * Sandpoint have the 8259 as a secondary controller.  Depending
+ * upon the processor type, the internal controller can have as
+ * few as 16 interrups or as many as 64.  We could use  the
+ * "clear_bit()" and "set_bit()" functions like other platforms,
+ * but they are overkill for us.
+ */
+
+static void m8xx_mask_irq(unsigned int irq_nr)
+{
+	int	bit, word;
+
+	bit = irq_nr & 0x1f;
+	word = irq_nr >> 5;
+
+	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
+						ppc_cached_irq_mask[word];
+}
+
+static void m8xx_unmask_irq(unsigned int irq_nr)
+{
+	int	bit, word;
+
+	bit = irq_nr & 0x1f;
+	word = irq_nr >> 5;
+
+	ppc_cached_irq_mask[word] |= (1 << (31-bit));
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
+						ppc_cached_irq_mask[word];
+}
+
+static void m8xx_end_irq(unsigned int irq_nr)
+{
+	if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))
+			&& irq_desc[irq_nr].action) {
+		int bit, word;
+
+		bit = irq_nr & 0x1f;
+		word = irq_nr >> 5;
+
+		ppc_cached_irq_mask[word] |= (1 << (31-bit));
+		((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask = 
+			ppc_cached_irq_mask[word];
+	}
+}
+
+
+static void m8xx_mask_and_ack(unsigned int irq_nr)
+{
+	int	bit, word;
+
+	bit = irq_nr & 0x1f;
+	word = irq_nr >> 5;
+
+	ppc_cached_irq_mask[word] &= ~(1 << (31-bit));
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_simask =
+						ppc_cached_irq_mask[word];
+	((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sipend = 1 << (31-bit);
+}
+
+struct hw_interrupt_type ppc8xx_pic = {
+	" 8xx SIU  ",
+	NULL,
+	NULL,
+	m8xx_unmask_irq,
+	m8xx_mask_irq,
+	m8xx_mask_and_ack,
+	m8xx_end_irq,
+	0
+};
+
+#if 0
+void
+m8xx_do_IRQ(struct pt_regs *regs,
+	   int            cpu)
+{
+	int irq;
+        unsigned long bits = 0;
+
+        /* For MPC8xx, read the SIVEC register and shift the bits down
+         * to get the irq number.         */
+        bits = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec;
+        irq = bits >> 26;
+#if 0
+        irq += ppc8xx_pic.irq_offset;
+#endif
+        bits = 1UL << irq;
+
+	if (irq < 0) {
+		printk(KERN_DEBUG "Bogus interrupt %d from PC = %lx\n",
+		       irq, regs->nip);
+		ppc_spurious_interrupts++;
+	}
+	else {
+                ppc_irq_dispatch_handler( regs, irq );
+	}
+
+}
+#endif
+
+
+/*
+ * We either return a valid interrupt or -1 if there is nothing pending
+ */
+int
+m8xx_get_irq(struct pt_regs *regs)
+{
+	int irq;
+
+	/* For MPC8xx, read the SIVEC register and shift the bits down
+	 * to get the irq number.
+	 */
+	irq = ((immap_t *)IMAP_ADDR)->im_siu_conf.sc_sivec >> 26;
+
+	/*
+	 * When we read the sivec without an interrupt to process, we will 
+	 * get back SIU_LEVEL7.  In this case, return -1
+	 */
+	if (irq == SIU_LEVEL7)
+		return -1;
+
+	return irq;
+}
+
+/* The MBX is the only 8xx board that uses the 8259.
+*/
+#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
+void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+	int bits, irq;
+
+	/* A bug in the QSpan chip causes it to give us 0xff always
+	 * when doing a character read.  So read 32 bits and shift.
+	 * This doesn't seem to return useful values anyway, but
+	 * read it to make sure things are acked.
+	 * -- Cort
+	 */
+	irq = (inl(0x508) >> 24)&0xff;
+	if ( irq != 0xff ) printk("iack %d\n", irq);
+	
+	outb(0x0C, 0x20);
+	irq = inb(0x20) & 7;
+	if (irq == 2)
+	{
+		outb(0x0C, 0xA0);
+		irq = inb(0xA0);
+		irq = (irq&7) + 8;
+	}
+	bits = 1UL << irq;
+	irq += i8259_pic.irq_offset;
+	ppc_irq_dispatch_handler( regs, irq );
+}
+#endif
+
+/* Only the MBX uses the external 8259.  This allows us to catch standard
+ * drivers that may mess up the internal interrupt controllers, and also
+ * allow them to run without modification on the MBX.
+ */
+int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+	unsigned long irqflags, const char * devname, void *dev_id)
+{
+
+#if defined(CONFIG_MBX) && defined(CONFIG_PCI)
+	irq += i8259_pic.irq_offset;
+	return (request_8xxirq(irq, handler, irqflags, devname, dev_id));
+#else
+	/*
+	 * Handle other "well-known" interrupts, but panic on unknown ones.
+	 */
+	switch (irq) {
+#ifdef	IDE0_INTERRUPT
+		case IDE0_INTERRUPT:	/* IDE0 */
+			return (request_8xxirq(irq, handler, irqflags, devname,
+						dev_id));
+#endif
+#ifdef	IDE1_INTERRUPT
+		case IDE1_INTERRUPT:	/* IDE1 */
+			return (request_8xxirq(irq, handler, irqflags, devname,
+						dev_id));
+#endif
+	default:			/* unknown IRQ -> panic */
+		panic("request_irq");
+	}
+#endif
+}
diff -Nru a/arch/ppc/syslib/ppc8xx_pic.h b/arch/ppc/syslib/ppc8xx_pic.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/ppc8xx_pic.h	Sun Nov 10 19:28:39 2002
@@ -0,0 +1,20 @@
+#ifndef _PPC_KERNEL_PPC8xx_H
+#define _PPC_KERNEL_PPC8xx_H
+
+#include <linux/config.h>
+#include <linux/irq.h>
+
+extern struct hw_interrupt_type ppc8xx_pic;
+
+void m8xx_pic_init(void);
+void m8xx_do_IRQ(struct pt_regs *regs,
+                 int            cpu);
+int m8xx_get_irq(struct pt_regs *regs);
+
+#ifdef CONFIG_MBX
+#include <asm/i8259.h>
+#include <asm/io.h>
+void mbx_i8259_action(int cpl, void *dev_id, struct pt_regs *regs);
+#endif
+
+#endif /* _PPC_KERNEL_PPC8xx_H */
diff -Nru a/arch/ppc/syslib/pplus_common.c b/arch/ppc/syslib/pplus_common.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/pplus_common.c	Sun Nov 10 19:28:40 2002
@@ -0,0 +1,317 @@
+/*
+ * arch/ppc/kernel/pplus_common.c
+ * 
+ * Common Motorola PowerPlus Platform--really Falcon/Raven or HAWK.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001 MontaVista Software 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.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pci.h>
+#include <asm/pci-bridge.h>
+#include <asm/open_pic.h>
+#include <asm/pplus.h>
+
+/*
+ * The Falcon/Raven and HAWK has 4 sets of registers:
+ *   1) PPC Registers which define the mappings from PPC bus to PCI bus,
+ *      etc.
+ *   2) PCI Registers which define the mappings from PCI bus to PPC bus and the
+ *      MPIC base address.
+ *   3) MPIC registers.
+ *   4) System Memory Controller (SMC) registers.
+ */
+
+/*
+ * Initialize the Motorola MCG Raven or HAWK host bridge.
+ *
+ * This means setting up the PPC bus to PCI memory and I/O space mappings,
+ * setting the PCI memory space address of the MPIC (mapped straight
+ * through), and ioremap'ing the mpic registers.
+ * This routine will set the PCI_CONFIG_ADDR or PCI_CONFIG_DATA
+ * addresses based on the PCI I/O address that is passed in.
+ * 'OpenPIC_Addr' will be set correctly by this routine.
+ */
+int __init
+pplus_init(struct pci_controller *hose,
+	     uint ppc_reg_base,
+	     ulong processor_pci_mem_start,
+	     ulong processor_pci_mem_end,
+	     ulong processor_pci_io_start,
+	     ulong processor_pci_io_end,
+	     ulong processor_mpic_base)
+{
+	uint		addr, offset;
+
+	/*
+	 * Some sanity checks...
+	 */
+	if (((processor_pci_mem_start&0xffff0000) != processor_pci_mem_start) ||
+	    ((processor_pci_io_start &0xffff0000) != processor_pci_io_start)) {
+		printk("pplus_init: %s\n",
+			"PPC to PCI mappings must start on 64 KB boundaries");
+		return -1;
+	}
+
+	if (((processor_pci_mem_end  &0x0000ffff) != 0x0000ffff) ||
+	    ((processor_pci_io_end   &0x0000ffff) != 0x0000ffff)) {
+		printk("pplus_init: PPC to PCI mappings %s\n",
+			"must end just before a 64 KB boundaries");
+		return -1;
+	}
+
+	if (((processor_pci_mem_end - processor_pci_mem_start) !=
+	     (hose->mem_space.end - hose->mem_space.start)) ||
+	    ((processor_pci_io_end - processor_pci_io_start) !=
+	     (hose->io_space.end - hose->io_space.start))) {
+		printk("pplus_init: %s\n",
+			"PPC and PCI memory or I/O space sizes don't match");
+		return -1;
+	}
+
+	if ((processor_mpic_base & 0xfffc0000) != processor_mpic_base) {
+		printk("pplus_init: %s\n",
+			"MPIC address must start on 256 MB boundary");
+		return -1;
+	}
+
+	if ((pci_dram_offset & 0xffff0000) != pci_dram_offset) {
+		printk("pplus_init: %s\n",
+			"pci_dram_offset must be multiple of 64 KB");
+		return -1;
+	}
+
+	/*
+	 * Disable previous PPC->PCI mappings.
+	 */
+	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF0_OFF), 0x00000000);
+	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF1_OFF), 0x00000000);
+	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF2_OFF), 0x00000000);
+	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF3_OFF), 0x00000000);
+
+	/*
+	 * Program the XSADD/XSOFF registers to set up the PCI Mem & I/O
+	 * space mappings.  These are the mappings going from the processor to
+	 * the PCI bus.
+	 *
+	 * Note: Don't need to 'AND' start/end addresses with 0xffff0000
+	 *	 because sanity check above ensures that they are properly
+	 *	 aligned.
+	 */
+
+	/* Set up PPC->PCI Mem mapping */
+	addr = processor_pci_mem_start | (processor_pci_mem_end >> 16);
+	offset = (hose->mem_space.start - processor_pci_mem_start) | 0xd2;
+	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD0_OFF), addr);
+	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF0_OFF), offset);
+
+	/* Set up PPC->MPIC mapping on the bridge */
+	addr = processor_mpic_base |
+	        (((processor_mpic_base + PPLUS_MPIC_SIZE) >> 16) - 1);
+	offset = 0xc2; /* No write posting for this PCI Mem space */
+	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD1_OFF), addr);
+	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF1_OFF), offset);
+
+	/* Set up PPC->PCI I/O mapping -- Contiguous I/O space */
+	addr = processor_pci_io_start | (processor_pci_io_end >> 16);
+	offset = (hose->io_space.start - processor_pci_io_start) | 0xc0;
+	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSADD3_OFF), addr);
+	out_be32((uint *)(ppc_reg_base + PPLUS_PPC_XSOFF3_OFF), offset);
+
+	hose->io_base_virt = (void *)ioremap(processor_pci_io_start,
+			(processor_pci_io_end - processor_pci_io_start + 1));
+
+	/*
+	 * Set up the indirect method of accessing PCI config space.
+	 * The PCI config addr/data pair based on start addr of PCI I/O space.
+	 */
+	setup_indirect_pci(hose,
+			   processor_pci_io_start + PPLUS_PCI_CONFIG_ADDR_OFF,
+			   processor_pci_io_start + PPLUS_PCI_CONFIG_DATA_OFF);
+
+	/*
+	 * Disable previous PCI->PPC mappings.
+	 */
+
+	/* XXXX Put in mappings from PCI bus to processor bus XXXX */
+
+	/*
+	 * Disable MPIC response to PCI I/O space (BAR 0).
+	 * Make MPIC respond to PCI Mem space at specified address.
+	 * (BAR 1).
+	 */
+	early_write_config_dword(hose,
+			         0,
+			         PCI_DEVFN(0,0),
+			         PCI_BASE_ADDRESS_0,
+			         0x00000000 | 0x1);
+
+	early_write_config_dword(hose,
+			         0,
+			         PCI_DEVFN(0,0),
+			         PCI_BASE_ADDRESS_1,
+			         processor_mpic_base | 0x0);
+
+	/* Map MPIC into vitual memory */
+	OpenPIC_Addr = ioremap(processor_mpic_base, PPLUS_MPIC_SIZE);
+
+	return 0;
+}
+
+/*
+ * Find the amount of RAM present.
+ * This assumes that PPCBug has initialized the memory controller (SMC)
+ * on the Falcon/HAWK correctly (i.e., it does no sanity checking).
+ * It also assumes that the memory base registers are set to configure the
+ * memory as contigous starting with "RAM A BASE", "RAM B BASE", etc.
+ * however, RAM base registers can be skipped (e.g. A, B, C are set,
+ * D is skipped but E is set is okay).
+ */
+#define	MB	(1024*1024)
+
+static uint reg_offset_table[] __initdata = {
+	PPLUS_SMC_RAM_A_SIZE_REG_OFF,
+	PPLUS_SMC_RAM_B_SIZE_REG_OFF,
+	PPLUS_SMC_RAM_C_SIZE_REG_OFF,
+	PPLUS_SMC_RAM_D_SIZE_REG_OFF,
+	PPLUS_SMC_RAM_E_SIZE_REG_OFF,
+	PPLUS_SMC_RAM_F_SIZE_REG_OFF,
+	PPLUS_SMC_RAM_G_SIZE_REG_OFF,
+	PPLUS_SMC_RAM_H_SIZE_REG_OFF
+};
+
+static uint falcon_size_table[] __initdata = {
+	   0 * MB, /* 0 ==>    0 MB */
+	  16 * MB, /* 1 ==>   16 MB */
+	  32 * MB, /* 2 ==>   32 MB */
+	  64 * MB, /* 3 ==>   64 MB */
+	 128 * MB, /* 4 ==>  128 MB */
+	 256 * MB, /* 5 ==>  256 MB */
+        1024 * MB, /* 6 ==> 1024 MB (1 GB) */
+};
+
+static uint hawk_size_table[] __initdata = {
+	  0 * MB, /* 0 ==>    0 MB */
+	 32 * MB, /* 1 ==>   32 MB */
+	 64 * MB, /* 2 ==>   64 MB */
+	 64 * MB, /* 3 ==>   64 MB */
+	128 * MB, /* 4 ==>  128 MB */
+	128 * MB, /* 5 ==>  128 MB */
+	128 * MB, /* 6 ==>  128 MB */
+	256 * MB, /* 7 ==>  256 MB */
+	256 * MB, /* 8 ==>  256 MB */
+	512 * MB, /* 9 ==>  512 MB */
+};
+
+/*
+ * *** WARNING: You MUST have a BAT set up to map in the SMC regs ***
+ *
+ * Read the memory controller's registers to determine the amount of system
+ * memory.  Assumes that the memory controller registers are already mapped
+ * into virtual memory--too early to use ioremap().
+ */
+unsigned long __init
+pplus_get_mem_size(uint smc_base)
+{
+	unsigned long	total;
+	int		i, size_table_entries, reg_limit;
+	uint		vend_dev_id;
+	uint		*size_table;
+	u_char		val;
+
+
+	vend_dev_id = in_be32((uint *)smc_base + PCI_VENDOR_ID);
+
+	if (((vend_dev_id & 0xffff0000) >> 16) != PCI_VENDOR_ID_MOTOROLA) {
+		printk("pplus_get_mem_size: %s (0x%x)\n",
+			"Not a Motorola Memory Controller", vend_dev_id);
+		return 0;
+	}
+
+	vend_dev_id &= 0x0000ffff;
+
+	if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_FALCON) {
+		size_table = falcon_size_table;
+		size_table_entries = sizeof(falcon_size_table) /
+				     sizeof(falcon_size_table[0]);
+
+		reg_limit = PPLUS_FALCON_SMC_REG_COUNT;
+	}
+	else if (vend_dev_id == PCI_DEVICE_ID_MOTOROLA_HAWK) {
+		size_table = hawk_size_table;
+		size_table_entries = sizeof(hawk_size_table) /
+				     sizeof(hawk_size_table[0]);
+		reg_limit = PPLUS_HAWK_SMC_REG_COUNT;
+	}
+	else {
+		printk("pplus_get_mem_size: %s (0x%x)\n",
+			"Not a Falcon or HAWK", vend_dev_id);
+		return 0;
+	}
+
+	total = 0;
+
+	/* Check every reg because PPCBug may skip some */
+	for (i=0; i<reg_limit; i++) {
+		val = in_8((u_char *)(smc_base + reg_offset_table[i]));
+
+		if (val & 0x80) {	/* If enabled */
+			val &= 0x0f;
+
+			/* Don't go past end of size_table */
+			if (val < size_table_entries) {
+				total += size_table[val];
+			}
+			else {	/* Register not set correctly */
+				break;
+			}
+		}
+	}
+
+	return total;
+}
+
+int __init
+pplus_mpic_init(unsigned int pci_mem_offset)
+{
+	unsigned short	devid;
+	unsigned int	pci_membase;
+
+	/* Check the first PCI device to see if it is a Raven or Hawk. */
+	early_read_config_word(0, 0, 0, PCI_DEVICE_ID, &devid);
+
+	switch (devid) {
+	case PCI_DEVICE_ID_MOTOROLA_RAVEN:
+	case PCI_DEVICE_ID_MOTOROLA_HAWK:
+		break;
+	default:
+		OpenPIC_Addr = NULL;
+		return 1;
+	}
+
+	/* 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 1;
+	}
+
+	/* Map the MPIC registers to virtual memory. */
+	OpenPIC_Addr = ioremap(pci_membase + pci_mem_offset, 0x22000);
+
+	return 0;
+}
diff -Nru a/arch/ppc/syslib/prep_nvram.c b/arch/ppc/syslib/prep_nvram.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/prep_nvram.c	Sun Nov 10 19:28:39 2002
@@ -0,0 +1,145 @@
+/*
+ * arch/ppc/kernel/prep_nvram.c
+ *
+ * Copyright (C) 1998  Corey Minyard
+ *
+ * This reads the NvRAM on PReP compliant machines (generally from IBM or
+ * Motorola).  Motorola kept the format of NvRAM in their ROM, PPCBUG, the
+ * same, long after they had stopped producing PReP compliant machines.  So
+ * this code is useful in those cases as well.
+ *
+ */
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/ioport.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>
+
+static char nvramData[MAX_PREP_NVRAM];
+static NVRAM_MAP *nvram=(NVRAM_MAP *)&nvramData[0];
+
+unsigned char __prep prep_nvram_read_val(int addr)
+{
+	outb(addr, PREP_NVRAM_AS0);
+	outb(addr>>8, PREP_NVRAM_AS1);
+	return inb(PREP_NVRAM_DATA);
+}
+  
+void __prep prep_nvram_write_val(int           addr,
+			  unsigned char val)
+{
+	outb(addr, PREP_NVRAM_AS0);
+	outb(addr>>8, PREP_NVRAM_AS1);
+   	outb(val, PREP_NVRAM_DATA);
+}
+  
+void __init init_prep_nvram(void)
+{
+	unsigned char *nvp;
+	int  i;
+	int  nvramSize;
+
+	/*
+	 * The following could fail if the NvRAM were corrupt but
+	 * we expect the boot firmware to have checked its checksum
+	 * before boot
+	 */
+	nvp = (char *) &nvram->Header;
+	for (i=0; i<sizeof(HEADER); i++)
+	{
+		*nvp = ppc_md.nvram_read_val(i);
+		nvp++;
+	}
+	
+	/*
+	 * The PReP NvRAM may be any size so read in the header to
+	 * determine how much we must read in order to get the complete
+	 * GE area
+	 */
+	nvramSize=(int)nvram->Header.GEAddress+nvram->Header.GELength;
+	if(nvramSize>MAX_PREP_NVRAM)
+	{
+		/*
+		 * NvRAM is too large
+		 */
+		nvram->Header.GELength=0;
+		return;
+	}
+
+	/*
+	 * Read the remainder of the PReP NvRAM
+	 */
+	nvp = (char *) &nvram->GEArea[0];
+	for (i=sizeof(HEADER); i<nvramSize; i++)
+	{
+		*nvp = ppc_md.nvram_read_val(i);
+		nvp++;
+	}
+}
+
+__prep
+char __prep *prep_nvram_get_var(const char *name)
+{
+	char *cp;
+	int  namelen;
+
+	namelen = strlen(name);
+	cp = prep_nvram_first_var();
+	while (cp != NULL) {
+		if ((strncmp(name, cp, namelen) == 0)
+		    && (cp[namelen] == '='))
+		{
+			return cp+namelen+1;
+		}
+		cp = prep_nvram_next_var(cp);
+	}
+
+	return NULL;
+}
+
+__prep
+char __prep *prep_nvram_first_var(void)
+{
+        if (nvram->Header.GELength == 0) {
+		return NULL;
+	} else {
+		return (((char *)nvram)
+			+ ((unsigned int) nvram->Header.GEAddress));
+	}
+}
+
+__prep
+char __prep *prep_nvram_next_var(char *name)
+{
+	char *cp;
+
+
+	cp = name;
+	while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength)
+	       && (*cp != '\0'))
+	{
+		cp++;
+	}
+
+	/* Skip over any null characters. */
+	while (((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength)
+	       && (*cp == '\0'))
+	{
+		cp++;
+	}
+
+	if ((cp - ((char *) nvram->GEArea)) < nvram->Header.GELength) {
+		return cp;
+	} else {
+		return NULL;
+	}
+}
+
+
+
diff -Nru a/arch/ppc/syslib/prom.c b/arch/ppc/syslib/prom.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/prom.c	Sun Nov 10 19:28:37 2002
@@ -0,0 +1,1258 @@
+/*
+ * Procedures for interfacing to the Open Firmware PROM on
+ * Power Macintosh computers.
+ *
+ * In particular, we are interested in the device tree
+ * and in using some of its services (exit, write to stdout).
+ *
+ * Paul Mackerras	August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <stdarg.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/threads.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/bootx.h>
+#include <asm/system.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/btext.h>
+#include <asm/pci-bridge.h>
+#include <asm/open_pic.h>
+
+#ifdef CONFIG_FB
+#include <asm/linux_logo.h>
+#endif
+
+struct pci_address {
+	unsigned a_hi;
+	unsigned a_mid;
+	unsigned a_lo;
+};
+
+struct pci_reg_property {
+	struct pci_address addr;
+	unsigned size_hi;
+	unsigned size_lo;
+};
+
+struct isa_reg_property {
+	unsigned space;
+	unsigned address;
+	unsigned size;
+};
+
+typedef unsigned long interpret_func(struct device_node *, unsigned long,
+				     int, int);
+static interpret_func interpret_pci_props;
+static interpret_func interpret_dbdma_props;
+static interpret_func interpret_isa_props;
+static interpret_func interpret_macio_props;
+static interpret_func interpret_root_props;
+
+extern char *klimit;
+
+/* Set for a newworld or CHRP machine */
+int use_of_interrupt_tree;
+struct device_node *dflt_interrupt_controller;
+int num_interrupt_controllers;
+
+int pmac_newworld;
+
+extern unsigned int rtas_entry;  /* physical pointer */
+
+extern struct device_node *allnodes;
+
+static unsigned long finish_node(struct device_node *, unsigned long,
+				 interpret_func *, int, int);
+static unsigned long finish_node_interrupts(struct device_node *, unsigned long);
+static struct device_node *find_phandle(phandle);
+
+extern void enter_rtas(void *);
+void phys_call_rtas(int, int, int, ...);
+
+extern char cmd_line[512];	/* XXX */
+extern boot_infos_t *boot_infos;
+unsigned long dev_tree_size;
+
+void __openfirmware
+phys_call_rtas(int service, int nargs, int nret, ...)
+{
+	va_list list;
+	union {
+		unsigned long words[16];
+		double align;
+	} u;
+	void (*rtas)(void *, unsigned long);
+	int i;
+
+	u.words[0] = service;
+	u.words[1] = nargs;
+	u.words[2] = nret;
+	va_start(list, nret);
+	for (i = 0; i < nargs; ++i)
+		u.words[i+3] = va_arg(list, unsigned long);
+	va_end(list);
+
+	rtas = (void (*)(void *, unsigned long)) rtas_entry;
+	rtas(&u, rtas_data);
+}
+
+/*
+ * finish_device_tree is called once things are running normally
+ * (i.e. with text and data mapped to the address they were linked at).
+ * It traverses the device tree and fills in the name, type,
+ * {n_}addrs and {n_}intrs fields of each node.
+ */
+void __init
+finish_device_tree(void)
+{
+	unsigned long mem = (unsigned long) klimit;
+	struct device_node *np;
+
+	/* All newworld pmac machines and CHRPs now use the interrupt tree */
+	for (np = allnodes; np != NULL; np = np->allnext) {
+		if (get_property(np, "interrupt-parent", 0)) {
+			use_of_interrupt_tree = 1;
+			break;
+		}
+	}
+	if (_machine == _MACH_Pmac && use_of_interrupt_tree)
+		pmac_newworld = 1;
+
+#ifdef CONFIG_BOOTX_TEXT
+	if (boot_infos && pmac_newworld) {
+		prom_print("WARNING ! BootX/miBoot booting is not supported on this machine\n");
+		prom_print("          You should use an Open Firmware bootloader\n");
+	}
+#endif /* CONFIG_BOOTX_TEXT */
+
+	if (use_of_interrupt_tree) {
+		/*
+		 * We want to find out here how many interrupt-controller
+		 * nodes there are, and if we are booted from BootX,
+		 * we need a pointer to the first (and hopefully only)
+		 * such node.  But we can't use find_devices here since
+		 * np->name has not been set yet.  -- paulus
+		 */
+		int n = 0;
+		char *name, *ic;
+		int iclen;
+
+		for (np = allnodes; np != NULL; np = np->allnext) {
+			ic = get_property(np, "interrupt-controller", &iclen);
+			name = get_property(np, "name", NULL);
+			/* checking iclen makes sure we don't get a false
+			   match on /chosen.interrupt_controller */
+			if ((name != NULL
+			     && strcmp(name, "interrupt-controller") == 0)
+			    || (ic != NULL && iclen == 0)) {
+				if (n == 0)
+					dflt_interrupt_controller = np;
+				++n;
+			}
+		}
+		num_interrupt_controllers = n;
+	}
+
+	mem = finish_node(allnodes, mem, NULL, 1, 1);
+	dev_tree_size = mem - (unsigned long) allnodes;
+	klimit = (char *) mem;
+}
+
+static unsigned long __init
+finish_node(struct device_node *np, unsigned long mem_start,
+	    interpret_func *ifunc, int naddrc, int nsizec)
+{
+	struct device_node *child;
+	int *ip;
+
+	np->name = get_property(np, "name", 0);
+	np->type = get_property(np, "device_type", 0);
+
+	if (!np->name)
+		np->name = "<NULL>";
+	if (!np->type)
+		np->type = "<NULL>";
+
+	/* get the device addresses and interrupts */
+	if (ifunc != NULL)
+		mem_start = ifunc(np, mem_start, naddrc, nsizec);
+
+	if (use_of_interrupt_tree)
+		mem_start = finish_node_interrupts(np, mem_start);
+
+	/* Look for #address-cells and #size-cells properties. */
+	ip = (int *) get_property(np, "#address-cells", 0);
+	if (ip != NULL)
+		naddrc = *ip;
+	ip = (int *) get_property(np, "#size-cells", 0);
+	if (ip != NULL)
+		nsizec = *ip;
+
+	if (np->parent == NULL)
+		ifunc = interpret_root_props;
+	else if (np->type == 0)
+		ifunc = NULL;
+	else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
+		ifunc = interpret_pci_props;
+	else if (!strcmp(np->type, "dbdma"))
+		ifunc = interpret_dbdma_props;
+	else if (!strcmp(np->type, "mac-io")
+		 || ifunc == interpret_macio_props)
+		ifunc = interpret_macio_props;
+	else if (!strcmp(np->type, "isa"))
+		ifunc = interpret_isa_props;
+	else if (!strcmp(np->name, "uni-n"))
+		ifunc = interpret_root_props;
+	else if (!((ifunc == interpret_dbdma_props
+		    || ifunc == interpret_macio_props)
+		   && (!strcmp(np->type, "escc")
+		       || !strcmp(np->type, "media-bay"))))
+		ifunc = NULL;
+
+	/* if we were booted from BootX, convert the full name */
+	if (boot_infos
+	    && strncmp(np->full_name, "Devices:device-tree", 19) == 0) {
+		if (np->full_name[19] == 0) {
+			strcpy(np->full_name, "/");
+		} else if (np->full_name[19] == ':') {
+			char *p = np->full_name + 19;
+			np->full_name = p;
+			for (; *p; ++p)
+				if (*p == ':')
+					*p = '/';
+		}
+	}
+
+	for (child = np->child; child != NULL; child = child->sibling)
+		mem_start = finish_node(child, mem_start, ifunc,
+					naddrc, nsizec);
+
+	return mem_start;
+}
+
+/*
+ * Find the interrupt parent of a node.
+ */
+static struct device_node * __init
+intr_parent(struct device_node *p)
+{
+	phandle *parp;
+
+	parp = (phandle *) get_property(p, "interrupt-parent", NULL);
+	if (parp == NULL)
+		return p->parent;
+	p = find_phandle(*parp);
+	if (p != NULL)
+		return p;
+	/*
+	 * On a powermac booted with BootX, we don't get to know the
+	 * phandles for any nodes, so find_phandle will return NULL.
+	 * Fortunately these machines only have one interrupt controller
+	 * so there isn't in fact any ambiguity.  -- paulus
+	 */
+	if (num_interrupt_controllers == 1)
+		p = dflt_interrupt_controller;
+	return p;
+}
+
+/*
+ * Find out the size of each entry of the interrupts property
+ * for a node.
+ */
+static int __init
+prom_n_intr_cells(struct device_node *np)
+{
+	struct device_node *p;
+	unsigned int *icp;
+
+	for (p = np; (p = intr_parent(p)) != NULL; ) {
+		icp = (unsigned int *)
+			get_property(p, "#interrupt-cells", NULL);
+		if (icp != NULL)
+			return *icp;
+		if (get_property(p, "interrupt-controller", NULL) != NULL
+		    || get_property(p, "interrupt-map", NULL) != NULL) {
+			printk("oops, node %s doesn't have #interrupt-cells\n",
+			       p->full_name);
+			return 1;
+		}
+	}
+	printk("prom_n_intr_cells failed for %s\n", np->full_name);
+	return 1;
+}
+
+/*
+ * Map an interrupt from a device up to the platform interrupt
+ * descriptor.
+ */
+static int __init
+map_interrupt(unsigned int **irq, struct device_node **ictrler,
+	      struct device_node *np, unsigned int *ints, int nintrc)
+{
+	struct device_node *p, *ipar;
+	unsigned int *imap, *imask, *ip;
+	int i, imaplen, match;
+	int newintrc, newaddrc;
+	unsigned int *reg;
+	int naddrc;
+
+	reg = (unsigned int *) get_property(np, "reg", NULL);
+	naddrc = prom_n_addr_cells(np);
+	p = intr_parent(np);
+	while (p != NULL) {
+		if (get_property(p, "interrupt-controller", NULL) != NULL)
+			/* this node is an interrupt controller, stop here */
+			break;
+		imap = (unsigned int *)
+			get_property(p, "interrupt-map", &imaplen);
+		if (imap == NULL) {
+			p = intr_parent(p);
+			continue;
+		}
+		imask = (unsigned int *)
+			get_property(p, "interrupt-map-mask", NULL);
+		if (imask == NULL) {
+			printk("oops, %s has interrupt-map but no mask\n",
+			       p->full_name);
+			return 0;
+		}
+		imaplen /= sizeof(unsigned int);
+		match = 0;
+		ipar = NULL;
+		while (imaplen > 0 && !match) {
+			/* check the child-interrupt field */
+			match = 1;
+			for (i = 0; i < naddrc && match; ++i)
+				match = ((reg[i] ^ imap[i]) & imask[i]) == 0;
+			for (; i < naddrc + nintrc && match; ++i)
+				match = ((ints[i-naddrc] ^ imap[i]) & imask[i]) == 0;
+			imap += naddrc + nintrc;
+			imaplen -= naddrc + nintrc;
+			/* grab the interrupt parent */
+			ipar = find_phandle((phandle) *imap++);
+			--imaplen;
+			if (ipar == NULL && num_interrupt_controllers == 1)
+				/* cope with BootX not giving us phandles */
+				ipar = dflt_interrupt_controller;
+			if (ipar == NULL) {
+				printk("oops, no int parent %x in map of %s\n",
+				       imap[-1], p->full_name);
+				return 0;
+			}
+			/* find the parent's # addr and intr cells */
+			ip = (unsigned int *)
+				get_property(ipar, "#interrupt-cells", NULL);
+			if (ip == NULL) {
+				printk("oops, no #interrupt-cells on %s\n",
+				       ipar->full_name);
+				return 0;
+			}
+			newintrc = *ip;
+			ip = (unsigned int *)
+				get_property(ipar, "#address-cells", NULL);
+			newaddrc = (ip == NULL)? 0: *ip;
+			imap += newaddrc + newintrc;
+			imaplen -= newaddrc + newintrc;
+		}
+		if (imaplen < 0) {
+			printk("oops, error decoding int-map on %s, len=%d\n",
+			       p->full_name, imaplen);
+			return 0;
+		}
+		if (!match) {
+			printk("oops, no match in %s int-map for %s\n",
+			       p->full_name, np->full_name);
+			return 0;
+		}
+		p = ipar;
+		naddrc = newaddrc;
+		nintrc = newintrc;
+		ints = imap - nintrc;
+		reg = ints - naddrc;
+	}
+	if (p == NULL)
+		printk("hmmm, int tree for %s doesn't have ctrler\n",
+		       np->full_name);
+	*irq = ints;
+	*ictrler = p;
+	return nintrc;
+}
+
+/*
+ * New version of finish_node_interrupts.
+ */
+static unsigned long __init
+finish_node_interrupts(struct device_node *np, unsigned long mem_start)
+{
+	unsigned int *ints;
+	int intlen, intrcells;
+	int i, j, n, offset;
+	unsigned int *irq;
+	struct device_node *ic;
+
+	ints = (unsigned int *) get_property(np, "interrupts", &intlen);
+	if (ints == NULL)
+		return mem_start;
+	intrcells = prom_n_intr_cells(np);
+	intlen /= intrcells * sizeof(unsigned int);
+	np->n_intrs = intlen;
+	np->intrs = (struct interrupt_info *) mem_start;
+	mem_start += intlen * sizeof(struct interrupt_info);
+
+	for (i = 0; i < intlen; ++i) {
+		np->intrs[i].line = 0;
+		np->intrs[i].sense = 1;
+		n = map_interrupt(&irq, &ic, np, ints, intrcells);
+		if (n <= 0)
+			continue;
+		offset = 0;
+		/*
+		 * On a CHRP we have an 8259 which is subordinate to
+		 * the openpic in the interrupt tree, but we want the
+		 * openpic's interrupt numbers offsetted, not the 8259's.
+		 * So we apply the offset if the controller is at the
+		 * root of the interrupt tree, i.e. has no interrupt-parent.
+		 * This doesn't cope with the general case of multiple
+		 * cascaded interrupt controllers, but then neither will
+		 * irq.c at the moment either.  -- paulus
+		 */
+		if (num_interrupt_controllers > 1 && ic != NULL
+		    && get_property(ic, "interrupt-parent", NULL) == NULL)
+			offset = 16;
+		np->intrs[i].line = irq[0] + offset;
+		if (n > 1)
+			np->intrs[i].sense = irq[1];
+		if (n > 2) {
+			printk("hmmm, got %d intr cells for %s:", n,
+			       np->full_name);
+			for (j = 0; j < n; ++j)
+				printk(" %d", irq[j]);
+			printk("\n");
+		}
+		ints += intrcells;
+	}
+
+	return mem_start;
+}
+
+/*
+ * When BootX makes a copy of the device tree from the MacOS
+ * Name Registry, it is in the format we use but all of the pointers
+ * are offsets from the start of the tree.
+ * This procedure updates the pointers.
+ */
+void __init
+relocate_nodes(void)
+{
+	unsigned long base;
+	struct device_node *np;
+	struct property *pp;
+
+#define ADDBASE(x)	(x = (x)? ((typeof (x))((unsigned long)(x) + base)): 0)
+
+	base = (unsigned long) boot_infos + boot_infos->deviceTreeOffset;
+	allnodes = (struct device_node *)(base + 4);
+	for (np = allnodes; np != 0; np = np->allnext) {
+		ADDBASE(np->full_name);
+		ADDBASE(np->properties);
+		ADDBASE(np->parent);
+		ADDBASE(np->child);
+		ADDBASE(np->sibling);
+		ADDBASE(np->allnext);
+		for (pp = np->properties; pp != 0; pp = pp->next) {
+			ADDBASE(pp->name);
+			ADDBASE(pp->value);
+			ADDBASE(pp->next);
+		}
+	}
+}
+
+int
+prom_n_addr_cells(struct device_node* np)
+{
+	int* ip;
+	do {
+		if (np->parent)
+			np = np->parent;
+		ip = (int *) get_property(np, "#address-cells", 0);
+		if (ip != NULL)
+			return *ip;
+	} while (np->parent);
+	/* No #address-cells property for the root node, default to 1 */
+	return 1;
+}
+
+int
+prom_n_size_cells(struct device_node* np)
+{
+	int* ip;
+	do {
+		if (np->parent)
+			np = np->parent;
+		ip = (int *) get_property(np, "#size-cells", 0);
+		if (ip != NULL)
+			return *ip;
+	} while (np->parent);
+	/* No #size-cells property for the root node, default to 1 */
+	return 1;
+}
+
+static unsigned long __init
+map_addr(struct device_node *np, unsigned long space, unsigned long addr)
+{
+	int na;
+	unsigned int *ranges;
+	int rlen = 0;
+	unsigned int type;
+
+	type = (space >> 24) & 3;
+	if (type == 0)
+		return addr;
+
+	while ((np = np->parent) != NULL) {
+		if (strcmp(np->type, "pci") != 0)
+			continue;
+		/* PCI bridge: map the address through the ranges property */
+		na = prom_n_addr_cells(np);
+		ranges = (unsigned int *) get_property(np, "ranges", &rlen);
+		while ((rlen -= (na + 5) * sizeof(unsigned int)) >= 0) {
+			if (((ranges[0] >> 24) & 3) == type
+			    && ranges[2] <= addr
+			    && addr - ranges[2] < ranges[na+4]) {
+				/* ok, this matches, translate it */
+				addr += ranges[na+2] - ranges[2];
+				break;
+			}
+			ranges += na + 5;
+		}
+	}
+	return addr;
+}
+
+static unsigned long __init
+interpret_pci_props(struct device_node *np, unsigned long mem_start,
+		    int naddrc, int nsizec)
+{
+	struct address_range *adr;
+	struct pci_reg_property *pci_addrs;
+	int i, l, *ip;
+
+	pci_addrs = (struct pci_reg_property *)
+		get_property(np, "assigned-addresses", &l);
+	if (pci_addrs != 0 && l >= sizeof(struct pci_reg_property)) {
+		i = 0;
+		adr = (struct address_range *) mem_start;
+		while ((l -= sizeof(struct pci_reg_property)) >= 0) {
+			adr[i].space = pci_addrs[i].addr.a_hi;
+			adr[i].address = map_addr(np, pci_addrs[i].addr.a_hi,
+						  pci_addrs[i].addr.a_lo);
+			adr[i].size = pci_addrs[i].size_lo;
+			++i;
+		}
+		np->addrs = adr;
+		np->n_addrs = i;
+		mem_start += i * sizeof(struct address_range);
+	}
+
+	if (use_of_interrupt_tree)
+		return mem_start;
+
+	ip = (int *) get_property(np, "AAPL,interrupts", &l);
+	if (ip == 0 && np->parent)
+		ip = (int *) get_property(np->parent, "AAPL,interrupts", &l);
+	if (ip == 0)
+		ip = (int *) get_property(np, "interrupts", &l);
+	if (ip != 0) {
+		np->intrs = (struct interrupt_info *) mem_start;
+		np->n_intrs = l / sizeof(int);
+		mem_start += np->n_intrs * sizeof(struct interrupt_info);
+		for (i = 0; i < np->n_intrs; ++i) {
+			np->intrs[i].line = *ip++;
+			np->intrs[i].sense = 1;
+		}
+	}
+
+	return mem_start;
+}
+
+static unsigned long __init
+interpret_dbdma_props(struct device_node *np, unsigned long mem_start,
+		      int naddrc, int nsizec)
+{
+	struct reg_property *rp;
+	struct address_range *adr;
+	unsigned long base_address;
+	int i, l, *ip;
+	struct device_node *db;
+
+	base_address = 0;
+	for (db = np->parent; db != NULL; db = db->parent) {
+		if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
+			base_address = db->addrs[0].address;
+			break;
+		}
+	}
+
+	rp = (struct reg_property *) get_property(np, "reg", &l);
+	if (rp != 0 && l >= sizeof(struct reg_property)) {
+		i = 0;
+		adr = (struct address_range *) mem_start;
+		while ((l -= sizeof(struct reg_property)) >= 0) {
+			adr[i].space = 2;
+			adr[i].address = rp[i].address + base_address;
+			adr[i].size = rp[i].size;
+			++i;
+		}
+		np->addrs = adr;
+		np->n_addrs = i;
+		mem_start += i * sizeof(struct address_range);
+	}
+
+	if (use_of_interrupt_tree)
+		return mem_start;
+
+	ip = (int *) get_property(np, "AAPL,interrupts", &l);
+	if (ip == 0)
+		ip = (int *) get_property(np, "interrupts", &l);
+	if (ip != 0) {
+		np->intrs = (struct interrupt_info *) mem_start;
+		np->n_intrs = l / sizeof(int);
+		mem_start += np->n_intrs * sizeof(struct interrupt_info);
+		for (i = 0; i < np->n_intrs; ++i) {
+			np->intrs[i].line = *ip++;
+			np->intrs[i].sense = 1;
+		}
+	}
+
+	return mem_start;
+}
+
+static unsigned long __init
+interpret_macio_props(struct device_node *np, unsigned long mem_start,
+		      int naddrc, int nsizec)
+{
+	struct reg_property *rp;
+	struct address_range *adr;
+	unsigned long base_address;
+	int i, l, *ip;
+	struct device_node *db;
+
+	base_address = 0;
+	for (db = np->parent; db != NULL; db = db->parent) {
+		if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
+			base_address = db->addrs[0].address;
+			break;
+		}
+	}
+
+	rp = (struct reg_property *) get_property(np, "reg", &l);
+	if (rp != 0 && l >= sizeof(struct reg_property)) {
+		i = 0;
+		adr = (struct address_range *) mem_start;
+		while ((l -= sizeof(struct reg_property)) >= 0) {
+			adr[i].space = 2;
+			adr[i].address = rp[i].address + base_address;
+			adr[i].size = rp[i].size;
+			++i;
+		}
+		np->addrs = adr;
+		np->n_addrs = i;
+		mem_start += i * sizeof(struct address_range);
+	}
+
+	if (use_of_interrupt_tree)
+		return mem_start;
+
+	ip = (int *) get_property(np, "interrupts", &l);
+	if (ip == 0)
+		ip = (int *) get_property(np, "AAPL,interrupts", &l);
+	if (ip != 0) {
+		np->intrs = (struct interrupt_info *) mem_start;
+		np->n_intrs = l / sizeof(int);
+		for (i = 0; i < np->n_intrs; ++i) {
+			np->intrs[i].line = *ip++;
+			np->intrs[i].sense = 1;
+		}
+		mem_start += np->n_intrs * sizeof(struct interrupt_info);
+	}
+
+	return mem_start;
+}
+
+static unsigned long __init
+interpret_isa_props(struct device_node *np, unsigned long mem_start,
+		    int naddrc, int nsizec)
+{
+	struct isa_reg_property *rp;
+	struct address_range *adr;
+	int i, l, *ip;
+
+	rp = (struct isa_reg_property *) get_property(np, "reg", &l);
+	if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
+		i = 0;
+		adr = (struct address_range *) mem_start;
+		while ((l -= sizeof(struct reg_property)) >= 0) {
+			adr[i].space = rp[i].space;
+			adr[i].address = rp[i].address
+				+ (adr[i].space? 0: _ISA_MEM_BASE);
+			adr[i].size = rp[i].size;
+			++i;
+		}
+		np->addrs = adr;
+		np->n_addrs = i;
+		mem_start += i * sizeof(struct address_range);
+	}
+
+	if (use_of_interrupt_tree)
+		return mem_start;
+
+	ip = (int *) get_property(np, "interrupts", &l);
+	if (ip != 0) {
+		np->intrs = (struct interrupt_info *) mem_start;
+		np->n_intrs = l / (2 * sizeof(int));
+		mem_start += np->n_intrs * sizeof(struct interrupt_info);
+		for (i = 0; i < np->n_intrs; ++i) {
+			np->intrs[i].line = *ip++;
+			np->intrs[i].sense = *ip++;
+		}
+	}
+
+	return mem_start;
+}
+
+static unsigned long __init
+interpret_root_props(struct device_node *np, unsigned long mem_start,
+		     int naddrc, int nsizec)
+{
+	struct address_range *adr;
+	int i, l, *ip;
+	unsigned int *rp;
+	int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
+
+	rp = (unsigned int *) get_property(np, "reg", &l);
+	if (rp != 0 && l >= rpsize) {
+		i = 0;
+		adr = (struct address_range *) mem_start;
+		while ((l -= rpsize) >= 0) {
+			adr[i].space = (naddrc >= 2? rp[naddrc-2]: 2);
+			adr[i].address = rp[naddrc - 1];
+			adr[i].size = rp[naddrc + nsizec - 1];
+			++i;
+			rp += naddrc + nsizec;
+		}
+		np->addrs = adr;
+		np->n_addrs = i;
+		mem_start += i * sizeof(struct address_range);
+	}
+
+	if (use_of_interrupt_tree)
+		return mem_start;
+
+	ip = (int *) get_property(np, "AAPL,interrupts", &l);
+	if (ip == 0)
+		ip = (int *) get_property(np, "interrupts", &l);
+	if (ip != 0) {
+		np->intrs = (struct interrupt_info *) mem_start;
+		np->n_intrs = l / sizeof(int);
+		mem_start += np->n_intrs * sizeof(struct interrupt_info);
+		for (i = 0; i < np->n_intrs; ++i) {
+			np->intrs[i].line = *ip++;
+			np->intrs[i].sense = 1;
+		}
+	}
+
+	return mem_start;
+}
+
+/*
+ * Work out the sense (active-low level / active-high edge)
+ * of each interrupt from the device tree.
+ */
+void __init
+prom_get_irq_senses(unsigned char *senses, int off, int max)
+{
+	struct device_node *np;
+	int i, j;
+
+	/* default to level-triggered */
+	memset(senses, 1, max - off);
+	if (!use_of_interrupt_tree)
+		return;
+
+	for (np = allnodes; np != 0; np = np->allnext) {
+		for (j = 0; j < np->n_intrs; j++) {
+			i = np->intrs[j].line;
+			if (i >= off && i < max) {
+				if (np->intrs[j].sense == 1)
+					senses[i-off] = (IRQ_SENSE_LEVEL
+						| IRQ_POLARITY_NEGATIVE);
+				else
+					senses[i-off] = (IRQ_SENSE_EDGE 
+						| IRQ_POLARITY_POSITIVE);
+			}
+		}
+	}
+}
+
+/*
+ * Construct and return a list of the device_nodes with a given name.
+ */
+struct device_node *
+find_devices(const char *name)
+{
+	struct device_node *head, **prevp, *np;
+
+	prevp = &head;
+	for (np = allnodes; np != 0; np = np->allnext) {
+		if (np->name != 0 && strcasecmp(np->name, name) == 0) {
+			*prevp = np;
+			prevp = &np->next;
+		}
+	}
+	*prevp = 0;
+	return head;
+}
+
+/*
+ * Construct and return a list of the device_nodes with a given type.
+ */
+struct device_node *
+find_type_devices(const char *type)
+{
+	struct device_node *head, **prevp, *np;
+
+	prevp = &head;
+	for (np = allnodes; np != 0; np = np->allnext) {
+		if (np->type != 0 && strcasecmp(np->type, type) == 0) {
+			*prevp = np;
+			prevp = &np->next;
+		}
+	}
+	*prevp = 0;
+	return head;
+}
+
+/*
+ * Returns all nodes linked together
+ */
+struct device_node * __openfirmware
+find_all_nodes(void)
+{
+	struct device_node *head, **prevp, *np;
+
+	prevp = &head;
+	for (np = allnodes; np != 0; np = np->allnext) {
+		*prevp = np;
+		prevp = &np->next;
+	}
+	*prevp = 0;
+	return head;
+}
+
+/* Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int
+device_is_compatible(struct device_node *device, const char *compat)
+{
+	const char* cp;
+	int cplen, l;
+
+	cp = (char *) get_property(device, "compatible", &cplen);
+	if (cp == NULL)
+		return 0;
+	while (cplen > 0) {
+		if (strncasecmp(cp, compat, strlen(compat)) == 0)
+			return 1;
+		l = strlen(cp) + 1;
+		cp += l;
+		cplen -= l;
+	}
+
+	return 0;
+}
+
+
+/*
+ * Indicates whether the root node has a given value in its
+ * compatible property.
+ */
+int
+machine_is_compatible(const char *compat)
+{
+	struct device_node *root;
+
+	root = find_path_device("/");
+	if (root == 0)
+		return 0;
+	return device_is_compatible(root, compat);
+}
+
+/*
+ * Construct and return a list of the device_nodes with a given type
+ * and compatible property.
+ */
+struct device_node *
+find_compatible_devices(const char *type, const char *compat)
+{
+	struct device_node *head, **prevp, *np;
+
+	prevp = &head;
+	for (np = allnodes; np != 0; np = np->allnext) {
+		if (type != NULL
+		    && !(np->type != 0 && strcasecmp(np->type, type) == 0))
+			continue;
+		if (device_is_compatible(np, compat)) {
+			*prevp = np;
+			prevp = &np->next;
+		}
+	}
+	*prevp = 0;
+	return head;
+}
+
+/*
+ * Find the device_node with a given full_name.
+ */
+struct device_node *
+find_path_device(const char *path)
+{
+	struct device_node *np;
+
+	for (np = allnodes; np != 0; np = np->allnext)
+		if (np->full_name != 0 && strcasecmp(np->full_name, path) == 0)
+			return np;
+	return NULL;
+}
+
+/*
+ * Find the device_node with a given phandle.
+ */
+static struct device_node * __init
+find_phandle(phandle ph)
+{
+	struct device_node *np;
+
+	for (np = allnodes; np != 0; np = np->allnext)
+		if (np->node == ph)
+			return np;
+	return NULL;
+}
+
+/*
+ * Find a property with a given name for a given node
+ * and return the value.
+ */
+unsigned char *
+get_property(struct device_node *np, const char *name, int *lenp)
+{
+	struct property *pp;
+
+	for (pp = np->properties; pp != 0; pp = pp->next)
+		if (pp->name != NULL && strcmp(pp->name, name) == 0) {
+			if (lenp != 0)
+				*lenp = pp->length;
+			return pp->value;
+		}
+	return 0;
+}
+
+/*
+ * Add a property to a node
+ */
+void __openfirmware
+prom_add_property(struct device_node* np, struct property* prop)
+{
+	struct property **next = &np->properties;
+
+	prop->next = NULL;
+	while (*next)
+		next = &(*next)->next;
+	*next = prop;
+}
+
+/* I quickly hacked that one, check against spec ! */
+static inline unsigned long __openfirmware
+bus_space_to_resource_flags(unsigned int bus_space)
+{
+	u8 space = (bus_space >> 24) & 0xf;
+	if (space == 0)
+		space = 0x02;
+	if (space == 0x02)
+		return IORESOURCE_MEM;
+	else if (space == 0x01)
+		return IORESOURCE_IO;
+	else {
+		printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n",
+		    	bus_space);
+		return 0;
+	}
+}
+
+static struct resource* __openfirmware
+find_parent_pci_resource(struct pci_dev* pdev, struct address_range *range)
+{
+	unsigned long mask;
+	int i;
+	
+	/* Check this one */ 
+	mask = bus_space_to_resource_flags(range->space);
+	for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
+		if ((pdev->resource[i].flags & mask) == mask &&
+			pdev->resource[i].start <= range->address &&
+			pdev->resource[i].end > range->address) {
+				if ((range->address + range->size - 1) > pdev->resource[i].end) {
+					/* Add better message */
+					printk(KERN_WARNING "PCI/OF resource overlap !\n");
+					return NULL;
+				}
+				break;
+			}
+	}
+	if (i == DEVICE_COUNT_RESOURCE)
+		return NULL;
+	return &pdev->resource[i];
+}
+
+/*
+ * Request an OF device resource. Currently handles child of PCI devices,
+ * or other nodes attached to the root node. Ultimately, put some
+ * link to resources in the OF node.
+ * WARNING: out_resource->name should be initialized before calling this
+ * function.
+ */
+struct resource* __openfirmware
+request_OF_resource(struct device_node* node, int index, const char* name_postfix)
+{
+	struct pci_dev* pcidev;
+	u8 pci_bus, pci_devfn;
+	unsigned long iomask;
+	struct device_node* nd;
+	struct resource* parent;
+	struct resource *res = NULL;
+	int nlen, plen;
+
+	if (index >= node->n_addrs)
+		goto fail;
+
+	/* Sanity check on bus space */
+	iomask = bus_space_to_resource_flags(node->addrs[index].space);
+	if (iomask & IORESOURCE_MEM)
+		parent = &iomem_resource;
+	else if (iomask & IORESOURCE_IO)
+		parent = &ioport_resource;
+	else
+		goto fail;
+		
+	/* Find a PCI parent if any */
+	nd = node;
+	pcidev = NULL;
+	while(nd) {
+		if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
+			pcidev = pci_find_slot(pci_bus, pci_devfn);
+		if (pcidev) break;
+		nd = nd->parent;
+	}
+	if (pcidev)
+		parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
+	if (!parent) {
+		printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
+			node->name);
+		goto fail;
+	}
+
+	res = __request_region(parent, node->addrs[index].address, node->addrs[index].size, NULL);
+	if (!res)
+		goto fail;
+	nlen = strlen(node->name);
+	plen = name_postfix ? strlen(name_postfix) : 0;
+	res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL);
+	if (res->name) {
+		strcpy((char *)res->name, node->name);
+		if (plen)
+			strcpy((char *)res->name+nlen, name_postfix);
+	}
+	return res;
+fail:
+	return NULL;
+}
+
+int __openfirmware
+release_OF_resource(struct device_node* node, int index)
+{
+	struct pci_dev* pcidev;
+	u8 pci_bus, pci_devfn;
+	unsigned long iomask;
+	struct device_node* nd;
+	struct resource* parent;
+	struct resource *res = NULL;
+
+	if (index >= node->n_addrs)
+		return -EINVAL;
+
+	/* Sanity check on bus space */
+	iomask = bus_space_to_resource_flags(node->addrs[index].space);
+	if (iomask & IORESOURCE_MEM)
+		parent = &iomem_resource;
+	else if (iomask & IORESOURCE_IO)
+		parent = &ioport_resource;
+	else
+		return -EINVAL;
+		
+	/* Find a PCI parent if any */
+	nd = node;
+	pcidev = NULL;
+	while(nd) {
+		if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
+			pcidev = pci_find_slot(pci_bus, pci_devfn);
+		if (pcidev) break;
+		nd = nd->parent;
+	}
+	if (pcidev)
+		parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
+	if (!parent) {
+		printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
+			node->name);
+		return -ENODEV;
+	}
+
+	/* Find us in the parent */
+	res = parent->child;
+	while (res) {
+		if (res->start == node->addrs[index].address &&
+		    res->end == (res->start + node->addrs[index].size - 1))
+		    	break;
+		res = res->sibling;
+	}
+	if (!res)
+		return -ENODEV;
+
+	if (res->name) {
+		kfree(res->name);
+		res->name = NULL;
+	}
+	release_resource(res);
+	kfree(res);
+
+	return 0;
+}
+
+#if 0
+void __openfirmware
+print_properties(struct device_node *np)
+{
+	struct property *pp;
+	char *cp;
+	int i, n;
+
+	for (pp = np->properties; pp != 0; pp = pp->next) {
+		printk(KERN_INFO "%s", pp->name);
+		for (i = strlen(pp->name); i < 16; ++i)
+			printk(" ");
+		cp = (char *) pp->value;
+		for (i = pp->length; i > 0; --i, ++cp)
+			if ((i > 1 && (*cp < 0x20 || *cp > 0x7e))
+			    || (i == 1 && *cp != 0))
+				break;
+		if (i == 0 && pp->length > 1) {
+			/* looks like a string */
+			printk(" %s\n", (char *) pp->value);
+		} else {
+			/* dump it in hex */
+			n = pp->length;
+			if (n > 64)
+				n = 64;
+			if (pp->length % 4 == 0) {
+				unsigned int *p = (unsigned int *) pp->value;
+
+				n /= 4;
+				for (i = 0; i < n; ++i) {
+					if (i != 0 && (i % 4) == 0)
+						printk("\n                ");
+					printk(" %08x", *p++);
+				}
+			} else {
+				unsigned char *bp = pp->value;
+
+				for (i = 0; i < n; ++i) {
+					if (i != 0 && (i % 16) == 0)
+						printk("\n                ");
+					printk(" %02x", *bp++);
+				}
+			}
+			printk("\n");
+			if (pp->length > 64)
+				printk("                 ... (length = %d)\n",
+				       pp->length);
+		}
+	}
+}
+#endif
+
+static spinlock_t rtas_lock = SPIN_LOCK_UNLOCKED;
+
+/* this can be called after setup -- Cort */
+int __openfirmware
+call_rtas(const char *service, int nargs, int nret,
+	  unsigned long *outputs, ...)
+{
+	va_list list;
+	int i;
+	unsigned long s;
+	struct device_node *rtas;
+	int *tokp;
+	union {
+		unsigned long words[16];
+		double align;
+	} u;
+
+	rtas = find_devices("rtas");
+	if (rtas == NULL)
+		return -1;
+	tokp = (int *) get_property(rtas, service, NULL);
+	if (tokp == NULL) {
+		printk(KERN_ERR "No RTAS service called %s\n", service);
+		return -1;
+	}
+	u.words[0] = *tokp;
+	u.words[1] = nargs;
+	u.words[2] = nret;
+	va_start(list, outputs);
+	for (i = 0; i < nargs; ++i)
+		u.words[i+3] = va_arg(list, unsigned long);
+	va_end(list);
+
+	/*
+	 * RTAS doesn't use floating point.
+	 * Or at least, according to the CHRP spec we enter RTAS
+	 * with FP disabled, and it doesn't change the FP registers.
+	 *  -- paulus.
+	 */
+	spin_lock_irqsave(&rtas_lock, s);
+	enter_rtas((void *)__pa(&u));
+	spin_unlock_irqrestore(&rtas_lock, s);
+
+	if (nret > 1 && outputs != NULL)
+		for (i = 0; i < nret-1; ++i)
+			outputs[i] = u.words[i+nargs+4];
+	return u.words[nargs+3];
+}
diff -Nru a/arch/ppc/syslib/prom_init.c b/arch/ppc/syslib/prom_init.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/prom_init.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,900 @@
+/*
+ * Note that prom_init() and anything called from prom_init()
+ * may be running at an address that is different from the address
+ * that it was linked at.  References to static data items are
+ * handled by compiling this file with -mrelocatable-lib.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/threads.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+
+#include <asm/sections.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+#include <asm/processor.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/smp.h>
+#include <asm/bootx.h>
+#include <asm/system.h>
+#include <asm/mmu.h>
+#include <asm/pgtable.h>
+#include <asm/bitops.h>
+#include <asm/bootinfo.h>
+#include <asm/btext.h>
+#include <asm/pci-bridge.h>
+#include <asm/open_pic.h>
+#include <asm/cacheflush.h>
+
+#ifdef CONFIG_FB
+#include <asm/linux_logo.h>
+#endif
+
+/*
+ * Properties whose value is longer than this get excluded from our
+ * copy of the device tree.  This way we don't waste space storing
+ * things like "driver,AAPL,MacOS,PowerPC" properties.  But this value
+ * does need to be big enough to ensure that we don't lose things
+ * like the interrupt-map property on a PCI-PCI bridge.
+ */
+#define MAX_PROPERTY_LENGTH	4096
+
+#ifndef FB_MAX			/* avoid pulling in all of the fb stuff */
+#define FB_MAX	8
+#endif
+
+#define ALIGNUL(x) (((x) + sizeof(unsigned long)-1) & -sizeof(unsigned long))
+
+struct prom_args {
+	const char *service;
+	int nargs;
+	int nret;
+	void *args[10];
+};
+
+struct pci_address {
+	unsigned a_hi;
+	unsigned a_mid;
+	unsigned a_lo;
+};
+
+struct pci_reg_property {
+	struct pci_address addr;
+	unsigned size_hi;
+	unsigned size_lo;
+};
+
+struct pci_range {
+	struct pci_address addr;
+	unsigned phys;
+	unsigned size_hi;
+	unsigned size_lo;
+};
+
+struct isa_reg_property {
+	unsigned space;
+	unsigned address;
+	unsigned size;
+};
+
+struct pci_intr_map {
+	struct pci_address addr;
+	unsigned dunno;
+	phandle int_ctrler;
+	unsigned intr;
+};
+
+static void prom_exit(void);
+static void *call_prom(const char *service, int nargs, int nret, ...);
+static void *call_prom_ret(const char *service, int nargs, int nret,
+			   void **rets, ...);
+static void prom_print_hex(unsigned int v);
+static int  prom_set_color(ihandle ih, int i, int r, int g, int b);
+static int  prom_next_node(phandle *nodep);
+static unsigned long check_display(unsigned long mem);
+static void setup_disp_fake_bi(ihandle dp);
+static unsigned long copy_device_tree(unsigned long mem_start,
+				unsigned long mem_end);
+static unsigned long inspect_node(phandle node, struct device_node *dad,
+				unsigned long mem_start, unsigned long mem_end,
+				struct device_node ***allnextpp);
+static void prom_hold_cpus(unsigned long mem);
+static void prom_instantiate_rtas(void);
+static void * early_get_property(unsigned long base, unsigned long node,
+				char *prop);
+
+prom_entry prom __initdata = 0;
+ihandle prom_chosen __initdata = 0;
+ihandle prom_stdout __initdata = 0;
+
+char *prom_display_paths[FB_MAX] __initdata = { 0, };
+phandle prom_display_nodes[FB_MAX] __initdata;
+unsigned int prom_num_displays __initdata = 0;
+static char *of_stdout_device __initdata = 0;
+static ihandle prom_disp_node __initdata = 0;
+
+unsigned int rtas_data;   /* physical pointer */
+unsigned int rtas_entry;  /* physical pointer */
+unsigned int rtas_size;
+unsigned int old_rtas;
+
+boot_infos_t *boot_infos;
+char *bootpath;
+char *bootdevice;
+struct device_node *allnodes;
+
+extern char *klimit;
+extern char _stext;
+
+static void __init
+prom_exit(void)
+{
+	struct prom_args args;
+
+	args.service = "exit";
+	args.nargs = 0;
+	args.nret = 0;
+	prom(&args);
+	for (;;)			/* should never get here */
+		;
+}
+
+static void * __init
+call_prom(const char *service, int nargs, int nret, ...)
+{
+	va_list list;
+	int i;
+	struct prom_args prom_args;
+
+	prom_args.service = service;
+	prom_args.nargs = nargs;
+	prom_args.nret = nret;
+	va_start(list, nret);
+	for (i = 0; i < nargs; ++i)
+		prom_args.args[i] = va_arg(list, void *);
+	va_end(list);
+	for (i = 0; i < nret; ++i)
+		prom_args.args[i + nargs] = 0;
+	prom(&prom_args);
+	return prom_args.args[nargs];
+}
+
+static void * __init
+call_prom_ret(const char *service, int nargs, int nret, void **rets, ...)
+{
+	va_list list;
+	int i;
+	struct prom_args prom_args;
+
+	prom_args.service = service;
+	prom_args.nargs = nargs;
+	prom_args.nret = nret;
+	va_start(list, rets);
+	for (i = 0; i < nargs; ++i)
+		prom_args.args[i] = va_arg(list, void *);
+	va_end(list);
+	for (i = 0; i < nret; ++i)
+		prom_args.args[i + nargs] = 0;
+	prom(&prom_args);
+	for (i = 1; i < nret; ++i)
+		rets[i-1] = prom_args.args[nargs + i];
+	return prom_args.args[nargs];
+}
+
+void __init
+prom_print(const char *msg)
+{
+	const char *p, *q;
+
+	if (prom_stdout == 0)
+		return;
+
+	for (p = msg; *p != 0; p = q) {
+		for (q = p; *q != 0 && *q != '\n'; ++q)
+			;
+		if (q > p)
+			call_prom("write", 3, 1, prom_stdout, p, q - p);
+		if (*q != 0) {
+			++q;
+			call_prom("write", 3, 1, prom_stdout, "\r\n", 2);
+		}
+	}
+}
+
+static void __init
+prom_print_hex(unsigned int v)
+{
+	char buf[16];
+	int i, c;
+
+	for (i = 0; i < 8; ++i) {
+		c = (v >> ((7-i)*4)) & 0xf;
+		c += (c >= 10)? ('a' - 10): '0';
+		buf[i] = c;
+	}
+	buf[i] = ' ';
+	buf[i+1] = 0;
+	prom_print(buf);
+}
+
+static int __init
+prom_set_color(ihandle ih, int i, int r, int g, int b)
+{
+	struct prom_args prom_args;
+
+	prom_args.service = "call-method";
+	prom_args.nargs = 6;
+	prom_args.nret = 1;
+	prom_args.args[0] = "color!";
+	prom_args.args[1] = ih;
+	prom_args.args[2] = (void *) i;
+	prom_args.args[3] = (void *) b;
+	prom_args.args[4] = (void *) g;
+	prom_args.args[5] = (void *) r;
+	prom(&prom_args);
+	return (int) prom_args.args[6];
+}
+
+static int __init
+prom_next_node(phandle *nodep)
+{
+	phandle node;
+
+	if ((node = *nodep) != 0
+	    && (*nodep = call_prom("child", 1, 1, node)) != 0)
+		return 1;
+	if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+		return 1;
+	for (;;) {
+		if ((node = call_prom("parent", 1, 1, node)) == 0)
+			return 0;
+		if ((*nodep = call_prom("peer", 1, 1, node)) != 0)
+			return 1;
+	}
+}
+
+/*
+ * If we have a display that we don't know how to drive,
+ * we will want to try to execute OF's open method for it
+ * later.  However, OF will probably fall over if we do that
+ * we've taken over the MMU.
+ * So we check whether we will need to open the display,
+ * and if so, open it now.
+ */
+static unsigned long __init
+check_display(unsigned long mem)
+{
+	phandle node;
+	ihandle ih;
+	int i;
+	char type[16], *path;
+	static unsigned char default_colors[] = {
+		0x00, 0x00, 0x00,
+		0x00, 0x00, 0xaa,
+		0x00, 0xaa, 0x00,
+		0x00, 0xaa, 0xaa,
+		0xaa, 0x00, 0x00,
+		0xaa, 0x00, 0xaa,
+		0xaa, 0xaa, 0x00,
+		0xaa, 0xaa, 0xaa,
+		0x55, 0x55, 0x55,
+		0x55, 0x55, 0xff,
+		0x55, 0xff, 0x55,
+		0x55, 0xff, 0xff,
+		0xff, 0x55, 0x55,
+		0xff, 0x55, 0xff,
+		0xff, 0xff, 0x55,
+		0xff, 0xff, 0xff
+	};
+
+	prom_disp_node = 0;
+
+	for (node = 0; prom_next_node(&node); ) {
+		type[0] = 0;
+		call_prom("getprop", 4, 1, node, "device_type",
+			  type, sizeof(type));
+		if (strcmp(type, "display") != 0)
+			continue;
+		/* It seems OF doesn't null-terminate the path :-( */
+		path = (char *) mem;
+		memset(path, 0, 256);
+		if ((int) call_prom("package-to-path", 3, 1,
+				    node, path, 255) < 0)
+			continue;
+
+		/*
+		 * If this display is the device that OF is using for stdout,
+		 * move it to the front of the list.
+		 */
+		mem += strlen(path) + 1;
+		i = prom_num_displays++;
+		if (of_stdout_device != 0 && i > 0
+		    && strcmp(of_stdout_device, path) == 0) {
+			for (; i > 0; --i) {
+				prom_display_paths[i]
+					= prom_display_paths[i-1];
+				prom_display_nodes[i]
+					= prom_display_nodes[i-1];
+			}
+		}
+		prom_display_paths[i] = path;
+		prom_display_nodes[i] = node;
+		if (i == 0)
+			prom_disp_node = node;
+		if (prom_num_displays >= FB_MAX)
+			break;
+	}
+
+try_again:
+	/*
+	 * Open the first display and set its colormap.
+	 */
+	if (prom_num_displays > 0) {
+		path = prom_display_paths[0];
+		prom_print("opening display ");
+		prom_print(path);
+		ih = call_prom("open", 1, 1, path);
+		if (ih == 0 || ih == (ihandle) -1) {
+			prom_print("... failed\n");
+			for (i=1; i<prom_num_displays; i++) {
+				prom_display_paths[i-1] = prom_display_paths[i];
+				prom_display_nodes[i-1] = prom_display_nodes[i];
+			}
+			if (--prom_num_displays > 0)
+				prom_disp_node = prom_display_nodes[0];
+			else
+				prom_disp_node = NULL;
+			goto try_again;
+		} else {
+			prom_print("... ok\n");
+			/*
+			 * Setup a usable color table when the appropriate
+			 * method is available.
+			 * Should update this to use set-colors.
+			 */
+			for (i = 0; i < 32; i++)
+				if (prom_set_color(ih, i, default_colors[i*3],
+						   default_colors[i*3+1],
+						   default_colors[i*3+2]) != 0)
+					break;
+
+#ifdef CONFIG_FB
+			for (i = 0; i < LINUX_LOGO_COLORS; i++)
+				if (prom_set_color(ih, i + 32,
+						   linux_logo_red[i],
+						   linux_logo_green[i],
+						   linux_logo_blue[i]) != 0)
+					break;
+#endif /* CONFIG_FB */
+		}
+	}
+
+	return ALIGNUL(mem);
+}
+
+/* This function will enable the early boot text when doing OF booting. This
+ * way, xmon output should work too
+ */
+static void __init
+setup_disp_fake_bi(ihandle dp)
+{
+#ifdef CONFIG_BOOTX_TEXT
+	int width = 640, height = 480, depth = 8, pitch;
+	unsigned address;
+	struct pci_reg_property addrs[8];
+	int i, naddrs;
+	char name[32];
+	char *getprop = "getprop";
+
+	prom_print("Initializing fake screen: ");
+
+	memset(name, 0, sizeof(name));
+	call_prom(getprop, 4, 1, dp, "name", name, sizeof(name));
+	name[sizeof(name)-1] = 0;
+	prom_print(name);
+	prom_print("\n");
+	call_prom(getprop, 4, 1, dp, "width", &width, sizeof(width));
+	call_prom(getprop, 4, 1, dp, "height", &height, sizeof(height));
+	call_prom(getprop, 4, 1, dp, "depth", &depth, sizeof(depth));
+	pitch = width * ((depth + 7) / 8);
+	call_prom(getprop, 4, 1, dp, "linebytes",
+		  &pitch, sizeof(pitch));
+	if (pitch == 1)
+		pitch = 0x1000;		/* for strange IBM display */
+	address = 0;
+	call_prom(getprop, 4, 1, dp, "address",
+		  &address, sizeof(address));
+	if (address == 0) {
+		/* look for an assigned address with a size of >= 1MB */
+		naddrs = (int) call_prom(getprop, 4, 1, dp,
+				"assigned-addresses",
+				addrs, sizeof(addrs));
+		naddrs /= sizeof(struct pci_reg_property);
+		for (i = 0; i < naddrs; ++i) {
+			if (addrs[i].size_lo >= (1 << 20)) {
+				address = addrs[i].addr.a_lo;
+				/* use the BE aperture if possible */
+				if (addrs[i].size_lo >= (16 << 20))
+					address += (8 << 20);
+				break;
+			}
+		}
+		if (address == 0) {
+			prom_print("Failed to get address\n");
+			return;
+		}
+	}
+	/* kludge for valkyrie */
+	if (strcmp(name, "valkyrie") == 0)
+		address += 0x1000;
+
+	btext_setup_display(width, height, depth, pitch, address);
+
+	btext_prepare_BAT();
+#endif /* CONFIG_BOOTX_TEXT */
+}
+
+/*
+ * Make a copy of the device tree from the PROM.
+ */
+static unsigned long __init
+copy_device_tree(unsigned long mem_start, unsigned long mem_end)
+{
+	phandle root;
+	unsigned long new_start;
+	struct device_node **allnextp;
+
+	root = call_prom("peer", 1, 1, (phandle)0);
+	if (root == (phandle)0) {
+		prom_print("couldn't get device tree root\n");
+		prom_exit();
+	}
+	allnextp = &allnodes;
+	mem_start = ALIGNUL(mem_start);
+	new_start = inspect_node(root, 0, mem_start, mem_end, &allnextp);
+	*allnextp = 0;
+	return new_start;
+}
+
+static unsigned long __init
+inspect_node(phandle node, struct device_node *dad,
+	     unsigned long mem_start, unsigned long mem_end,
+	     struct device_node ***allnextpp)
+{
+	int l;
+	phandle child;
+	struct device_node *np;
+	struct property *pp, **prev_propp;
+	char *prev_name, *namep;
+	unsigned char *valp;
+
+	np = (struct device_node *) mem_start;
+	mem_start += sizeof(struct device_node);
+	memset(np, 0, sizeof(*np));
+	np->node = node;
+	**allnextpp = PTRUNRELOC(np);
+	*allnextpp = &np->allnext;
+	if (dad != 0) {
+		np->parent = PTRUNRELOC(dad);
+		/* we temporarily use the `next' field as `last_child'. */
+		if (dad->next == 0)
+			dad->child = PTRUNRELOC(np);
+		else
+			dad->next->sibling = PTRUNRELOC(np);
+		dad->next = np;
+	}
+
+	/* get and store all properties */
+	prev_propp = &np->properties;
+	prev_name = "";
+	for (;;) {
+		pp = (struct property *) mem_start;
+		namep = (char *) (pp + 1);
+		pp->name = PTRUNRELOC(namep);
+		if ((int) call_prom("nextprop", 3, 1, node, prev_name,
+				    namep) <= 0)
+			break;
+		mem_start = ALIGNUL((unsigned long)namep + strlen(namep) + 1);
+		prev_name = namep;
+		valp = (unsigned char *) mem_start;
+		pp->value = PTRUNRELOC(valp);
+		pp->length = (int)
+			call_prom("getprop", 4, 1, node, namep,
+				  valp, mem_end - mem_start);
+		if (pp->length < 0)
+			continue;
+#ifdef MAX_PROPERTY_LENGTH
+		if (pp->length > MAX_PROPERTY_LENGTH)
+			continue; /* ignore this property */
+#endif
+		mem_start = ALIGNUL(mem_start + pp->length);
+		*prev_propp = PTRUNRELOC(pp);
+		prev_propp = &pp->next;
+	}
+	if (np->node != NULL) {
+		/* Add a "linux,phandle" property" */
+		pp = (struct property *) mem_start;
+		*prev_propp = PTRUNRELOC(pp);
+		prev_propp = &pp->next;
+		namep = (char *) (pp + 1);
+		pp->name = PTRUNRELOC(namep);
+		strcpy(namep, "linux,phandle");
+		mem_start = ALIGNUL((unsigned long)namep + strlen(namep) + 1);
+		pp->value = (unsigned char *) PTRUNRELOC(&np->node);
+		pp->length = sizeof(np->node);
+	}
+	*prev_propp = NULL;
+
+	/* get the node's full name */
+	l = (int) call_prom("package-to-path", 3, 1, node,
+			    (char *) mem_start, mem_end - mem_start);
+	if (l >= 0) {
+		np->full_name = PTRUNRELOC((char *) mem_start);
+		*(char *)(mem_start + l) = 0;
+		mem_start = ALIGNUL(mem_start + l + 1);
+	}
+
+	/* do all our children */
+	child = call_prom("child", 1, 1, node);
+	while (child != (void *)0) {
+		mem_start = inspect_node(child, np, mem_start, mem_end,
+					 allnextpp);
+		child = call_prom("peer", 1, 1, child);
+	}
+
+	return mem_start;
+}
+
+unsigned long smp_chrp_cpu_nr __initdata = 0;
+
+/*
+ * With CHRP SMP we need to use the OF to start the other
+ * processors so we can't wait until smp_boot_cpus (the OF is
+ * trashed by then) so we have to put the processors into
+ * a holding pattern controlled by the kernel (not OF) before
+ * we destroy the OF.
+ *
+ * This uses a chunk of high memory, puts some holding pattern
+ * code there and sends the other processors off to there until
+ * smp_boot_cpus tells them to do something.  We do that by using
+ * physical address 0x0.  The holding pattern checks that address
+ * until its cpu # is there, when it is that cpu jumps to
+ * __secondary_start().  smp_boot_cpus() takes care of setting those
+ * values.
+ *
+ * We also use physical address 0x4 here to tell when a cpu
+ * is in its holding pattern code.
+ *
+ * -- Cort
+ *
+ * Note that we have to do this if we have more than one CPU,
+ * even if this is a UP kernel.  Otherwise when we trash OF
+ * the other CPUs will start executing some random instructions
+ * and crash the system.  -- paulus
+ */
+static void __init
+prom_hold_cpus(unsigned long mem)
+{
+	extern void __secondary_hold(void);
+	unsigned long i;
+	int cpu;
+	phandle node;
+	char type[16], *path;
+	unsigned int reg;
+
+	/*
+	 * XXX: hack to make sure we're chrp, assume that if we're
+	 *      chrp we have a device_type property -- Cort
+	 */
+	node = call_prom("finddevice", 1, 1, "/");
+	if ((int)call_prom("getprop", 4, 1, node,
+			   "device_type",type, sizeof(type)) <= 0)
+		return;
+
+	/* copy the holding pattern code to someplace safe (0) */
+	/* the holding pattern is now within the first 0x100
+	   bytes of the kernel image -- paulus */
+	memcpy((void *)0, &_stext, 0x100);
+	flush_icache_range(0, 0x100);
+
+	/* look for cpus */
+	*(unsigned long *)(0x0) = 0;
+	asm volatile("dcbf 0,%0": : "r" (0) : "memory");
+	for (node = 0; prom_next_node(&node); ) {
+		type[0] = 0;
+		call_prom("getprop", 4, 1, node, "device_type",
+			  type, sizeof(type));
+		if (strcmp(type, "cpu") != 0)
+			continue;
+		path = (char *) mem;
+		memset(path, 0, 256);
+		if ((int) call_prom("package-to-path", 3, 1,
+				    node, path, 255) < 0)
+			continue;
+		reg = -1;
+		call_prom("getprop", 4, 1, node, "reg", &reg, sizeof(reg));
+		cpu = smp_chrp_cpu_nr++;
+#ifdef CONFIG_SMP
+		smp_hw_index[cpu] = reg;
+#endif /* CONFIG_SMP */
+		/* XXX: hack - don't start cpu 0, this cpu -- Cort */
+		if (cpu == 0)
+			continue;
+		prom_print("starting cpu ");
+		prom_print(path);
+		*(ulong *)(0x4) = 0;
+		call_prom("start-cpu", 3, 0, node,
+			  (char *)__secondary_hold - &_stext, cpu);
+		prom_print("...");
+		for ( i = 0 ; (i < 10000) && (*(ulong *)(0x4) == 0); i++ )
+			;
+		if (*(ulong *)(0x4) == cpu)
+			prom_print("ok\n");
+		else {
+			prom_print("failed: ");
+			prom_print_hex(*(ulong *)0x4);
+			prom_print("\n");
+		}
+	}
+}
+
+static void __init
+prom_instantiate_rtas(void)
+{
+	ihandle prom_rtas;
+	unsigned int i;
+	struct prom_args prom_args;
+
+	prom_rtas = call_prom("finddevice", 1, 1, "/rtas");
+	if (prom_rtas == (void *) -1)
+		return;
+
+	rtas_size = 0;
+	call_prom("getprop", 4, 1, prom_rtas,
+		  "rtas-size", &rtas_size, sizeof(rtas_size));
+	prom_print("instantiating rtas");
+	if (rtas_size == 0) {
+		rtas_data = 0;
+	} else {
+		/*
+		 * Ask OF for some space for RTAS.
+		 * Actually OF has bugs so we just arbitrarily
+		 * use memory at the 6MB point.
+		 */
+		rtas_data = 6 << 20;
+		prom_print(" at ");
+		prom_print_hex(rtas_data);
+	}
+
+	prom_rtas = call_prom("open", 1, 1, "/rtas");
+	prom_print("...");
+	prom_args.service = "call-method";
+	prom_args.nargs = 3;
+	prom_args.nret = 2;
+	prom_args.args[0] = "instantiate-rtas";
+	prom_args.args[1] = prom_rtas;
+	prom_args.args[2] = (void *) rtas_data;
+	prom(&prom_args);
+	i = 0;
+	if (prom_args.args[3] == 0)
+		i = (unsigned int)prom_args.args[4];
+	rtas_entry = i;
+	if ((rtas_entry == -1) || (rtas_entry == 0))
+		prom_print(" failed\n");
+	else
+		prom_print(" done\n");
+}
+
+/*
+ * We enter here early on, when the Open Firmware prom is still
+ * handling exceptions and the MMU hash table for us.
+ */
+unsigned long __init
+prom_init(int r3, int r4, prom_entry pp)
+{
+	unsigned long mem;
+	ihandle prom_mmu;
+	unsigned long offset = reloc_offset();
+	int i, l;
+	char *p, *d;
+ 	unsigned long phys;
+	void *result[3];
+
+ 	/* Default */
+ 	phys = (unsigned long) &_stext;
+
+	/* First get a handle for the stdout device */
+	prom = pp;
+	prom_chosen = call_prom("finddevice", 1, 1,
+				       "/chosen");
+	if (prom_chosen == (void *)-1)
+		prom_exit();
+	if ((int) call_prom("getprop", 4, 1, prom_chosen,
+			    "stdout", &prom_stdout,
+			    sizeof(prom_stdout)) <= 0)
+		prom_exit();
+
+	/* Get the full OF pathname of the stdout device */
+	mem = (unsigned long) klimit + offset;
+	p = (char *) mem;
+	memset(p, 0, 256);
+	call_prom("instance-to-path", 3, 1, prom_stdout, p, 255);
+	of_stdout_device = p;
+	mem += strlen(p) + 1;
+
+	/* Get the boot device and translate it to a full OF pathname. */
+	p = (char *) mem;
+	l = (int) call_prom("getprop", 4, 1, prom_chosen,
+			    "bootpath", p, 1<<20);
+	if (l > 0) {
+		p[l] = 0;	/* should already be null-terminated */
+		bootpath = PTRUNRELOC(p);
+		mem += l + 1;
+		d = (char *) mem;
+		*d = 0;
+		call_prom("canon", 3, 1, p, d, 1<<20);
+		bootdevice = PTRUNRELOC(d);
+		mem = ALIGNUL(mem + strlen(d) + 1);
+	}
+
+	prom_instantiate_rtas();
+
+	mem = check_display(mem);
+
+	prom_print("copying OF device tree...");
+	mem = copy_device_tree(mem, mem + (1<<20));
+	prom_print("done\n");
+
+	prom_hold_cpus(mem);
+
+	klimit = (char *) (mem - offset);
+
+	/* If we are already running at 0xc0000000, we assume we were
+	 * loaded by an OF bootloader which did set a BAT for us.
+	 * This breaks OF translate so we force phys to be 0.
+	 */
+	if (offset == 0)
+		phys = 0;
+	else if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu",
+				 &prom_mmu, sizeof(prom_mmu)) <= 0) {
+		prom_print(" no MMU found\n");
+	} else if ((int)call_prom_ret("call-method", 4, 4, result, "translate",
+				      prom_mmu, &_stext, 1) != 0) {
+		prom_print(" (translate failed)\n");
+	} else {
+		/* We assume the phys. address size is 3 cells */
+		phys = (unsigned long)result[2];
+	}
+
+	if (prom_disp_node != 0)
+		setup_disp_fake_bi(prom_disp_node);
+
+	/* Use quiesce call to get OF to shut down any devices it's using */
+	prom_print("Calling quiesce ...\n");
+	call_prom("quiesce", 0, 0);
+
+	/* Relocate various pointers which will be used once the
+	   kernel is running at the address it was linked at. */
+	for (i = 0; i < prom_num_displays; ++i)
+		prom_display_paths[i] = PTRUNRELOC(prom_display_paths[i]);
+
+	prom_print("returning 0x");
+	prom_print_hex(phys);
+	prom_print("from prom_init\n");
+	prom_stdout = 0;
+
+	return phys;
+}
+
+/*
+ * early_get_property is used to access the device tree image prepared
+ * by BootX very early on, before the pointers in it have been relocated.
+ */
+static void * __init
+early_get_property(unsigned long base, unsigned long node, char *prop)
+{
+	struct device_node *np = (struct device_node *)(base + node);
+	struct property *pp;
+
+	for (pp = np->properties; pp != 0; pp = pp->next) {
+		pp = (struct property *) (base + (unsigned long)pp);
+		if (strcmp((char *)((unsigned long)pp->name + base),
+			   prop) == 0) {
+			return (void *)((unsigned long)pp->value + base);
+		}
+	}
+	return 0;
+}
+
+/* Is boot-info compatible ? */
+#define BOOT_INFO_IS_COMPATIBLE(bi)		((bi)->compatible_version <= BOOT_INFO_VERSION)
+#define BOOT_INFO_IS_V2_COMPATIBLE(bi)	((bi)->version >= 2)
+#define BOOT_INFO_IS_V4_COMPATIBLE(bi)	((bi)->version >= 4)
+
+void __init
+bootx_init(unsigned long r4, unsigned long phys)
+{
+	boot_infos_t *bi = (boot_infos_t *) r4;
+	unsigned long space;
+	unsigned long ptr, x;
+	char *model;
+
+	boot_infos = PTRUNRELOC(bi);
+	if (!BOOT_INFO_IS_V2_COMPATIBLE(bi))
+		bi->logicalDisplayBase = 0;
+
+#ifdef CONFIG_BOOTX_TEXT
+	btext_init(bi);
+
+	/*
+	 * Test if boot-info is compatible.  Done only in config
+	 * CONFIG_BOOTX_TEXT since there is nothing much we can do
+	 * with an incompatible version, except display a message
+	 * and eventually hang the processor...
+	 *
+	 * I'll try to keep enough of boot-info compatible in the
+	 * future to always allow display of this message;
+	 */
+	if (!BOOT_INFO_IS_COMPATIBLE(bi)) {
+		btext_drawstring(" !!! WARNING - Incompatible version of BootX !!!\n\n\n");
+		btext_flushscreen();
+	}
+#endif	/* CONFIG_BOOTX_TEXT */
+
+	/* New BootX enters kernel with MMU off, i/os are not allowed
+	   here. This hack will have been done by the boostrap anyway.
+	*/
+	if (bi->version < 4) {
+		/*
+		 * XXX If this is an iMac, turn off the USB controller.
+		 */
+		model = (char *) early_get_property
+			(r4 + bi->deviceTreeOffset, 4, "model");
+		if (model
+		    && (strcmp(model, "iMac,1") == 0
+			|| strcmp(model, "PowerMac1,1") == 0)) {
+			out_le32((unsigned *)0x80880008, 1);	/* XXX */
+		}
+	}
+
+	/* Move klimit to enclose device tree, args, ramdisk, etc... */
+	if (bi->version < 5) {
+		space = bi->deviceTreeOffset + bi->deviceTreeSize;
+		if (bi->ramDisk)
+			space = bi->ramDisk + bi->ramDiskSize;
+	} else
+		space = bi->totalParamsSize;
+	klimit = PTRUNRELOC((char *) bi + space);
+
+	/* New BootX will have flushed all TLBs and enters kernel with
+	   MMU switched OFF, so this should not be useful anymore.
+	*/
+	if (bi->version < 4) {
+		/*
+		 * Touch each page to make sure the PTEs for them
+		 * are in the hash table - the aim is to try to avoid
+		 * getting DSI exceptions while copying the kernel image.
+		 */
+		for (ptr = ((unsigned long) &_stext) & PAGE_MASK;
+		     ptr < (unsigned long)bi + space; ptr += PAGE_SIZE)
+			x = *(volatile unsigned long *)ptr;
+	}
+
+#ifdef CONFIG_BOOTX_TEXT
+	/*
+	 * Note that after we call btext_prepare_BAT, we can't do
+	 * prom_draw*, flushscreen or clearscreen until we turn the MMU
+	 * on, since btext_prepare_BAT sets disp_bi.logicalDisplayBase
+	 * to a virtual address.
+	 */
+	btext_prepare_BAT();
+#endif
+}
diff -Nru a/arch/ppc/syslib/qspan_pci.c b/arch/ppc/syslib/qspan_pci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/qspan_pci.c	Sun Nov 10 19:28:37 2002
@@ -0,0 +1,379 @@
+/*
+ * QSpan pci routines.
+ * Most 8xx boards use the QSpan PCI bridge.  The config address register
+ * is located 0x500 from the base of the bridge control/status registers.
+ * The data register is located at 0x504.
+ * This is a two step operation.  First, the address register is written,
+ * then the data register is read/written as required.
+ * I don't know what to do about interrupts (yet).
+ *
+ * The RPX Classic implementation shares a chip select for normal
+ * PCI access and QSpan control register addresses.  The selection is
+ * further selected by a bit setting in a board control register.
+ * Although it should happen, we disable interrupts during this operation
+ * to make sure some driver doesn't accidentally access the PCI while
+ * we have switched the chip select.
+ */
+
+#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 <asm/io.h>
+#include <asm/mpc8xx.h>
+#include <asm/system.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+
+
+/*
+ * This blows......
+ * When reading the configuration space, if something does not respond
+ * the bus times out and we get a machine check interrupt.  So, the
+ * good ol' exception tables come to mind to trap it and return some
+ * value.
+ *
+ * On an error we just return a -1, since that is what the caller wants
+ * returned if nothing is present.  I copied this from __get_user_asm,
+ * with the only difference of returning -1 instead of EFAULT.
+ * There is an associated hack in the machine check trap code.
+ *
+ * The QSPAN is also a big endian device, that is it makes the PCI
+ * look big endian to us.  This presents a problem for the Linux PCI
+ * functions, which assume little endian.  For example, we see the
+ * first 32-bit word like this:
+ *	------------------------
+ *	| Device ID | Vendor ID |
+ *	------------------------
+ * If we read/write as a double word, that's OK.  But in our world,
+ * when read as a word, device ID is at location 0, not location 2 as
+ * the little endian PCI would believe.  We have to switch bits in
+ * the PCI addresses given to us to get the data to/from the correct
+ * byte lanes.
+ *
+ * The QSPAN only supports 4 bits of "slot" in the dev_fn instead of 5.
+ * It always forces the MS bit to zero.  Therefore, dev_fn values
+ * greater than 128 are returned as "no device found" errors.
+ *
+ * The QSPAN can only perform long word (32-bit) configuration cycles.
+ * The "offset" must have the two LS bits set to zero.  Read operations
+ * require we read the entire word and then sort out what should be
+ * returned.  Write operations other than long word require that we
+ * read the long word, update the proper word or byte, then write the
+ * entire long word back.
+ *
+ * PCI Bridge hack.  We assume (correctly) that bus 0 is the primary
+ * PCI bus from the QSPAN.  If we are called with a bus number other
+ * than zero, we create a Type 1 configuration access that a downstream
+ * PCI bridge will interpret.
+ */
+
+#define __get_qspan_pci_config(x, addr, op)		\
+	__asm__ __volatile__(				\
+		"1:	"op" %0,0(%1)\n"		\
+		"	eieio\n"			\
+		"2:\n"					\
+		".section .fixup,\"ax\"\n"		\
+		"3:	li %0,-1\n"			\
+		"	b 2b\n"				\
+		".section __ex_table,\"a\"\n"		\
+		"	.align 2\n"			\
+		"	.long 1b,3b\n"			\
+		".text"					\
+		: "=r"(x) : "r"(addr) : " %0")
+
+#define QS_CONFIG_ADDR	((volatile uint *)(PCI_CSR_ADDR + 0x500))
+#define QS_CONFIG_DATA	((volatile uint *)(PCI_CSR_ADDR + 0x504))
+
+#define mk_config_addr(bus, dev, offset) \
+	(((bus)<<16) | ((dev)<<8) | (offset & 0xfc))
+
+#define mk_config_type1(bus, dev, offset) \
+	mk_config_addr(bus, dev, offset) | 1;
+
+int qspan_pcibios_read_config_byte(unsigned char bus, unsigned char dev_fn,
+				  unsigned char offset, unsigned char *val)
+{
+	uint	temp;
+	u_char	*cp;
+#ifdef CONFIG_RPXCLASSIC
+	unsigned long flags;
+#endif
+
+	if ((bus > 7) || (dev_fn > 127)) {
+		*val = 0xff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+#ifdef CONFIG_RPXCLASSIC
+	save_flags(flags);
+	cli();
+	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
+	eieio();
+#endif
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	__get_qspan_pci_config(temp, QS_CONFIG_DATA, "lwz");
+
+#ifdef CONFIG_RPXCLASSIC
+	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
+	eieio();
+	restore_flags(flags);
+#endif
+
+	offset ^= 0x03;
+	cp = ((u_char *)&temp) + (offset & 0x03);
+	*val = *cp;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int qspan_pcibios_read_config_word(unsigned char bus, unsigned char dev_fn,
+				  unsigned char offset, unsigned short *val)
+{
+	uint	temp;
+	ushort	*sp;
+#ifdef CONFIG_RPXCLASSIC
+	unsigned long flags;
+#endif
+
+	if ((bus > 7) || (dev_fn > 127)) {
+		*val = 0xffff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+#ifdef CONFIG_RPXCLASSIC
+	save_flags(flags);
+	cli();
+	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
+	eieio();
+#endif
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	__get_qspan_pci_config(temp, QS_CONFIG_DATA, "lwz");
+	offset ^= 0x02;
+
+#ifdef CONFIG_RPXCLASSIC
+	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
+	eieio();
+	restore_flags(flags);
+#endif
+
+	sp = ((ushort *)&temp) + ((offset >> 1) & 1);
+	*val = *sp;
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int qspan_pcibios_read_config_dword(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned int *val)
+{
+#ifdef CONFIG_RPXCLASSIC
+	unsigned long flags;
+#endif
+
+	if ((bus > 7) || (dev_fn > 127)) {
+		*val = 0xffffffff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+#ifdef CONFIG_RPXCLASSIC
+	save_flags(flags);
+	cli();
+	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
+	eieio();
+#endif
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	__get_qspan_pci_config(*val, QS_CONFIG_DATA, "lwz");
+
+#ifdef CONFIG_RPXCLASSIC
+	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
+	eieio();
+	restore_flags(flags);
+#endif
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int qspan_pcibios_write_config_byte(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned char val)
+{
+	uint	temp;
+	u_char	*cp;
+#ifdef CONFIG_RPXCLASSIC
+	unsigned long flags;
+#endif
+
+	if ((bus > 7) || (dev_fn > 127))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	qspan_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
+
+	offset ^= 0x03;
+	cp = ((u_char *)&temp) + (offset & 0x03);
+	*cp = val;
+
+#ifdef CONFIG_RPXCLASSIC
+	save_flags(flags);
+	cli();
+	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
+	eieio();
+#endif
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	*QS_CONFIG_DATA = temp;
+
+#ifdef CONFIG_RPXCLASSIC
+	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
+	eieio();
+	restore_flags(flags);
+#endif
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int qspan_pcibios_write_config_word(unsigned char bus, unsigned char dev_fn,
+				   unsigned char offset, unsigned short val)
+{
+	uint	temp;
+	ushort	*sp;
+#ifdef CONFIG_RPXCLASSIC
+	unsigned long flags;
+#endif
+
+	if ((bus > 7) || (dev_fn > 127))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	qspan_pcibios_read_config_dword(bus, dev_fn, offset, &temp);
+
+	offset ^= 0x02;
+	sp = ((ushort *)&temp) + ((offset >> 1) & 1);
+	*sp = val;
+
+#ifdef CONFIG_RPXCLASSIC
+	save_flags(flags);
+	cli();
+	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
+	eieio();
+#endif
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	*QS_CONFIG_DATA = temp;
+
+#ifdef CONFIG_RPXCLASSIC
+	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
+	eieio();
+	restore_flags(flags);
+#endif
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int qspan_pcibios_write_config_dword(unsigned char bus, unsigned char dev_fn,
+				    unsigned char offset, unsigned int val)
+{
+#ifdef CONFIG_RPXCLASSIC
+	unsigned long flags;
+#endif
+
+	if ((bus > 7) || (dev_fn > 127))
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+#ifdef CONFIG_RPXCLASSIC
+	save_flags(flags);
+	cli();
+	*((uint *)RPX_CSR_ADDR) &= ~BCSR2_QSPACESEL;
+	eieio();
+#endif
+
+	if (bus == 0)
+		*QS_CONFIG_ADDR = mk_config_addr(bus, dev_fn, offset);
+	else
+		*QS_CONFIG_ADDR = mk_config_type1(bus, dev_fn, offset);
+	*(unsigned int *)QS_CONFIG_DATA = val;
+
+#ifdef CONFIG_RPXCLASSIC
+	*((uint *)RPX_CSR_ADDR) |= BCSR2_QSPACESEL;
+	eieio();
+	restore_flags(flags);
+#endif
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+int qspan_pcibios_find_device(unsigned short vendor, unsigned short dev_id,
+			     unsigned short index, unsigned char *bus_ptr,
+			     unsigned char *dev_fn_ptr)
+{
+    int num, devfn;
+    unsigned int x, vendev;
+
+    if (vendor == 0xffff)
+	return PCIBIOS_BAD_VENDOR_ID;
+    vendev = (dev_id << 16) + vendor;
+    num = 0;
+    for (devfn = 0;  devfn < 32;  devfn++) {
+	qspan_pcibios_read_config_dword(0, devfn<<3, PCI_VENDOR_ID, &x);
+	if (x == vendev) {
+	    if (index == num) {
+		*bus_ptr = 0;
+		*dev_fn_ptr = devfn<<3;
+		return PCIBIOS_SUCCESSFUL;
+	    }
+	    ++num;
+	}
+    }
+    return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+int qspan_pcibios_find_class(unsigned int class_code, unsigned short index,
+			    unsigned char *bus_ptr, unsigned char *dev_fn_ptr)
+{
+    int devnr, x, num;
+
+    num = 0;
+    for (devnr = 0;  devnr < 32;  devnr++) {
+	qspan_pcibios_read_config_dword(0, devnr<<3, PCI_CLASS_REVISION, &x);
+	if ((x>>8) == class_code) {
+	    if (index == num) {
+		*bus_ptr = 0;
+		*dev_fn_ptr = devnr<<3;
+		return PCIBIOS_SUCCESSFUL;
+	    }
+	    ++num;
+	}
+    }
+    return PCIBIOS_DEVICE_NOT_FOUND;
+}
+
+void __init
+m8xx_pcibios_fixup(void))
+{
+   /* Lots to do here, all board and configuration specific. */
+}
+
+void __init
+m8xx_setup_pci_ptrs(void))
+{
+	set_config_access_method(qspan);
+
+	ppc_md.pcibios_fixup = m8xx_pcibios_fixup;
+}
+
diff -Nru a/arch/ppc/syslib/todc_time.c b/arch/ppc/syslib/todc_time.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc/syslib/todc_time.c	Sun Nov 10 19:28:40 2002
@@ -0,0 +1,456 @@
+/*
+ * arch/ppc/kernel/todc_time.c
+ * 
+ * Time of Day Clock support for the M48T35, M48T37, M48T59, and MC146818
+ * Real Time Clocks/Timekeepers.
+ *
+ * Author: Mark A. Greer
+ *         mgreer@mvista.com
+ *
+ * Copyright 2001 MontaVista Software 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.
+ */
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+
+#include <asm/machdep.h>
+#include <asm/io.h>
+#include <asm/time.h>
+#include <asm/todc.h>
+
+/*
+ * Depending on the hardware on your board and your board design, the
+ * RTC/NVRAM may be accessed either directly (like normal memory) or via
+ * address/data registers.  If your board uses the direct method, set
+ * 'nvram_data' to the base address of your nvram and leave 'nvram_as0' and
+ * 'nvram_as1' NULL.  If your board uses address/data regs to access nvram,
+ * set 'nvram_as0' to the address of the lower byte, set 'nvram_as1' to the
+ * address of the upper byte (leave NULL if using mv146818), and set
+ * 'nvram_data' to the address of the 8-bit data register.
+ *
+ * You also need to set 'ppc_md.nvram_read_val' and 'ppc_md.nvram_write_val' to
+ * the proper routines.  There are standard ones defined further down in
+ * this file that you can use.
+ *
+ * There is a built in assumption that the RTC and NVRAM are accessed by the
+ * same mechanism (i.e., ppc_md.nvram_read_val, etc works for both).
+ *
+ * Note: Even though the documentation for the various RTC chips say that it
+ * 	 take up to a second before it starts updating once the 'R' bit is
+ * 	 cleared, they always seem to update even though we bang on it many
+ * 	 times a second.  This is true, except for the Dallas Semi 1746/1747
+ * 	 (possibly others).  Those chips seem to have a real problem whenever
+ * 	 we set the 'R' bit before reading them, they basically stop counting.
+ * 	 					--MAG
+ */
+
+/*
+ * 'todc_info' should be initialized in your *_setup.c file to
+ * point to a fully initialized 'todc_info_t' structure.
+ * This structure holds all the register offsets for your particular
+ * TODC/RTC chip.
+ * TODC_ALLOC()/TODC_INIT() will allocate and initialize this table for you.
+ */
+
+#ifdef	RTC_FREQ_SELECT
+#undef	RTC_FREQ_SELECT
+#define	RTC_FREQ_SELECT		control_b	/* Register A */
+#endif
+
+#ifdef	RTC_CONTROL
+#undef	RTC_CONTROL
+#define	RTC_CONTROL		control_a	/* Register B */
+#endif
+
+#ifdef	RTC_INTR_FLAGS
+#undef	RTC_INTR_FLAGS
+#define	RTC_INTR_FLAGS		watchdog	/* Register C */
+#endif
+
+#ifdef	RTC_VALID
+#undef	RTC_VALID
+#define	RTC_VALID		interrupts	/* Register D */
+#endif
+
+/* Access routines when RTC accessed directly (like normal memory) */
+u_char
+todc_direct_read_val(int addr)
+{
+	return readb(todc_info->nvram_data + addr);
+}
+  
+void
+todc_direct_write_val(int addr, unsigned char val)
+{
+	writeb(val, todc_info->nvram_data + addr);
+	return;
+}
+
+/* Access routines for accessing m48txx type chips via addr/data regs */
+u_char
+todc_m48txx_read_val(int addr)
+{
+	outb(addr, todc_info->nvram_as0);
+	outb(addr>>todc_info->as0_bits, todc_info->nvram_as1);
+	return inb(todc_info->nvram_data);
+}
+  
+void
+todc_m48txx_write_val(int addr, unsigned char val)
+{
+	outb(addr, todc_info->nvram_as0);
+	outb(addr>>todc_info->as0_bits, todc_info->nvram_as1);
+   	outb(val, todc_info->nvram_data);
+	return;
+}
+
+/* Access routines for accessing mc146818 type chips via addr/data regs */
+u_char
+todc_mc146818_read_val(int addr)
+{
+	outb(addr, todc_info->nvram_as0);
+	return inb(todc_info->nvram_data);
+}
+  
+void
+todc_mc146818_write_val(int addr, unsigned char val)
+{
+	outb(addr, todc_info->nvram_as0);
+   	outb(val, todc_info->nvram_data);
+	return;
+}
+
+/*
+ * TODC routines
+ *
+ * There is some ugly stuff in that there are assumptions for the mc146818.
+ *
+ * Assumptions:
+ *	- todc_info->control_a has the offset as mc146818 Register B reg
+ *	- todc_info->control_b has the offset as mc146818 Register A reg
+ *	- m48txx control reg's write enable or 'W' bit is same as
+ *	  mc146818 Register B 'SET' bit (i.e., 0x80)
+ *
+ * These assumptions were made to make the code simpler.
+ */
+long __init
+todc_time_init(void)
+{
+	static u_char	not_initialized = 1;
+
+	/* Make sure clocks are running */
+	if (not_initialized) {
+		u_char	cntl_b;
+
+		cntl_b = ppc_md.nvram_read_val(todc_info->control_b);
+
+		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+			if ((cntl_b & 0x70) != 0x20) {
+				printk(KERN_INFO "TODC %s %s\n",
+					"real-time-clock was stopped.",
+					"Now starting...");
+				cntl_b &= ~0x70;
+				cntl_b |= 0x20;
+			}
+
+			ppc_md.nvram_write_val(todc_info->control_b, cntl_b);
+		}
+		else if (todc_info->rtc_type == TODC_TYPE_DS1501) {
+			u_char	month;
+
+			todc_info->enable_read = TODC_DS1501_CNTL_B_TE;
+			todc_info->enable_write = TODC_DS1501_CNTL_B_TE;
+
+			month = ppc_md.nvram_read_val(todc_info->month);
+
+			if ((month & 0x80) == 0x80) {
+				printk(KERN_INFO "TODC %s %s\n",
+					"real-time-clock was stopped.",
+					"Now starting...");
+				month &= ~0x80;
+				ppc_md.nvram_write_val(todc_info->month, month);
+			}
+
+			cntl_b &= ~TODC_DS1501_CNTL_B_TE;
+			ppc_md.nvram_write_val(todc_info->control_b, cntl_b);
+		}
+		else { /* must be a m48txx type */
+			u_char	cntl_a;
+
+			todc_info->enable_read = TODC_MK48TXX_CNTL_A_R;
+			todc_info->enable_write = TODC_MK48TXX_CNTL_A_W;
+
+			cntl_a = ppc_md.nvram_read_val(todc_info->control_a);
+
+			/* Check & clear STOP bit in control B register */
+			if (cntl_b & TODC_MK48TXX_DAY_CB) {
+				printk(KERN_INFO "TODC %s %s\n",
+					"real-time-clock was stopped.",
+					"Now starting...");
+
+				cntl_a |= todc_info->enable_write;
+				cntl_b &= ~TODC_MK48TXX_DAY_CB;/* Start Oscil */
+
+				ppc_md.nvram_write_val(todc_info->control_a,
+						       cntl_a);
+				ppc_md.nvram_write_val(todc_info->control_b,
+						       cntl_b);
+			}
+
+			/* Make sure READ & WRITE bits are cleared. */
+			cntl_a &= ~(todc_info->enable_write |
+				    todc_info->enable_read);
+			ppc_md.nvram_write_val(todc_info->control_a, cntl_a);
+		}
+
+		not_initialized = 0;
+	}
+
+
+	return 0;
+}
+
+/*
+ * There is some ugly stuff in that there are assumptions that for a mc146818,
+ * the todc_info->control_a has the offset of the mc146818 Register B reg and
+ * that the register'ss 'SET' bit is the same as the m48txx's write enable
+ * bit in the control register of the m48txx (i.e., 0x80).
+ *
+ * It was done to make the code look simpler.
+ */
+ulong
+todc_get_rtc_time(void)
+{
+	uint	year, mon, day, hour, min, sec;
+	uint	limit, i;
+	u_char	save_control, uip;
+
+	save_control = ppc_md.nvram_read_val(todc_info->control_a);
+
+	if (todc_info->rtc_type != TODC_TYPE_MC146818) {
+		limit = 1;
+
+		switch (todc_info->rtc_type) {
+			case TODC_TYPE_DS1557:
+			case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
+			case TODC_TYPE_DS1747:
+				break;
+			default:
+				ppc_md.nvram_write_val(todc_info->control_a,
+				       (save_control | todc_info->enable_read));
+		}
+	}
+	else {
+		limit = 100000000;
+	}
+
+	for (i=0; i<limit; i++) {
+		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+			uip = ppc_md.nvram_read_val(todc_info->RTC_FREQ_SELECT);
+		}
+
+		sec = ppc_md.nvram_read_val(todc_info->seconds) & 0x7f;
+		min = ppc_md.nvram_read_val(todc_info->minutes) & 0x7f;
+		hour = ppc_md.nvram_read_val(todc_info->hours) & 0x3f;
+		day = ppc_md.nvram_read_val(todc_info->day_of_month) & 0x3f;
+		mon = ppc_md.nvram_read_val(todc_info->month) & 0x1f;
+		year = ppc_md.nvram_read_val(todc_info->year) & 0xff;
+
+		if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+			uip |= ppc_md.nvram_read_val(
+					todc_info->RTC_FREQ_SELECT);
+			if ((uip & RTC_UIP) == 0) break;
+		}
+	}
+
+	if (todc_info->rtc_type != TODC_TYPE_MC146818) {
+		switch (todc_info->rtc_type) {
+			case TODC_TYPE_DS1557:
+			case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
+			case TODC_TYPE_DS1747:
+				break;
+			default:
+				save_control &= ~(todc_info->enable_read);
+				ppc_md.nvram_write_val(todc_info->control_a,
+						       save_control);
+		}
+	}
+
+	if ((todc_info->rtc_type != TODC_TYPE_MC146818) ||
+	    ((save_control & RTC_DM_BINARY) == 0) ||
+	    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);
+	}
+
+	year = year + 1900;
+	if (year < 1970) {
+		year += 100;
+	}
+
+	return mktime(year, mon, day, hour, min, sec);
+}
+
+int
+todc_set_rtc_time(unsigned long nowtime)
+{
+	struct rtc_time	tm;
+	u_char		save_control, save_freq_select;
+
+	to_tm(nowtime, &tm);
+
+	save_control = ppc_md.nvram_read_val(todc_info->control_a);
+
+	/* Assuming MK48T59_RTC_CA_WRITE & RTC_SET are equal */
+	ppc_md.nvram_write_val(todc_info->control_a,
+			       (save_control | todc_info->enable_write));
+	save_control &= ~(todc_info->enable_write); /* in case it was set */
+
+	if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+		save_freq_select =
+			ppc_md.nvram_read_val(todc_info->RTC_FREQ_SELECT);
+		ppc_md.nvram_write_val(todc_info->RTC_FREQ_SELECT,
+				       save_freq_select | RTC_DIV_RESET2);
+	}
+
+
+        tm.tm_year = (tm.tm_year - 1900) % 100;
+
+	if ((todc_info->rtc_type != TODC_TYPE_MC146818) ||
+	    ((save_control & RTC_DM_BINARY) == 0) ||
+	    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);
+	}
+
+	ppc_md.nvram_write_val(todc_info->seconds,      tm.tm_sec);
+	ppc_md.nvram_write_val(todc_info->minutes,      tm.tm_min);
+	ppc_md.nvram_write_val(todc_info->hours,        tm.tm_hour);
+	ppc_md.nvram_write_val(todc_info->month,        tm.tm_mon);
+	ppc_md.nvram_write_val(todc_info->day_of_month, tm.tm_mday);
+	ppc_md.nvram_write_val(todc_info->year,         tm.tm_year);
+	
+	ppc_md.nvram_write_val(todc_info->control_a, save_control);
+
+	if (todc_info->rtc_type == TODC_TYPE_MC146818) {
+		ppc_md.nvram_write_val(todc_info->RTC_FREQ_SELECT,
+				       save_freq_select);
+	}
+
+	return 0;
+}
+
+/*
+ * Manipulates read bit to reliably read seconds at a high rate.
+ */
+static unsigned char __init todc_read_timereg(int addr)
+{
+	unsigned char save_control, val;
+
+	switch (todc_info->rtc_type) {
+		case TODC_TYPE_DS1557:
+		case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
+		case TODC_TYPE_DS1747:
+		case TODC_TYPE_MC146818:
+			break;
+		default:
+			save_control =
+				ppc_md.nvram_read_val(todc_info->control_a);
+			ppc_md.nvram_write_val(todc_info->control_a,
+				       (save_control | todc_info->enable_read));
+	}
+	val = ppc_md.nvram_read_val(addr);
+
+	switch (todc_info->rtc_type) {
+		case TODC_TYPE_DS1557:
+		case TODC_TYPE_DS1746:	/* XXXX BAD HACK -> FIX */
+		case TODC_TYPE_DS1747:
+		case TODC_TYPE_MC146818:
+			break;
+		default:
+			save_control &= ~(todc_info->enable_read);
+			ppc_md.nvram_write_val(todc_info->control_a,
+					       save_control);
+	}
+
+	return val;
+} 
+
+/*
+ * This was taken from prep_setup.c
+ * Use the NVRAM RTC to time a second to calibrate the decrementer.
+ */
+void __init
+todc_calibrate_decr(void)
+{
+	ulong	freq;
+	ulong	tbl, tbu;
+        long	i, loop_count;
+        u_char	sec;
+ 
+	todc_time_init();
+
+	/*
+	 * 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.
+	 */
+	/*
+	 * Need to make sure the tbl doesn't roll over so if tbu increments
+	 * during this test, we need to do it again.
+	 */
+	loop_count = 0;
+
+	sec = todc_read_timereg(todc_info->seconds) & 0x7f;
+
+	do {
+		tbu = get_tbu();
+
+		for (i = 0 ; i < 10000000 ; i++) {/* may take up to 1 second */
+		   tbl = get_tbl();
+
+		   if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) {
+		      break;
+		   }
+		}
+
+		sec = todc_read_timereg(todc_info->seconds) & 0x7f;
+
+		for (i = 0 ; i < 10000000 ; i++) { /* Should take 1 second */
+		   freq = get_tbl();
+
+		   if ((todc_read_timereg(todc_info->seconds) & 0x7f) != sec) {
+		      break;
+		   }
+		}
+
+		freq -= tbl;
+	} while ((get_tbu() != tbu) && (++loop_count < 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);
+
+	return;
+}
diff -Nru a/arch/ppc/vmlinux.lds.S b/arch/ppc/vmlinux.lds.S
--- a/arch/ppc/vmlinux.lds.S	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc/vmlinux.lds.S	Sun Nov 10 19:28:41 2002
@@ -51,6 +51,20 @@
   .ctors     : { *(.ctors)   }
   .dtors     : { *(.dtors)   }
 
+  .fixup   : { *(.fixup) }
+
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
+
+  __start___ksymtab = .;	/* Kernel symbol table */
+  __ksymtab : { *(__ksymtab) }
+  __stop___ksymtab = .;
+
+  __start___kallsyms = .;     /* All kernel symbols */
+  __kallsyms : { *(__kallsyms) }
+  __stop___kallsyms = .;
+
   /* Read-write section, merged into data segment: */
   . = ALIGN(4096);
   .data    :
@@ -63,25 +77,13 @@
     *(.dynamic)
     CONSTRUCTORS
   }
-  _edata  =  .;
-  PROVIDE (edata = .);
-
-  .fixup   : { *(.fixup) }
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
-  __start___ksymtab = .;	/* Kernel symbol table */
-  __ksymtab : { *(__ksymtab) }
-  __stop___ksymtab = .;
-
-  __start___ftr_fixup = .;
-  __ftr_fixup : { *(__ftr_fixup) }
-  __stop___ftr_fixup = .;
 
   . = ALIGN(32);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
+  _edata  =  .;
+  PROVIDE (edata = .);
+
   . = ALIGN(8192);
   .data.init_task : { *(.data.init_task) }
 
@@ -112,10 +114,21 @@
 	*(.initcall7.init)
   }
   __initcall_end = .;
+
+  __start___ftr_fixup = .;
+  __ftr_fixup : { *(__ftr_fixup) }
+  __stop___ftr_fixup = .;
+
   . = ALIGN(32);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
+
+  . = ALIGN(4096);
+  __initramfs_start = .;
+  .init.ramfs : { *(.init.ramfs) }
+  __initramfs_end = .;
+
   . = ALIGN(4096);
   __init_end = .;
 
@@ -146,10 +159,6 @@
   .openfirmware.data : { *(.openfirmware.data) }
   . = ALIGN(4096);
   __openfirmware_end = .;
-
-  __start___kallsyms = .;     /* All kernel symbols */
-  __kallsyms : { *(__kallsyms) }
-  __stop___kallsyms = .;
 
   __bss_start = .;
   .bss       :
diff -Nru a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig
--- a/arch/ppc64/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc64/Kconfig	Sun Nov 10 19:28:40 2002
@@ -1,6 +1,6 @@
 # 
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 
 config MMU
diff -Nru a/arch/ppc64/Makefile b/arch/ppc64/Makefile
--- a/arch/ppc64/Makefile	Sun Nov 10 19:28:37 2002
+++ b/arch/ppc64/Makefile	Sun Nov 10 19:28:37 2002
@@ -18,6 +18,7 @@
 LDFLAGS		:= -m elf64ppc
 LDFLAGS_vmlinux	= -Bstatic \
 		-e $(KERNELLOAD) -Ttext $(KERNELLOAD)
+LDFLAGS_BLOB	:= --format binary --oformat elf64-powerpc
 CFLAGS		:= $(CFLAGS) -msoft-float -pipe \
 		-Wno-uninitialized -mminimal-toc -mtraceback=full \
 		-finline-limit-2000 -mcpu=power4
diff -Nru a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile
--- a/arch/ppc64/boot/Makefile	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc64/boot/Makefile	Sun Nov 10 19:28:41 2002
@@ -29,9 +29,22 @@
 BOOTAS = $(CROSS32_COMPILE)as
 BOOTAFLAGS = -D__ASSEMBLY__ $(HOSTCFLAGS)
 
-.c.o:
+$(obj)/start.o:	$(obj)/start.c
 	$(BOOTCC) $(BOOTCFLAGS) -c -o $*.o $<
-.S.o:
+
+$(obj)/main.o:	$(obj)/main.c
+	$(BOOTCC) $(BOOTCFLAGS) -c -o $*.o $<
+
+$(obj)/zlib.o:	$(obj)/zlib.c
+	$(BOOTCC) $(BOOTCFLAGS) -c -o $*.o $<
+
+$(obj)/imagesize.o:	$(obj)/imagesize.c
+	$(BOOTCC) $(BOOTCFLAGS) -c -o $*.o $<
+
+$(obj)/no_initrd.o:	$(obj)/no_initrd.c
+	$(BOOTCC) $(BOOTCFLAGS) -c -o $*.o $<
+
+$(obj)/crt0.o:	$(obj)/crt0.S
 	$(BOOTCC) $(BOOTAFLAGS) -traditional -c -o $*.o $<
 
 CFLAGS	= $(CPPFLAGS) -O -fno-builtin -DSTDC_HEADERS
diff -Nru a/arch/ppc64/defconfig b/arch/ppc64/defconfig
--- a/arch/ppc64/defconfig	Sun Nov 10 19:28:38 2002
+++ b/arch/ppc64/defconfig	Sun Nov 10 19:28:38 2002
@@ -1,8 +1,8 @@
 #
 # Automatically generated make config: don't edit
 #
-# CONFIG_UID16 is not set
-# CONFIG_RWSEM_GENERIC_SPINLOCK is not set
+CONFIG_MMU=y
+CONFIG_SWAP=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_HAVE_DEC_LOCK=y
@@ -40,16 +40,11 @@
 CONFIG_NR_CPUS=32
 # CONFIG_HMT is not set
 # CONFIG_DISCONTIGMEM is not set
-# CONFIG_PREEMPT is not set
 # CONFIG_RTAS_FLASH is not set
 
 #
 # General setup
 #
-# CONFIG_ISA is not set
-# CONFIG_SBUS is not set
-# CONFIG_MCA is not set
-# CONFIG_EISA is not set
 CONFIG_PCI=y
 CONFIG_KCORE_ELF=y
 CONFIG_BINFMT_ELF=y
@@ -57,8 +52,6 @@
 # CONFIG_BINFMT_MISC is not set
 CONFIG_PCI_NAMES=y
 # CONFIG_HOTPLUG is not set
-# CONFIG_PCMCIA is not set
-# CONFIG_HOTPLUG_PCI is not set
 CONFIG_PROC_DEVICETREE=y
 # CONFIG_CMDLINE_BOOL is not set
 
@@ -76,18 +69,13 @@
 # Plug and Play configuration
 #
 # CONFIG_PNP is not set
-# CONFIG_ISAPNP is not set
-# CONFIG_PNPBIOS is not set
 
 #
 # Block devices
 #
 CONFIG_BLK_DEV_FD=y
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_PARIDE is not set
 # CONFIG_BLK_CPQ_DA is not set
 # CONFIG_BLK_CPQ_CISS_DA is not set
-# CONFIG_CISS_SCSI_TAPE is not set
 # CONFIG_BLK_DEV_DAC960 is not set
 # CONFIG_BLK_DEV_UMEM is not set
 CONFIG_BLK_DEV_LOOP=y
@@ -100,7 +88,6 @@
 # ATA/ATAPI/MFM/RLL support
 #
 # CONFIG_IDE is not set
-# CONFIG_BLK_DEV_HD is not set
 
 #
 # SCSI device support
@@ -111,12 +98,10 @@
 # SCSI support type (disk, tape, CD-ROM)
 #
 CONFIG_BLK_DEV_SD=y
-CONFIG_SD_EXTRA_DEVS=40
 CONFIG_CHR_DEV_ST=y
 # CONFIG_CHR_DEV_OSST is not set
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_SR_EXTRA_DEVS=2
 CONFIG_CHR_DEV_SG=y
 
 #
@@ -131,7 +116,6 @@
 # SCSI low-level drivers
 #
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-# CONFIG_SCSI_7000FASST is not set
 # CONFIG_SCSI_ACARD is not set
 # CONFIG_SCSI_AACRAID is not set
 # CONFIG_SCSI_AIC7XXX is not set
@@ -144,33 +128,27 @@
 # 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_GENERIC_NCR5380_MMIO is not set
 # CONFIG_SCSI_INITIO is not set
 # CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
 # CONFIG_SCSI_NCR53C7xx is not set
 CONFIG_SCSI_SYM53C8XX_2=y
 CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
 CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
 CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
 # CONFIG_SCSI_SYM53C8XX_IOMAPPED 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_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_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
@@ -179,22 +157,11 @@
 # Multi-device support (RAID and LVM)
 #
 # CONFIG_MD is not set
-# CONFIG_BLK_DEV_MD is not set
-# CONFIG_MD_LINEAR is not set
-# CONFIG_MD_RAID0 is not set
-# CONFIG_MD_RAID1 is not set
-# CONFIG_MD_RAID5 is not set
-# CONFIG_MD_MULTIPATH is not set
-# CONFIG_BLK_DEV_LVM is not set
 
 #
 # Fusion MPT device support
 #
 # CONFIG_FUSION is not set
-# CONFIG_FUSION_BOOT is not set
-# CONFIG_FUSION_ISENSE is not set
-# CONFIG_FUSION_CTL is not set
-# CONFIG_FUSION_LAN is not set
 
 #
 # IEEE 1394 (FireWire) support (EXPERIMENTAL)
@@ -205,11 +172,6 @@
 # I2O device support
 #
 # CONFIG_I2O is not set
-# CONFIG_I2O_PCI is not set
-# CONFIG_I2O_BLOCK is not set
-# CONFIG_I2O_LAN is not set
-# CONFIG_I2O_SCSI is not set
-# CONFIG_I2O_PROC is not set
 
 #
 # Networking options
@@ -220,6 +182,7 @@
 # CONFIG_NETFILTER is not set
 CONFIG_FILTER=y
 CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -230,19 +193,18 @@
 # CONFIG_ARPD is not set
 # CONFIG_INET_ECN is not set
 CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
 CONFIG_IPV6=m
 
 #
-#    SCTP Configuration (EXPERIMENTAL)
+# SCTP Configuration (EXPERIMENTAL)
 #
-CONFIG_IPV6_SCTP__=m
+CONFIG_IPV6_SCTP__=y
 # CONFIG_IP_SCTP is not set
 # CONFIG_ATM is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_LLC is not set
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
-# CONFIG_DEV_APPLETALK is not set
 # CONFIG_DECNET is not set
 # CONFIG_BRIDGE is not set
 # CONFIG_X25 is not set
@@ -259,6 +221,11 @@
 # CONFIG_NET_SCHED is not set
 
 #
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+
+#
 # Network device support
 #
 CONFIG_NETDEVICES=y
@@ -277,23 +244,11 @@
 # Ethernet (10 or 100Mbit)
 #
 CONFIG_NET_ETHERNET=y
-# CONFIG_MACE is not set
-# CONFIG_BMAC is not set
 # CONFIG_OAKNET is not set
-# CONFIG_SUNLANCE is not set
 # CONFIG_HAPPYMEAL is not set
-# CONFIG_SUNBMAC is not set
-# CONFIG_SUNQE is not set
 # CONFIG_SUNGEM is not set
 CONFIG_NET_VENDOR_3COM=y
-# CONFIG_EL1 is not set
-# CONFIG_EL2 is not set
-# CONFIG_ELPLUS is not set
-# CONFIG_EL16 is not set
-# CONFIG_ELMC is not set
-# CONFIG_ELMC_II is not set
 CONFIG_VORTEX=y
-# CONFIG_LANCE is not set
 # CONFIG_NET_VENDOR_SMC is not set
 # CONFIG_NET_VENDOR_RACAL is not set
 
@@ -302,34 +257,22 @@
 #
 # CONFIG_NET_TULIP is not set
 # CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
 CONFIG_NET_PCI=y
 CONFIG_PCNET32=y
 # CONFIG_ADAPTEC_STARFIRE is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
 # CONFIG_DGRS is not set
 # CONFIG_EEPRO100 is not set
 CONFIG_E100=y
-# CONFIG_LNE390 is not set
 # CONFIG_FEALNX is not set
 # CONFIG_NATSEMI is not set
 # CONFIG_NE2K_PCI is not set
-# CONFIG_NE3210 is not set
-# CONFIG_ES3210 is not set
 # CONFIG_8139CP is not set
 # CONFIG_8139TOO is not set
-# CONFIG_8139TOO_PIO is not set
-# CONFIG_8139TOO_TUNE_TWISTER is not set
-# CONFIG_8139TOO_8129 is not set
-# CONFIG_8139_OLD_RX_RESET is not set
 # CONFIG_SIS900 is not set
 # CONFIG_EPIC100 is not set
 # CONFIG_SUNDANCE is not set
-# CONFIG_SUNDANCE_MMIO is not set
 # CONFIG_TLAN is not set
 # CONFIG_VIA_RHINE is not set
-# CONFIG_VIA_RHINE_MMIO is not set
 # CONFIG_NET_POCKET is not set
 
 #
@@ -340,7 +283,6 @@
 # CONFIG_DL2K is not set
 CONFIG_E1000=y
 # CONFIG_E1000_NAPI is not set
-# CONFIG_MYRI_SBUS is not set
 # CONFIG_NS83820 is not set
 # CONFIG_HAMACHI is not set
 # CONFIG_YELLOWFIN is not set
@@ -348,7 +290,6 @@
 # CONFIG_TIGON3 is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
-# CONFIG_PLIP is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
 
@@ -389,8 +330,6 @@
 # Telephony Support
 #
 # CONFIG_PHONE is not set
-# CONFIG_PHONE_IXJ is not set
-# CONFIG_PHONE_IXJ_PCMCIA is not set
 
 #
 # Input device support
@@ -414,17 +353,10 @@
 #
 # CONFIG_GAMEPORT is not set
 CONFIG_SOUND_GAMEPORT=y
-# CONFIG_GAMEPORT_NS558 is not set
-# CONFIG_GAMEPORT_L4 is not set
-# CONFIG_GAMEPORT_EMU10K1 is not set
-# CONFIG_GAMEPORT_VORTEX is not set
-# CONFIG_GAMEPORT_FM801 is not set
-# CONFIG_GAMEPORT_CS461x is not set
 CONFIG_SERIO=y
 CONFIG_SERIO_I8042=y
 # CONFIG_SERIO_SERPORT is not set
 # CONFIG_SERIO_CT82C710 is not set
-# CONFIG_SERIO_PARKBD is not set
 
 #
 # Input Device Drivers
@@ -437,34 +369,8 @@
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
 # CONFIG_MOUSE_SERIAL is not set
-# CONFIG_MOUSE_INPORT is not set
-# CONFIG_MOUSE_LOGIBM is not set
-# CONFIG_MOUSE_PC110PAD is not set
 # CONFIG_INPUT_JOYSTICK is not set
-# CONFIG_JOYSTICK_ANALOG is not set
-# CONFIG_JOYSTICK_A3D is not set
-# CONFIG_JOYSTICK_ADI is not set
-# CONFIG_JOYSTICK_COBRA is not set
-# CONFIG_JOYSTICK_GF2K is not set
-# CONFIG_JOYSTICK_GRIP is not set
-# CONFIG_JOYSTICK_GRIP_MP is not set
-# CONFIG_JOYSTICK_GUILLEMOT is not set
-# CONFIG_JOYSTICK_INTERACT is not set
-# CONFIG_JOYSTICK_SIDEWINDER is not set
-# CONFIG_JOYSTICK_TMDC is not set
-# CONFIG_JOYSTICK_IFORCE is not set
-# CONFIG_JOYSTICK_WARRIOR is not set
-# CONFIG_JOYSTICK_MAGELLAN is not set
-# CONFIG_JOYSTICK_SPACEORB is not set
-# CONFIG_JOYSTICK_SPACEBALL is not set
-# CONFIG_JOYSTICK_STINGER is not set
-# CONFIG_JOYSTICK_TWIDDLER is not set
-# CONFIG_JOYSTICK_DB9 is not set
-# CONFIG_JOYSTICK_GAMECON is not set
-# CONFIG_JOYSTICK_TURBOGRAFX is not set
-# CONFIG_INPUT_JOYDUMP is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
-# CONFIG_TOUCHSCREEN_GUNZE is not set
 CONFIG_INPUT_MISC=y
 CONFIG_INPUT_PCSPKR=y
 # CONFIG_INPUT_UINPUT is not set
@@ -482,13 +388,7 @@
 #
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
-# CONFIG_SERIAL_8250_CS is not set
 # CONFIG_SERIAL_8250_EXTENDED is not set
-# CONFIG_SERIAL_8250_MANY_PORTS is not set
-# CONFIG_SERIAL_8250_SHARE_IRQ is not set
-# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-# CONFIG_SERIAL_8250_MULTIPORT is not set
-# CONFIG_SERIAL_8250_RSA is not set
 
 #
 # Non-8250 serial port support
@@ -527,7 +427,6 @@
 # CONFIG_FTAPE is not set
 # CONFIG_AGP is not set
 # CONFIG_DRM is not set
-# CONFIG_SCx200_GPIO is not set
 CONFIG_RAW_DRIVER=y
 
 #
@@ -539,60 +438,49 @@
 # File systems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_QFMT_V1 is not set
-# CONFIG_QFMT_V2 is not set
 CONFIG_AUTOFS_FS=y
 # CONFIG_AUTOFS4_FS is not set
 CONFIG_REISERFS_FS=y
 # 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_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
 CONFIG_JBD=y
 # CONFIG_JBD_DEBUG is not set
 CONFIG_FAT_FS=y
 CONFIG_MSDOS_FS=y
-# CONFIG_UMSDOS_FS is not set
 CONFIG_VFAT_FS=y
 # CONFIG_EFS_FS is not set
-# CONFIG_JFFS_FS is not set
-# CONFIG_JFFS2_FS is not set
 # CONFIG_CRAMFS is not set
 # CONFIG_TMPFS is not set
 CONFIG_RAMFS=y
 CONFIG_ISO9660_FS=y
 # CONFIG_JOLIET is not set
 # CONFIG_ZISOFS is not set
-CONFIG_JFS_FS=y
-# CONFIG_JFS_DEBUG is not set
-# CONFIG_JFS_STATISTICS is not set
+# CONFIG_JFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_NTFS_FS is not set
-# CONFIG_NTFS_DEBUG is not set
-# CONFIG_NTFS_RW is not set
 # CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
 # CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
-# CONFIG_DEVFS_DEBUG is not set
 CONFIG_DEVPTS_FS=y
 # CONFIG_QNX4FS_FS is not set
-# CONFIG_QNX4FS_RW is not set
 # CONFIG_ROMFS_FS is not set
 CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UDF_FS is not set
-# CONFIG_UDF_RW is not set
 # CONFIG_UFS_FS is not set
-# CONFIG_UFS_FS_WRITE is not set
 CONFIG_XFS_FS=y
 # CONFIG_XFS_RT is not set
 # CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_POSIX_ACL is not set
 
 #
 # Network File Systems
@@ -602,10 +490,9 @@
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
 CONFIG_NFS_V4=y
-# CONFIG_ROOT_NFS is not set
 CONFIG_NFSD=y
 CONFIG_NFSD_V3=y
-CONFIG_NFSD_V4=y
+# CONFIG_NFSD_V4 is not set
 CONFIG_NFSD_TCP=y
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
@@ -614,24 +501,14 @@
 CONFIG_CIFS=y
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
-# CONFIG_NCPFS_PACKET_SIGNING is not set
-# CONFIG_NCPFS_IOCTL_LOCKING is not set
-# CONFIG_NCPFS_STRONG is not set
-# CONFIG_NCPFS_NFS_NS is not set
-# CONFIG_NCPFS_OS2_NS is not set
-# CONFIG_NCPFS_SMALLDOS is not set
-# CONFIG_NCPFS_NLS is not set
-# CONFIG_NCPFS_EXTRAS is not set
 CONFIG_AFS_FS=y
 CONFIG_RXRPC=y
-# CONFIG_ZISOFS_FS is not set
 
 #
 # Partition Types
 #
 # CONFIG_PARTITION_ADVANCED is not set
 CONFIG_MSDOS_PARTITION=y
-# CONFIG_SMB_NLS is not set
 CONFIG_NLS=y
 
 #
@@ -688,10 +565,7 @@
 # CONFIG_FB_CLGEN is not set
 # CONFIG_FB_PM2 is not set
 # CONFIG_FB_CYBER2000 is not set
-# CONFIG_FB_OF is not set
-# CONFIG_FB_CONTROL is not set
-# CONFIG_FB_PLATINUM is not set
-# CONFIG_FB_VALKYRIE is not set
+# CONFIG_FB_ATY is not set
 # CONFIG_FB_CT65550 is not set
 # CONFIG_FB_IMSTT is not set
 # CONFIG_FB_S3TRIO is not set
@@ -703,7 +577,6 @@
 CONFIG_FB_MATROX_G450=y
 CONFIG_FB_MATROX_G100=y
 CONFIG_FB_MATROX_MULTIHEAD=y
-# CONFIG_FB_ATY is not set
 # CONFIG_FB_RADEON is not set
 # CONFIG_FB_ATY128 is not set
 # CONFIG_FB_SIS is not set
@@ -719,10 +592,10 @@
 CONFIG_FBCON_CFB24=y
 CONFIG_FBCON_CFB32=y
 CONFIG_FBCON_FONTWIDTH8_ONLY=y
+# CONFIG_FONT_SUN8x16 is not set
 CONFIG_FBCON_FONTS=y
 CONFIG_FONT_8x8=y
 CONFIG_FONT_8x16=y
-# CONFIG_FONT_SUN8x16 is not set
 # CONFIG_FONT_PEARL_8x8 is not set
 # CONFIG_FONT_ACORN_8x8 is not set
 # CONFIG_FONT_MINI_4x6 is not set
@@ -758,8 +631,11 @@
 CONFIG_SECURITY_CAPABILITIES=y
 
 #
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
 # Library routines
 #
 CONFIG_CRC32=y
-# CONFIG_ZLIB_INFLATE is not set
-# CONFIG_ZLIB_DEFLATE is not set
diff -Nru a/arch/ppc64/kernel/htab.c b/arch/ppc64/kernel/htab.c
--- a/arch/ppc64/kernel/htab.c	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc64/kernel/htab.c	Sun Nov 10 19:28:40 2002
@@ -50,27 +50,35 @@
 /*
  * Note:  pte   --> Linux PTE
  *        HPTE  --> PowerPC Hashed Page Table Entry
+ *
+ * Execution context:
+ *   htab_initialize is called with the MMU off (of course), but
+ *   the kernel has been copied down to zero so it can directly
+ *   reference global data.  At this point it is very difficult
+ *   to print debug info.
+ *
  */
 
 HTAB htab_data = {NULL, 0, 0, 0, 0};
 
 extern unsigned long _SDR1;
-extern unsigned long klimit;
-
-extern unsigned long reloc_offset(void);
-#define PTRRELOC(x)	((typeof(x))((unsigned long)(x) - offset))
-#define PTRUNRELOC(x)	((typeof(x))((unsigned long)(x) + offset))
-#define RELOC(x)	(*PTRRELOC(&(x)))
 
 #define KB (1024)
 #define MB (1024*KB)
+
+static inline void
+loop_forever(void)
+{
+	volatile unsigned long x = 1;
+	for(;x;x|=1)
+		;
+}
+
 static inline void
 create_pte_mapping(unsigned long start, unsigned long end,
-		   unsigned long mode, unsigned long mask, int large)
+		   unsigned long mode, int large)
 {
-	unsigned long addr, offset = reloc_offset();
-	HTAB *_htab_data = PTRRELOC(&htab_data);
-	HPTE *htab = (HPTE *)__v2a(_htab_data->htab);
+	unsigned long addr;
 	unsigned int step;
 
 	if (large)
@@ -79,14 +87,33 @@
 		step = 4*KB;
 
 	for (addr = start; addr < end; addr += step) {
+		unsigned long vpn, hash, hpteg;
 		unsigned long vsid = get_kernel_vsid(addr);
 		unsigned long va = (vsid << 28) | (addr & 0xfffffff);
+		int ret;
+
+		if (large)
+			vpn = va >> LARGE_PAGE_SHIFT;
+		else
+			vpn = va >> PAGE_SHIFT;
+
+		hash = hpt_hash(vpn, large);
+
+		hpteg = ((hash & htab_data.htab_hash_mask)*HPTES_PER_GROUP);
+
 		if (naca->platform == PLATFORM_PSERIES_LPAR)
-			pSeries_lpar_make_pte(htab, va,
-				(unsigned long)__v2a(addr), mode, mask, large);
+			ret = pSeries_lpar_hpte_insert(hpteg, va,
+				(unsigned long)__v2a(addr) >> PAGE_SHIFT,
+				0, mode, 1, large);
 		else
-			pSeries_make_pte(htab, va,
-				(unsigned long)__v2a(addr), mode, mask, large);
+			ret = pSeries_hpte_insert(hpteg, va,
+				(unsigned long)__v2a(addr) >> PAGE_SHIFT,
+				0, mode, 1, large);
+
+		if (ret == -1) {
+			ppc64_terminate_msg(0x20, "create_pte_mapping");
+			loop_forever();
+		}
 	}
 }
 
@@ -95,16 +122,13 @@
 {
 	unsigned long table, htab_size_bytes;
 	unsigned long pteg_count;
-	unsigned long mode_rw, mask;
-	unsigned long offset = reloc_offset();
-	struct naca_struct *_naca = RELOC(naca);
-	HTAB *_htab_data = PTRRELOC(&htab_data);
+	unsigned long mode_rw;
 
 	/*
 	 * Calculate the required size of the htab.  We want the number of
 	 * PTEGs to equal one half the number of real pages.
 	 */ 
-	htab_size_bytes = 1UL << _naca->pftSize;
+	htab_size_bytes = 1UL << naca->pftSize;
 	pteg_count = htab_size_bytes >> 7;
 
 	/* For debug, make the HTAB 1/8 as big as it normally would be. */
@@ -113,42 +137,44 @@
 		htab_size_bytes = pteg_count << 7;
 	}
 
-	_htab_data->htab_num_ptegs = pteg_count;
-	_htab_data->htab_hash_mask = pteg_count - 1;
+	htab_data.htab_num_ptegs = pteg_count;
+	htab_data.htab_hash_mask = pteg_count - 1;
 
 	if (naca->platform == PLATFORM_PSERIES) {
 		/* Find storage for the HPT.  Must be contiguous in
 		 * the absolute address space.
 		 */
 		table = lmb_alloc(htab_size_bytes, htab_size_bytes);
-		if ( !table )
-			panic("ERROR, cannot find space for HPTE\n");
-		_htab_data->htab = (HPTE *)__a2v(table);
+		if ( !table ) {
+			ppc64_terminate_msg(0x20, "hpt space");
+			loop_forever();
+		}
+		htab_data.htab = (HPTE *)__a2v(table);
 
 		/* htab absolute addr + encoded htabsize */
-		RELOC(_SDR1) = table + __ilog2(pteg_count) - 11;
+		_SDR1 = table + __ilog2(pteg_count) - 11;
 
 		/* Initialize the HPT with no entries */
 		memset((void *)table, 0, htab_size_bytes);
 	} else {
-		_htab_data->htab = NULL;
-		RELOC(_SDR1) = 0; 
+		/* Using a hypervisor which owns the htab */
+		htab_data.htab = NULL;
+		_SDR1 = 0; 
 	}
 
 	mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;
-	mask = pteg_count-1;
 
 	/* XXX we currently map kernel text rw, should fix this */
-	if (cpu_has_largepage() && _naca->physicalMemorySize > 256*MB) {
+	if (cpu_has_largepage() && naca->physicalMemorySize > 256*MB) {
 		create_pte_mapping((unsigned long)KERNELBASE, 
-				   KERNELBASE + 256*MB, mode_rw, mask, 0);
+				   KERNELBASE + 256*MB, mode_rw, 0);
 		create_pte_mapping((unsigned long)KERNELBASE + 256*MB, 
-				   KERNELBASE + (_naca->physicalMemorySize), 
-				   mode_rw, mask, 1);
+				   KERNELBASE + (naca->physicalMemorySize), 
+				   mode_rw, 1);
 	} else {
 		create_pte_mapping((unsigned long)KERNELBASE, 
-				   KERNELBASE+(_naca->physicalMemorySize), 
-				   mode_rw, mask, 0);
+				   KERNELBASE+(naca->physicalMemorySize), 
+				   mode_rw, 0);
 	}
 }
 #undef KB
@@ -194,7 +220,7 @@
  * to be valid via Linux page tables, return 1. If handled return 0
  */
 int __hash_page(unsigned long ea, unsigned long access, unsigned long vsid,
-		pte_t *ptep, unsigned long trap)
+		pte_t *ptep, unsigned long trap, int local)
 {
 	unsigned long va, vpn;
 	unsigned long newpp, prpn;
@@ -202,9 +228,16 @@
 	long slot;
 	pte_t old_pte, new_pte;
 
+	/* XXX fix for large ptes */
+	int large = 0;
+
 	/* Search the Linux page table for a match with va */
 	va = (vsid << 28) | (ea & 0x0fffffff);
-	vpn = va >> PAGE_SHIFT;
+
+	if (large)
+		vpn = va >> LARGE_PAGE_SHIFT;
+	else
+		vpn = va >> PAGE_SHIFT;
 
 	/*
 	 * If no pte found or not present, send the problem up to
@@ -266,16 +299,14 @@
 		/* There MIGHT be an HPTE for this pte */
 		unsigned long hash, slot, secondary;
 
-		/* XXX fix large pte flag */
-		hash = hpt_hash(vpn, 0);
+		hash = hpt_hash(vpn, large);
 		secondary = (pte_val(old_pte) & _PAGE_SECONDARY) >> 15;
 		if (secondary)
 			hash = ~hash;
 		slot = (hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP;
 		slot += (pte_val(old_pte) & _PAGE_GROUP_IX) >> 12;
 
-		/* XXX fix large pte flag */
-		if (ppc_md.hpte_updatepp(slot, newpp, va, 0) == -1)
+		if (ppc_md.hpte_updatepp(slot, newpp, va, large, local) == -1)
 			pte_val(old_pte) &= ~_PAGE_HPTEFLAGS;
 		else
 			if (!pte_same(old_pte, new_pte))
@@ -283,8 +314,7 @@
 	}
 
 	if (likely(!(pte_val(old_pte) & _PAGE_HASHPTE))) {
-		/* XXX fix large pte flag */
-		unsigned long hash = hpt_hash(vpn, 0);
+		unsigned long hash = hpt_hash(vpn, large);
 		unsigned long hpte_group;
 		prpn = pte_val(old_pte) >> PTE_SHIFT;
 
@@ -299,23 +329,21 @@
 		/* copy appropriate flags from linux pte */
 		hpteflags = (pte_val(new_pte) & 0x1f8) | newpp;
 
-		/* XXX fix large pte flag */
-		slot = ppc_md.insert_hpte(hpte_group, vpn, prpn, 0,
-					  hpteflags, 0, 0);
+		slot = ppc_md.hpte_insert(hpte_group, va, prpn, 0,
+					  hpteflags, 0, large);
 
 		/* Primary is full, try the secondary */
 		if (slot == -1) {
 			pte_val(new_pte) |= 1 << 15;
 			hpte_group = ((~hash & htab_data.htab_hash_mask) *
 				      HPTES_PER_GROUP) & ~0x7UL; 
-			/* XXX fix large pte flag */
-			slot = ppc_md.insert_hpte(hpte_group, vpn, prpn,
-						  1, hpteflags, 0, 0);
+			slot = ppc_md.hpte_insert(hpte_group, va, prpn,
+						  1, hpteflags, 0, large);
 			if (slot == -1) {
 				if (mftb() & 0x1)
 					hpte_group = ((hash & htab_data.htab_hash_mask) * HPTES_PER_GROUP) & ~0x7UL;
 
-				ppc_md.remove_hpte(hpte_group);
+				ppc_md.hpte_remove(hpte_group);
 				goto repeat;
                         }
 		}
@@ -341,6 +369,8 @@
 	struct mm_struct *mm;
 	pte_t *ptep;
 	int ret;
+	int user_region = 0;
+	int local = 0;
 
 	/* Check for invalid addresses. */
 	if (!IS_VALID_EA(ea))
@@ -348,6 +378,7 @@
 
  	switch (REGION_ID(ea)) {
 	case USER_REGION_ID:
+		user_region = 1;
 		mm = current->mm;
 		if (mm == NULL)
 			return 1;
@@ -363,21 +394,20 @@
 		vsid = get_kernel_vsid(ea);
 		break;
 	case IO_UNMAPPED_REGION_ID:
-		udbg_printf("EEH Error ea = 0x%lx\n", ea);
-		PPCDBG_ENTER_DEBUGGER();
-		panic("EEH Error ea = 0x%lx\n", ea);
-		break;
+		/*
+		 * Should only be hit if there is an access to MMIO space
+		 * which is protected by EEH.
+		 * Send the problem up to do_page_fault 
+		 */
 	case KERNEL_REGION_ID:
 		/*
-		 * As htab_initialize is now, we shouldn't ever get here since
-		 * we're bolting the entire 0xC0... region.
+		 * Should never get here - entire 0xC0... region is bolted.
+		 * Send the problem up to do_page_fault 
 		 */
-		udbg_printf("Little faulted on kernel address 0x%lx\n", ea);
-		PPCDBG_ENTER_DEBUGGER();
-		panic("Little faulted on kernel address 0x%lx\n", ea);
-		break;
 	default:
-		/* Not a valid range, send the problem up to do_page_fault */
+		/* Not a valid range
+		 * Send the problem up to do_page_fault 
+		 */
 		return 1;
 		break;
 	}
@@ -392,8 +422,12 @@
 	 * from modifying entries while we search and update
 	 */
 	spin_lock(&mm->page_table_lock);
+
+	if (user_region && (mm->cpu_vm_mask == (1 << smp_processor_id())))
+		local = 1;
+
 	ptep = find_linux_pte(pgdir, ea);
-	ret = __hash_page(ea, access, vsid, ptep, trap);
+	ret = __hash_page(ea, access, vsid, ptep, trap, local);
 	spin_unlock(&mm->page_table_lock);
 
 	return ret;
diff -Nru a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c
--- a/arch/ppc64/kernel/ioctl32.c	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc64/kernel/ioctl32.c	Sun Nov 10 19:28:41 2002
@@ -58,14 +58,12 @@
 #include <linux/netdevice.h>
 #include <linux/raw.h>
 #include <linux/smb_fs.h>
+#include <linux/ncp_fs.h>
 #include <linux/blkpg.h>
 #include <linux/blk.h>
 #include <linux/elevator.h>
 #include <linux/rtc.h>
 #include <linux/pci.h>
-#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
-#include <linux/lvm.h>
-#endif /* LVM */
 #include <linux/dm-ioctl.h>
 
 #include <scsi/scsi.h>
@@ -826,12 +824,40 @@
 	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));
+		if (copy_to_user ((struct hd_geometry32 *)arg, &geo, 4) ||
+		    __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start)))
+			err = -EFAULT;
 	}
-	return err ? -EFAULT : 0;
+	return err;
 }
 
+struct hd_big_geometry32 {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned int cylinders;
+	u32 start;
+};
+                        
+static int hdio_getgeo_big(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct hd_big_geometry geo;
+	int err;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&geo);
+	set_fs (old_fs);
+	if (!err) {
+		struct hd_big_geometry32 *up = (struct hd_big_geometry32 *) arg;
+
+		if (put_user(geo.heads, &up->heads) ||
+		    __put_user(geo.sectors, &up->sectors) ||
+		    __put_user(geo.cylinders, &up->cylinders) ||
+		    __put_user(((u32) geo.start), &up->start))
+			err = -EFAULT;
+	}
+	return err;
+}
 
 static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
@@ -2037,6 +2063,306 @@
 	return err;
 }
 
+struct ncp_ioctl_request_32 {
+	unsigned int function;
+	unsigned int size;
+	__kernel_caddr_t32 data;
+};
+
+struct ncp_fs_info_v2_32 {
+	int version;
+	unsigned int mounted_uid;
+	unsigned int connection;
+	unsigned int buffer_size;
+
+	unsigned int volume_number;
+	__u32 directory_id;
+
+	__u32 dummy1;
+	__u32 dummy2;
+	__u32 dummy3;
+};
+
+struct ncp_objectname_ioctl_32
+{
+	int		auth_type;
+	unsigned int	object_name_len;
+	__kernel_caddr_t32	object_name;	/* an userspace data, in most cases user name */
+};
+
+struct ncp_privatedata_ioctl_32
+{
+	unsigned int	len;
+	__kernel_caddr_t32	data;		/* ~1000 for NDS */
+};
+
+#define	NCP_IOC_NCPREQUEST_32		_IOR('n', 1, struct ncp_ioctl_request_32)
+
+#define NCP_IOC_GETMOUNTUID2_32		_IOW('n', 2, unsigned int)
+
+#define NCP_IOC_GET_FS_INFO_V2_32	_IOWR('n', 4, struct ncp_fs_info_v2_32)
+
+#define NCP_IOC_GETOBJECTNAME_32	_IOWR('n', 9, struct ncp_objectname_ioctl_32)
+#define NCP_IOC_SETOBJECTNAME_32	_IOR('n', 9, struct ncp_objectname_ioctl_32)
+#define NCP_IOC_GETPRIVATEDATA_32	_IOWR('n', 10, struct ncp_privatedata_ioctl_32)
+#define NCP_IOC_SETPRIVATEDATA_32	_IOR('n', 10, struct ncp_privatedata_ioctl_32)
+
+static int do_ncp_ncprequest(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_ioctl_request_32 n32;
+	struct ncp_ioctl_request n;
+	mm_segment_t old_fs;
+	int err;
+
+	if (copy_from_user(&n32, (struct ncp_ioctl_request_32*)arg,
+	    sizeof(n32)))
+		return -EFAULT;
+
+	n.function = n32.function;
+	n.size = n32.size;
+	if (n.size > 65536)
+		return -EINVAL;
+	n.data = vmalloc(65536);	/* 65536 must be same as NCP_PACKET_SIZE_INTERNAL in ncpfs */
+	if (!n.data)
+		return -ENOMEM;
+	err = -EFAULT;
+	if (copy_from_user(n.data, (void *)A(n32.data), n.size))
+		goto out;
+
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, NCP_IOC_NCPREQUEST, (unsigned long)&n);
+	set_fs (old_fs);
+        if(err <= 0)
+		goto out;
+	if (err > 65536) {
+		err = -EINVAL;
+		goto out;
+	}
+	if (copy_to_user((void *)A(n32.data), n.data, err)) {
+		err = -EFAULT;
+		goto out;
+	}
+ out:
+	vfree(n.data);
+	return err;
+}
+
+static int do_ncp_getmountuid2(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	__kernel_uid_t kuid;
+	int err;
+
+	cmd = NCP_IOC_GETMOUNTUID2;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&kuid);
+	set_fs(old_fs);
+
+	if (!err)
+		err = put_user(kuid, (unsigned int*)arg);
+
+	return err;
+}
+
+static int do_ncp_getfsinfo2(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	mm_segment_t old_fs = get_fs();
+	struct ncp_fs_info_v2_32 n32;
+	struct ncp_fs_info_v2 n;
+	int err;
+
+	if (copy_from_user(&n32, (struct ncp_fs_info_v2_32*)arg, sizeof(n32)))
+		return -EFAULT;
+	if (n32.version != NCP_GET_FS_INFO_VERSION_V2)
+		return -EINVAL;
+	n.version = NCP_GET_FS_INFO_VERSION_V2;
+
+	set_fs(KERNEL_DS);
+	err = sys_ioctl(fd, NCP_IOC_GET_FS_INFO_V2, (unsigned long)&n);
+	set_fs(old_fs);
+
+	if (!err) {
+		n32.version = n.version;
+		n32.mounted_uid = n.mounted_uid;
+		n32.connection = n.connection;
+		n32.buffer_size = n.buffer_size;
+		n32.volume_number = n.volume_number;
+		n32.directory_id = n.directory_id;
+		n32.dummy1 = n.dummy1;
+		n32.dummy2 = n.dummy2;
+		n32.dummy3 = n.dummy3;
+		err = copy_to_user((struct ncp_fs_info_v2_32*)arg, &n32, sizeof(n32)) ? -EFAULT : 0;
+	}
+	return err;
+}
+
+static int do_ncp_getobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_objectname_ioctl_32 n32;
+	struct ncp_objectname_ioctl n;
+	mm_segment_t old_fs;
+	int err;
+	size_t tl;
+
+	if (copy_from_user(&n32, (struct ncp_objectname_ioctl_32*)arg,
+	    sizeof(n32)))
+		return -EFAULT;
+
+	n.object_name_len = tl = n32.object_name_len;
+	if (tl) {
+		n.object_name = kmalloc(tl, GFP_KERNEL);
+		if (!n.object_name)
+			return -ENOMEM;
+	} else {
+		n.object_name = NULL;
+	}
+
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, NCP_IOC_GETOBJECTNAME, (unsigned long)&n);
+	set_fs (old_fs);
+        if(err)
+		goto out;
+		
+	if (tl > n.object_name_len)
+		tl = n.object_name_len;
+
+	err = -EFAULT;
+	if (tl && copy_to_user((void *)A(n32.object_name), n.object_name, tl))
+		goto out;
+
+	n32.auth_type = n.auth_type;
+	n32.object_name_len = n.object_name_len;
+	
+	if (copy_to_user((struct ncp_objectname_ioctl_32*)arg, &n32, sizeof(n32)))
+		goto out;
+	
+	err = 0;
+ out:
+ 	if (n.object_name)
+		kfree(n.object_name);
+
+	return err;
+}
+
+static int do_ncp_setobjectname(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_objectname_ioctl_32 n32;
+	struct ncp_objectname_ioctl n;
+	mm_segment_t old_fs;
+	int err;
+	size_t tl;
+
+	if (copy_from_user(&n32, (struct ncp_objectname_ioctl_32*)arg,
+	    sizeof(n32)))
+		return -EFAULT;
+
+	n.auth_type = n32.auth_type;
+	n.object_name_len = tl = n32.object_name_len;
+	if (tl) {
+		n.object_name = kmalloc(tl, GFP_KERNEL);
+		if (!n.object_name)
+			return -ENOMEM;
+		err = -EFAULT;
+		if (copy_from_user(n.object_name, (void *)A(n32.object_name), tl))
+			goto out;
+	} else {
+		n.object_name = NULL;
+	}
+	
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, NCP_IOC_SETOBJECTNAME, (unsigned long)&n);
+	set_fs (old_fs);
+		
+ out:
+	if (n.object_name)
+		kfree(n.object_name);
+
+	return err;
+}
+
+static int do_ncp_getprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_privatedata_ioctl_32 n32;
+	struct ncp_privatedata_ioctl n;
+	mm_segment_t old_fs;
+	int err;
+	size_t tl;
+
+	if (copy_from_user(&n32, (struct ncp_privatedata_ioctl_32*)arg,
+	    sizeof(n32)))
+		return -EFAULT;
+
+	n.len = tl = n32.len;
+	if (tl) {
+		n.data = kmalloc(tl, GFP_KERNEL);
+		if (!n.data)
+			return -ENOMEM;
+	} else {
+		n.data = NULL;
+	}
+
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, NCP_IOC_GETPRIVATEDATA, (unsigned long)&n);
+	set_fs (old_fs);
+        if(err)
+		goto out;
+		
+	if (tl > n.len)
+		tl = n.len;
+
+	err = -EFAULT;
+	if (tl && copy_to_user((void *)A(n32.data), n.data, tl))
+		goto out;
+
+	n32.len = n.len;
+	
+	if (copy_to_user((struct ncp_privatedata_ioctl_32*)arg, &n32, sizeof(n32)))
+		goto out;
+	
+	err = 0;
+ out:
+ 	if (n.data)
+		kfree(n.data);
+
+	return err;
+}
+
+static int do_ncp_setprivatedata(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ncp_privatedata_ioctl_32 n32;
+	struct ncp_privatedata_ioctl n;
+	mm_segment_t old_fs;
+	int err;
+	size_t tl;
+
+	if (copy_from_user(&n32, (struct ncp_privatedata_ioctl_32*)arg,
+	    sizeof(n32)))
+		return -EFAULT;
+
+	n.len = tl = n32.len;
+	if (tl) {
+		n.data = kmalloc(tl, GFP_KERNEL);
+		if (!n.data)
+			return -ENOMEM;
+		err = -EFAULT;
+		if (copy_from_user(n.data, (void *)A(n32.data), tl))
+			goto out;
+	} else {
+		n.data = NULL;
+	}
+	
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, NCP_IOC_SETPRIVATEDATA, (unsigned long)&n);
+	set_fs (old_fs);
+		
+ out:
+	if (n.data)
+		kfree(n.data);
+
+	return err;
+}
+
 struct atmif_sioc32 {
         int                number;
         int                length;
@@ -2253,443 +2579,6 @@
         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
-
 #if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
 /* This really belongs in include/linux/drm.h -DaveM */
 #include "../../../drivers/char/drm/drm.h"
@@ -4288,6 +4177,18 @@
 COMPATIBLE_IOCTL(RAW_GETBIND),
 /* SMB ioctls which do not need any translations */
 COMPATIBLE_IOCTL(SMB_IOC_NEWCONN),
+/* NCP ioctls which do not need any translations */
+COMPATIBLE_IOCTL(NCP_IOC_CONN_LOGGED_IN),
+COMPATIBLE_IOCTL(NCP_IOC_SIGN_INIT),
+COMPATIBLE_IOCTL(NCP_IOC_SIGN_WANTED),
+COMPATIBLE_IOCTL(NCP_IOC_SET_SIGN_WANTED),
+COMPATIBLE_IOCTL(NCP_IOC_LOCKUNLOCK),
+COMPATIBLE_IOCTL(NCP_IOC_GETROOT),
+COMPATIBLE_IOCTL(NCP_IOC_SETROOT),
+COMPATIBLE_IOCTL(NCP_IOC_GETCHARSETS),
+COMPATIBLE_IOCTL(NCP_IOC_SETCHARSETS),
+COMPATIBLE_IOCTL(NCP_IOC_GETDENTRYTTL),
+COMPATIBLE_IOCTL(NCP_IOC_SETDENTRYTTL),
 /* Little a */
 COMPATIBLE_IOCTL(ATMSIGD_CTRL),
 COMPATIBLE_IOCTL(ATMARPD_CTRL),
@@ -4304,28 +4205,6 @@
 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),
@@ -4365,10 +4244,20 @@
 COMPATIBLE_IOCTL(HCIDEVUP),
 COMPATIBLE_IOCTL(HCIDEVDOWN),
 COMPATIBLE_IOCTL(HCIDEVRESET),
+COMPATIBLE_IOCTL(HCIDEVRESTAT),
 COMPATIBLE_IOCTL(HCIGETDEVLIST),
+COMPATIBLE_IOCTL(HCIGETDEVINFO),
+COMPATIBLE_IOCTL(HCIGETCONNLIST),
+COMPATIBLE_IOCTL(HCIGETCONNINFO),
 COMPATIBLE_IOCTL(HCISETRAW),
 COMPATIBLE_IOCTL(HCISETSCAN),
 COMPATIBLE_IOCTL(HCISETAUTH),
+COMPATIBLE_IOCTL(HCISETENCRYPT),
+COMPATIBLE_IOCTL(HCISETPTYPE),
+COMPATIBLE_IOCTL(HCISETLINKPOL),
+COMPATIBLE_IOCTL(HCISETLINKMODE),
+COMPATIBLE_IOCTL(HCISETACLMTU),
+COMPATIBLE_IOCTL(HCISETSCOMTU),
 COMPATIBLE_IOCTL(HCIINQUIRY),
 COMPATIBLE_IOCTL(PCIIOC_CONTROLLER),
 COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO),
@@ -4463,6 +4352,7 @@
 HANDLE_IOCTL(SIOCRTMSG, ret_einval),
 HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp),
 HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo),
+HANDLE_IOCTL(HDIO_GETGEO_BIG_RAW, hdio_getgeo_big),
 HANDLE_IOCTL(BLKGETSIZE, w_long),
 HANDLE_IOCTL(0x1260, broken_blkgetsize),
 HANDLE_IOCTL(BLKSECTGET, w_long),
@@ -4523,6 +4413,14 @@
 HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl),
 /* One SMB ioctl needs translations. */
 HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid),
+/* NCPFS */
+HANDLE_IOCTL(NCP_IOC_NCPREQUEST_32, do_ncp_ncprequest),
+HANDLE_IOCTL(NCP_IOC_GETMOUNTUID2_32, do_ncp_getmountuid2),
+HANDLE_IOCTL(NCP_IOC_GET_FS_INFO_V2_32, do_ncp_getfsinfo2),
+HANDLE_IOCTL(NCP_IOC_GETOBJECTNAME_32, do_ncp_getobjectname),
+HANDLE_IOCTL(NCP_IOC_SETOBJECTNAME_32, do_ncp_setobjectname),
+HANDLE_IOCTL(NCP_IOC_GETPRIVATEDATA_32, do_ncp_getprivatedata),
+HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata),
 HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl),
 HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl),
 HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl),
@@ -4548,22 +4446,6 @@
 HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl),
 HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl),
 HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl),
-#if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
-HANDLE_IOCTL(VG_STATUS, do_lvm_ioctl),
-HANDLE_IOCTL(VG_CREATE_OLD, do_lvm_ioctl),
-HANDLE_IOCTL(VG_CREATE, do_lvm_ioctl),
-HANDLE_IOCTL(VG_EXTEND, do_lvm_ioctl),
-HANDLE_IOCTL(LV_CREATE, do_lvm_ioctl),
-HANDLE_IOCTL(LV_REMOVE, do_lvm_ioctl),
-HANDLE_IOCTL(LV_EXTEND, do_lvm_ioctl),
-HANDLE_IOCTL(LV_REDUCE, do_lvm_ioctl),
-HANDLE_IOCTL(LV_RENAME, do_lvm_ioctl),
-HANDLE_IOCTL(LV_STATUS_BYNAME, do_lvm_ioctl),
-HANDLE_IOCTL(LV_STATUS_BYINDEX, do_lvm_ioctl),
-HANDLE_IOCTL(LV_STATUS_BYDEV, do_lvm_ioctl),
-HANDLE_IOCTL(PV_CHANGE, do_lvm_ioctl),
-HANDLE_IOCTL(PV_STATUS, do_lvm_ioctl),
-#endif /* LVM */
 #if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
 HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version),
 HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique),
diff -Nru a/arch/ppc64/kernel/nvram.c b/arch/ppc64/kernel/nvram.c
--- a/arch/ppc64/kernel/nvram.c	Sun Nov 10 19:28:36 2002
+++ b/arch/ppc64/kernel/nvram.c	Sun Nov 10 19:28:36 2002
@@ -126,8 +126,7 @@
 	nvram_store = rtas_token("nvram-store");
 	printk(KERN_INFO "PPC64 nvram contains %d bytes\n", rtas_nvram_size);
 
-	misc_register(&nvram_dev);
-	return 0;
+	return misc_register(&nvram_dev);
 }
 
 void __exit nvram_cleanup(void)
diff -Nru a/arch/ppc64/kernel/pSeries_htab.c b/arch/ppc64/kernel/pSeries_htab.c
--- a/arch/ppc64/kernel/pSeries_htab.c	Sun Nov 10 19:28:38 2002
+++ b/arch/ppc64/kernel/pSeries_htab.c	Sun Nov 10 19:28:38 2002
@@ -22,46 +22,6 @@
 #include <asm/tlbflush.h>
 #include <asm/tlb.h>
 
-/*
- * Create a pte. Used during initialization only.
- * We assume the PTE will fit in the primary PTEG.
- */
-void pSeries_make_pte(HPTE *htab, unsigned long va, unsigned long pa,
-		      int mode, unsigned long hash_mask, int large)
-{
-	HPTE *hptep;
-	unsigned long hash, i;
-	unsigned long vpn;
-
-	if (large)
-		vpn = va >> LARGE_PAGE_SHIFT;
-	else
-		vpn = va >> PAGE_SHIFT;
-
-	hash = hpt_hash(vpn, large);
-
-	hptep  = htab + ((hash & hash_mask)*HPTES_PER_GROUP);
-
-	for (i = 0; i < 8; ++i, ++hptep) {
-		if (hptep->dw0.dw0.v == 0) {		/* !valid */
-			hptep->dw1.dword1 = pa | mode;
-			hptep->dw0.dword0 = 0;
-			hptep->dw0.dw0.avpn = va >> 23;
-			hptep->dw0.dw0.bolted = 1;	/* bolted */
-			if (large) {
-				hptep->dw0.dw0.l = 1;
-				hptep->dw0.dw0.avpn &= ~0x1UL;
-			}
-			hptep->dw0.dw0.v = 1;		/* make valid */
-			return;
-		}
-	}
-
-	/* We should _never_ get here and too early to call xmon. */
-	while(1)
-		;
-}
-
 #define HPTE_LOCK_BIT 3
 
 static inline void pSeries_lock_hpte(HPTE *hptep)
@@ -72,7 +32,7 @@
 		if (!test_and_set_bit(HPTE_LOCK_BIT, word))
 			break;
 		while(test_bit(HPTE_LOCK_BIT, word))
-			barrier();
+			cpu_relax();
 	}
 }
 
@@ -86,11 +46,10 @@
 
 static spinlock_t pSeries_tlbie_lock = SPIN_LOCK_UNLOCKED;
 
-static long pSeries_insert_hpte(unsigned long hpte_group, unsigned long vpn,
-				unsigned long prpn, int secondary,
-				unsigned long hpteflags, int bolted, int large)
+long pSeries_hpte_insert(unsigned long hpte_group, unsigned long va,
+			 unsigned long prpn, int secondary,
+			 unsigned long hpteflags, int bolted, int large)
 {
-	unsigned long avpn = vpn >> 11;
 	unsigned long arpn = physRpn_to_absRpn(prpn);
 	HPTE *hptep = htab_data.htab + hpte_group;
 	Hpte_dword0 dw0;
@@ -120,13 +79,15 @@
 	lhpte.dw1.flags.flags = hpteflags;
 
 	lhpte.dw0.dword0      = 0;
-	lhpte.dw0.dw0.avpn    = avpn;
+	lhpte.dw0.dw0.avpn    = va >> 23;
 	lhpte.dw0.dw0.h       = secondary;
 	lhpte.dw0.dw0.bolted  = bolted;
 	lhpte.dw0.dw0.v       = 1;
 
-	if (large)
+	if (large) {
 		lhpte.dw0.dw0.l = 1;
+		lhpte.dw0.dw0.avpn &= ~0x1UL;
+	}
 
 	hptep->dw1.dword1 = lhpte.dw1.dword1;
 
@@ -144,23 +105,16 @@
 	return i;
 }
 
-static long pSeries_remove_hpte(unsigned long hpte_group)
+static long pSeries_hpte_remove(unsigned long hpte_group)
 {
 	HPTE *hptep;
 	Hpte_dword0 dw0;
 	int i;
 	int slot_offset;
-	unsigned long vsid, group, pi, pi_high;
-	unsigned long slot;
-	unsigned long flags;
-	int large;
-	unsigned long va;
 
-	/* pick a random slot to start at */
+	/* pick a random entry to start at */
 	slot_offset = mftb() & 0x7;
 
-	udbg_printf("remove_hpte in %d\n", slot_offset);
-
 	for (i = 0; i < HPTES_PER_GROUP; i++) {
 		hptep = htab_data.htab + hpte_group + slot_offset;
 		dw0 = hptep->dw0.dw0;
@@ -181,30 +135,9 @@
 	if (i == HPTES_PER_GROUP)
 		return -1;
 
-	large = dw0.l;
-
 	/* Invalidate the hpte. NOTE: this also unlocks it */
 	hptep->dw0.dword0 = 0;
 
-	/* Invalidate the tlb */
-	vsid = dw0.avpn >> 5;
-	slot = hptep - htab_data.htab;
-	group = slot >> 3;
-	if (dw0.h)
-		group = ~group;
-	pi = (vsid ^ group) & 0x7ff;
-	pi_high = (dw0.avpn & 0x1f) << 11;
-	pi |= pi_high;
-
-	if (large)
-		va = pi << LARGE_PAGE_SHIFT;
-	else
-		va = pi << PAGE_SHIFT;
-
-	spin_lock_irqsave(&pSeries_tlbie_lock, flags);
-	_tlbie(va, large);
-	spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
-
 	return i;
 }
 
@@ -259,41 +192,40 @@
 }
 
 static long pSeries_hpte_updatepp(unsigned long slot, unsigned long newpp,
-				  unsigned long va, int large)
+				  unsigned long va, int large, int local)
 {
 	HPTE *hptep = htab_data.htab + slot;
 	Hpte_dword0 dw0;
-	unsigned long vpn, avpn;
+	unsigned long avpn = va >> 23;
 	unsigned long flags;
+	int ret = 0;
 
 	if (large)
-		vpn = va >> LARGE_PAGE_SHIFT;
-	else
-		vpn = va >> PAGE_SHIFT;
-
-	avpn = vpn >> 11;
+		avpn &= ~0x1UL;
 
 	pSeries_lock_hpte(hptep);
 
 	dw0 = hptep->dw0.dw0;
 
+	/* Even if we miss, we need to invalidate the TLB */
 	if ((dw0.avpn != avpn) || !dw0.v) {
 		pSeries_unlock_hpte(hptep);
-		udbg_printf("updatepp missed\n");
-		return -1;
+		ret = -1;
+	} else {
+		set_pp_bit(newpp, hptep);
+		pSeries_unlock_hpte(hptep);
 	}
 
-	set_pp_bit(newpp, hptep);
-
-	pSeries_unlock_hpte(hptep);
-
 	/* Ensure it is out of the tlb too */
-	/* XXX use tlbiel where possible */
-	spin_lock_irqsave(&pSeries_tlbie_lock, flags);
-	_tlbie(va, large);
-	spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
+	if (cpu_has_tlbiel() && !large && local) {
+		_tlbiel(va);
+	} else {
+		spin_lock_irqsave(&pSeries_tlbie_lock, flags);
+		_tlbie(va, large);
+		spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
+	}
 
-	return 0;
+	return ret;
 }
 
 /*
@@ -322,7 +254,6 @@
 	set_pp_bit(newpp, hptep);
 
 	/* Ensure it is out of the tlb too */
-	/* XXX use tlbiel where possible */
 	spin_lock_irqsave(&pSeries_tlbie_lock, flags);
 	_tlbie(va, 0);
 	spin_unlock_irqrestore(&pSeries_tlbie_lock, flags);
@@ -333,29 +264,24 @@
 {
 	HPTE *hptep = htab_data.htab + slot;
 	Hpte_dword0 dw0;
-	unsigned long vpn, avpn;
+	unsigned long avpn = va >> 23;
 	unsigned long flags;
 
 	if (large)
-		vpn = va >> LARGE_PAGE_SHIFT;
-	else
-		vpn = va >> PAGE_SHIFT;
-
-	avpn = vpn >> 11;
+		avpn &= ~0x1UL;
 
 	pSeries_lock_hpte(hptep);
 
 	dw0 = hptep->dw0.dw0;
 
+	/* Even if we miss, we need to invalidate the TLB */
 	if ((dw0.avpn != avpn) || !dw0.v) {
 		pSeries_unlock_hpte(hptep);
-		udbg_printf("invalidate missed\n");
-		return;
+	} else {
+		/* Invalidate the hpte. NOTE: this also unlocks it */
+		hptep->dw0.dword0 = 0;
 	}
 
-	/* Invalidate the hpte. NOTE: this also unlocks it */
-	hptep->dw0.dword0 = 0;
-
 	/* Invalidate the tlb */
 	if (cpu_has_tlbiel() && !large && local) {
 		_tlbiel(va);
@@ -374,6 +300,7 @@
 	HPTE *hptep;
 	Hpte_dword0 dw0;
 	struct ppc64_tlb_batch *batch = &ppc64_tlb_batch[smp_processor_id()];
+
 	/* XXX fix for large ptes */
 	unsigned long large = 0;
 
@@ -399,22 +326,24 @@
 		slot += (pte_val(batch->pte[i]) & _PAGE_GROUP_IX) >> 12;
 
 		hptep = htab_data.htab + slot;
-		avpn = vpn >> 11;
+
+		avpn = va >> 23;
+		if (large)
+			avpn &= ~0x1UL;
 
 		pSeries_lock_hpte(hptep);
 
 		dw0 = hptep->dw0.dw0;
 
+		/* Even if we miss, we need to invalidate the TLB */
 		if ((dw0.avpn != avpn) || !dw0.v) {
 			pSeries_unlock_hpte(hptep);
-			udbg_printf("invalidate missed\n");
-			continue;
+		} else {
+			/* Invalidate the hpte. NOTE: this also unlocks it */
+			hptep->dw0.dword0 = 0;
 		}
 
 		j++;
-
-		/* Invalidate the hpte. NOTE: this also unlocks it */
-		hptep->dw0.dword0 = 0;
 	}
 
 	if (cpu_has_tlbiel() && !large && local) {
@@ -455,9 +384,8 @@
 	ppc_md.hpte_invalidate	= pSeries_hpte_invalidate;
 	ppc_md.hpte_updatepp	= pSeries_hpte_updatepp;
 	ppc_md.hpte_updateboltedpp = pSeries_hpte_updateboltedpp;
-	ppc_md.insert_hpte	= pSeries_insert_hpte;
-	ppc_md.remove_hpte	= pSeries_remove_hpte;
-	ppc_md.make_pte		= pSeries_make_pte;
+	ppc_md.hpte_insert	= pSeries_hpte_insert;
+	ppc_md.hpte_remove     	= pSeries_hpte_remove;
 
 	/* Disable TLB batching on nighthawk */
 	root = find_path_device("/");
diff -Nru a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c
--- a/arch/ppc64/kernel/pSeries_lpar.c	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc64/kernel/pSeries_lpar.c	Sun Nov 10 19:28:41 2002
@@ -403,67 +403,11 @@
 
 
 
-
-/*
- * Create a pte - LPAR .  Used during initialization only.
- * We assume the PTE will fit in the primary PTEG.
- */
-void pSeries_lpar_make_pte(HPTE *htab, unsigned long va, unsigned long pa,
-			   int mode, unsigned long hash_mask, int large)
-{
-	HPTE local_hpte;
-	unsigned long hash, slot, flags, lpar_rc, vpn;
-	unsigned long dummy1, dummy2;
-
-	if (large)
-		vpn = va >> LARGE_PAGE_SHIFT;
-	else
-		vpn = va >> PAGE_SHIFT;
-
-	hash = hpt_hash(vpn, large);
-
-	slot = ((hash & hash_mask)*HPTES_PER_GROUP);
-
-	local_hpte.dw1.dword1 = pa | mode;
-	local_hpte.dw0.dword0 = 0;
-	local_hpte.dw0.dw0.avpn = va >> 23;
-	local_hpte.dw0.dw0.bolted = 1;		/* bolted */
-	if (large) {
-		local_hpte.dw0.dw0.l = 1;	/* large page */
-		local_hpte.dw0.dw0.avpn &= ~0x1UL;
-	}
-	local_hpte.dw0.dw0.v = 1;
-
-	/* Set CEC cookie to 0                   */
-	/* Zero page = 0                         */
-	/* I-cache Invalidate = 0                */
-	/* I-cache synchronize = 0               */
-	/* Exact = 0 - modify any entry in group */
-	flags = 0;
-
-	lpar_rc =  plpar_pte_enter(flags, slot, local_hpte.dw0.dword0,
-				   local_hpte.dw1.dword1, &dummy1, &dummy2);
-
-	if (lpar_rc == H_PTEG_Full) {
-		while(1)
-			;
-	}
-
-	/*
-	 * NOTE: we explicitly do not check return status here because it is
-	 * "normal" for early boot code to map io regions for which a partition
-	 * has no access.  However, we will die if we actually fault on these
-	 * "permission denied" pages.
-	 */
-}
-
-static long pSeries_lpar_insert_hpte(unsigned long hpte_group,
-				     unsigned long vpn, unsigned long prpn,
-				     int secondary, unsigned long hpteflags,
-				     int bolted, int large)
+long pSeries_lpar_hpte_insert(unsigned long hpte_group,
+			      unsigned long va, unsigned long prpn,
+			      int secondary, unsigned long hpteflags,
+			      int bolted, int large)
 {
-	/* XXX fix for large page */
-	unsigned long avpn = vpn >> 11;
 	unsigned long arpn = physRpn_to_absRpn(prpn);
 	unsigned long lpar_rc;
 	unsigned long flags;
@@ -476,13 +420,15 @@
 	lhpte.dw1.flags.flags = hpteflags;
 
 	lhpte.dw0.dword0      = 0;
-	lhpte.dw0.dw0.avpn    = avpn;
+	lhpte.dw0.dw0.avpn    = va >> 23;
 	lhpte.dw0.dw0.h       = secondary;
 	lhpte.dw0.dw0.bolted  = bolted;
 	lhpte.dw0.dw0.v       = 1;
 
-	if (large)
+	if (large) {
 		lhpte.dw0.dw0.l = 1;
+		lhpte.dw0.dw0.avpn &= ~0x1UL;
+	}
 
 	/* Now fill in the actual HPTE */
 	/* Set CEC cookie to 0         */
@@ -522,7 +468,7 @@
 
 static spinlock_t pSeries_lpar_tlbie_lock = SPIN_LOCK_UNLOCKED;
 
-static long pSeries_lpar_remove_hpte(unsigned long hpte_group)
+static long pSeries_lpar_hpte_remove(unsigned long hpte_group)
 {
 	unsigned long slot_offset;
 	unsigned long lpar_rc;
@@ -559,12 +505,15 @@
  * already zero.  For now I am paranoid.
  */
 static long pSeries_lpar_hpte_updatepp(unsigned long slot, unsigned long newpp,
-				       unsigned long va, int large)
+				       unsigned long va, int large, int local)
 {
 	unsigned long lpar_rc;
 	unsigned long flags = (newpp & 7) | H_AVPN;
 	unsigned long avpn = va >> 23;
 
+	if (large)
+		avpn &= ~0x1UL;
+
 	lpar_rc = plpar_pte_protect(flags, slot, (avpn << 7));
 
 	if (lpar_rc == H_Not_Found) {
@@ -662,6 +611,9 @@
 	unsigned long lpar_rc;
 	unsigned long dummy1, dummy2;
 
+	if (large)
+		avpn &= ~0x1UL;
+
 	lpar_rc = plpar_pte_remove(H_AVPN, slot, (avpn << 7), &dummy1,
 				   &dummy2);
 
@@ -695,11 +647,10 @@
 
 void pSeries_lpar_mm_init(void)
 {
-	ppc_md.hpte_invalidate  = pSeries_lpar_hpte_invalidate;
-	ppc_md.hpte_updatepp    = pSeries_lpar_hpte_updatepp;
+	ppc_md.hpte_invalidate	= pSeries_lpar_hpte_invalidate;
+	ppc_md.hpte_updatepp	= pSeries_lpar_hpte_updatepp;
 	ppc_md.hpte_updateboltedpp = pSeries_lpar_hpte_updateboltedpp;
-	ppc_md.insert_hpte      = pSeries_lpar_insert_hpte;
-	ppc_md.remove_hpte      = pSeries_lpar_remove_hpte;
-	ppc_md.make_pte         = pSeries_lpar_make_pte;
+	ppc_md.hpte_insert	= pSeries_lpar_hpte_insert;
+	ppc_md.hpte_remove	= pSeries_lpar_hpte_remove;
 	ppc_md.flush_hash_range	= pSeries_lpar_flush_hash_range;
 }
diff -Nru a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
--- a/arch/ppc64/kernel/pci.c	Sun Nov 10 19:28:41 2002
+++ b/arch/ppc64/kernel/pci.c	Sun Nov 10 19:28:41 2002
@@ -121,8 +121,8 @@
 }
 
 
-void pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
-				struct pbus_set_ranges_data *pranges)
+void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
+					 struct pbus_set_ranges_data *pranges)
 {
 }
 
diff -Nru a/arch/ppc64/kernel/udbg.c b/arch/ppc64/kernel/udbg.c
--- a/arch/ppc64/kernel/udbg.c	Sun Nov 10 19:28:36 2002
+++ b/arch/ppc64/kernel/udbg.c	Sun Nov 10 19:28:36 2002
@@ -116,8 +116,6 @@
 		if (s && *s != '\0') {
 			while ((c = *s++) != '\0')
 				ppc_md.udbg_putc(c);
-		} else {
-			udbg_puts("NULL");
 		}
 	} else {
 		printk("%s", s);
@@ -135,8 +133,7 @@
 		while ( (( c = *s++ ) != '\0') && (remain-- > 0)) {
 			ppc_md.udbg_putc(c);
 		}
-	} else
-		udbg_puts("NULL");
+	}
 	return n - remain;
 }
 
diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
--- a/arch/ppc64/mm/init.c	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc64/mm/init.c	Sun Nov 10 19:28:40 2002
@@ -220,16 +220,26 @@
 		set_pte(ptep, pfn_pte(pa >> PAGE_SHIFT, __pgprot(flags)));
 		spin_unlock(&ioremap_mm.page_table_lock);
 	} else {
-		/* If the mm subsystem is not fully up, we cannot create a
+		unsigned long va, vpn, hash, hpteg;
+
+		/*
+		 * If the mm subsystem is not fully up, we cannot create a
 		 * linux page table entry for this mapping.  Simply bolt an
 		 * entry in the hardware page table. 
 		 */
 		vsid = get_kernel_vsid(ea);
-		ppc_md.make_pte(htab_data.htab,
-			(vsid << 28) | (ea & 0xFFFFFFF), // va (NOT the ea)
-			pa, 
-			_PAGE_NO_CACHE | _PAGE_GUARDED | PP_RWXX,
-			htab_data.htab_hash_mask, 0);
+		va = (vsid << 28) | (ea & 0xFFFFFFF);
+		vpn = va >> PAGE_SHIFT;
+
+		hash = hpt_hash(vpn, 0);
+
+		hpteg = ((hash & htab_data.htab_hash_mask)*HPTES_PER_GROUP);
+
+		if (ppc_md.hpte_insert(hpteg, va, pa >> PAGE_SHIFT, 0,
+				       _PAGE_NO_CACHE|_PAGE_GUARDED|PP_RWXX,
+				       1, 0) == -1) {
+			panic("map_io_page: could not insert mapping");
+		}
 	}
 }
 
@@ -522,7 +532,7 @@
 {
 	int nid;
 
-        for (nid = 0; nid < MAX_NUMNODES; nid++) {
+        for (nid = 0; nid < numnodes; nid++) {
 		if (numa_node_exists[nid]) {
 			printk("freeing bootmem node %x\n", nid);
 			totalram_pages +=
@@ -649,7 +659,7 @@
 
 extern pte_t *find_linux_pte(pgd_t *pgdir, unsigned long ea);
 int __hash_page(unsigned long ea, unsigned long access, unsigned long vsid,
-		pte_t *ptep, unsigned long trap);
+		pte_t *ptep, unsigned long trap, int local);
 
 /*
  * This is called at the end of handling a user page fault, when the
@@ -665,6 +675,7 @@
 	unsigned long vsid;
 	void *pgdir;
 	pte_t *ptep;
+	int local = 0;
 
 	/* We only want HPTEs for linux PTEs that have _PAGE_ACCESSED set */
 	if (!pte_young(pte))
@@ -677,6 +688,9 @@
 	ptep = find_linux_pte(pgdir, ea);
 	vsid = get_vsid(vma->vm_mm->context, ea);
 
+	if (vma->vm_mm->cpu_vm_mask == (1 << smp_processor_id()))
+		local = 1;
+
 	__hash_page(ea, pte_val(pte) & (_PAGE_USER|_PAGE_RW), vsid, ptep,
-		    0x300);
+		    0x300, local);
 }
diff -Nru a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c
--- a/arch/ppc64/mm/numa.c	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc64/mm/numa.c	Sun Nov 10 19:28:40 2002
@@ -1,5 +1,5 @@
 /*
- * NUMA support
+ * pSeries NUMA support
  *
  * Copyright (C) 2002 Anton Blanchard <anton@au.ibm.com>, IBM
  *
@@ -15,10 +15,10 @@
 #include <linux/mmzone.h>
 #include <asm/lmb.h>
 
-#if 0
-#define dbg(format, arg...) udbg_printf(format, arg)
+#if 1
+#define dbg(args...) udbg_printf(args)
 #else
-#define dbg(format, arg...)
+#define dbg(args...)
 #endif
 
 int numa_cpu_lookup_table[NR_CPUS] = { [ 0 ... (NR_CPUS - 1)] = -1};
@@ -31,8 +31,137 @@
 
 static int __init parse_numa_properties(void)
 {
-	/* XXX implement */
-	return -1;
+	struct device_node *cpu;
+	struct device_node *memory;
+	int *cpu_associativity;
+	int *memory_associativity;
+	int depth;
+	int max_domain = 0;
+
+	cpu = find_type_devices("cpu");
+	if (!cpu)
+		return -1;
+
+	memory = find_type_devices("memory");
+	if (!memory)
+		return -1;
+
+	cpu_associativity = (int *)get_property(cpu, "ibm,associativity", NULL);
+	if (!cpu_associativity)
+		return -1;
+
+	memory_associativity = (int *)get_property(memory, "ibm,associativity",
+						   NULL);
+	if (!memory_associativity)
+		return -1;
+
+	/* find common depth */
+	if (cpu_associativity[0] < memory_associativity[0])
+		depth = cpu_associativity[0];
+	else
+		depth = memory_associativity[0];
+
+	for (cpu = find_type_devices("cpu"); cpu; cpu = cpu->next) {
+		int *tmp;
+		int cpu_nr, numa_domain;
+
+		tmp = (int *)get_property(cpu, "reg", NULL);
+		if (!tmp)
+			continue;
+		cpu_nr = *tmp;
+
+		tmp = (int *)get_property(cpu, "ibm,associativity",
+					  NULL);
+		if (!tmp)
+			continue;
+		numa_domain = tmp[depth];
+
+		/* FIXME */
+		if (numa_domain == 0xffff) {
+			dbg("cpu %d has no numa doman\n", cpu_nr);
+			numa_domain = 0;
+		}
+
+		if (numa_domain >= MAX_NUMNODES)
+			BUG();
+
+		if (max_domain < numa_domain)
+			max_domain = numa_domain;
+
+		numa_cpu_lookup_table[cpu_nr] = numa_domain;
+
+		dbg("cpu %d maps to domain %d\n", cpu_nr, numa_domain);
+	}
+
+	for (memory = find_type_devices("memory"); memory;
+	     memory = memory->next) {
+		int *tmp1, *tmp2;
+		unsigned long i;
+		unsigned long start = 0;
+		unsigned long size = 0;
+		int numa_domain;
+		int ranges;
+
+		tmp1 = (int *)get_property(memory, "reg", NULL);
+		if (!tmp1)
+			continue;
+
+		ranges = memory->n_addrs;
+new_range:
+
+		i = prom_n_size_cells(memory);
+		while (i--) {
+			start = (start << 32) | *tmp1;
+			tmp1++;
+		}
+
+		i = prom_n_size_cells(memory);
+		while (i--) {
+			size = (size << 32) | *tmp1;
+			tmp1++;
+		}
+
+		start = _ALIGN_DOWN(start, MEMORY_INCREMENT);
+		size = _ALIGN_UP(size, MEMORY_INCREMENT);
+
+		if ((start + size) > MAX_MEMORY)
+			BUG();
+
+		tmp2 = (int *)get_property(memory, "ibm,associativity",
+					   NULL);
+		if (!tmp2)
+			continue;
+		numa_domain = tmp2[depth];
+
+		/* FIXME */
+		if (numa_domain == 0xffff) {
+			dbg("cpu has no numa doman\n");
+			numa_domain = 0;
+		}
+
+		if (numa_domain >= MAX_NUMNODES)
+			BUG();
+
+		if (max_domain < numa_domain)
+			max_domain = numa_domain;
+
+		numa_node_exists[numa_domain] = 1;
+
+		for (i = start ; i < (start+size); i += MEMORY_INCREMENT)
+			numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] =
+				numa_domain;
+
+		dbg("memory region %lx to %lx maps to domain %d\n",
+		    start, start+size, numa_domain);
+
+		ranges--;
+		if (ranges)
+			goto new_range;
+	}
+
+	numnodes = max_domain + 1;
+
+	return 0;
 }
 
 void __init do_init_bootmem(void)
@@ -42,15 +171,16 @@
 	min_low_pfn = 0;
 	max_low_pfn = lmb_end_of_DRAM() >> PAGE_SHIFT;
 
+	/* XXX FIXME: support machines without associativity information */
 	if (parse_numa_properties())
 		BUG();
 
-	for (nid = 0; nid < MAX_NUMNODES; nid++) {
+	for (nid = 0; nid < numnodes; nid++) {
 		unsigned long start, end;
 		unsigned long start_paddr, end_paddr;
 		int i;
 		unsigned long bootmem_paddr;
-		unsigned long bootmap_size;
+		unsigned long bootmap_pages;
 
 		if (!numa_node_exists[nid])
 			continue;
@@ -74,20 +204,16 @@
 
 		NODE_DATA(nid)->bdata = &plat_node_bdata[nid];
 
-		/* XXX FIXME: first bitmap hardwired to 1G */
-		if (start_paddr == 0)
-			bootmem_paddr = (1 << 30);
-		else
-			bootmem_paddr = start_paddr;
+		bootmap_pages = bootmem_bootmap_pages(end_paddr - start_paddr);
+		dbg("bootmap_pages = %lx\n", bootmap_pages);
 
+		bootmem_paddr = lmb_alloc_base(bootmap_pages << PAGE_SHIFT,
+				PAGE_SIZE, end_paddr);
 		dbg("bootmap_paddr = %lx\n", bootmem_paddr);
 
-		bootmap_size = init_bootmem_node(NODE_DATA(nid),
-						 bootmem_paddr >> PAGE_SHIFT,
-						 start_paddr >> PAGE_SHIFT,
-						 end_paddr >> PAGE_SHIFT);
-
-		dbg("bootmap_size = %lx\n", bootmap_size);
+		init_bootmem_node(NODE_DATA(nid), bootmem_paddr >> PAGE_SHIFT,
+				  start_paddr >> PAGE_SHIFT,
+				  end_paddr >> PAGE_SHIFT);
 
 		for (i = 0; i < lmb.memory.cnt; i++) {
 			unsigned long physbase, size;
@@ -137,10 +263,6 @@
 						     size);
 			}
 		}
-
-		dbg("reserve_bootmem %lx %lx\n", bootmem_paddr, bootmap_size);
-		reserve_bootmem_node(NODE_DATA(nid), bootmem_paddr,
-				     bootmap_size);
 	}
 }
 
@@ -152,7 +274,7 @@
 	for (i = 1; i < MAX_NR_ZONES; i++)
 		zones_size[i] = 0;
 
-	for (nid = 0; nid < MAX_NUMNODES; nid++) {
+	for (nid = 0; nid < numnodes; nid++) {
 		unsigned long start_pfn;
 		unsigned long end_pfn;
 
@@ -163,8 +285,8 @@
 		end_pfn = plat_node_bdata[nid].node_low_pfn;
 
 		zones_size[ZONE_DMA] = end_pfn - start_pfn;
-		dbg("free_area_init node %d %lx %lx\n", nid, zones_size,
-		    start_pfn);
+		dbg("free_area_init node %d %lx %lx\n", nid,
+				zones_size[ZONE_DMA], start_pfn);
 		free_area_init_node(nid, NODE_DATA(nid), NULL, zones_size,
 				    start_pfn, NULL);
 	}
diff -Nru a/arch/ppc64/vmlinux.lds.S b/arch/ppc64/vmlinux.lds.S
--- a/arch/ppc64/vmlinux.lds.S	Sun Nov 10 19:28:40 2002
+++ b/arch/ppc64/vmlinux.lds.S	Sun Nov 10 19:28:40 2002
@@ -1,5 +1,4 @@
 OUTPUT_ARCH(powerpc:common64)
-SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib);
 /* Do we need any of these for elf?
    __DYNAMIC = 0;    */
 jiffies = jiffies_64;
@@ -62,7 +61,6 @@
   _edata  =  .;
   PROVIDE (edata = .);
 
-  .fixup   : { *(.fixup) }
   __start___ex_table = .;
   __ex_table : { *(__ex_table) }
   __stop___ex_table = .;
@@ -70,6 +68,7 @@
   __start___ksymtab = .;        /* Kernel symbol table */
   __ksymtab : { *(__ksymtab) }
   __stop___ksymtab = .;
+
   __start___kallsyms = .;	/* All kernel symbols */
   __kallsyms : { *(__kallsyms) }
   __stop___kallsyms = .;
@@ -83,21 +82,14 @@
   . = ALIGN(128);
   .data.cacheline_aligned : { *(.data.cacheline_aligned) }
 
+  /* will be freed after init */
   . = ALIGN(4096);
   __init_begin = .;
-  .text.init : { *(.text.init) }
-  .data.init : { 
-    *(.data.init);
-    __vtop_table_begin = .;
-    *(.vtop_fixup);
-    __vtop_table_end = .;
-    __ptov_table_begin = .;
-    *(.ptov_fixup);
-    __ptov_table_end = .;
-  }
+  .init.text : { *(.init.text) }
+  .init.data : { *(.init.data) }
   . = ALIGN(16);
   __setup_start = .;
-  .setup.init : { *(.setup.init) }
+  .init.setup : { *(.init.setup) }
   __setup_end = .;
   __initcall_start = .;
   .initcall.init : {
@@ -110,29 +102,26 @@
 	*(.initcall7.init)
   }
   __initcall_end = .;
+  . = ALIGN(4096);
+  __initramfs_start = .;
+  .init.ramfs : { *(.init.ramfs) }
+  __initramfs_end = .;
   . = ALIGN(32);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
   __per_cpu_end = .;
   . = ALIGN(4096);
   __init_end = .;
+  /* freed after init ends here */
 
   __toc_start = .;
-  .toc       :
-  {
-   *(.toc)
-  }
+  .toc : { *(.toc) }
   . = ALIGN(4096);
   __toc_end = .;
 
   __bss_start = .;
-  .bss       :
-  {
-   *(.sbss) *(.scommon)
-   *(.dynbss)
-   *(.bss)
-   *(COMMON)
-  }
+  .bss : { *(.bss) }
+  __bss_stop = .;
 
   . = ALIGN(4096);
   _end = . ;
diff -Nru a/arch/s390/Kconfig b/arch/s390/Kconfig
--- a/arch/s390/Kconfig	Sun Nov 10 19:28:39 2002
+++ b/arch/s390/Kconfig	Sun Nov 10 19:28:39 2002
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 
 config MMU
diff -Nru a/arch/s390x/Kconfig b/arch/s390x/Kconfig
--- a/arch/s390x/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/arch/s390x/Kconfig	Sun Nov 10 19:28:40 2002
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 
 config MMU
diff -Nru a/arch/sh/Kconfig b/arch/sh/Kconfig
--- a/arch/sh/Kconfig	Sun Nov 10 19:28:41 2002
+++ b/arch/sh/Kconfig	Sun Nov 10 19:28:41 2002
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 
 mainmenu "Linux/SuperH Kernel Configuration"
diff -Nru a/arch/sh/kernel/pci-dc.c b/arch/sh/kernel/pci-dc.c
--- a/arch/sh/kernel/pci-dc.c	Sun Nov 10 19:28:38 2002
+++ b/arch/sh/kernel/pci-dc.c	Sun Nov 10 19:28:38 2002
@@ -113,7 +113,7 @@
 }
 
 
-void __init pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
+void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *bus, struct pbus_set_ranges_data *ranges)
 {
 }                                                                                
 
diff -Nru a/arch/sh/kernel/pci-sh7751.c b/arch/sh/kernel/pci-sh7751.c
--- a/arch/sh/kernel/pci-sh7751.c	Sun Nov 10 19:28:40 2002
+++ b/arch/sh/kernel/pci-sh7751.c	Sun Nov 10 19:28:40 2002
@@ -250,8 +250,8 @@
 	{ 0 }
 };
 
-void __init pcibios_fixup_pbus_ranges(struct pci_bus *b,
-		struct pbus_set_ranges_data *range)
+void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *b,
+					 struct pbus_set_ranges_data *range)
 {
 	/* No fixups needed */
 }
diff -Nru a/arch/sh/kernel/pci_st40.c b/arch/sh/kernel/pci_st40.c
--- a/arch/sh/kernel/pci_st40.c	Sun Nov 10 19:28:41 2002
+++ b/arch/sh/kernel/pci_st40.c	Sun Nov 10 19:28:41 2002
@@ -380,7 +380,7 @@
 }
 
 
-void __init
+void __devinit
 pcibios_fixup_pbus_ranges(struct pci_bus *bus,
 			  struct pbus_set_ranges_data *ranges)
 {
diff -Nru a/arch/sparc/Kconfig b/arch/sparc/Kconfig
--- a/arch/sparc/Kconfig	Sun Nov 10 19:28:36 2002
+++ b/arch/sparc/Kconfig	Sun Nov 10 19:28:36 2002
@@ -1,6 +1,6 @@
 # $Id: config.in,v 1.113 2002/01/24 22:14:44 davem Exp $
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 
 mainmenu "Linux/SPARC Kernel Configuration"
diff -Nru a/arch/sparc/Makefile b/arch/sparc/Makefile
--- a/arch/sparc/Makefile	Sun Nov 10 19:28:37 2002
+++ b/arch/sparc/Makefile	Sun Nov 10 19:28:37 2002
@@ -21,6 +21,7 @@
 ifeq ($(NEW_GAS),y)
 AS              := $(AS) -32
 LDFLAGS		:= -m elf32_sparc
+LDFLAGS_BLOB	:= --format binary --oformat elf32-sparc
 endif
 
 #CFLAGS := $(CFLAGS) -g -pipe -fcall-used-g5 -fcall-used-g7
@@ -41,13 +42,20 @@
 libs-y += arch/sparc/prom/ arch/sparc/lib/
 
 # Export what is needed by arch/sparc/boot/Makefile
-export init-y core-y drivers-y net-y libs-y HEAD
+# Renaming is done to avoid confusing pattern matching rules in 2.5.45 (multy-)
+INIT_Y		:= $(patsubst %/, %/built-in.o, $(init-y))
+CORE_Y		:= $(core-y)
+CORE_Y		+= kernel/ mm/ fs/ ipc/ security/ crypto/
+CORE_Y		:= $(patsubst %/, %/built-in.o, $(CORE_Y))
+DRIVERS_Y	:= $(patsubst %/, %/built-in.o, $(drivers-y))
+NET_Y		:= $(patsubst %/, %/built-in.o, $(net-y))
+LIBS_Y		:= $(patsubst %/, %/lib.a, $(libs-y))
+export INIT_Y CORE_Y DRIVERS_Y NET_Y LIBS_Y HEAD
 
 image: vmlinux
 	$(MAKE) -C arch/sparc/boot image
 
 archclean:
-	rm -f arch/sparc/kernel/include
 	rm -f $(TOPDIR)/vmlinux.aout
 	-$(MAKE) -C arch/sparc/boot clean
 
diff -Nru a/arch/sparc/boot/Makefile b/arch/sparc/boot/Makefile
--- a/arch/sparc/boot/Makefile	Sun Nov 10 19:28:41 2002
+++ b/arch/sparc/boot/Makefile	Sun Nov 10 19:28:41 2002
@@ -22,8 +22,8 @@
 clean:
 	rm -f btfixupprep piggyback tftpboot.img btfix.o btfix.s image
 
-BTOBJS := $(HEAD) $(init-y)
-BTLIBS := $(core-y) $(libs-y) $(drivers-y) $(net-y)
+BTOBJS := $(HEAD) $(INIT_Y)
+BTLIBS := $(CORE_Y) $(LIBS_Y) $(DRIVERS_Y) $(NET_Y)
 
 # Actual linking
 image: btfix.o
diff -Nru a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c
--- a/arch/sparc/kernel/ioport.c	Sun Nov 10 19:28:41 2002
+++ b/arch/sparc/kernel/ioport.c	Sun Nov 10 19:28:41 2002
@@ -514,7 +514,7 @@
 
 	mmu_inval_dma_area(va, len_total);
 
-#if 1
+#if 0
 /* P3 */ printk("pci_alloc_consistent: kva %lx uncva %lx phys %lx size %x\n",
   (long)va, (long)res->start, (long)virt_to_phys(va), len_total);
 #endif
diff -Nru a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
--- a/arch/sparc/kernel/sys_sparc.c	Sun Nov 10 19:28:39 2002
+++ b/arch/sparc/kernel/sys_sparc.c	Sun Nov 10 19:28:39 2002
@@ -269,6 +269,21 @@
 	return do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
 }
 
+extern int sys_remap_file_pages(unsigned long start, unsigned long size,
+				unsigned long prot, unsigned long pgoff,
+				unsigned long flags);
+
+int sparc_remap_file_pages(unsigned long start, unsigned long size,
+			   unsigned long prot, unsigned long pgoff,
+			   unsigned long flags)
+{
+	/* This works on an existing mmap so we don't need to validate
+	 * the range as that was done at the original mmap call.
+	 */
+	return sys_remap_file_pages(start, size, prot,
+				    (pgoff >> (PAGE_SHIFT - 12)), flags);
+}
+
 extern unsigned long do_mremap(unsigned long addr,
 	unsigned long old_len, unsigned long new_len,
 	unsigned long flags, unsigned long new_addr);
diff -Nru a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
--- a/arch/sparc/kernel/systbls.S	Sun Nov 10 19:28:39 2002
+++ b/arch/sparc/kernel/systbls.S	Sun Nov 10 19:28:39 2002
@@ -56,7 +56,7 @@
 /*175*/	.long sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/	.long sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_sigpending, sys_query_module
 /*185*/	.long sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_newuname
-/*190*/	.long sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*190*/	.long sys_init_module, sys_personality, sparc_remap_file_pages, sys_nis_syscall, sys_nis_syscall
 /*195*/	.long sys_nis_syscall, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask
 /*200*/	.long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
 /*205*/	.long sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_nis_syscall
diff -Nru a/arch/sparc/mm/sun4c.c b/arch/sparc/mm/sun4c.c
--- a/arch/sparc/mm/sun4c.c	Sun Nov 10 19:28:40 2002
+++ b/arch/sparc/mm/sun4c.c	Sun Nov 10 19:28:40 2002
@@ -292,7 +292,7 @@
 		switch (idprom->id_machtype) {
 
 		case (SM_SUN4|SM_4_110):
-			sun4c_vacinfo.type = NONE;
+			sun4c_vacinfo.type = VAC_NONE;
 			sun4c_vacinfo.num_bytes = 0;
 			sun4c_vacinfo.linesize = 0;
 			sun4c_vacinfo.do_hwflushes = 0;
@@ -301,21 +301,21 @@
 			break;
 
 		case (SM_SUN4|SM_4_260):
-			sun4c_vacinfo.type = WRITE_BACK;
+			sun4c_vacinfo.type = VAC_WRITE_BACK;
 			sun4c_vacinfo.num_bytes = 128 * 1024;
 			sun4c_vacinfo.linesize = 16;
 			sun4c_vacinfo.do_hwflushes = 0;
 			break;
 
 		case (SM_SUN4|SM_4_330):
-			sun4c_vacinfo.type = WRITE_THROUGH;
+			sun4c_vacinfo.type = VAC_WRITE_THROUGH;
 			sun4c_vacinfo.num_bytes = 128 * 1024;
 			sun4c_vacinfo.linesize = 16;
 			sun4c_vacinfo.do_hwflushes = 0;
 			break;
 
 		case (SM_SUN4|SM_4_470):
-			sun4c_vacinfo.type = WRITE_BACK;
+			sun4c_vacinfo.type = VAC_WRITE_BACK;
 			sun4c_vacinfo.num_bytes = 128 * 1024;
 			sun4c_vacinfo.linesize = 32;
 			sun4c_vacinfo.do_hwflushes = 0;
@@ -326,7 +326,7 @@
 			prom_halt();
 		};
 	} else {
-		sun4c_vacinfo.type = WRITE_THROUGH;
+		sun4c_vacinfo.type = VAC_WRITE_THROUGH;
 
 		if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
 		    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
diff -Nru a/arch/sparc/vmlinux.lds.S b/arch/sparc/vmlinux.lds.S
--- a/arch/sparc/vmlinux.lds.S	Sun Nov 10 19:28:37 2002
+++ b/arch/sparc/vmlinux.lds.S	Sun Nov 10 19:28:37 2002
@@ -56,6 +56,10 @@
 	*(.initcall7.init)
   }
   __initcall_end = .;
+  . = ALIGN(4096);
+  __initramfs_start = .;
+  .init.ramfs : { *(.init.ramfs) }
+  __initramfs_end = .;
   . = ALIGN(32);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
diff -Nru a/arch/sparc64/Makefile b/arch/sparc64/Makefile
--- a/arch/sparc64/Makefile	Sun Nov 10 19:28:41 2002
+++ b/arch/sparc64/Makefile	Sun Nov 10 19:28:41 2002
@@ -31,6 +31,7 @@
 else
 AS		:= $(AS) -64
 LDFLAGS		:= -m elf64_sparc
+LDFLAGS_BLOB	:= --format binary --oformat elf64-sparc
 endif
 ELFTOAOUT	= elftoaout
 ifneq ($(UNDECLARED_REGS),y)
diff -Nru a/arch/sparc64/kernel/cpu.c b/arch/sparc64/kernel/cpu.c
--- a/arch/sparc64/kernel/cpu.c	Sun Nov 10 19:28:41 2002
+++ b/arch/sparc64/kernel/cpu.c	Sun Nov 10 19:28:41 2002
@@ -28,7 +28,7 @@
 
 struct cpu_fp_info linux_sparc_fpu[] = {
   { 0x17, 0x10, 0, "UltraSparc I integrated FPU"},
-  { 0x22, 0x10, 0, "UltraSparc II integrated FPU"},
+  { 0x22, 0x10, 0, "UltraSparc I integrated FPU"},
   { 0x17, 0x11, 0, "UltraSparc II integrated FPU"},
   { 0x17, 0x12, 0, "UltraSparc IIi integrated FPU"},
   { 0x17, 0x13, 0, "UltraSparc IIe integrated FPU"},
@@ -40,7 +40,7 @@
 
 struct cpu_iu_info linux_sparc_chips[] = {
   { 0x17, 0x10, "TI UltraSparc I   (SpitFire)"},
-  { 0x22, 0x10, "TI UltraSparc II  (BlackBird)"},
+  { 0x22, 0x10, "TI UltraSparc I   (SpitFire)"},
   { 0x17, 0x11, "TI UltraSparc II  (BlackBird)"},
   { 0x17, 0x12, "TI UltraSparc IIi"},
   { 0x17, 0x13, "TI UltraSparc IIe"},
diff -Nru a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
--- a/arch/sparc64/kernel/ioctl32.c	Sun Nov 10 19:28:41 2002
+++ b/arch/sparc64/kernel/ioctl32.c	Sun Nov 10 19:28:41 2002
@@ -55,6 +55,7 @@
 #if defined(CONFIG_BLK_DEV_LVM) || defined(CONFIG_BLK_DEV_LVM_MODULE)
 #include <linux/lvm.h>
 #endif /* LVM */
+#include <linux/dm-ioctl.h>
 
 #include <scsi/scsi.h>
 /* Ugly hack. */
@@ -5012,6 +5013,19 @@
 COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
 COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS)
 COMPATIBLE_IOCTL(NBD_DISCONNECT)
+/* device-mapper */
+COMPATIBLE_IOCTL(DM_VERSION)
+COMPATIBLE_IOCTL(DM_REMOVE_ALL)
+COMPATIBLE_IOCTL(DM_DEV_CREATE)
+COMPATIBLE_IOCTL(DM_DEV_REMOVE)
+COMPATIBLE_IOCTL(DM_DEV_RELOAD)
+COMPATIBLE_IOCTL(DM_DEV_SUSPEND)
+COMPATIBLE_IOCTL(DM_DEV_RENAME)
+COMPATIBLE_IOCTL(DM_DEV_DEPS)
+COMPATIBLE_IOCTL(DM_DEV_STATUS)
+COMPATIBLE_IOCTL(DM_TARGET_STATUS)
+COMPATIBLE_IOCTL(DM_TARGET_WAIT)
+
 /* And these ioctls need translation */
 HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
 HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
diff -Nru a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
--- a/arch/sparc64/kernel/pci.c	Sun Nov 10 19:28:36 2002
+++ b/arch/sparc64/kernel/pci.c	Sun Nov 10 19:28:36 2002
@@ -479,8 +479,8 @@
 {
 }
 
-void pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
-			       struct pbus_set_ranges_data *pranges)
+void __devinit pcibios_fixup_pbus_ranges(struct pci_bus *pbus,
+					 struct pbus_set_ranges_data *pranges)
 {
 }
 
diff -Nru a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S
--- a/arch/sparc64/kernel/sys32.S	Sun Nov 10 19:28:37 2002
+++ b/arch/sparc64/kernel/sys32.S	Sun Nov 10 19:28:37 2002
@@ -42,7 +42,7 @@
 	 and		%o2, %g2, %o2
 
 	.align		32
-	.globl		sys32_sendto, sys32_recvfrom, sys32_getsockopt
+	.globl		sys32_sendto, sys32_recvfrom
 sys32_sendto:
 	sethi		%hi(sys_sendto), %g1
 	jmpl		%g1 + %lo(sys_sendto), %g0
@@ -52,10 +52,6 @@
 	sethi		%hi(sys_recvfrom), %g1
 	jmpl		%g1 + %lo(sys_recvfrom), %g0
 	 srl		%o5, 0, %o5
-sys32_getsockopt:
-	sethi		%hi(sys_getsockopt), %g1
-	jmpl		%g1 + %lo(sys_getsockopt), %g0
-	 srl		%o4, 0, %o4
 
 	.globl		sys32_bdflush
 sys32_bdflush:
diff -Nru a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
--- a/arch/sparc64/kernel/sys_sparc32.c	Sun Nov 10 19:28:40 2002
+++ b/arch/sparc64/kernel/sys_sparc32.c	Sun Nov 10 19:28:40 2002
@@ -2731,17 +2731,76 @@
 	return ret;
 }
 
+static int do_set_sock_timeout(int fd, int level, int optname, char *optval, int optlen)
+{
+	struct timeval32 *up = (struct timeval32 *) optval;
+	struct timeval ktime;
+	mm_segment_t old_fs;
+	int err;
+
+	if (optlen < sizeof(*up))
+		return -EINVAL;
+	if (get_user(ktime.tv_sec, &up->tv_sec) ||
+	    __get_user(ktime.tv_usec, &up->tv_usec))
+		return -EFAULT;
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_setsockopt(fd, level, optname, (char *) &ktime, sizeof(ktime));
+	set_fs(old_fs);
+
+	return err;
+}
+
 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 (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
+		return do_set_sock_timeout(fd, level, optname, optval, optlen);
 	if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER)
 		return do_set_icmpv6_filter(fd, level, optname,
 					    optval, optlen);
 
 	return sys_setsockopt(fd, level, optname, optval, optlen);
+}
+
+extern asmlinkage long sys_getsockopt(int fd, int level, int optname,
+				      char *optval, int *optlen);
+
+static int do_get_sock_timeout(int fd, int level, int optname, char *optval, int *optlen)
+{
+	struct timeval32 *up = (struct timeval32 *) optval;
+	struct timeval ktime;
+	mm_segment_t old_fs;
+	int len, err;
+
+	if (get_user(len, optlen))
+		return -EFAULT;
+	if (len < sizeof(*up))
+		return -EINVAL;
+	len = sizeof(ktime);
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	err = sys_getsockopt(fd, level, optname, (char *) &ktime, &len);
+	set_fs(old_fs);
+
+	if (!err) {
+		if (put_user(sizeof(*up), optlen) ||
+		    put_user(ktime.tv_sec, &up->tv_sec) ||
+		    __put_user(ktime.tv_usec, &up->tv_usec))
+			err = -EFAULT;
+	}
+	return err;
+}
+
+asmlinkage int sys32_getsockopt(int fd, int level, int optname,
+				char *optval, int *optlen)
+{
+	if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
+		return do_get_sock_timeout(fd, level, optname, optval, optlen);
+	return sys_getsockopt(fd, level, optname, optval, optlen);
 }
 
 extern void check_pending(int signum);
diff -Nru a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
--- a/arch/sparc64/kernel/systbls.S	Sun Nov 10 19:28:39 2002
+++ b/arch/sparc64/kernel/systbls.S	Sun Nov 10 19:28:39 2002
@@ -57,7 +57,7 @@
 	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys32_sigpending, sys32_query_module
 	.word sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sparc64_newuname
-/*190*/	.word sys32_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*190*/	.word sys32_init_module, sparc64_personality, sys_remap_file_pages, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys_uselib, old32_readdir
 	.word sys32_readahead, sys32_socketcall, sys_syslog, sys_lookup_dcookie, sys_nis_syscall
@@ -116,7 +116,7 @@
 	.word sys_setsid, sys_fchdir, sys_fgetxattr, sys_listxattr, sys_llistxattr
 /*180*/	.word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_nis_syscall, sys_query_module
 	.word sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sparc64_newuname
-/*190*/	.word sys_init_module, sparc64_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
+/*190*/	.word sys_init_module, sparc64_personality, sys_remap_file_pages, sys_nis_syscall, sys_nis_syscall
 	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
 /*200*/	.word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
 	.word sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_nis_syscall
diff -Nru a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
--- a/arch/sparc64/kernel/traps.c	Sun Nov 10 19:28:41 2002
+++ b/arch/sparc64/kernel/traps.c	Sun Nov 10 19:28:41 2002
@@ -1524,6 +1524,8 @@
 {
 	siginfo_t info;
 
+	if (regs->tstate & TSTATE_PRIV)
+		die_if_kernel("TL0: Kernel divide by zero.", regs);
 	if (test_thread_flag(TIF_32BIT)) {
 		regs->tpc &= 0xffffffff;
 		regs->tnpc &= 0xffffffff;
diff -Nru a/arch/sparc64/vmlinux.lds.S b/arch/sparc64/vmlinux.lds.S
--- a/arch/sparc64/vmlinux.lds.S	Sun Nov 10 19:28:41 2002
+++ b/arch/sparc64/vmlinux.lds.S	Sun Nov 10 19:28:41 2002
@@ -57,6 +57,10 @@
 	*(.initcall7.init)
   }
   __initcall_end = .;
+  . = ALIGN(8192); 
+  __initramfs_start = .;
+  .init.ramfs : { *(.init.ramfs) }
+  __initramfs_end = .;
   . = ALIGN(32);
   __per_cpu_start = .;
   .data.percpu  : { *(.data.percpu) }
diff -Nru a/arch/v850/Kconfig b/arch/v850/Kconfig
--- a/arch/v850/Kconfig	Sun Nov 10 19:28:39 2002
+++ b/arch/v850/Kconfig	Sun Nov 10 19:28:39 2002
@@ -1,7 +1,7 @@
 #############################################################################
 #
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 #############################################################################
 
diff -Nru a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
--- a/arch/x86_64/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/arch/x86_64/Kconfig	Sun Nov 10 19:28:40 2002
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 # Note: ISA is disabled and will hopefully never be enabled.
 # If you managed to buy an ISA x86-64 box you'll have to fix all the
diff -Nru a/crypto/Kconfig b/crypto/Kconfig
--- a/crypto/Kconfig	Sun Nov 10 19:28:41 2002
+++ b/crypto/Kconfig	Sun Nov 10 19:28:41 2002
@@ -9,30 +9,58 @@
 	help
 	  This option provides the core Cryptographic API.
 
+config CRYPTO_HMAC
+	bool "HMAC support"
+	depends on CRYPTO
+	help
+	  HMAC: Keyed-Hashing for Message Authentication (RFC2104).
+	  This is required for IPSec.
+
 config CRYPTO_MD4
 	tristate "MD4 digest algorithm"
 	depends on CRYPTO
 	help
-	  MD4 message digest algorithm (RFC1320), including HMAC (RFC2104).
-	  
+	  MD4 message digest algorithm (RFC1320).
 
 config CRYPTO_MD5
 	tristate "MD5 digest algorithm"
 	depends on CRYPTO
 	help
-	  MD5 message digest algorithm (RFC1321), including HMAC (RFC2104, RFC2403).
+	  MD5 message digest algorithm (RFC1321).
 
 config CRYPTO_SHA1
-	tristate "SHA-1 digest algorithm"
+	tristate "SHA1 digest algorithm"
 	depends on CRYPTO
 	help
-	  SHA-1 secure hash standard (FIPS 180-1), including HMAC (RFC2104, RFC2404).
+	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+config CRYPTO_SHA256
+	tristate "SHA256 digest algorithm"
+	depends on CRYPTO
+	help
+	  SHA256 secure hash standard (DFIPS 180-2).
+	  
+	  This version of SHA implements a 256 bit hash with 128 bits of
+	  security against collision attacks.
 
 config CRYPTO_DES
 	tristate "DES and Triple DES EDE cipher algorithms"
 	depends on CRYPTO
 	help
 	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+config CRYPTO_BLOWFISH
+	tristate "Blowfish cipher algorithm"
+	depends on CRYPTO
+	help
+	  Blowfish cipher algorithm, by Bruce Schneier.
+	  
+	  This is a variable key length cipher which can use keys from 32
+	  bits to 448 bits in length.  It's fast, simple and specifically
+	  designed for use on "large microprocessors".
+	  
+	  See also:
+	  http://www.counterpane.com/blowfish.html
 
 config CRYPTO_TEST
 	tristate "Testing module"
diff -Nru a/crypto/Makefile b/crypto/Makefile
--- a/crypto/Makefile	Sun Nov 10 19:28:41 2002
+++ b/crypto/Makefile	Sun Nov 10 19:28:41 2002
@@ -2,15 +2,19 @@
 # Cryptographic API
 #
 
-export-objs := api.o
+export-objs := api.o hmac.o
 
-obj-$(CONFIG_CRYPTO) += api.o cipher.o digest.o compress.o
-obj-$(CONFIG_KMOD) += autoload.o
+autoload-crypto-$(CONFIG_KMOD) = autoload.o
 
+obj-$(CONFIG_CRYPTO) += api.o cipher.o digest.o compress.o $(autoload-crypto-y)
+
+obj-$(CONFIG_CRYPTO_HMAC) += hmac.o
 obj-$(CONFIG_CRYPTO_MD4) += md4.o
 obj-$(CONFIG_CRYPTO_MD5) += md5.o
 obj-$(CONFIG_CRYPTO_SHA1) += sha1.o
+obj-$(CONFIG_CRYPTO_SHA256) += sha256.o
 obj-$(CONFIG_CRYPTO_DES) += des.o
+obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish.o
 
 obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
 
diff -Nru a/crypto/api.c b/crypto/api.c
--- a/crypto/api.c	Sun Nov 10 19:28:41 2002
+++ b/crypto/api.c	Sun Nov 10 19:28:41 2002
@@ -67,9 +67,10 @@
 		return crypto_init_compress_flags(tfm, flags);
 	
 	default:
-		BUG();
+		break;
 	}
 	
+	BUG();
 	return -EINVAL;
 }
 
@@ -99,13 +100,7 @@
 	struct crypto_tfm *tfm = NULL;
 	struct crypto_alg *alg;
 
-	alg = crypto_alg_lookup(name);
-#ifdef CONFIG_KMOD
-	if (alg == NULL) {
-		crypto_alg_autoload(name);
-		alg = crypto_alg_lookup(name);
-	}
-#endif
+	alg = crypto_alg_mod_lookup(name);
 	if (alg == NULL)
 		goto out;
 	
@@ -113,6 +108,8 @@
 	if (tfm == NULL)
 		goto out_put;
 
+	memset(tfm, 0, sizeof(*tfm));
+
 	if (alg->cra_ctxsize) {
 		tfm->crt_ctx = kmalloc(alg->cra_ctxsize, GFP_KERNEL);
 		if (tfm->crt_ctx == NULL)
@@ -121,13 +118,24 @@
 
 	tfm->__crt_alg = alg;
 	
+	if (alg->cra_blocksize) {
+		tfm->crt_work_block = kmalloc(alg->cra_blocksize + 1,
+					      GFP_KERNEL);
+		if (tfm->crt_work_block == NULL)
+			goto out_free_ctx;
+	}
+
 	if (crypto_init_flags(tfm, flags))
-		goto out_free_ctx;
+		goto out_free_work_block;
 		
 	crypto_init_ops(tfm);
 	
 	goto out;
 
+out_free_work_block:
+	if (tfm->__crt_alg->cra_blocksize)
+		kfree(tfm->crt_work_block);
+
 out_free_ctx:
 	if (tfm->__crt_alg->cra_ctxsize)
 		kfree(tfm->crt_ctx);
@@ -145,6 +153,9 @@
 	if (tfm->__crt_alg->cra_ctxsize)
 		kfree(tfm->crt_ctx);
 		
+	if (tfm->__crt_alg->cra_blocksize)
+		kfree(tfm->crt_work_block);
+		
 	if (crypto_tfm_alg_type(tfm) == CRYPTO_ALG_TYPE_CIPHER)
 		if (tfm->crt_cipher.cit_iv)
 			kfree(tfm->crt_cipher.cit_iv);
@@ -207,6 +218,19 @@
 	return ret;
 }
 
+int crypto_alg_available(const char *name, u32 flags)
+{
+	int ret = 0;
+	struct crypto_alg *alg = crypto_alg_mod_lookup(name);
+	
+	if (alg) {
+		crypto_alg_put(alg);
+		ret = 1;
+	}
+	
+	return ret;
+}
+
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
 	struct list_head *v;
@@ -238,19 +262,23 @@
 {
 	struct crypto_alg *alg = (struct crypto_alg *)p;
 	
-	seq_printf(m, "name       : %s\n", alg->cra_name);
-	seq_printf(m, "module     : %s\n", alg->cra_module ?
+	seq_printf(m, "name         : %s\n", alg->cra_name);
+	seq_printf(m, "module       : %s\n", alg->cra_module ?
 					alg->cra_module->name : "[static]");
-	seq_printf(m, "blocksize  : %u\n", alg->cra_blocksize);
+	seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
 	
 	switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
 	case CRYPTO_ALG_TYPE_CIPHER:
-		seq_printf(m, "keysize    : %u\n", alg->cra_cipher.cia_keysize);
-		seq_printf(m, "ivsize     : %u\n", alg->cra_cipher.cia_ivsize);
+		seq_printf(m, "min keysize  : %u\n",
+					alg->cra_cipher.cia_min_keysize);
+		seq_printf(m, "max keysize  : %u\n",
+					alg->cra_cipher.cia_max_keysize);
+		seq_printf(m, "ivsize       : %u\n",
+					alg->cra_cipher.cia_ivsize);
 		break;
 		
 	case CRYPTO_ALG_TYPE_DIGEST:
-		seq_printf(m, "digestsize : %u\n",
+		seq_printf(m, "digestsize   : %u\n",
 		           alg->cra_digest.dia_digestsize);
 		break;
 	}
@@ -296,3 +324,4 @@
 EXPORT_SYMBOL_GPL(crypto_unregister_alg);
 EXPORT_SYMBOL_GPL(crypto_alloc_tfm);
 EXPORT_SYMBOL_GPL(crypto_free_tfm);
+EXPORT_SYMBOL_GPL(crypto_alg_available);
diff -Nru a/crypto/autoload.c b/crypto/autoload.c
--- a/crypto/autoload.c	Sun Nov 10 19:28:39 2002
+++ b/crypto/autoload.c	Sun Nov 10 19:28:39 2002
@@ -25,3 +25,13 @@
 {
 	request_module(name);
 }
+
+struct crypto_alg *crypto_alg_mod_lookup(const char *name)
+{
+	struct crypto_alg *alg = crypto_alg_lookup(name);
+	if (alg == NULL) {
+		crypto_alg_autoload(name);
+		alg = crypto_alg_lookup(name);
+	}
+	return alg;
+}
diff -Nru a/crypto/blowfish.c b/crypto/blowfish.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/crypto/blowfish.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,479 @@
+/* 
+ * Cryptographic API.
+ *
+ * Blowfish Cipher Algorithm, by Bruce Schneier.
+ * http://www.counterpane.com/blowfish.html
+ * 
+ * Adapated from Kerneli implementation.
+ * 
+ * Copyright (c) Herbert Valerio Riedel <hvr@hvrlab.org>
+ * Copyright (c) Kyle McMartin <kyle@debian.org>
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.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/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <asm/scatterlist.h>
+#include <linux/crypto.h>
+
+#define BF_BLOCK_SIZE 8
+#define BF_MIN_KEY_SIZE 4
+#define BF_MAX_KEY_SIZE 56
+
+struct bf_ctx {
+	u32 p[18];
+	u32 s[1024];
+};
+
+const static u32 bf_pbox[16 + 2] = {
+	0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
+	0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
+	0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
+	0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
+	0x9216d5d9, 0x8979fb1b,
+};
+
+const static u32 bf_sbox[256 * 4] = {
+	0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
+	0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
+	0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
+	0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
+	0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
+	0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
+	0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
+	0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
+	0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
+	0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
+	0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
+	0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
+	0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
+	0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
+	0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
+	0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
+	0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
+	0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
+	0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
+	0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
+	0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
+	0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
+	0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
+	0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
+	0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
+	0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
+	0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
+	0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
+	0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
+	0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
+	0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
+	0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
+	0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
+	0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
+	0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
+	0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
+	0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
+	0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
+	0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
+	0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
+	0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
+	0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
+	0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
+	0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
+	0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
+	0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
+	0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
+	0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
+	0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
+	0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
+	0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
+	0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
+	0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
+	0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
+	0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
+	0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
+	0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
+	0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
+	0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
+	0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
+	0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
+	0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
+	0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
+	0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
+	0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
+	0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
+	0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
+	0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
+	0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
+	0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
+	0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
+	0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
+	0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
+	0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
+	0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
+	0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
+	0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
+	0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
+	0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
+	0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
+	0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
+	0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
+	0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
+	0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
+	0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
+	0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
+	0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
+	0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
+	0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
+	0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
+	0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
+	0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
+	0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
+	0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
+	0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
+	0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
+	0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
+	0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
+	0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
+	0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
+	0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
+	0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
+	0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
+	0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
+	0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
+	0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
+	0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
+	0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
+	0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
+	0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
+	0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
+	0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
+	0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
+	0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
+	0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
+	0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
+	0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
+	0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
+	0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
+	0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
+	0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
+	0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
+	0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
+	0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
+	0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
+	0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
+	0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
+	0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
+	0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
+	0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
+	0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
+	0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
+	0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
+	0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
+	0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
+	0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
+	0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
+	0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
+	0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
+	0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
+	0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
+	0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
+	0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
+	0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
+	0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
+	0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
+	0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
+	0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
+	0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
+	0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
+	0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
+	0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
+	0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
+	0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
+	0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
+	0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
+	0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
+	0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
+	0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
+	0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
+	0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
+	0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
+	0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
+	0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
+	0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
+	0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
+	0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
+	0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
+	0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
+	0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
+	0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
+	0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
+	0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
+	0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
+	0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
+	0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
+	0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
+	0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
+	0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
+	0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
+	0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
+	0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
+	0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
+	0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
+	0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
+	0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
+	0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
+	0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
+	0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
+	0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
+	0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
+	0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
+	0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
+	0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
+	0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
+	0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
+	0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
+	0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
+	0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
+	0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
+	0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
+	0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
+	0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
+	0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
+	0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
+	0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
+	0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
+	0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
+	0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
+	0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
+	0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
+	0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
+	0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
+	0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
+	0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
+	0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
+	0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
+	0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
+	0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
+	0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
+	0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
+	0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
+	0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
+	0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
+	0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
+	0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
+	0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
+	0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
+	0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
+	0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
+	0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
+	0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
+	0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
+	0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
+	0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
+	0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
+	0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
+	0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
+	0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
+	0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
+	0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
+	0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
+	0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
+	0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
+	0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
+	0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
+	0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
+	0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
+	0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
+	0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
+	0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
+	0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
+	0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
+	0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
+	0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
+	0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
+};
+
+/* 
+ * Round loop unrolling macros, S is a pointer to a S-Box array
+ * organized in 4 unsigned longs at a row.
+ */
+#define GET32_3(x) (((x) & 0xff))
+#define GET32_2(x) (((x) >> (8)) & (0xff))
+#define GET32_1(x) (((x) >> (16)) & (0xff))
+#define GET32_0(x) (((x) >> (24)) & (0xff))
+
+#define bf_F(x) (((S[GET32_0(x)] + S[256 + GET32_1(x)]) ^ \
+          S[512 + GET32_2(x)]) + S[768 + GET32_3(x)])
+
+#define ROUND(a, b, n)  b ^= P[n]; a ^= bf_F (b)
+
+/*
+ * The blowfish encipher, processes 64-bit blocks.
+ * NOTE: This function MUSTN'T respect endianess 
+ */
+static inline void encrypt_block(struct bf_ctx *bctx, u32 *dst, u32 *src)
+{
+	const u32 *P = bctx->p;
+	const u32 *S = bctx->s;
+	u32 yl = src[0];
+	u32 yr = src[1];
+
+	ROUND(yr, yl, 0);
+	ROUND(yl, yr, 1);
+	ROUND(yr, yl, 2);
+	ROUND(yl, yr, 3);
+	ROUND(yr, yl, 4);
+	ROUND(yl, yr, 5);
+	ROUND(yr, yl, 6);
+	ROUND(yl, yr, 7);
+	ROUND(yr, yl, 8);
+	ROUND(yl, yr, 9);
+	ROUND(yr, yl, 10);
+	ROUND(yl, yr, 11);
+	ROUND(yr, yl, 12);
+	ROUND(yl, yr, 13);
+	ROUND(yr, yl, 14);
+	ROUND(yl, yr, 15);
+
+	yl ^= P[16];
+	yr ^= P[17];
+
+	dst[0] = yr;
+	dst[1] = yl;
+}
+
+static void bf_encrypt(void *ctx, u8 *dst, const u8 *src)
+{
+	const u32 *in_blk = (const u32 *)src;
+	u32 *const out_blk = (u32 *)dst;
+	u32 in32[2], out32[2];
+
+	in32[0] = be32_to_cpu(in_blk[0]);
+	in32[1] = be32_to_cpu(in_blk[1]);
+	encrypt_block(ctx, out32, in32);
+	out_blk[0] = cpu_to_be32(out32[0]);
+	out_blk[1] = cpu_to_be32(out32[1]);
+}
+
+static void bf_decrypt(void *ctx, u8 *dst, const u8 *src)
+{
+	const u32 *in_blk = (const u32 *)src;
+	u32 *const out_blk = (u32 *)dst;
+	const u32 *P = ((struct bf_ctx *)ctx)->p;
+	const u32 *S = ((struct bf_ctx *)ctx)->s;
+	u32 yl = be32_to_cpu(in_blk[0]);
+	u32 yr = be32_to_cpu(in_blk[1]);
+
+	ROUND(yr, yl, 17);
+	ROUND(yl, yr, 16);
+	ROUND(yr, yl, 15);
+	ROUND(yl, yr, 14);
+	ROUND(yr, yl, 13);
+	ROUND(yl, yr, 12);
+	ROUND(yr, yl, 11);
+	ROUND(yl, yr, 10);
+	ROUND(yr, yl, 9);
+	ROUND(yl, yr, 8);
+	ROUND(yr, yl, 7);
+	ROUND(yl, yr, 6);
+	ROUND(yr, yl, 5);
+	ROUND(yl, yr, 4);
+	ROUND(yr, yl, 3);
+	ROUND(yl, yr, 2);
+
+	yl ^= P[1];
+	yr ^= P[0];
+
+	out_blk[0] = cpu_to_be32(yr);
+	out_blk[1] = cpu_to_be32(yl);
+}
+
+/* 
+ * Calculates the blowfish S and P boxes for encryption and decryption.
+ */
+static int bf_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
+{
+	short i, j, count;
+	u32 data[2], temp;
+	u32 *P = ((struct bf_ctx *)ctx)->p;
+	u32 *S = ((struct bf_ctx *)ctx)->s;
+
+	/* Copy the initialization s-boxes */
+	for (i = 0, count = 0; i < 256; i++)
+		for (j = 0; j < 4; j++, count++)
+			S[count] = bf_sbox[count];
+
+	/* Set the p-boxes */
+	for (i = 0; i < 16 + 2; i++)
+		P[i] = bf_pbox[i];
+
+	/* Actual subkey generation */
+	for (j = 0, i = 0; i < 16 + 2; i++) {
+		temp = (((u32 )key[j] << 24) |
+			((u32 )key[(j + 1) % keylen] << 16) |
+			((u32 )key[(j + 2) % keylen] << 8) |
+			((u32 )key[(j + 3) % keylen]));
+
+		P[i] = P[i] ^ temp;
+		j = (j + 4) % keylen;
+	}
+
+	data[0] = 0x00000000;
+	data[1] = 0x00000000;
+
+	for (i = 0; i < 16 + 2; i += 2) {
+		encrypt_block((struct bf_ctx *)ctx, data, data);
+
+		P[i] = data[0];
+		P[i + 1] = data[1];
+	}
+
+	for (i = 0; i < 4; i++) {
+		for (j = 0, count = i * 256; j < 256; j += 2, count += 2) {
+			encrypt_block((struct bf_ctx *)ctx, data, data);
+
+			S[count] = data[0];
+			S[count + 1] = data[1];
+		}
+	}
+	
+	/* Bruce says not to bother with the weak key check. */
+	return 0;
+}
+
+static struct crypto_alg alg = {
+	.cra_name		=	"blowfish",
+	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		=	BF_BLOCK_SIZE,
+	.cra_ctxsize		=	sizeof(struct bf_ctx),
+	.cra_module		=	THIS_MODULE,
+	.cra_list		=	LIST_HEAD_INIT(alg.cra_list),
+	.cra_u			=	{ .cipher = {
+	.cia_min_keysize	=	BF_MIN_KEY_SIZE,
+	.cia_max_keysize	=	BF_MAX_KEY_SIZE,
+	.cia_ivsize		=	BF_BLOCK_SIZE,
+	.cia_setkey   		= 	bf_setkey,
+	.cia_encrypt 		=	bf_encrypt,
+	.cia_decrypt  		=	bf_decrypt } }
+};
+
+static int __init init(void)
+{
+	return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+	crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Blowfish Cipher Algorithm");
diff -Nru a/crypto/cipher.c b/crypto/cipher.c
--- a/crypto/cipher.c	Sun Nov 10 19:28:40 2002
+++ b/crypto/cipher.c	Sun Nov 10 19:28:40 2002
@@ -188,8 +188,14 @@
 
 static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
 {
-	return tfm->__crt_alg->cra_cipher.cia_setkey(tfm->crt_ctx, key,
-	                                             keylen, &tfm->crt_flags);
+	struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher;
+	
+	if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) {
+		tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+		return -EINVAL;
+	} else
+		return cia->cia_setkey(tfm->crt_ctx, key, keylen,
+		                       &tfm->crt_flags);
 }
 
 static int ecb_encrypt(struct crypto_tfm *tfm,
diff -Nru a/crypto/des.c b/crypto/des.c
--- a/crypto/des.c	Sun Nov 10 19:28:41 2002
+++ b/crypto/des.c	Sun Nov 10 19:28:41 2002
@@ -1032,11 +1032,6 @@
 	u32 n, w;
 	u8 bits0[56], bits1[56];
 
-	if (keylen != DES_KEY_SIZE) {
-		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
-		return -EINVAL;
-	}
-
 	n  = parity[key[0]]; n <<= 4;
 	n |= parity[key[1]]; n <<= 4;
 	n |= parity[key[2]]; n <<= 4;
@@ -1208,11 +1203,6 @@
 	unsigned int i, off;
 	struct des3_ede_ctx *dctx = ctx;
 
-	if (keylen != DES3_EDE_KEY_SIZE) {
-		*flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
-		return -EINVAL;
-	}
-
 	if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) && 
 	    memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2],
 	    					DES_KEY_SIZE))) {
@@ -1249,33 +1239,35 @@
 }
 
 static struct crypto_alg des_alg = {
-	.cra_name	=	"des",
-	.cra_flags	=	CRYPTO_ALG_TYPE_CIPHER,
-	.cra_blocksize	=	DES_BLOCK_SIZE,
-	.cra_ctxsize	=	sizeof(struct des_ctx),
-	.cra_module	=	THIS_MODULE,
-	.cra_list	=	LIST_HEAD_INIT(des_alg.cra_list),
-	.cra_u		=	{ .cipher = {
-	.cia_keysize	=	DES_KEY_SIZE,
-	.cia_ivsize	=	DES_BLOCK_SIZE,
-	.cia_setkey   	= 	des_setkey,
-	.cia_encrypt 	=	des_encrypt,
-	.cia_decrypt  	=	des_decrypt } }
+	.cra_name		=	"des",
+	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		=	DES_BLOCK_SIZE,
+	.cra_ctxsize		=	sizeof(struct des_ctx),
+	.cra_module		=	THIS_MODULE,
+	.cra_list		=	LIST_HEAD_INIT(des_alg.cra_list),
+	.cra_u			=	{ .cipher = {
+	.cia_min_keysize	=	DES_KEY_SIZE,
+	.cia_max_keysize	=	DES_KEY_SIZE,
+	.cia_ivsize		=	DES_BLOCK_SIZE,
+	.cia_setkey		= 	des_setkey,
+	.cia_encrypt		=	des_encrypt,
+	.cia_decrypt		=	des_decrypt } }
 };
 
 static struct crypto_alg des3_ede_alg = {
-	.cra_name	=	"des3_ede",
-	.cra_flags	=	CRYPTO_ALG_TYPE_CIPHER,
-	.cra_blocksize	=	DES3_EDE_BLOCK_SIZE,
-	.cra_ctxsize	=	sizeof(struct des3_ede_ctx),
-	.cra_module	=	THIS_MODULE,
-	.cra_list	=	LIST_HEAD_INIT(des3_ede_alg.cra_list),
-	.cra_u		=	{ .cipher = {
-	.cia_keysize	=	DES3_EDE_KEY_SIZE,
-	.cia_ivsize	=	DES3_EDE_BLOCK_SIZE,
-	.cia_setkey   	= 	des3_ede_setkey,
-	.cia_encrypt 	=	des3_ede_encrypt,
-	.cia_decrypt  	=	des3_ede_decrypt } }
+	.cra_name		=	"des3_ede",
+	.cra_flags		=	CRYPTO_ALG_TYPE_CIPHER,
+	.cra_blocksize		=	DES3_EDE_BLOCK_SIZE,
+	.cra_ctxsize		=	sizeof(struct des3_ede_ctx),
+	.cra_module		=	THIS_MODULE,
+	.cra_list		=	LIST_HEAD_INIT(des3_ede_alg.cra_list),
+	.cra_u			=	{ .cipher = {
+	.cia_min_keysize	=	DES3_EDE_KEY_SIZE,
+	.cia_max_keysize	=	DES3_EDE_KEY_SIZE,
+	.cia_ivsize		=	DES3_EDE_BLOCK_SIZE,
+	.cia_setkey	   	= 	des3_ede_setkey,
+	.cia_encrypt	 	=	des3_ede_encrypt,
+	.cia_decrypt	  	=	des3_ede_decrypt } }
 };
 
 static int __init init(void)
diff -Nru a/crypto/digest.c b/crypto/digest.c
--- a/crypto/digest.c	Sun Nov 10 19:28:36 2002
+++ b/crypto/digest.c	Sun Nov 10 19:28:36 2002
@@ -5,9 +5,6 @@
  *
  * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
  *
- * The HMAC implementation is derived from USAGI.
- * Copyright (c) 2002 Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI
- *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
  * Software Foundation; either version 2 of the License, or (at your option) 
@@ -61,56 +58,6 @@
 	crypto_digest_final(tfm, out);
 }
 
-static void hmac(struct crypto_tfm *tfm, u8 *key, unsigned int keylen,
-                 struct scatterlist *sg, unsigned int nsg, u8 *out)
-{
-	unsigned int i;
-	struct scatterlist tmp;
-	char ipad[crypto_tfm_alg_blocksize(tfm) + 1];
-	char opad[crypto_tfm_alg_blocksize(tfm) + 1];
-
-	if (keylen > crypto_tfm_alg_blocksize(tfm)) {
-		tmp.page = virt_to_page(key);
-		tmp.offset = ((long)key & ~PAGE_MASK);
-		tmp.length = keylen;
-		crypto_digest_digest(tfm, &tmp, 1, key);
-		keylen = crypto_tfm_alg_digestsize(tfm);
-	}
-
-	memset(ipad, 0, sizeof(ipad));
-	memset(opad, 0, sizeof(opad));
-	memcpy(ipad, key, keylen);
-	memcpy(opad, key, keylen);
-
-	for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++) {
-		ipad[i] ^= 0x36;
-		opad[i] ^= 0x5c;
-	}
-
-	tmp.page = virt_to_page(ipad);
-	tmp.offset = ((long)ipad & ~PAGE_MASK);
-	tmp.length = crypto_tfm_alg_blocksize(tfm);
-
-	crypto_digest_init(tfm);
-	crypto_digest_update(tfm, &tmp, 1);
-	crypto_digest_update(tfm, sg, nsg);
-	crypto_digest_final(tfm, out);
-
-	tmp.page = virt_to_page(opad);
-	tmp.offset = ((long)opad & ~PAGE_MASK);
-	tmp.length = crypto_tfm_alg_blocksize(tfm);
-
-	crypto_digest_init(tfm);
-	crypto_digest_update(tfm, &tmp, 1);
-	
-	tmp.page = virt_to_page(out);
-	tmp.offset = ((long)out & ~PAGE_MASK);
-	tmp.length = crypto_tfm_alg_digestsize(tfm);
-	
-	crypto_digest_update(tfm, &tmp, 1);
-	crypto_digest_final(tfm, out);
-}
-
 int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags)
 {
 	return crypto_cipher_flags(flags) ? -EINVAL : 0;
@@ -120,9 +67,8 @@
 {
 	struct digest_tfm *ops = &tfm->crt_digest;
 	
-	ops->dit_init   = init;
-	ops->dit_update = update;
-	ops->dit_final  = final;
-	ops->dit_digest = digest;
-	ops->dit_hmac   = hmac;
+	ops->dit_init		= init;
+	ops->dit_update		= update;
+	ops->dit_final		= final;
+	ops->dit_digest		= digest;
 }
diff -Nru a/crypto/hmac.c b/crypto/hmac.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/crypto/hmac.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,112 @@
+/*
+ * Cryptographic API.
+ *
+ * HMAC: Keyed-Hashing for Message Authentication (RFC2104).
+ *
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ *
+ * The HMAC implementation is derived from USAGI.
+ * Copyright (c) 2002 Kazunori Miyazawa <miyazawa@linux-ipv6.org> / USAGI
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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/crypto.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <asm/scatterlist.h>
+#include "internal.h"
+
+static void hash_key(struct crypto_tfm *tfm, u8 *key, unsigned int keylen)
+{
+	struct scatterlist tmp;
+	
+	tmp.page = virt_to_page(key);
+	tmp.offset = ((long)key & ~PAGE_MASK);
+	tmp.length = keylen;
+	crypto_digest_digest(tfm, &tmp, 1, key);
+		
+}
+
+void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen)
+{
+	unsigned int i;
+	struct scatterlist tmp;
+	char *ipad = tfm->crt_work_block;
+
+	if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
+		hash_key(tfm, key, *keylen);
+		*keylen = crypto_tfm_alg_digestsize(tfm);
+	}
+
+	memset(ipad, 0, crypto_tfm_alg_blocksize(tfm) + 1);
+	memcpy(ipad, key, *keylen);
+
+	for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
+		ipad[i] ^= 0x36;
+
+	tmp.page = virt_to_page(ipad);
+	tmp.offset = ((long)ipad & ~PAGE_MASK);
+	tmp.length = crypto_tfm_alg_blocksize(tfm);
+	
+	crypto_digest_init(tfm);
+	crypto_digest_update(tfm, &tmp, 1);
+}
+
+void crypto_hmac_update(struct crypto_tfm *tfm,
+                        struct scatterlist *sg, unsigned int nsg)
+{
+	crypto_digest_update(tfm, sg, nsg);
+}
+
+void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
+                       unsigned int *keylen, u8 *out)
+{
+	unsigned int i;
+	struct scatterlist tmp;
+	char *opad = tfm->crt_work_block;
+
+	if (*keylen > crypto_tfm_alg_blocksize(tfm)) {
+		hash_key(tfm, key, *keylen);
+		*keylen = crypto_tfm_alg_digestsize(tfm);
+	}
+
+	crypto_digest_final(tfm, out);
+
+	memset(opad, 0, crypto_tfm_alg_blocksize(tfm) + 1);
+	memcpy(opad, key, *keylen);
+		
+	for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
+		opad[i] ^= 0x5c;
+
+	tmp.page = virt_to_page(opad);
+	tmp.offset = ((long)opad & ~PAGE_MASK);
+	tmp.length = crypto_tfm_alg_blocksize(tfm);
+
+	crypto_digest_init(tfm);
+	crypto_digest_update(tfm, &tmp, 1);
+	
+	tmp.page = virt_to_page(out);
+	tmp.offset = ((long)out & ~PAGE_MASK);
+	tmp.length = crypto_tfm_alg_digestsize(tfm);
+	
+	crypto_digest_update(tfm, &tmp, 1);
+	crypto_digest_final(tfm, out);
+}
+
+void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen,
+                 struct scatterlist *sg, unsigned int nsg, u8 *out)
+{
+	crypto_hmac_init(tfm, key, keylen);
+	crypto_hmac_update(tfm, sg, nsg);
+	crypto_hmac_final(tfm, key, keylen, out);
+}
+
+EXPORT_SYMBOL_GPL(crypto_hmac_init);
+EXPORT_SYMBOL_GPL(crypto_hmac_update);
+EXPORT_SYMBOL_GPL(crypto_hmac_final);
+EXPORT_SYMBOL_GPL(crypto_hmac);
+
diff -Nru a/crypto/internal.h b/crypto/internal.h
--- a/crypto/internal.h	Sun Nov 10 19:28:36 2002
+++ b/crypto/internal.h	Sun Nov 10 19:28:36 2002
@@ -35,13 +35,21 @@
 		cond_resched();
 }
 
-static inline int crypto_cipher_flags(u32 flags)
+static inline u32 crypto_cipher_flags(u32 flags)
 {
 	return flags & (CRYPTO_TFM_MODE_MASK|CRYPTO_TFM_REQ_WEAK_KEY);
 }
 
+struct crypto_alg *crypto_alg_lookup(const char *name);
+
 #ifdef CONFIG_KMOD
 void crypto_alg_autoload(const char *name);
+struct crypto_alg *crypto_alg_mod_lookup(const char *name);
+#else
+static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name)
+{
+	return crypto_alg_lookup(name);
+}
 #endif
 
 int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags);
diff -Nru a/crypto/sha1.c b/crypto/sha1.c
--- a/crypto/sha1.c	Sun Nov 10 19:28:38 2002
+++ b/crypto/sha1.c	Sun Nov 10 19:28:38 2002
@@ -5,10 +5,10 @@
  *
  * Derived from cryptoapi implementation, adapted for in-place
  * scatterlist interface.  Originally based on the public domain
- * implementation written by Steve Raid.
+ * implementation written by Steve Reid.
  *
  * Copyright (c) Alan Smithee.
- * Copyright (c) McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
  * Copyright (c) Jean-Francois Dive <jef@linuxbe.org>
  *
  * This program is free software; you can redistribute it and/or modify it
diff -Nru a/crypto/sha256.c b/crypto/sha256.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/crypto/sha256.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,362 @@
+/*
+ * Cryptographic API.
+ *
+ * SHA-256, as specified in
+ * http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf
+ *
+ * SHA-256 code by Jean-Luc Cooke <jlcooke@certainkey.com>.
+ *
+ * Copyright (c) Jean-Luc Cooke <jlcooke@certainkey.com>
+ * Copyright (c) Andrew McDonald <andrew@mcdonald.org.uk>
+ * Copyright (c) 2002 James Morris <jmorris@intercode.com.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/init.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/crypto.h>
+#include <asm/scatterlist.h>
+#include <asm/byteorder.h>
+
+#define SHA256_DIGEST_SIZE	32
+#define SHA256_HMAC_BLOCK_SIZE	64
+
+struct sha256_ctx {
+	u32 count[2];
+	u32 state[8];
+	u8 buf[128];
+};
+
+static inline u32 Ch(u32 x, u32 y, u32 z)
+{
+	return ((x & y) ^ (~x & z));
+}
+
+static inline u32 Maj(u32 x, u32 y, u32 z)
+{
+	return ((x & y) ^ (x & z) ^ (y & z));
+}
+
+static inline u32 RORu32(u32 x, u32 y)
+{
+	return (x >> y) | (x << (32 - y));
+}
+
+#define e0(x)       (RORu32(x, 2) ^ RORu32(x,13) ^ RORu32(x,22))
+#define e1(x)       (RORu32(x, 6) ^ RORu32(x,11) ^ RORu32(x,25))
+#define s0(x)       (RORu32(x, 7) ^ RORu32(x,18) ^ (x >> 3))
+#define s1(x)       (RORu32(x,17) ^ RORu32(x,19) ^ (x >> 10))
+
+#define H0         0x6a09e667
+#define H1         0xbb67ae85
+#define H2         0x3c6ef372
+#define H3         0xa54ff53a
+#define H4         0x510e527f
+#define H5         0x9b05688c
+#define H6         0x1f83d9ab
+#define H7         0x5be0cd19
+
+static inline void LOAD_OP(int I, u32 *W, const u8 *input)
+{
+	u32 t1 = input[(4 * I)] & 0xff;
+
+	t1 <<= 8;
+	t1 |= input[(4 * I) + 1] & 0xff;
+	t1 <<= 8;
+	t1 |= input[(4 * I) + 2] & 0xff;
+	t1 <<= 8;
+	t1 |= input[(4 * I) + 3] & 0xff;
+	W[I] = t1;
+}
+
+static inline void BLEND_OP(int I, u32 *W)
+{
+	W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16];
+}
+
+static void sha256_transform(u32 *state, const u8 *input)
+{
+	u32 a, b, c, d, e, f, g, h, t1, t2;
+	u32 W[64];
+	int i;
+
+	/* load the input */
+	for (i = 0; i < 16; i++)
+		LOAD_OP(i, W, input);
+
+	/* now blend */
+	for (i = 16; i < 64; i++)
+		BLEND_OP(i, W);
+    
+	/* load the state into our registers */
+	a=state[0];  b=state[1];  c=state[2];  d=state[3];
+	e=state[4];  f=state[5];  g=state[6];  h=state[7];
+
+	/* now iterate */
+	t1 = h + e1(e) + Ch(e,f,g) + 0x428a2f98 + W[ 0];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0x71374491 + W[ 1];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0xb5c0fbcf + W[ 2];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0xe9b5dba5 + W[ 3];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0x3956c25b + W[ 4];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0x59f111f1 + W[ 5];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0x923f82a4 + W[ 6];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0xab1c5ed5 + W[ 7];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0xd807aa98 + W[ 8];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0x12835b01 + W[ 9];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0x243185be + W[10];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0x550c7dc3 + W[11];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0x72be5d74 + W[12];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0x80deb1fe + W[13];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0x9bdc06a7 + W[14];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0xc19bf174 + W[15];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0xe49b69c1 + W[16];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0xefbe4786 + W[17];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0x0fc19dc6 + W[18];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0x240ca1cc + W[19];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0x2de92c6f + W[20];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0x4a7484aa + W[21];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0x5cb0a9dc + W[22];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0x76f988da + W[23];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0x983e5152 + W[24];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0xa831c66d + W[25];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0xb00327c8 + W[26];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0xbf597fc7 + W[27];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0xc6e00bf3 + W[28];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0xd5a79147 + W[29];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0x06ca6351 + W[30];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0x14292967 + W[31];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0x27b70a85 + W[32];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0x2e1b2138 + W[33];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0x4d2c6dfc + W[34];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0x53380d13 + W[35];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0x650a7354 + W[36];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0x766a0abb + W[37];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0x81c2c92e + W[38];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0x92722c85 + W[39];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0xa2bfe8a1 + W[40];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0xa81a664b + W[41];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0xc24b8b70 + W[42];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0xc76c51a3 + W[43];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0xd192e819 + W[44];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0xd6990624 + W[45];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0xf40e3585 + W[46];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0x106aa070 + W[47];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0x19a4c116 + W[48];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0x1e376c08 + W[49];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0x2748774c + W[50];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0x34b0bcb5 + W[51];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0x391c0cb3 + W[52];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0x4ed8aa4a + W[53];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0x5b9cca4f + W[54];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0x682e6ff3 + W[55];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	t1 = h + e1(e) + Ch(e,f,g) + 0x748f82ee + W[56];
+	t2 = e0(a) + Maj(a,b,c);    d+=t1;    h=t1+t2;
+	t1 = g + e1(d) + Ch(d,e,f) + 0x78a5636f + W[57];
+	t2 = e0(h) + Maj(h,a,b);    c+=t1;    g=t1+t2;
+	t1 = f + e1(c) + Ch(c,d,e) + 0x84c87814 + W[58];
+	t2 = e0(g) + Maj(g,h,a);    b+=t1;    f=t1+t2;
+	t1 = e + e1(b) + Ch(b,c,d) + 0x8cc70208 + W[59];
+	t2 = e0(f) + Maj(f,g,h);    a+=t1;    e=t1+t2;
+	t1 = d + e1(a) + Ch(a,b,c) + 0x90befffa + W[60];
+	t2 = e0(e) + Maj(e,f,g);    h+=t1;    d=t1+t2;
+	t1 = c + e1(h) + Ch(h,a,b) + 0xa4506ceb + W[61];
+	t2 = e0(d) + Maj(d,e,f);    g+=t1;    c=t1+t2;
+	t1 = b + e1(g) + Ch(g,h,a) + 0xbef9a3f7 + W[62];
+	t2 = e0(c) + Maj(c,d,e);    f+=t1;    b=t1+t2;
+	t1 = a + e1(f) + Ch(f,g,h) + 0xc67178f2 + W[63];
+	t2 = e0(b) + Maj(b,c,d);    e+=t1;    a=t1+t2;
+
+	state[0] += a; state[1] += b; state[2] += c; state[3] += d;
+	state[4] += e; state[5] += f; state[6] += g; state[7] += h;
+
+	/* clear any sensitive info... */
+	a = b = c = d = e = f = g = h = t1 = t2 = 0;
+	memset(W, 0, 64 * sizeof(u32));
+}
+
+static void sha256_init(void *ctx)
+{
+	struct sha256_ctx *sctx = ctx;
+	sctx->state[0] = H0;
+	sctx->state[1] = H1;
+	sctx->state[2] = H2;
+	sctx->state[3] = H3;
+	sctx->state[4] = H4;
+	sctx->state[5] = H5;
+	sctx->state[6] = H6;
+	sctx->state[7] = H7;
+	sctx->count[0] = sctx->count[1] = 0;
+	memset(sctx->buf, 0, sizeof(sctx->buf));
+}
+
+static void sha256_update(void *ctx, const u8 *data, unsigned int len)
+{
+	struct sha256_ctx *sctx = ctx;
+	unsigned int i, index, part_len;
+
+	/* Compute number of bytes mod 128 */
+	index = (unsigned int)((sctx->count[0] >> 3) & 0x3f);
+
+	/* Update number of bits */
+	if ((sctx->count[0] += (len << 3)) < (len << 3)) {
+		sctx->count[1]++;
+		sctx->count[1] += (len >> 29);
+	}
+
+	part_len = 64 - index;
+
+	/* Transform as many times as possible. */
+	if (len >= part_len) {
+		memcpy(&sctx->buf[index], data, part_len);
+		sha256_transform(sctx->state, sctx->buf);
+
+		for (i = part_len; i + 63 < len; i += 64)
+			sha256_transform(sctx->state, &data[i]);
+		index = 0;
+	} else {
+		i = 0;
+	}
+	
+	/* Buffer remaining input */
+	memcpy(&sctx->buf[index], &data[i], len-i);
+}
+
+static void sha256_final(void* ctx, u8 *out)
+{
+	struct sha256_ctx *sctx = ctx;
+	u8 bits[8];
+	unsigned int index, pad_len, t;
+	int i, j;
+	const u8 padding[64] = { 0x80, };
+
+	/* Save number of bits */
+	t = sctx->count[0];
+	bits[7] = t; t >>= 8;
+	bits[6] = t; t >>= 8;
+	bits[5] = t; t >>= 8;
+	bits[4] = t;
+	t = sctx->count[1];
+	bits[3] = t; t >>= 8;
+	bits[2] = t; t >>= 8;
+	bits[1] = t; t >>= 8;
+	bits[0] = t;
+
+	/* Pad out to 56 mod 64. */
+	index = (sctx->count[0] >> 3) & 0x3f;
+	pad_len = (index < 56) ? (56 - index) : ((64+56) - index);
+	sha256_update(sctx, padding, pad_len);
+
+	/* Append length (before padding) */
+	sha256_update(sctx, bits, 8);
+
+	/* Store state in digest */
+	for (i = j = 0; i < 8; i++, j += 4) {
+		t = sctx->state[i];
+		out[j+3] = t; t >>= 8;
+		out[j+2] = t; t >>= 8;
+		out[j+1] = t; t >>= 8;
+		out[j  ] = t;
+	}
+
+	/* Zeroize sensitive information. */
+	memset(sctx, 0, sizeof(*sctx));
+}
+
+
+static struct crypto_alg alg = {
+	.cra_name	=	"sha256",
+	.cra_flags	=	CRYPTO_ALG_TYPE_DIGEST,
+	.cra_blocksize	=	SHA256_HMAC_BLOCK_SIZE,
+	.cra_ctxsize	=	sizeof(struct sha256_ctx),
+	.cra_module	=	THIS_MODULE,
+	.cra_list       =       LIST_HEAD_INIT(alg.cra_list),
+	.cra_u		=	{ .digest = {
+	.dia_digestsize	=	SHA256_DIGEST_SIZE,
+	.dia_init   	= 	sha256_init,
+	.dia_update 	=	sha256_update,
+	.dia_final  	=	sha256_final } }
+};
+
+static int __init init(void)
+{
+	return crypto_register_alg(&alg);
+}
+
+static void __exit fini(void)
+{
+	crypto_unregister_alg(&alg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm");
diff -Nru a/crypto/tcrypt.c b/crypto/tcrypt.c
--- a/crypto/tcrypt.c	Sun Nov 10 19:28:40 2002
+++ b/crypto/tcrypt.c	Sun Nov 10 19:28:40 2002
@@ -46,6 +46,11 @@
 static char *xbuf;
 static char *tvmem;
 
+static char *check[] = {
+	"des", "md5", "des3_ede", "rot13", "sha1", "sha256", "blowfish",
+	 NULL
+};
+
 static void
 hexdump(unsigned char *buf, unsigned int len)
 {
@@ -64,7 +69,6 @@
 	char result[128];
 	struct crypto_tfm *tfm;
 	struct md5_testvec *md5_tv;
-	struct hmac_md5_testvec *hmac_md5_tv;
 	unsigned int tsize;
 
 	printk("\ntesting md5\n");
@@ -129,14 +133,34 @@
 	printk("%s\n",
 	       memcmp(result, md5_tv[4].digest,
 		      crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass");
+	crypto_free_tfm(tfm);
+}
 
-	printk("\ntesting hmac_md5\n");
+#ifdef CONFIG_CRYPTO_HMAC
+static void
+test_hmac_md5(void)
+{
+	char *p;
+	unsigned int i, klen;
+	struct scatterlist sg[2];
+	char result[128];
+	struct crypto_tfm *tfm;
+	struct hmac_md5_testvec *hmac_md5_tv;
+	unsigned int tsize;
+
+	tfm = crypto_alloc_tfm("md5", 0);
+	if (tfm == NULL) {
+		printk("failed to load transform for md5\n");
+		return;
+	}
 
+	printk("\ntesting hmac_md5\n");
+	
 	tsize = sizeof (hmac_md5_tv_template);
 	if (tsize > TVMEMSIZE) {
 		printk("template (%u) too big for tvmem (%u)\n", tsize,
 		       TVMEMSIZE);
-		return;
+		goto out;
 	}
 
 	memcpy(tvmem, hmac_md5_tv_template, tsize);
@@ -151,8 +175,8 @@
 		sg[0].offset = ((long) p & ~PAGE_MASK);
 		sg[0].length = strlen(hmac_md5_tv[i].plaintext);
 
-		crypto_digest_hmac(tfm, hmac_md5_tv[i].key,
-				   strlen(hmac_md5_tv[i].key), sg, 1, result);
+		klen = strlen(hmac_md5_tv[i].key);
+		crypto_hmac(tfm, hmac_md5_tv[i].key, &klen, sg, 1, result);
 
 		hexdump(result, crypto_tfm_alg_digestsize(tfm));
 		printk("%s\n",
@@ -179,17 +203,157 @@
 	sg[1].length = 12;
 
 	memset(result, 0, sizeof (result));
-	crypto_digest_hmac(tfm, hmac_md5_tv[1].key, strlen(hmac_md5_tv[1].key),
-			   sg, 2, result);
+	klen = strlen(hmac_md5_tv[7].key);
+	crypto_hmac(tfm, hmac_md5_tv[7].key, &klen, sg, 2, result);
+	hexdump(result, crypto_tfm_alg_digestsize(tfm));
+
+	printk("%s\n",
+	       memcmp(result, hmac_md5_tv[7].digest,
+		      crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass");
+out:
+	crypto_free_tfm(tfm);
+}
+
+static void
+test_hmac_sha1(void)
+{
+	char *p;
+	unsigned int i, klen;
+	struct crypto_tfm *tfm;
+	struct hmac_sha1_testvec *hmac_sha1_tv;
+	struct scatterlist sg[2];
+	unsigned int tsize;
+	char result[SHA1_DIGEST_SIZE];
+
+	tfm = crypto_alloc_tfm("sha1", 0);
+	if (tfm == NULL) {
+		printk("failed to load transform for sha1\n");
+		return;
+	}
+
+	printk("\ntesting hmac_sha1\n");
+
+	tsize = sizeof (hmac_sha1_tv_template);
+	if (tsize > TVMEMSIZE) {
+		printk("template (%u) too big for tvmem (%u)\n", tsize,
+		       TVMEMSIZE);
+		goto out;
+	}
+
+	memcpy(tvmem, hmac_sha1_tv_template, tsize);
+	hmac_sha1_tv = (void *) tvmem;
+
+	for (i = 0; i < HMAC_SHA1_TEST_VECTORS; i++) {
+		printk("test %u:\n", i + 1);
+		memset(result, 0, sizeof (result));
+
+		p = hmac_sha1_tv[i].plaintext;
+		sg[0].page = virt_to_page(p);
+		sg[0].offset = ((long) p & ~PAGE_MASK);
+		sg[0].length = strlen(hmac_sha1_tv[i].plaintext);
+
+		klen = strlen(hmac_sha1_tv[i].key);
+		
+		crypto_hmac(tfm, hmac_sha1_tv[i].key, &klen, sg, 1, result);
+
+		hexdump(result, sizeof (result));
+		printk("%s\n",
+		       memcmp(result, hmac_sha1_tv[i].digest,
+			      crypto_tfm_alg_digestsize(tfm)) ? "fail" :
+		       "pass");
+	}
+
+	printk("\ntesting hmac_sha1 across pages\n");
+
+	/* setup the dummy buffer first */
+	memset(xbuf, 0, sizeof (xbuf));
+
+	memcpy(&xbuf[IDX1], "what do ya want ", 16);
+	memcpy(&xbuf[IDX2], "for nothing?", 12);
+
+	p = &xbuf[IDX1];
+	sg[0].page = virt_to_page(p);
+	sg[0].offset = ((long) p & ~PAGE_MASK);
+	sg[0].length = 16;
+
+	p = &xbuf[IDX2];
+	sg[1].page = virt_to_page(p);
+	sg[1].offset = ((long) p & ~PAGE_MASK);
+	sg[1].length = 12;
+
+	memset(result, 0, sizeof (result));
+	klen = strlen(hmac_sha1_tv[7].key);
+	crypto_hmac(tfm, hmac_sha1_tv[7].key, &klen, sg, 2, result);
 	hexdump(result, crypto_tfm_alg_digestsize(tfm));
 
 	printk("%s\n",
-	       memcmp(result, hmac_md5_tv[1].digest,
+	       memcmp(result, hmac_sha1_tv[7].digest,
 		      crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass");
+out:
+	crypto_free_tfm(tfm);
+}
+
+static void
+test_hmac_sha256(void)
+{
+	char *p;
+	unsigned int i, klen;
+	struct crypto_tfm *tfm;
+	struct hmac_sha256_testvec *hmac_sha256_tv;
+	struct scatterlist sg[2];
+	unsigned int tsize;
+	char result[SHA256_DIGEST_SIZE];
+
+	tfm = crypto_alloc_tfm("sha256", 0);
+	if (tfm == NULL) {
+		printk("failed to load transform for sha256\n");
+		return;
+	}
+
+	printk("\ntesting hmac_sha256\n");
+
+	tsize = sizeof (hmac_sha256_tv_template);
+	if (tsize > TVMEMSIZE) {
+		printk("template (%u) too big for tvmem (%u)\n", tsize,
+		       TVMEMSIZE);
+		goto out;
+	}
+
+	memcpy(tvmem, hmac_sha256_tv_template, tsize);
+	hmac_sha256_tv = (void *) tvmem;
 
+	for (i = 0; i < HMAC_SHA256_TEST_VECTORS; i++) {
+		printk("test %u:\n", i + 1);
+		memset(result, 0, sizeof (result));
+
+		p = hmac_sha256_tv[i].plaintext;
+		sg[0].page = virt_to_page(p);
+		sg[0].offset = ((long) p & ~PAGE_MASK);
+		sg[0].length = strlen(hmac_sha256_tv[i].plaintext);
+
+		klen = strlen(hmac_sha256_tv[i].key);
+	
+		//printk("DS=%u\n", crypto_tfm_alg_digestsize(tfm));
+		
+		//printk("K=");
+		hexdump(hmac_sha256_tv[i].key, strlen(hmac_sha256_tv[i].key));
+		//printk("P=%s\n", hmac_sha256_tv[i].plaintext);
+		
+		crypto_hmac(tfm, hmac_sha256_tv[i].key, &klen, sg, 1, result);
+
+		//printk("H=");
+		hexdump(result, crypto_tfm_alg_digestsize(tfm));
+		printk("%s\n",
+		       memcmp(result, hmac_sha256_tv[i].digest,
+		       crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass");
+	}
+
+out:
 	crypto_free_tfm(tfm);
 }
 
+#endif	/* CONFIG_CRYPTO_HMAC */
+
 static void
 test_md4(void)
 {
@@ -247,7 +411,6 @@
 	unsigned int i;
 	struct crypto_tfm *tfm;
 	struct sha1_testvec *sha1_tv;
-	struct hmac_sha1_testvec *hmac_sha1_tv;
 	struct scatterlist sg[2];
 	unsigned int tsize;
 	char result[SHA1_DIGEST_SIZE];
@@ -313,64 +476,82 @@
 	printk("%s\n",
 	       memcmp(result, sha1_tv[1].digest,
 		      crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass");
+	crypto_free_tfm(tfm);
+}
 
-	printk("\ntesting hmac_sha1\n");
+static void
+test_sha256(void)
+{
+	char *p;
+	unsigned int i;
+	struct crypto_tfm *tfm;
+	struct sha256_testvec *sha256_tv;
+	struct scatterlist sg[2];
+	unsigned int tsize;
+	char result[SHA256_DIGEST_SIZE];
 
-	tsize = sizeof (hmac_sha1_tv_template);
+	printk("\ntesting sha256\n");
+
+	tsize = sizeof (sha256_tv_template);
 	if (tsize > TVMEMSIZE) {
 		printk("template (%u) too big for tvmem (%u)\n", tsize,
 		       TVMEMSIZE);
 		return;
 	}
 
-	memcpy(tvmem, hmac_sha1_tv_template, tsize);
-	hmac_sha1_tv = (void *) tvmem;
+	memcpy(tvmem, sha256_tv_template, tsize);
+	sha256_tv = (void *) tvmem;
 
-	for (i = 0; i < HMAC_SHA1_TEST_VECTORS; i++) {
+	tfm = crypto_alloc_tfm("sha256", 0);
+	if (tfm == NULL) {
+		printk("failed to load transform for sha256\n");
+		return;
+	}
+
+	for (i = 0; i < SHA256_TEST_VECTORS; i++) {
 		printk("test %u:\n", i + 1);
 		memset(result, 0, sizeof (result));
 
-		p = hmac_sha1_tv[i].plaintext;
+		p = sha256_tv[i].plaintext;
 		sg[0].page = virt_to_page(p);
 		sg[0].offset = ((long) p & ~PAGE_MASK);
-		sg[0].length = strlen(hmac_sha1_tv[i].plaintext);
+		sg[0].length = strlen(sha256_tv[i].plaintext);
 
-		crypto_digest_hmac(tfm, hmac_sha1_tv[i].key,
-				   strlen(hmac_sha1_tv[i].key), sg, 1, result);
+		crypto_digest_init(tfm);
+		crypto_digest_update(tfm, sg, 1);
+		crypto_digest_final(tfm, result);
 
-		hexdump(result, sizeof (result));
+		hexdump(result, crypto_tfm_alg_digestsize(tfm));
 		printk("%s\n",
-		       memcmp(result, hmac_sha1_tv[i].digest,
+		       memcmp(result, sha256_tv[i].digest,
 			      crypto_tfm_alg_digestsize(tfm)) ? "fail" :
 		       "pass");
 	}
 
-	printk("\ntesting hmac_sha1 across pages\n");
+	printk("\ntesting sha256 across pages\n");
 
 	/* setup the dummy buffer first */
 	memset(xbuf, 0, sizeof (xbuf));
-
-	memcpy(&xbuf[IDX1], "what do ya want ", 16);
-	memcpy(&xbuf[IDX2], "for nothing?", 12);
+	memcpy(&xbuf[IDX1], "abcdbcdecdefdefgefghfghighij", 28);
+	memcpy(&xbuf[IDX2], "hijkijkljklmklmnlmnomnopnopq", 28);
 
 	p = &xbuf[IDX1];
 	sg[0].page = virt_to_page(p);
 	sg[0].offset = ((long) p & ~PAGE_MASK);
-	sg[0].length = 16;
+	sg[0].length = 28;
 
 	p = &xbuf[IDX2];
 	sg[1].page = virt_to_page(p);
 	sg[1].offset = ((long) p & ~PAGE_MASK);
-	sg[1].length = 12;
+	sg[1].length = 28;
 
 	memset(result, 0, sizeof (result));
-	crypto_digest_hmac(tfm, hmac_sha1_tv[1].key,
-			   strlen(hmac_sha1_tv[1].key), sg, 2, result);
+	crypto_digest_digest(tfm, sg, 2, result);
 	hexdump(result, crypto_tfm_alg_digestsize(tfm));
-
 	printk("%s\n",
-	       memcmp(result, hmac_sha1_tv[1].digest,
+	       memcmp(result, sha256_tv[1].digest,
 		      crypto_tfm_alg_digestsize(tfm)) ? "fail" : "pass");
+		     
 	crypto_free_tfm(tfm);
 }
 
@@ -732,7 +913,7 @@
 	hexdump(q, 8);
 	printk("%s\n", memcmp(q, des_tv[i].result + 8, 8) ? "fail" : "pass");
 
-	printk("\ntesting des ecb encryption chunking scenario D (atomic)\n");
+	printk("\ntesting des ecb encryption chunking scenario D\n");
 
 	/*
 	 * Scenario D, torture test, one byte per frag.
@@ -971,7 +1152,7 @@
 		return;
 	}
 
-	printk("\ntesting des cbc encryption (atomic)\n");
+	printk("\ntesting des cbc encryption\n");
 
 	tsize = sizeof (des_cbc_enc_tv_template);
 	if (tsize > TVMEMSIZE) {
@@ -1299,6 +1480,223 @@
 	crypto_free_tfm(tfm);
 }
 
+void
+test_blowfish(void)
+{
+	unsigned int ret, i;
+	unsigned int tsize;
+	char *p, *q;
+	struct crypto_tfm *tfm;
+	char *key;
+	struct bf_tv *bf_tv;
+	struct scatterlist sg[1];
+
+	printk("\ntesting blowfish encryption\n");
+
+	tsize = sizeof (bf_enc_tv_template);
+	if (tsize > TVMEMSIZE) {
+		printk("template (%u) too big for tvmem (%u)\n", tsize,
+		       TVMEMSIZE);
+		return;
+	}
+
+	memcpy(tvmem, bf_enc_tv_template, tsize);
+	bf_tv = (void *) tvmem;
+
+	tfm = crypto_alloc_tfm("blowfish", 0);
+	if (tfm == NULL) {
+		printk("failed to load transform for blowfish (default ecb)\n");
+		return;
+	}
+
+	for (i = 0; i < BF_ENC_TEST_VECTORS; i++) {
+		printk("test %u (%d bit key):\n",
+			i + 1, bf_tv[i].keylen * 8);
+		key = bf_tv[i].key;
+
+		ret = crypto_cipher_setkey(tfm, key, bf_tv[i].keylen);
+		if (ret) {
+			printk("setkey() failed flags=%x\n", tfm->crt_flags);
+
+			if (!bf_tv[i].fail)
+				goto out;
+		}
+
+		p = bf_tv[i].plaintext;
+		sg[0].page = virt_to_page(p);
+		sg[0].offset = ((long) p & ~PAGE_MASK);
+		sg[0].length = bf_tv[i].plen;
+		ret = crypto_cipher_encrypt(tfm, sg, 1);
+		if (ret) {
+			printk("encrypt() failed flags=%x\n", tfm->crt_flags);
+			goto out;
+		}
+
+		q = kmap(sg[0].page) + sg[0].offset;
+		hexdump(q, bf_tv[i].rlen);
+
+		printk("%s\n", memcmp(q, bf_tv[i].result, bf_tv[i].rlen) ?
+			"fail" : "pass");
+	}
+
+	printk("\ntesting blowfish decryption\n");
+
+	tsize = sizeof (bf_dec_tv_template);
+	if (tsize > TVMEMSIZE) {
+		printk("template (%u) too big for tvmem (%u)\n", tsize,
+		       TVMEMSIZE);
+		return;
+	}
+
+	memcpy(tvmem, bf_dec_tv_template, tsize);
+	bf_tv = (void *) tvmem;
+
+	for (i = 0; i < BF_DEC_TEST_VECTORS; i++) {
+		printk("test %u (%d bit key):\n",
+			i + 1, bf_tv[i].keylen * 8);
+		key = bf_tv[i].key;
+
+		ret = crypto_cipher_setkey(tfm, key, bf_tv[i].keylen);
+		if (ret) {
+			printk("setkey() failed flags=%x\n", tfm->crt_flags);
+
+			if (!bf_tv[i].fail)
+				goto out;
+		}
+
+		p = bf_tv[i].plaintext;
+		sg[0].page = virt_to_page(p);
+		sg[0].offset = ((long) p & ~PAGE_MASK);
+		sg[0].length = bf_tv[i].plen;
+		ret = crypto_cipher_decrypt(tfm, sg, 1);
+		if (ret) {
+			printk("decrypt() failed flags=%x\n", tfm->crt_flags);
+			goto out;
+		}
+
+		q = kmap(sg[0].page) + sg[0].offset;
+		hexdump(q, bf_tv[i].rlen);
+
+		printk("%s\n", memcmp(q, bf_tv[i].result, bf_tv[i].rlen) ?
+			"fail" : "pass");
+	}
+	
+	crypto_free_tfm(tfm);
+	
+	tfm = crypto_alloc_tfm("blowfish", CRYPTO_TFM_MODE_CBC);
+	if (tfm == NULL) {
+		printk("failed to load transform for blowfish cbc\n");
+		return;
+	}
+
+	printk("\ntesting blowfish cbc encryption\n");
+
+	tsize = sizeof (bf_cbc_enc_tv_template);
+	if (tsize > TVMEMSIZE) {
+		printk("template (%u) too big for tvmem (%u)\n", tsize,
+		       TVMEMSIZE);
+		goto out;
+	}
+	memcpy(tvmem, bf_cbc_enc_tv_template, tsize);
+	bf_tv = (void *) tvmem;
+
+	for (i = 0; i < BF_CBC_ENC_TEST_VECTORS; i++) {
+		printk("test %u (%d bit key):\n",
+			i + 1, bf_tv[i].keylen * 8);
+
+		key = bf_tv[i].key;
+
+		ret = crypto_cipher_setkey(tfm, key, bf_tv[i].keylen);
+		if (ret) {
+			printk("setkey() failed flags=%x\n", tfm->crt_flags);
+			goto out;
+		}
+
+		p = bf_tv[i].plaintext;
+
+		sg[0].page = virt_to_page(p);
+		sg[0].offset = ((long) p & ~PAGE_MASK);
+		sg[0].length =  bf_tv[i].plen;;
+
+		crypto_cipher_set_iv(tfm, bf_tv[i].iv,
+				     crypto_tfm_alg_ivsize(tfm));
+
+		ret = crypto_cipher_encrypt(tfm, sg, 1);
+		if (ret) {
+			printk("blowfish_cbc_encrypt() failed flags=%x\n",
+			       tfm->crt_flags);
+			goto out;
+		}
+
+		q = kmap(sg[0].page) + sg[0].offset;
+		hexdump(q, bf_tv[i].rlen);
+
+		printk("%s\n", memcmp(q, bf_tv[i].result, bf_tv[i].rlen)
+			? "fail" : "pass");
+	}
+
+	printk("\ntesting blowfish cbc decryption\n");
+
+	tsize = sizeof (bf_cbc_dec_tv_template);
+	if (tsize > TVMEMSIZE) {
+		printk("template (%u) too big for tvmem (%u)\n", tsize,
+		       TVMEMSIZE);
+		goto out;
+	}
+	memcpy(tvmem, bf_cbc_dec_tv_template, tsize);
+	bf_tv = (void *) tvmem;
+
+	for (i = 0; i < BF_CBC_ENC_TEST_VECTORS; i++) {
+		printk("test %u (%d bit key):\n",
+			i + 1, bf_tv[i].keylen * 8);
+		key = bf_tv[i].key;
+
+		ret = crypto_cipher_setkey(tfm, key, bf_tv[i].keylen);
+		if (ret) {
+			printk("setkey() failed flags=%x\n", tfm->crt_flags);
+			goto out;
+		}
+
+		p = bf_tv[i].plaintext;
+
+		sg[0].page = virt_to_page(p);
+		sg[0].offset = ((long) p & ~PAGE_MASK);
+		sg[0].length =  bf_tv[i].plen;;
+
+		crypto_cipher_set_iv(tfm, bf_tv[i].iv,
+				     crypto_tfm_alg_ivsize(tfm));
+
+		ret = crypto_cipher_decrypt(tfm, sg, 1);
+		if (ret) {
+			printk("blowfish_cbc_decrypt() failed flags=%x\n",
+			       tfm->crt_flags);
+			goto out;
+		}
+
+		q = kmap(sg[0].page) + sg[0].offset;
+		hexdump(q, bf_tv[i].rlen);
+
+		printk("%s\n", memcmp(q, bf_tv[i].result, bf_tv[i].rlen)
+			? "fail" : "pass");
+	}
+
+out:
+	crypto_free_tfm(tfm);
+}
+
+static void
+test_available(void)
+{
+	char **name = check;
+	
+	while (*name) {
+		printk("alg %s ", *name);
+		printk((crypto_alg_available(*name, 0)) ?
+			"found\n" : "not found\n");
+		name++;
+	}	
+}
+
 static void
 do_test(void)
 {
@@ -1310,6 +1708,13 @@
 		test_des();
 		test_des3_ede();
 		test_md4();
+		test_sha256();
+		test_blowfish();
+#ifdef CONFIG_CRYPTO_HMAC
+		test_hmac_md5();
+		test_hmac_sha1();
+		test_hmac_sha256();
+#endif		
 		break;
 
 	case 1:
@@ -1331,7 +1736,34 @@
 	case 5:
 		test_md4();
 		break;
+		
+	case 6:
+		test_sha256();
+		break;
+	
+	case 7:
+		test_blowfish();
+		break;
 
+#ifdef CONFIG_CRYPTO_HMAC
+	case 100:
+		test_hmac_md5();
+		break;
+		
+	case 101:
+		test_hmac_sha1();
+		break;
+	
+	case 102:
+		test_hmac_sha256();
+		break;
+
+#endif
+
+	case 1000:
+		test_available();
+		break;
+		
 	default:
 		/* useful for debugging */
 		printk("not testing anything\n");
diff -Nru a/crypto/tcrypt.h b/crypto/tcrypt.h
--- a/crypto/tcrypt.h	Sun Nov 10 19:28:41 2002
+++ b/crypto/tcrypt.h	Sun Nov 10 19:28:41 2002
@@ -19,6 +19,7 @@
 #define MD5_DIGEST_SIZE		16
 #define MD4_DIGEST_SIZE		16
 #define SHA1_DIGEST_SIZE	20
+#define SHA256_DIGEST_SIZE	32
 
 /*
  * MD4 test vectors from RFC1320
@@ -105,6 +106,7 @@
 		  0xac, 0x49, 0xda, 0x2e, 0x21, 0x07, 0xb6, 0x7a } }
 };
 
+#ifdef CONFIG_CRYPTO_HMAC
 /*
  * HMAC-MD5 test vectors from RFC2202
  * (These need to be fixed to not use strlen).
@@ -214,7 +216,19 @@
 		
 		{ 0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee,
 		  0x1f, 0xb1, 0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e }
-	}
+	},
+	
+	/* cross page test, need to retain key */
+	
+	{
+		{ 'J', 'e', 'f', 'e', 0 },
+		
+		"what do ya want for nothing?",
+		
+		{ 0x75, 0x0c, 0x78, 0x3e, 0x6a, 0xb0, 0xb5, 0x03,
+		  0xea, 0xa8, 0x6e, 0x31, 0x0a, 0x5d, 0xb7, 0x38 }
+	},
+	
 };
 
 	
@@ -334,10 +348,203 @@
 		
 		{ 0xe8, 0xe9, 0x9d, 0x0f, 0x45, 0x23, 0x7d, 0x78, 0x6d, 0x6b, 
 		  0xba, 0xa7, 0x96, 0x5c, 0x78, 0x08, 0xbb, 0xff, 0x1a, 0x91 }
-	}
+	},
+	
+	/* cross page test */
+	{
+		{ 'J', 'e', 'f', 'e', 0 },
+		
+		"what do ya want for nothing?",
+
+		{ 0xef, 0xfc, 0xdf, 0x6a, 0xe5, 0xeb, 0x2f, 0xa2, 0xd2, 0x74, 
+		  0x16, 0xd5, 0xf1, 0x84, 0xdf, 0x9c, 0x25, 0x9a, 0x7c, 0x79 }
+
+	},
+
+};
+
+/*
+ * HMAC-SHA256 test vectors from
+ * draft-ietf-ipsec-ciph-sha-256-01.txt
+ */
+#define HMAC_SHA256_TEST_VECTORS	10
+
+struct hmac_sha256_testvec {
+	char key[128];
+	char plaintext[128];
+	char digest[SHA256_DIGEST_SIZE];
+} hmac_sha256_tv_template[] = {
+
+	{
+		{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+		  0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+		  0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+		  0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x00 },
+		  
+	
+		{ "abc" },
+		
+		{ 0xa2, 0x1b, 0x1f, 0x5d, 0x4c, 0xf4, 0xf7, 0x3a,
+		  0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a,
+		  0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66,
+		  0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81 },
+
+	},
+	
+	{
+		{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+		  0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+		  0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+		   0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x00 },
+		
+		{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+		
+		{ 0x10, 0x4f, 0xdc, 0x12, 0x57, 0x32, 0x8f, 0x08,
+		  0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae,
+		  0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49,
+		  0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30 }
+	},
+
+	{
+		{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+		  0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+		  0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+		  0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x00 },
+		
+		{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+		  "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" },
+		
+		{ 0x47, 0x03, 0x05, 0xfc, 0x7e, 0x40, 0xfe, 0x34,
+		  0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab,
+		  0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5,
+		  0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3 }
+	},
+
+	{
+		{ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+		  0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+		  0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+		  0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x00 },
+		
+		{ "Hi There" },
+		
+		{ 0x19, 0x8a, 0x60, 0x7e, 0xb4, 0x4b, 0xfb, 0xc6,
+		  0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5,
+		  0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c,
+		  0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7 }
+	},
+
+	{
+		{ "Jefe" },
+		
+		{ "what do ya want for nothing?" },
+		
+		{ 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e,
+		  0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
+		  0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
+		  0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43 }
+	},
+
+	{
+		{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00 },
+		
+		{ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+		  0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+		  0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+		  0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+		  0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+		  0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+		  0xdd, 0xdd, 0x00 },
+		
+		{ 0xcd, 0xcb, 0x12, 0x20, 0xd1, 0xec, 0xcc, 0xea,
+		  0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62,
+		  0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc,
+		  0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0 }
+	},
+
+	{
+		{ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+		  0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+		  0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+		  0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+		  0x21, 0x22, 0x23, 0x24, 0x25, 0x00 },
+		
+		{ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+		  0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+		  0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+		  0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+		  0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+		  0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+		  0xcd, 0xcd, 0x00 },
+		
+		{ 0xd4, 0x63, 0x3c, 0x17, 0xf6, 0xfb, 0x8d, 0x74,
+		  0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55,
+		  0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85,
+		  0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17 }
+	},
+
+	{
+		{ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+		  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+		  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+		  0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x00 },
+		
+		{ "Test With Truncation" },
+		
+		{ 0x75, 0x46, 0xaf, 0x01, 0x84, 0x1f, 0xc0, 0x9b,
+		  0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17,
+		  0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27,
+		  0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42 }
+	},
+	
+	{
+		{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00 },
+		
+		{ "Test Using Larger Than Block-Size Key - Hash Key First" },
+		
+		{ 0x69, 0x53, 0x02, 0x5e, 0xd9, 0x6f, 0x0c, 0x09,
+		  0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb,
+		  0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e,
+		  0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f }
+	},
+
+	{
+		{ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+		  0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0x00 },
+		
+		{ "Test Using Larger Than Block-Size Key and Larger Than "
+		  "One Block-Size Data" },
+		
+		{ 0x63, 0x55, 0xac, 0x22, 0xe8, 0x90, 0xd0, 0xa3,
+		  0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8,
+		  0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc,
+		  0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6 }
+	},
 };
 
 
+#endif	/* CONFIG_CRYPTO_HMAC */
+
 /*
  * SHA1 test vectors  from from FIPS PUB 180-1
  */
@@ -360,7 +567,31 @@
 };
 
 /*
- * DES test vectors (also need to test for weak keys etc).
+ * SHA256 test vectors from from NIST
+ */
+#define SHA256_TEST_VECTORS	2
+
+struct sha256_testvec {
+	char plaintext[128];
+	char digest[SHA256_DIGEST_SIZE];
+} sha256_tv_template[] = {
+	{ "abc",
+	  { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
+	    0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
+	    0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+	    0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }
+	},
+	        	
+	{ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+	  { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
+	    0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
+	    0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
+	    0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }
+	},
+};
+
+/*
+ * DES test vectors.
  */
 #define DES_ENC_TEST_VECTORS		5
 #define DES_DEC_TEST_VECTORS		2
@@ -741,6 +972,199 @@
 		{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00  },
 	},
 };
+
+/*
+ * Blowfish test vectors.
+ */
+#define BF_ENC_TEST_VECTORS	6
+#define BF_DEC_TEST_VECTORS	6
+#define BF_CBC_ENC_TEST_VECTORS	1
+#define BF_CBC_DEC_TEST_VECTORS	1
+
+struct bf_tv {
+	unsigned int keylen;
+	unsigned int plen;
+	unsigned int rlen;
+	int fail;
+	char key[56];
+	char iv[8];
+	char plaintext[32];
+	char result[32];
+};
+
+struct bf_tv bf_enc_tv_template[] = {
+
+	/* DES test vectors from OpenSSL */
+	{
+		8, 8, 8, 0,
+		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
+		{ 0 },
+		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
+		{ 0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78 },
+	},
 	
-#endif	/* _CRYPTO_TCRYPT_H */
+	{
+		8, 8, 8, 0,
+		{ 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E,  },
+		{ 0 },
+		{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF },
+		{ 0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE },
+	},
+	
+	{
+		8, 8, 8, 0,
+		{ 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, },
+		{ 0 },
+		{ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		{ 0xE8, 0x7A, 0x24, 0x4E, 0x2C, 0xC8, 0x5E, 0x82 }
+	},
+	
+	/* Vary the keylength... */
+	
+	{
+		16, 8, 8, 0,
+		{ 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87,
+		  0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F },
+		{ 0 },
+		{ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		{ 0x93, 0x14, 0x28, 0x87, 0xEE, 0x3B, 0xE1, 0x5C }
+	},
+	
+	{
+		21, 8, 8, 0,
+		{ 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87,
+		  0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F,
+		  0x00, 0x11, 0x22, 0x33, 0x44 },
+		{ 0 },
+		{ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		{ 0xE6, 0xF5, 0x1E, 0xD7, 0x9B, 0x9D, 0xB2, 0x1F }
+	},
+	
+	/* Generated with bf488 */
+	{
+		56, 8, 8, 0,
+		{ 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87,
+		  0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F,
+		  0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+		  0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F, 
+		  0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76, 
+		  0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E, 
+		  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+		  { 0 },
+		  { 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		  { 0xc0, 0x45, 0x04, 0x01, 0x2e, 0x4e, 0x1f, 0x53 }
+	}
+	
+};
+
+struct bf_tv bf_dec_tv_template[] = {
+
+	/* DES test vectors from OpenSSL */
+	{
+		8, 8, 8, 0,
+		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, },
+		{ 0 },
+		{ 0x4E, 0xF9, 0x97, 0x45, 0x61, 0x98, 0xDD, 0x78 },
+		{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+	},
+	
+	{
+		8, 8, 8, 0,
+		{ 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E,  },
+		{ 0 },
+		{ 0xA7, 0x90, 0x79, 0x51, 0x08, 0xEA, 0x3C, 0xAE },
+		{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }
+	},
+	
+	{
+		8, 8, 8, 0,
+		{ 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87, },
+		{ 0 },
+		{ 0xE8, 0x7A, 0x24, 0x4E, 0x2C, 0xC8, 0x5E, 0x82 },
+		{ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }
+	},
+	
+	/* Vary the keylength... */
+	
+	{
+		16, 8, 8, 0,
+		{ 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87,
+		  0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F },
+		{ 0 },
+		{ 0x93, 0x14, 0x28, 0x87, 0xEE, 0x3B, 0xE1, 0x5C },
+		{ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }
+	},
+	
+	{
+		21, 8, 8, 0,
+		{ 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87,
+		  0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F,
+		  0x00, 0x11, 0x22, 0x33, 0x44 },
+		{ 0 },
+		{ 0xE6, 0xF5, 0x1E, 0xD7, 0x9B, 0x9D, 0xB2, 0x1F },
+		{ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }
+	},
+	
+	/* Generated with bf488, using OpenSSL, Libgcrypt and Nettle */
+	{
+		56, 8, 8, 0,
+		{ 0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87,
+		  0x78, 0x69, 0x5A, 0x4B, 0x3C, 0x2D, 0x1E, 0x0F,
+		  0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+		  0x04, 0x68, 0x91, 0x04, 0xC2, 0xFD, 0x3B, 0x2F, 
+		  0x58, 0x40, 0x23, 0x64, 0x1A, 0xBA, 0x61, 0x76, 
+		  0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E, 
+		  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },
+		{ 0 },
+		{ 0xc0, 0x45, 0x04, 0x01, 0x2e, 0x4e, 0x1f, 0x53 },
+		{ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 }
+	}
+};
+
+struct bf_tv bf_cbc_enc_tv_template[] = {
+
+	/* From OpenSSL */
+	{
+		16, 32, 32, 0,
+		
+		{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+		  0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 },
+		  
+		{ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		
+		{ 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20,
+		  0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,
+		  0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20,
+		  0x66, 0x6F, 0x72, 0x20, 0x00, 0x00, 0x00, 0x00 },
+		  
+		{ 0x6B, 0x77, 0xB4, 0xD6, 0x30, 0x06, 0xDE, 0xE6,
+		  0x05, 0xB1, 0x56, 0xE2, 0x74, 0x03, 0x97, 0x93,
+		  0x58, 0xDE, 0xB9, 0xE7, 0x15, 0x46, 0x16, 0xD9,
+		  0x59, 0xF1, 0x65, 0x2B, 0xD5, 0xFF, 0x92, 0xCC }
+	},
+};
 
+struct bf_tv bf_cbc_dec_tv_template[] = {
+
+	/* From OpenSSL */
+	{
+		16, 32, 32, 0,
+		
+		{ 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF,
+		  0xF0, 0xE1, 0xD2, 0xC3, 0xB4, 0xA5, 0x96, 0x87 },
+		  
+		{ 0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10 },
+		
+		{ 0x6B, 0x77, 0xB4, 0xD6, 0x30, 0x06, 0xDE, 0xE6,
+		  0x05, 0xB1, 0x56, 0xE2, 0x74, 0x03, 0x97, 0x93,
+		  0x58, 0xDE, 0xB9, 0xE7, 0x15, 0x46, 0x16, 0xD9,
+		  0x59, 0xF1, 0x65, 0x2B, 0xD5, 0xFF, 0x92, 0xCC },
+		  
+		{ 0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20,
+		  0x4E, 0x6F, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,
+		  0x68, 0x65, 0x20, 0x74, 0x69, 0x6D, 0x65, 0x20,
+		  0x66, 0x6F, 0x72, 0x20, 0x00, 0x00, 0x00, 0x00 }
+	},
+};
+
+#endif	/* _CRYPTO_TCRYPT_H */
diff -Nru a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c
--- a/drivers/acorn/block/fd1772.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/acorn/block/fd1772.c	Sun Nov 10 19:28:38 2002
@@ -378,23 +378,19 @@
 
 /************************* End of Prototypes **************************/
 
-static struct timer_list motor_off_timer = {
-	.function	= fd_motor_off_timer,
-};
+static struct timer_list motor_off_timer =
+	TIMER_INITIALIZER(fd_motor_off_timer, 0, 0);
 
 #ifdef TRACKBUFFER
-static struct timer_list readtrack_timer = {
-	.function 	= fd_readtrack_check,
-};
+static struct timer_list readtrack_timer =
+	TIMER_INITIALIZER(fd_readtrack_check, 0, 0);
 #endif
 
-static struct timer_list timeout_timer = {
-	.function	= fd_times_out,
-};
+static struct timer_list timeout_timer =
+	TIMER_INITIALIZER(fd_times_out, 0, 0);
 
-static struct timer_list fd_timer = {
-	.function	= check_change,
-};
+static struct timer_list fd_timer =
+	TIMER_INITIALIZER(check_change, 0, 0);
 
 /* DAG: Haven't got a clue what this is? */
 int stdma_islocked(void)
diff -Nru a/drivers/acorn/scsi/arxescsi.c b/drivers/acorn/scsi/arxescsi.c
--- a/drivers/acorn/scsi/arxescsi.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/acorn/scsi/arxescsi.c	Sun Nov 10 19:28:40 2002
@@ -35,6 +35,7 @@
 #include <asm/irq.h>
 #include <asm/ecard.h>
 
+#include "../../scsi/scsi.h"
 #include "../../scsi/hosts.h"
 #include "arxescsi.h"
 #include "fas216.h"
diff -Nru a/drivers/acorn/scsi/cumana_2.c b/drivers/acorn/scsi/cumana_2.c
--- a/drivers/acorn/scsi/cumana_2.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/acorn/scsi/cumana_2.c	Sun Nov 10 19:28:40 2002
@@ -35,6 +35,7 @@
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 
+#include "../../scsi/scsi.h"
 #include "../../scsi/hosts.h"
 #include "fas216.h"
 #include "scsi.h"
diff -Nru a/drivers/acorn/scsi/eesox.c b/drivers/acorn/scsi/eesox.c
--- a/drivers/acorn/scsi/eesox.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/acorn/scsi/eesox.c	Sun Nov 10 19:28:41 2002
@@ -41,6 +41,7 @@
 #include <asm/ecard.h>
 #include <asm/pgtable.h>
 
+#include "../../scsi/scsi.h"
 #include "../../scsi/hosts.h"
 #include "fas216.h"
 #include "scsi.h"
diff -Nru a/drivers/acorn/scsi/powertec.c b/drivers/acorn/scsi/powertec.c
--- a/drivers/acorn/scsi/powertec.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/acorn/scsi/powertec.c	Sun Nov 10 19:28:40 2002
@@ -38,6 +38,7 @@
 #include <asm/irq.h>
 #include <asm/pgtable.h>
 
+#include "../../scsi/scsi.h"
 #include "../../scsi/hosts.h"
 #include "fas216.h"
 #include "scsi.h"
diff -Nru a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c
--- a/drivers/atm/idt77105.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/atm/idt77105.c	Sun Nov 10 19:28:40 2002
@@ -48,12 +48,10 @@
 static void idt77105_restart_timer_func(unsigned long);
 
 
-static struct timer_list stats_timer = {
-    function:	&idt77105_stats_timer_func
-};
-static struct timer_list restart_timer = {
-    function:	&idt77105_restart_timer_func
-};
+static struct timer_list stats_timer =
+    TIMER_INITIALIZER(idt77105_stats_timer_func, 0, 0);
+static struct timer_list restart_timer =
+    TIMER_INITIALIZER(idt77105_restart_timer_func, 0, 0);
 static int start_timer = 1;
 static struct idt77105_priv *idt77105_all = NULL;
 
diff -Nru a/drivers/atm/iphase.c b/drivers/atm/iphase.c
--- a/drivers/atm/iphase.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/atm/iphase.c	Sun Nov 10 19:28:41 2002
@@ -78,7 +78,7 @@
 static struct atm_dev *_ia_dev[8];
 static int iadev_count;
 static void ia_led_timer(unsigned long arg);
-static struct timer_list ia_timer = { function: ia_led_timer };
+static struct timer_list ia_timer = TIMER_INITIALIZER(ia_led_timer, 0, 0);
 struct atm_vcc *vcc_close_que[100];
 static int IA_TX_BUF = DFL_TX_BUFFERS, IA_TX_BUF_SZ = DFL_TX_BUF_SZ;
 static int IA_RX_BUF = DFL_RX_BUFFERS, IA_RX_BUF_SZ = DFL_RX_BUF_SZ;
diff -Nru a/drivers/block/acsi.c b/drivers/block/acsi.c
--- a/drivers/block/acsi.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/block/acsi.c	Sun Nov 10 19:28:41 2002
@@ -374,7 +374,7 @@
 /************************* End of Prototypes **************************/
 
 
-struct timer_list acsi_timer = { function: acsi_times_out };
+struct timer_list acsi_timer = TIMER_INITIALIZER(acsi_times_out, 0, 0);
 
 
 #ifdef CONFIG_ATARI_SLM
diff -Nru a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
--- a/drivers/block/acsi_slm.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/block/acsi_slm.c	Sun Nov 10 19:28:36 2002
@@ -270,15 +270,15 @@
 /************************* End of Prototypes **************************/
 
 
-static struct timer_list slm_timer = { function: slm_test_ready };
+static struct timer_list slm_timer = TIMER_INITIALIZER(slm_test_ready, 0, 0);
 
 static struct file_operations slm_fops = {
-	owner:		THIS_MODULE,
-	read:		slm_read,
-	write:		slm_write,
-	ioctl:		slm_ioctl,
-	open:		slm_open,
-	release:	slm_release,
+	.owner =	THIS_MODULE,
+	.read =		slm_read,
+	.write =	slm_write,
+	.ioctl =	slm_ioctl,
+	.open =		slm_open,
+	.release =	slm_release,
 };
 
 
diff -Nru a/drivers/block/ataflop.c b/drivers/block/ataflop.c
--- a/drivers/block/ataflop.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/block/ataflop.c	Sun Nov 10 19:28:37 2002
@@ -395,15 +395,15 @@
 /************************* End of Prototypes **************************/
 
 static struct timer_list motor_off_timer =
-	{ function: fd_motor_off_timer };
-static struct timer_list readtrack_timer =
-	{ function: fd_readtrack_check };
+	TIMER_INITIALIZER(fd_motor_off_timer, 0, 0);
+static struct timer_list readtrack_timer
+	TIMER_INITIALIZER(fd_readtrack_check, 0, 0);
 
 static struct timer_list timeout_timer =
-	{ function: fd_times_out };
+	TIMER_INITIALIZER(fd_times_out, 0, 0);
 
 static struct timer_list fd_timer =
-	{ function: check_change };
+	TIMER_INITIALIZER(check_change, 0, 0);
 	
 static inline void
 start_motor_off_timer(void)
diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c
--- a/drivers/block/cciss.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/block/cciss.c	Sun Nov 10 19:28:41 2002
@@ -2505,10 +2505,10 @@
 }	
 
 static struct pci_driver cciss_pci_driver = {
-	name:		"cciss",
-	probe:		cciss_init_one,
-	remove:		__devexit_p(cciss_remove_one),
-	id_table:	cciss_pci_device_id, /* id_table */
+	.name =		"cciss",
+	.probe =	cciss_init_one,
+	.remove =	__devexit_p(cciss_remove_one),
+	.id_table =	cciss_pci_device_id, /* id_table */
 };
 
 /*
diff -Nru a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c
--- a/drivers/block/deadline-iosched.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/block/deadline-iosched.c	Sun Nov 10 19:28:40 2002
@@ -25,7 +25,7 @@
  * front fifo request expires.
  */
 static int read_expire = HZ / 2;	/* 500ms start timeout */
-static int fifo_batch = 32;		/* 4 seeks, or 64 contig */
+static int fifo_batch = 16;
 static int seek_cost = 16;		/* seek is 16 times more expensive */
 
 /*
@@ -207,7 +207,7 @@
 			break;
 		}
 
-		if (__rq->flags & REQ_BARRIER)
+		if (__rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER))
 			break;
 
 		/*
@@ -413,7 +413,7 @@
 	 * flush hash on barrier insert, as not to allow merges before a
 	 * barrier.
 	 */
-	if (unlikely(rq->flags & REQ_BARRIER)) {
+	if (unlikely(rq->flags & REQ_HARDBARRIER)) {
 		DL_INVALIDATE_HASH(dd);
 		q->last_merge = NULL;
 	}
diff -Nru a/drivers/block/elevator.c b/drivers/block/elevator.c
--- a/drivers/block/elevator.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/block/elevator.c	Sun Nov 10 19:28:40 2002
@@ -176,7 +176,9 @@
 	while ((entry = entry->prev) != &q->queue_head) {
 		__rq = list_entry_rq(entry);
 
-		if (__rq->flags & (REQ_BARRIER | REQ_STARTED))
+		if (__rq->flags & (REQ_SOFTBARRIER | REQ_HARDBARRIER))
+			break;
+		else if (__rq->flags & REQ_STARTED)
 			break;
 
 		if (!(__rq->flags & REQ_CMD))
@@ -200,7 +202,7 @@
 	/*
 	 * new merges must not precede this barrier
 	 */
-	if (rq->flags & REQ_BARRIER)
+	if (rq->flags & REQ_HARDBARRIER)
 		q->last_merge = NULL;
 	else if (!q->last_merge)
 		q->last_merge = &rq->queuelist;
@@ -380,9 +382,9 @@
 }
 
 elevator_t elevator_noop = {
-	elevator_merge_fn:		elevator_noop_merge,
-	elevator_next_req_fn:		elevator_noop_next_request,
-	elevator_add_req_fn:		elevator_noop_add_request,
+	.elevator_merge_fn		= elevator_noop_merge,
+	.elevator_next_req_fn		= elevator_noop_next_request,
+	.elevator_add_req_fn		= elevator_noop_add_request,
 };
 
 module_init(elevator_global_init);
diff -Nru a/drivers/block/floppy.c b/drivers/block/floppy.c
--- a/drivers/block/floppy.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/block/floppy.c	Sun Nov 10 19:28:37 2002
@@ -554,7 +554,7 @@
 static void floppy_start(void);
 static void process_fd_request(void);
 static void recalibrate_floppy(void);
-static void floppy_shutdown(void);
+static void floppy_shutdown(unsigned long);
 
 static int floppy_grab_irq_and_dma(void);
 static void floppy_release_irq_and_dma(void);
@@ -628,7 +628,7 @@
 }
 
 typedef void (*timeout_fn)(unsigned long);
-static struct timer_list fd_timeout ={ function: (timeout_fn) floppy_shutdown };
+static struct timer_list fd_timeout = TIMER_INITIALIZER(floppy_shutdown, 0, 0);
 
 static const char *timeout_message;
 
@@ -1011,7 +1011,7 @@
 	schedule_work(&floppy_work);
 }
 
-static struct timer_list fd_timer;
+static struct timer_list fd_timer = TIMER_INITIALIZER(NULL, 0, 0);
 
 static void cancel_activity(void)
 {
@@ -1900,7 +1900,7 @@
 	printk("\n");
 }
 
-static void floppy_shutdown(void)
+static void floppy_shutdown(unsigned long data)
 {
 	unsigned long flags;
 	
@@ -4347,6 +4347,7 @@
 	}
 	
 	for (drive = 0; drive < N_DRIVE; drive++) {
+		init_timer(&motor_off_timer[drive]);
 		motor_off_timer[drive].data = drive;
 		motor_off_timer[drive].function = motor_off_callback;
 		if (!(allowed_drive_mask & (1 << drive)))
diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c
--- a/drivers/block/genhd.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/block/genhd.c	Sun Nov 10 19:28:39 2002
@@ -242,10 +242,10 @@
 }
 
 struct seq_operations partitions_op = {
-	start:	part_start,
-	next:	part_next,
-	stop:	part_stop,
-	show:	show_partition
+	.start =part_start,
+	.next =	part_next,
+	.stop =	part_stop,
+	.show =	show_partition
 };
 #endif
 
@@ -324,9 +324,16 @@
 {
 	return off ? 0 : sprintf(page, "%llu\n",(unsigned long long)get_capacity(disk));
 }
-static inline unsigned MSEC(unsigned x)
+
+static inline unsigned jiffies_to_msec(unsigned jif)
 {
-	return x * 1000 / HZ;
+#if 1000 % HZ == 0
+	return jif * (1000 / HZ);
+#elif HZ % 1000 == 0
+	return jif / (HZ / 1000);
+#else
+	return (jif / HZ) * 1000 + (jif % HZ) * 1000 / HZ;
+#endif
 }
 static ssize_t disk_stat_read(struct gendisk * disk,
 			      char *page, size_t count, loff_t off)
@@ -338,11 +345,11 @@
 		"%8u %8u %8u"
 		"\n",
 		disk->reads, disk->read_merges, (u64)disk->read_sectors,
-		MSEC(disk->read_ticks),
+		jiffies_to_msec(disk->read_ticks),
 		disk->writes, disk->write_merges, (u64)disk->write_sectors,
-		MSEC(disk->write_ticks),
-		disk->in_flight, MSEC(disk->io_ticks),
-		MSEC(disk->time_in_queue));
+		jiffies_to_msec(disk->write_ticks),
+		disk->in_flight, jiffies_to_msec(disk->io_ticks),
+		jiffies_to_msec(disk->time_in_queue));
 }
 static struct disk_attribute disk_attr_dev = {
 	.attr = {.name = "dev", .mode = S_IRUGO },
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/block/ll_rw_blk.c	Sun Nov 10 19:28:37 2002
@@ -28,11 +28,6 @@
 #include <linux/slab.h>
 
 /*
- * Disk stats 
- */
-struct disk_stat dkstat;
-
-/*
  * For the allocated request tables
  */
 static kmem_cache_t *request_cachep;
@@ -56,7 +51,6 @@
 static int batch_requests;
 
 unsigned long blk_max_low_pfn, blk_max_pfn;
-atomic_t nr_iowait_tasks = ATOMIC_INIT(0);
 int blk_nohighio = 0;
 
 static struct congestion_state {
@@ -115,27 +109,6 @@
 		atomic_inc(&congestion_states[rw].nr_congested_queues);
 }
 
-/*
- * This task is about to go to sleep on IO.  Increment nr_iowait_tasks so
- * that process accounting knows that this is a task in IO wait state.
- *
- * But don't do that if it is a deliberate, throttling IO wait (this task
- * has set its backing_dev_info: the queue against which it should throttle)
- */
-void io_schedule(void)
-{
-	atomic_inc(&nr_iowait_tasks);
-	schedule();
-	atomic_dec(&nr_iowait_tasks);
-}
-
-void io_schedule_timeout(long timeout)
-{
-	atomic_inc(&nr_iowait_tasks);
-	schedule_timeout(timeout);
-	atomic_dec(&nr_iowait_tasks);
-}
-
 /**
  * blk_get_backing_dev_info - get the address of a queue's backing_dev_info
  * @dev:	device
@@ -644,7 +617,8 @@
 static char *rq_flags[] = {
 	"REQ_RW",
 	"REQ_RW_AHEAD",
-	"REQ_BARRIER",
+	"REQ_SOFTBARRIER",
+	"REQ_HARDBARRIER",
 	"REQ_CMD",
 	"REQ_NOMERGE",
 	"REQ_STARTED",
@@ -1392,7 +1366,7 @@
 	 * must not attempt merges on this) and that it acts as a soft
 	 * barrier
 	 */
-	rq->flags |= REQ_SPECIAL | REQ_BARRIER;
+	rq->flags |= REQ_SPECIAL | REQ_SOFTBARRIER;
 
 	rq->special = data;
 
@@ -1433,19 +1407,6 @@
 
 	major = rq->rq_disk->major;
 	index = rq->rq_disk->first_minor >> rq->rq_disk->minor_shift;
-
-	if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR))
-		return;
-
-	dkstat.drive[major][index] += new_io;
-	if (rw == READ) {
-		dkstat.drive_rio[major][index] += new_io;
-		dkstat.drive_rblk[major][index] += nr_sectors;
-	} else if (rw == WRITE) {
-		dkstat.drive_wio[major][index] += new_io;
-		dkstat.drive_wblk[major][index] += nr_sectors;
-	} else
-		printk(KERN_ERR "drive_stat_acct: cmd not R/W?\n");
 }
 
 /*
@@ -1788,7 +1749,7 @@
 	 * REQ_BARRIER implies no merging, but lets make it explicit
 	 */
 	if (barrier)
-		req->flags |= (REQ_BARRIER | REQ_NOMERGE);
+		req->flags |= (REQ_HARDBARRIER | REQ_NOMERGE);
 
 	req->errors = 0;
 	req->hard_sector = req->sector = sector;
diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/block/loop.c	Sun Nov 10 19:28:40 2002
@@ -137,15 +137,15 @@
 }
 
 struct loop_func_table none_funcs = { 
-	number: LO_CRYPT_NONE,
-	transfer: transfer_none,
-	init: none_status,
+	.number = LO_CRYPT_NONE,
+	.transfer = transfer_none,
+	.init = none_status,
 }; 	
 
 struct loop_func_table xor_funcs = { 
-	number: LO_CRYPT_XOR,
-	transfer: transfer_xor,
-	init: xor_status
+	.number = LO_CRYPT_XOR,
+	.transfer = transfer_xor,
+	.init = xor_status
 }; 	
 
 /* xfer_funcs[0] is special - its release function is never called */ 
@@ -303,22 +303,22 @@
 		struct bio_vec *bvec, int bsize, loff_t pos)
 {
 	struct lo_read_data cookie;
-	read_descriptor_t desc;
 	struct file *file;
+	int error;
 
 	cookie.lo = lo;
 	cookie.data = kmap(bvec->bv_page) + bvec->bv_offset;
 	cookie.bsize = bsize;
-	desc.written = 0;
-	desc.count = bvec->bv_len;
-	desc.buf = (char*)&cookie;
-	desc.error = 0;
+
+	/* umm, what does this lock actually try to protect? */
 	spin_lock_irq(&lo->lo_lock);
 	file = lo->lo_backing_file;
 	spin_unlock_irq(&lo->lo_lock);
-	do_generic_file_read(file, &pos, &desc, lo_read_actor);
+
+	error = file->f_op->sendfile(file, &pos, bvec->bv_len,
+			lo_read_actor, &cookie);
 	kunmap(bvec->bv_page);
-	return desc.error;
+	return error;
 }
 
 static int
@@ -682,7 +682,7 @@
 		 * If we can't read - sorry. If we only can't write - well,
 		 * it's going to be read-only.
 		 */
-		if (!aops->readpage)
+		if (!inode->i_fop->sendfile)
 			goto out_putf;
 
 		if (!aops->prepare_write || !aops->commit_write)
@@ -969,10 +969,10 @@
 }
 
 static struct block_device_operations lo_fops = {
-	owner:		THIS_MODULE,
-	open:		lo_open,
-	release:	lo_release,
-	ioctl:		lo_ioctl,
+	.owner =	THIS_MODULE,
+	.open =		lo_open,
+	.release =	lo_release,
+	.ioctl =	lo_ioctl,
 };
 
 /*
@@ -1070,8 +1070,8 @@
 out_mem2:
 	while (i--)
 		put_disk(disks[i]);
-out_mem:
 	kfree(disks);
+out_mem:
 	kfree(loop_dev);
 	printk(KERN_ERR "loop: ran out of memory\n");
 	return -ENOMEM;
diff -Nru a/drivers/block/nbd.c b/drivers/block/nbd.c
--- a/drivers/block/nbd.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/block/nbd.c	Sun Nov 10 19:28:38 2002
@@ -65,10 +65,8 @@
 /* #define DEBUG( s ) printk( s ) 
  */
 
-#ifdef PARANOIA
 static int requests_in;
 static int requests_out;
-#endif
 
 static int nbd_open(struct inode *inode, struct file *file)
 {
@@ -261,18 +259,8 @@
 			printk(KERN_ALERT "req should never be null\n" );
 			goto out;
 		}
-#ifdef PARANOIA
-		if (lo != req->rq_disk->private_data) {
-			printk(KERN_ALERT "NBD: request corrupted!\n");
-			continue;
-		}
-		if (lo->magic != LO_MAGIC) {
-			printk(KERN_ALERT "NBD: nbd_dev[] corrupted: Not enough magic\n");
-			goto out;
-		}
-#endif
+		BUG_ON(lo->magic != LO_MAGIC);
 		nbd_end_request(req);
-
 	}
  out:
 	return;
@@ -282,12 +270,7 @@
 {
 	struct request *req;
 
-#ifdef PARANOIA
-	if (lo->magic != LO_MAGIC) {
-		printk(KERN_ERR "NBD: nbd_dev[] corrupted: Not enough magic when clearing!\n");
-		return;
-	}
-#endif
+	BUG_ON(lo->magic != LO_MAGIC);
 
 	do {
 		req = NULL;
@@ -333,11 +316,9 @@
 			if (lo->flags & NBD_READ_ONLY)
 				FAIL("Write on read-only");
 		}
-#ifdef PARANOIA
-		if (lo->magic != LO_MAGIC)
-			FAIL("nbd[] is not magical!");
+		BUG_ON(lo->magic != LO_MAGIC);
 		requests_in++;
-#endif
+
 		req->errors = 0;
 		blkdev_dequeue_request(req);
 		spin_unlock_irq(q->queue_lock);
@@ -466,10 +447,10 @@
 
 static struct block_device_operations nbd_fops =
 {
-	owner:		THIS_MODULE,
-	open:		nbd_open,
-	release:	nbd_release,
-	ioctl:		nbd_ioctl,
+	.owner =	THIS_MODULE,
+	.open =		nbd_open,
+	.release =	nbd_release,
+	.ioctl =	nbd_ioctl,
 };
 
 /*
diff -Nru a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
--- a/drivers/block/paride/pg.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/block/paride/pg.c	Sun Nov 10 19:28:41 2002
@@ -254,11 +254,11 @@
 /* kernel glue structures */
 
 static struct file_operations pg_fops = {
-	owner:		THIS_MODULE,
-	read:		pg_read,
-	write:		pg_write,
-	open:		pg_open,
-	release:	pg_release,
+	.owner =	THIS_MODULE,
+	.read =		pg_read,
+	.write =	pg_write,
+	.open =		pg_open,
+	.release =	pg_release,
 };
 
 void pg_init_units( void )
diff -Nru a/drivers/block/paride/pseudo.h b/drivers/block/paride/pseudo.h
--- a/drivers/block/paride/pseudo.h	Sun Nov 10 19:28:38 2002
+++ b/drivers/block/paride/pseudo.h	Sun Nov 10 19:28:38 2002
@@ -49,7 +49,7 @@
 
 static spinlock_t ps_spinlock __attribute__((unused)) = SPIN_LOCK_UNLOCKED;
 
-static struct timer_list ps_timer = { function: ps_timer_int };
+static struct timer_list ps_timer = TIMER_INITIALIZER(ps_timer_int, 0, 0);
 static DECLARE_WORK(ps_tq, ps_tq_int, NULL);
 
 static void ps_set_intr( void (*continuation)(void), 
diff -Nru a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
--- a/drivers/block/paride/pt.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/block/paride/pt.c	Sun Nov 10 19:28:38 2002
@@ -256,12 +256,12 @@
 /* kernel glue structures */
 
 static struct file_operations pt_fops = {
-	owner:		THIS_MODULE,
-	read:		pt_read,
-	write:		pt_write,
-	ioctl:		pt_ioctl,
-	open:		pt_open,
-	release:	pt_release,
+	.owner =	THIS_MODULE,
+	.read =		pt_read,
+	.write =	pt_write,
+	.ioctl =	pt_ioctl,
+	.open =		pt_open,
+	.release =	pt_release,
 };
 
 void pt_init_units( void )
diff -Nru a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
--- a/drivers/block/ps2esdi.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/block/ps2esdi.c	Sun Nov 10 19:28:36 2002
@@ -107,7 +107,8 @@
 static int no_int_yet;
 static int ps2esdi_drives;
 static u_short io_base;
-static struct timer_list esdi_timer = { function: ps2esdi_reset_timer };
+static struct timer_list esdi_timer =
+		TIMER_INITIALIZER(ps2esdi_reset_timer, 0, 0);
 static int reset_status;
 static int ps2esdi_slot = -1;
 static int tp720esdi = 0;	/* Is it Integrated ESDI of ThinkPad-720? */
diff -Nru a/drivers/block/rd.c b/drivers/block/rd.c
--- a/drivers/block/rd.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/block/rd.c	Sun Nov 10 19:28:40 2002
@@ -140,10 +140,10 @@
 }
 
 static struct address_space_operations ramdisk_aops = {
-	readpage: ramdisk_readpage,
-	writepage: fail_writepage,
-	prepare_write: ramdisk_prepare_write,
-	commit_write: ramdisk_commit_write,
+	.readpage = ramdisk_readpage,
+	.writepage = fail_writepage,
+	.prepare_write = ramdisk_prepare_write,
+	.commit_write = ramdisk_commit_write,
 };
 
 static int rd_blkdev_pagecache_IO(int rw, struct bio_vec *vec, sector_t sector,
@@ -316,8 +316,8 @@
 
 
 static struct file_operations initrd_fops = {
-	read:		initrd_read,
-	release:	initrd_release,
+	.read =		initrd_read,
+	.release =	initrd_release,
 };
 
 #endif
@@ -361,9 +361,9 @@
 }
 
 static struct block_device_operations rd_bd_op = {
-	owner:		THIS_MODULE,
-	open:		rd_open,
-	ioctl:		rd_ioctl,
+	.owner =	THIS_MODULE,
+	.open =		rd_open,
+	.ioctl =	rd_ioctl,
 };
 
 /* Before freeing the module, invalidate all of the protected buffers! */
diff -Nru a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
--- a/drivers/block/swim_iop.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/block/swim_iop.c	Sun Nov 10 19:28:36 2002
@@ -464,6 +464,7 @@
 	save_flags(flags); cli();
 	if (fs->timeout_pending)
 		del_timer(&fs->timeout);
+	init_timer(&fs->timeout);
 	fs->timeout.expires = jiffies + nticks;
 	fs->timeout.function = proc;
 	fs->timeout.data = (unsigned long) fs;
diff -Nru a/drivers/block/umem.c b/drivers/block/umem.c
--- a/drivers/block/umem.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/block/umem.c	Sun Nov 10 19:28:41 2002
@@ -1117,18 +1117,21 @@
 }
 
 static const struct pci_device_id __devinitdata mm_pci_ids[] = { {
-	vendor:		PCI_VENDOR_ID_MICRO_MEMORY,
-	device:		PCI_DEVICE_ID_MICRO_MEMORY_5415CN,
+	.vendor =	PCI_VENDOR_ID_MICRO_MEMORY,
+	.device =	PCI_DEVICE_ID_MICRO_MEMORY_5415CN,
+	}, {
+	.vendor =	PCI_VENDOR_ID_MICRO_MEMORY,
+	.device =	PCI_DEVICE_ID_MICRO_MEMORY_5425CN,
 	}, { /* end: all zeroes */ }
 };
 
 MODULE_DEVICE_TABLE(pci, mm_pci_ids);
 
 static struct pci_driver mm_pci_driver = {
-	name:		"umem",
-	id_table:	mm_pci_ids,
-	probe:		mm_pci_probe,
-	remove:		mm_pci_remove,
+	.name =		"umem",
+	.id_table =	mm_pci_ids,
+	.probe =	mm_pci_probe,
+	.remove =	mm_pci_remove,
 };
 /*
 -----------------------------------------------------------------------------------
diff -Nru a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
--- a/drivers/cdrom/aztcd.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/cdrom/aztcd.c	Sun Nov 10 19:28:41 2002
@@ -299,7 +299,7 @@
 
 static int AztTimeout, AztTries;
 static DECLARE_WAIT_QUEUE_HEAD(azt_waitq);
-static struct timer_list delay_timer;
+static struct timer_list delay_timer = TIMER_INITIALIZER(NULL, 0, 0);
 
 static struct azt_DiskInfo DiskInfo;
 static struct azt_Toc Toc[MAX_TRACKS];
diff -Nru a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
--- a/drivers/cdrom/cm206.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/cdrom/cm206.c	Sun Nov 10 19:28:41 2002
@@ -451,6 +451,7 @@
 int sleep_or_timeout(wait_queue_head_t * wait, int timeout)
 {
 	cd->timed_out = 0;
+	init_timer(&cd->timer);
 	cd->timer.data = (unsigned long) wait;
 	cd->timer.expires = jiffies + timeout;
 	add_timer(&cd->timer);
diff -Nru a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
--- a/drivers/cdrom/gscd.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/cdrom/gscd.c	Sun Nov 10 19:28:36 2002
@@ -148,7 +148,7 @@
 static int AudioEnd_m;
 static int AudioEnd_f;
 
-static struct timer_list gscd_timer;
+static struct timer_list gscd_timer = TIMER_INITIALIZER(NULL, 0, 0);
 static spinlock_t gscd_lock = SPIN_LOCK_UNLOCKED;
 struct request_queue gscd_queue;
 
diff -Nru a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
--- a/drivers/cdrom/mcd.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/cdrom/mcd.c	Sun Nov 10 19:28:40 2002
@@ -193,7 +193,7 @@
 		    void *arg);
 static int mcd_drive_status(struct cdrom_device_info *cdi, int slot_nr);
 
-static struct timer_list mcd_timer;
+static struct timer_list mcd_timer = TIMER_INITIALIZER(NULL, 0, 0);
 
 static struct cdrom_device_ops mcd_dops = {
 	.open			= mcd_open,
diff -Nru a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
--- a/drivers/cdrom/optcd.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/cdrom/optcd.c	Sun Nov 10 19:28:38 2002
@@ -265,7 +265,7 @@
 static int sleep_timeout;	/* max # of ticks to sleep */
 static DECLARE_WAIT_QUEUE_HEAD(waitq);
 static void sleep_timer(unsigned long data);
-static struct timer_list delay_timer = {function: sleep_timer};
+static struct timer_list delay_timer = TIMER_INITIALIZER(sleep_timer, 0, 0);
 static spinlock_t optcd_lock = SPIN_LOCK_UNLOCKED;
 static struct request_queue opt_queue;
 
diff -Nru a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
--- a/drivers/cdrom/sbpcd.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/cdrom/sbpcd.c	Sun Nov 10 19:28:37 2002
@@ -743,10 +743,13 @@
 unsigned long cli_sti; /* for saving the processor flags */
 #endif
 /*==========================================================================*/
-static struct timer_list delay_timer = { function: mark_timeout_delay};
-static struct timer_list data_timer = { function: mark_timeout_data};
+static struct timer_list delay_timer =
+		TIMER_INITIALIZER(mark_timeout_delay, 0, 0);
+static struct timer_list data_timer =
+		TIMER_INITIALIZER(mark_timeout_data, 0, 0);
 #if 0
-static struct timer_list audio_timer = { function: mark_timeout_audio};
+static struct timer_list audio_timer =
+		TIMER_INITIALIZER(mark_timeout_audio, 0, 0);
 #endif
 /*==========================================================================*/
 /*
diff -Nru a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
--- a/drivers/cdrom/sjcd.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/cdrom/sjcd.c	Sun Nov 10 19:28:40 2002
@@ -152,7 +152,7 @@
 /*
  * Timer.
  */
-static struct timer_list sjcd_delay_timer;
+static struct timer_list sjcd_delay_timer = TIMER_INITIALIZER(NULL, 0, 0);
 
 #define SJCD_SET_TIMER( func, tmout )           \
     ( sjcd_delay_timer.expires = jiffies+tmout,         \
diff -Nru a/drivers/char/ChangeLog b/drivers/char/ChangeLog
--- a/drivers/char/ChangeLog	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/ChangeLog	Sun Nov 10 19:28:40 2002
@@ -550,7 +550,7 @@
 		the StarTech 16650 chip.  Treat it as a 16450 for now,
 		because of its FIFO bugs.
 
-Thu Jan  5 21:21:57 1995  <dhinds@allegro.stanford.edu>
+Thu Jan  5 21:21:57 1995  <dahinds@users.sourceforge.net>
 
 	* serial.c: (receive_char): Added counter to prevent infinite loop
 		when a PCMCIA serial device is ejected.
diff -Nru a/drivers/char/acquirewdt.c b/drivers/char/acquirewdt.c
--- a/drivers/char/acquirewdt.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/acquirewdt.c	Sun Nov 10 19:28:40 2002
@@ -186,12 +186,12 @@
  
  
 static struct file_operations acq_fops = {
-	owner:		THIS_MODULE,
-	read:		acq_read,
-	write:		acq_write,
-	ioctl:		acq_ioctl,
-	open:		acq_open,
-	release:	acq_close,
+	.owner		= THIS_MODULE,
+	.read		= acq_read,
+	.write		= acq_write,
+	.ioctl		= acq_ioctl,
+	.open		= acq_open,
+	.release	= acq_close,
 };
 
 static struct miscdevice acq_miscdev=
diff -Nru a/drivers/char/advantechwdt.c b/drivers/char/advantechwdt.c
--- a/drivers/char/advantechwdt.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/advantechwdt.c	Sun Nov 10 19:28:39 2002
@@ -200,12 +200,12 @@
  */
  
 static struct file_operations advwdt_fops = {
-	owner:		THIS_MODULE,
-	read:		advwdt_read,
-	write:		advwdt_write,
-	ioctl:		advwdt_ioctl,
-	open:		advwdt_open,
-	release:	advwdt_close,
+	.owner		= THIS_MODULE,
+	.read		= advwdt_read,
+	.write		= advwdt_write,
+	.ioctl		= advwdt_ioctl,
+	.open		= advwdt_open,
+	.release	= advwdt_close,
 };
 
 static struct miscdevice advwdt_miscdev = {
diff -Nru a/drivers/char/agp/agp.c b/drivers/char/agp/agp.c
--- a/drivers/char/agp/agp.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/agp/agp.c	Sun Nov 10 19:28:40 2002
@@ -1150,6 +1150,14 @@
 		.chipset_setup	= via_generic_setup
 	},
 	{
+		.device_id	= PCI_DEVICE_ID_VIA_8653_0,
+		.vendor_id	= PCI_VENDOR_ID_VIA,
+		.chipset	= VIA_APOLLO_PRO,
+		.vendor_name	= "Via",
+		.chipset_name	= "Apollo Pro266T",
+		.chipset_setup	= via_generic_setup
+	},
+	{
 		.device_id	= 0,
 		.vendor_id	= PCI_VENDOR_ID_VIA,
 		.chipset	= VIA_GENERIC,
diff -Nru a/drivers/char/amd768_rng.c b/drivers/char/amd768_rng.c
--- a/drivers/char/amd768_rng.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/amd768_rng.c	Sun Nov 10 19:28:39 2002
@@ -167,10 +167,10 @@
 
 
 static struct file_operations rng_chrdev_ops = {
-	owner:		THIS_MODULE,
-	open:		rng_dev_open,
-	release:	rng_dev_release,
-	read:		rng_dev_read,
+	.owner		= THIS_MODULE,
+	.open		= rng_dev_open,
+	.release	= rng_dev_release,
+	.read		= rng_dev_read,
 };
 
 
diff -Nru a/drivers/char/applicom.c b/drivers/char/applicom.c
--- a/drivers/char/applicom.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/char/applicom.c	Sun Nov 10 19:28:41 2002
@@ -119,11 +119,11 @@
 static void ac_interrupt(int, void *, struct pt_regs *);
 
 static struct file_operations ac_fops = {
-	owner:THIS_MODULE,
-	llseek:no_llseek,
-	read:ac_read,
-	write:ac_write,
-	ioctl:ac_ioctl,
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.read = ac_read,
+	.write = ac_write,
+	.ioctl = ac_ioctl,
 };
 
 static struct miscdevice ac_miscdev = {
diff -Nru a/drivers/char/busmouse.c b/drivers/char/busmouse.c
--- a/drivers/char/busmouse.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/busmouse.c	Sun Nov 10 19:28:40 2002
@@ -336,13 +336,13 @@
 
 struct file_operations busmouse_fops=
 {
-	owner:		THIS_MODULE,
-	read:		busmouse_read,
-	write:		busmouse_write,
-	poll:		busmouse_poll,
-	open:		busmouse_open,
-	release:	busmouse_release,
-	fasync:		busmouse_fasync,
+	.owner		= THIS_MODULE,
+	.read		= busmouse_read,
+	.write		= busmouse_write,
+	.poll		= busmouse_poll,
+	.open		= busmouse_open,
+	.release	= busmouse_release,
+	.fasync		= busmouse_fasync,
 };
 
 /**
diff -Nru a/drivers/char/cyclades.c b/drivers/char/cyclades.c
--- a/drivers/char/cyclades.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/char/cyclades.c	Sun Nov 10 19:28:37 2002
@@ -883,8 +883,7 @@
 static long cyz_polling_cycle = CZ_DEF_POLL;
 
 static int cyz_timeron = 0;
-static struct timer_list cyz_timerlist = {
-    function: cyz_poll
+static struct timer_list cyz_timerlist = TIMER_INITIALIZER(cyz_poll, 0, 0);
 };
 #else /* CONFIG_CYZ_INTR */
 static void cyz_rx_restart(unsigned long);
@@ -5667,6 +5666,7 @@
                     info->jiffies[2] = 0;
                     info->rflush_count = 0;
 #ifdef CONFIG_CYZ_INTR
+		    init_timer(&cyz_rx_full_timer[port]);
 		    cyz_rx_full_timer[port].function = NULL;
 #endif
                 }
diff -Nru a/drivers/char/ds1620.c b/drivers/char/ds1620.c
--- a/drivers/char/ds1620.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/char/ds1620.c	Sun Nov 10 19:28:37 2002
@@ -337,9 +337,9 @@
 #endif
 
 static struct file_operations ds1620_fops = {
-	owner:		THIS_MODULE,
-	read:		ds1620_read,
-	ioctl:		ds1620_ioctl,
+	.owner		= THIS_MODULE,
+	.read		= ds1620_read,
+	.ioctl		= ds1620_ioctl,
 };
 
 static struct miscdevice ds1620_miscdev = {
diff -Nru a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
--- a/drivers/char/dsp56k.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/dsp56k.c	Sun Nov 10 19:28:40 2002
@@ -488,12 +488,12 @@
 }
 
 static struct file_operations dsp56k_fops = {
-	owner:		THIS_MODULE,
-	read:		dsp56k_read,
-	write:		dsp56k_write,
-	ioctl:		dsp56k_ioctl,
-	open:		dsp56k_open,
-	release:	dsp56k_release,
+	.owner		= THIS_MODULE,
+	.read		= dsp56k_read,
+	.write		= dsp56k_write,
+	.ioctl		= dsp56k_ioctl,
+	.open		= dsp56k_open,
+	.release	= dsp56k_release,
 };
 
 
diff -Nru a/drivers/char/dtlk.c b/drivers/char/dtlk.c
--- a/drivers/char/dtlk.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/dtlk.c	Sun Nov 10 19:28:39 2002
@@ -98,13 +98,13 @@
 
 static struct file_operations dtlk_fops =
 {
-	owner:		THIS_MODULE,
-	read:		dtlk_read,
-	write:		dtlk_write,
-	poll:		dtlk_poll,
-	ioctl:		dtlk_ioctl,
-	open:		dtlk_open,
-	release:	dtlk_release,
+	.owner		= THIS_MODULE,
+	.read		= dtlk_read,
+	.write		= dtlk_write,
+	.poll		= dtlk_poll,
+	.ioctl		= dtlk_ioctl,
+	.open		= dtlk_open,
+	.release	= dtlk_release,
 };
 
 /* local prototypes */
diff -Nru a/drivers/char/dz.c b/drivers/char/dz.c
--- a/drivers/char/dz.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/char/dz.c	Sun Nov 10 19:28:37 2002
@@ -1601,12 +1601,12 @@
 }
 
 static struct console dz_sercons = {
-    name:	"ttyS",
-    write:	dz_console_print,
-    device:	dz_console_device,
-    setup:	dz_console_setup,
-    flags:	CON_CONSDEV | CON_PRINTBUFFER,
-    index:	CONSOLE_LINE,
+    .name	= "ttyS",
+    .write	= dz_console_print,
+    .device	= dz_console_device,
+    .setup	= dz_console_setup,
+    .flags	= CON_CONSDEV | CON_PRINTBUFFER,
+    .index	= CONSOLE_LINE,
 };
 
 void __init dz_serial_console_init(void)
diff -Nru a/drivers/char/efirtc.c b/drivers/char/efirtc.c
--- a/drivers/char/efirtc.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/efirtc.c	Sun Nov 10 19:28:40 2002
@@ -282,10 +282,10 @@
  */
 
 static struct file_operations efi_rtc_fops = {
-	owner:		THIS_MODULE,
-	ioctl:		efi_rtc_ioctl,
-	open:		efi_rtc_open,
-	release:	efi_rtc_close,
+	.owner		= THIS_MODULE,
+	.ioctl		= efi_rtc_ioctl,
+	.open		= efi_rtc_open,
+	.release	= efi_rtc_close,
 };
 
 static struct miscdevice efi_rtc_dev=
diff -Nru a/drivers/char/eurotechwdt.c b/drivers/char/eurotechwdt.c
--- a/drivers/char/eurotechwdt.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/char/eurotechwdt.c	Sun Nov 10 19:28:37 2002
@@ -388,12 +388,12 @@
  
  
 static struct file_operations eurwdt_fops = {
-        owner:          THIS_MODULE,
-        llseek:         no_llseek,
-        write:          eurwdt_write,
-        ioctl:          eurwdt_ioctl,
-        open:           eurwdt_open,
-        release:        eurwdt_release,
+        .owner          = THIS_MODULE,
+        .llseek         = no_llseek,
+        .write          = eurwdt_write,
+        .ioctl          = eurwdt_ioctl,
+        .open           = eurwdt_open,
+        .release        = eurwdt_release,
 };
 
 static struct miscdevice eurwdt_miscdev =
diff -Nru a/drivers/char/hp_psaux.c b/drivers/char/hp_psaux.c
--- a/drivers/char/hp_psaux.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/char/hp_psaux.c	Sun Nov 10 19:28:41 2002
@@ -370,18 +370,18 @@
 }
 
 static struct file_operations psaux_fops = {
-	read:		read_aux,
-	write:		write_aux,
-	poll:		aux_poll,
-	open:		open_aux,
-	release:	release_aux,
-	fasync:		fasync_aux,
+	.read		= read_aux,
+	.write		= write_aux,
+	.poll		= aux_poll,
+	.open		= open_aux,
+	.release	= release_aux,
+	.fasync		= fasync_aux,
 };
 
 static struct miscdevice psaux_mouse = {
-	minor:		PSMOUSE_MINOR,
-	name:		"psaux",
-	fops:		&psaux_fops,
+	.minor		= PSMOUSE_MINOR,
+	.name		= "psaux",
+	.fops		= &psaux_fops,
 };
 
 #endif /* CONFIG_PSMOUSE */
@@ -452,12 +452,12 @@
 extern int pckbd_translate(unsigned char, unsigned char *, char);
 
 static struct kbd_ops gsc_ps2_kbd_ops = {
-	translate:	pckbd_translate,
-	init_hw:	lasi_ps2_init_hw,
-	leds:		lasikbd_leds,
+	.translate	= pckbd_translate,
+	.init_hw	= lasi_ps2_init_hw,
+	.leds		= lasikbd_leds,
 #ifdef CONFIG_MAGIC_SYSRQ
-	sysrq_key:	0x54,
-	sysrq_xlate:	hp_ps2kbd_sysrq_xlate,
+	.sysrq_key	= 0x54,
+	.sysrq_xlate	= hp_ps2kbd_sysrq_xlate,
 #endif
 };
 
diff -Nru a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
--- a/drivers/char/hvc_console.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/char/hvc_console.c	Sun Nov 10 19:28:41 2002
@@ -340,12 +340,12 @@
 }
 
 struct console hvc_con_driver = {
-	name:		"hvc",
-	write:		hvc_console_print,
-	device:		hvc_console_device,
-	setup:		hvc_console_setup,
-	flags:		CON_PRINTBUFFER,
-	index:		-1,
+	.name		= "hvc",
+	.write		= hvc_console_print,
+	.device		= hvc_console_device,
+	.setup		= hvc_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
 };
 
 int __init hvc_console_init(void)
diff -Nru a/drivers/char/i810_rng.c b/drivers/char/i810_rng.c
--- a/drivers/char/i810_rng.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/i810_rng.c	Sun Nov 10 19:28:39 2002
@@ -27,6 +27,7 @@
 #include <linux/miscdevice.h>
 #include <linux/smp_lock.h>
 #include <linux/mm.h>
+#include <linux/delay.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
@@ -243,8 +244,13 @@
 		if (filp->f_flags & O_NONBLOCK)
 			return ret ? : -EAGAIN;
 
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(1);
+		if (need_resched())
+		{
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(1);
+		}
+		else
+			udelay(200);
 
 		if (signal_pending (current))
 			return ret ? : -ERESTARTSYS;
@@ -255,10 +261,10 @@
 
 
 static struct file_operations rng_chrdev_ops = {
-	owner:		THIS_MODULE,
-	open:		rng_dev_open,
-	release:	rng_dev_release,
-	read:		rng_dev_read,
+	.owner		= THIS_MODULE,
+	.open		= rng_dev_open,
+	.release	= rng_dev_release,
+	.read		= rng_dev_read,
 };
 
 
diff -Nru a/drivers/char/i8k.c b/drivers/char/i8k.c
--- a/drivers/char/i8k.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/char/i8k.c	Sun Nov 10 19:28:37 2002
@@ -82,8 +82,8 @@
 		     unsigned long);
 
 static struct file_operations i8k_fops = {
-    read:	i8k_read,
-    ioctl:	i8k_ioctl,
+    .read	= i8k_read,
+    .ioctl	= i8k_ioctl,
 };
 
 typedef struct {
diff -Nru a/drivers/char/ib700wdt.c b/drivers/char/ib700wdt.c
--- a/drivers/char/ib700wdt.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/char/ib700wdt.c	Sun Nov 10 19:28:41 2002
@@ -239,12 +239,12 @@
  */
 
 static struct file_operations ibwdt_fops = {
-	owner:		THIS_MODULE,
-	read:		ibwdt_read,
-	write:		ibwdt_write,
-	ioctl:		ibwdt_ioctl,
-	open:		ibwdt_open,
-	release:	ibwdt_close,
+	.owner		= THIS_MODULE,
+	.read		= ibwdt_read,
+	.write		= ibwdt_write,
+	.ioctl		= ibwdt_ioctl,
+	.open		= ibwdt_open,
+	.release	= ibwdt_close,
 };
 
 static struct miscdevice ibwdt_miscdev = {
diff -Nru a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c
--- a/drivers/char/ip2/i2ellis.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/char/ip2/i2ellis.c	Sun Nov 10 19:28:36 2002
@@ -87,6 +87,7 @@
 iiEllisInit(void)
 {
 	pDelayTimer = kmalloc ( sizeof (struct timer_list), GFP_KERNEL );
+	init_timer(pDelayTimer);
 	init_waitqueue_head(&pDelayWait);
 	LOCK_INIT(&Dl_spinlock);
 }
diff -Nru a/drivers/char/ip2main.c b/drivers/char/ip2main.c
--- a/drivers/char/ip2main.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/char/ip2main.c	Sun Nov 10 19:28:41 2002
@@ -334,11 +334,11 @@
  * download the loadware to the boards.
  */
 static struct file_operations ip2_ipl = {
-	owner:		THIS_MODULE,
-	read:		ip2_ipl_read,
-	write:		ip2_ipl_write,
-	ioctl:		ip2_ipl_ioctl,
-	open:		ip2_ipl_open,
+	.owner		= THIS_MODULE,
+	.read		= ip2_ipl_read,
+	.write		= ip2_ipl_write,
+	.ioctl		= ip2_ipl_ioctl,
+	.open		= ip2_ipl_open,
 }; 
 
 static unsigned long irq_counter = 0;
@@ -352,7 +352,7 @@
  * selected, the board is serviced periodically to see if anything needs doing.
  */
 #define  POLL_TIMEOUT   (jiffies + 1)
-static struct timer_list PollTimer = { function: ip2_poll };
+static struct timer_list PollTimer = TIMER_INITIALIZER(ip2_poll, 0, 0);
 static char  TimerOn;
 
 #ifdef IP2DEBUG_TRACE
diff -Nru a/drivers/char/isicom.c b/drivers/char/isicom.c
--- a/drivers/char/isicom.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/char/isicom.c	Sun Nov 10 19:28:36 2002
@@ -113,8 +113,8 @@
  */
 
 static struct file_operations ISILoad_fops = {
-	owner:		THIS_MODULE,
-	ioctl:		ISILoad_ioctl,
+	.owner		= THIS_MODULE,
+	.ioctl		= ISILoad_ioctl,
 };
 
 struct miscdevice isiloader_device = {
diff -Nru a/drivers/char/istallion.c b/drivers/char/istallion.c
--- a/drivers/char/istallion.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/istallion.c	Sun Nov 10 19:28:40 2002
@@ -213,8 +213,8 @@
  *	at 9600 baud, 8 data bits, no parity, 1 stop bit.
  */
 static struct termios		stli_deftermios = {
-	c_cflag:	(B9600 | CS8 | CREAD | HUPCL | CLOCAL),
-	c_cc:		INIT_C_CC,
+	.c_cflag	= (B9600 | CS8 | CREAD | HUPCL | CLOCAL),
+	.c_cc		= INIT_C_CC,
 };
 
 /*
@@ -783,10 +783,10 @@
  *	board. This is also a very useful debugging tool.
  */
 static struct file_operations	stli_fsiomem = {
-	owner:		THIS_MODULE,
-	read:		stli_memread,
-	write:		stli_memwrite,
-	ioctl:		stli_memioctl,
+	.owner		= THIS_MODULE,
+	.read		= stli_memread,
+	.write		= stli_memwrite,
+	.ioctl		= stli_memioctl,
 };
 
 /*****************************************************************************/
@@ -797,8 +797,7 @@
  *	much cheaper on host cpu than using interrupts. It turns out to
  *	not increase character latency by much either...
  */
-static struct timer_list	stli_timerlist = {
-	function: stli_poll
+static struct timer_list stli_timerlist = TIMER_INITIALIZER(stli_poll, 0, 0);
 };
 
 static int	stli_timeron;
diff -Nru a/drivers/char/ite_gpio.c b/drivers/char/ite_gpio.c
--- a/drivers/char/ite_gpio.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/ite_gpio.c	Sun Nov 10 19:28:40 2002
@@ -373,10 +373,10 @@
 
 static struct file_operations ite_gpio_fops =
 {
-	owner:		THIS_MODULE,
-	ioctl:		ite_gpio_ioctl,
-	open:		ite_gpio_open,
-	release:	ite_gpio_release,
+	.owner		= THIS_MODULE,
+	.ioctl		= ite_gpio_ioctl,
+	.open		= ite_gpio_open,
+	.release	= ite_gpio_release,
 };
 
 /* GPIO_MINOR in include/linux/miscdevice.h */
diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c
--- a/drivers/char/keyboard.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/keyboard.c	Sun Nov 10 19:28:39 2002
@@ -233,7 +233,8 @@
 	}
 }
 
-static struct timer_list kd_mksound_timer = { function: kd_nosound };
+static struct timer_list kd_mksound_timer =
+		TIMER_INITIALIZER(kd_nosound, 0, 0);
 
 void kd_mksound(unsigned int hz, unsigned int ticks)
 {
@@ -1171,13 +1172,13 @@
 
 static struct input_device_id kbd_ids[] = {
 	{
-                flags: INPUT_DEVICE_ID_MATCH_EVBIT,
-                evbit: { BIT(EV_KEY) },
+                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+                .evbit = { BIT(EV_KEY) },
         },
 	
 	{
-                flags: INPUT_DEVICE_ID_MATCH_EVBIT,
-                evbit: { BIT(EV_SND) },
+                .flags = INPUT_DEVICE_ID_MATCH_EVBIT,
+                .evbit = { BIT(EV_SND) },
         },	
 
 	{ },    /* Terminating entry */
@@ -1186,11 +1187,11 @@
 MODULE_DEVICE_TABLE(input, kbd_ids);
 
 static struct input_handler kbd_handler = {
-	event:		kbd_event,
-	connect:	kbd_connect,
-	disconnect:	kbd_disconnect,
-	name:		"kbd",
-	id_table:	kbd_ids,
+	.event		= kbd_event,
+	.connect	= kbd_connect,
+	.disconnect	= kbd_disconnect,
+	.name		= "kbd",
+	.id_table	= kbd_ids,
 };
 
 int __init kbd_init(void)
diff -Nru a/drivers/char/lp.c b/drivers/char/lp.c
--- a/drivers/char/lp.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/char/lp.c	Sun Nov 10 19:28:36 2002
@@ -660,13 +660,13 @@
 }
 
 static struct file_operations lp_fops = {
-	owner:		THIS_MODULE,
-	write:		lp_write,
-	ioctl:		lp_ioctl,
-	open:		lp_open,
-	release:	lp_release,
+	.owner		= THIS_MODULE,
+	.write		= lp_write,
+	.ioctl		= lp_ioctl,
+	.open		= lp_open,
+	.release	= lp_release,
 #ifdef CONFIG_PARPORT_1284
-	read:		lp_read,
+	.read		= lp_read,
 #endif
 };
 
@@ -741,10 +741,10 @@
 }
 
 static struct console lpcons = {
-	name:		"lp",
-	write:		lp_console_write,
-	device:		lp_console_device,
-	flags:		CON_PRINTBUFFER,
+	.name		= "lp",
+	.write		= lp_console_write,
+	.device		= lp_console_device,
+	.flags		= CON_PRINTBUFFER,
 };
 
 #endif /* console on line printer */
diff -Nru a/drivers/char/machzwd.c b/drivers/char/machzwd.c
--- a/drivers/char/machzwd.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/char/machzwd.c	Sun Nov 10 19:28:37 2002
@@ -117,9 +117,9 @@
 #define PFX "machzwd"
 
 static struct watchdog_info zf_info = {
-	options:		WDIOF_KEEPALIVEPING, 
-	firmware_version:	1, 
-	identity:		"ZF-Logic watchdog"
+	.options		= WDIOF_KEEPALIVEPING, 
+	.firmware_version	= 1, 
+	.identity		= "ZF-Logic watchdog"
 };
 
 
@@ -449,12 +449,12 @@
 
 
 static struct file_operations zf_fops = {
-	owner:          THIS_MODULE,
-	read:           zf_read,
-	write:          zf_write,
-	ioctl:          zf_ioctl,
-	open:           zf_open,
-	release:        zf_close,
+	.owner          = THIS_MODULE,
+	.read           = zf_read,
+	.write          = zf_write,
+	.ioctl          = zf_ioctl,
+	.open           = zf_open,
+	.release        = zf_close,
 };
 
 static struct miscdevice zf_miscdev = {
diff -Nru a/drivers/char/mem.c b/drivers/char/mem.c
--- a/drivers/char/mem.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/mem.c	Sun Nov 10 19:28:40 2002
@@ -49,7 +49,7 @@
 	ssize_t written;
 
 	written = 0;
-#if defined(__sparc__) || defined(__mc68000__)
+#if defined(__sparc__) || (defined(__mc68000__) && defined(CONFIG_MMU))
 	/* we don't have page 0 mapped on sparc and m68k.. */
 	if (realp < PAGE_SIZE) {
 		unsigned long sz = PAGE_SIZE-realp;
@@ -86,7 +86,7 @@
 	if (count > end_mem - p)
 		count = end_mem - p;
 	read = 0;
-#if defined(__sparc__) || defined(__mc68000__)
+#if defined(__sparc__) || (defined(__mc68000__) && defined(CONFIG_MMU))
 	/* we don't have page 0 mapped on sparc and m68k.. */
 	if (p < PAGE_SIZE) {
 		unsigned long sz = PAGE_SIZE-p;
@@ -140,7 +140,7 @@
 		prot |= _PAGE_PCD | _PAGE_PWT;
 #elif defined(__powerpc__)
 	prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
-#elif defined(__mc68000__)
+#elif defined(__mc68000__) && defined(CONFIG_MMU)
 #ifdef SUN3_PAGE_NOCACHE
 	if (MMU_IS_SUN3)
 		prot |= SUN3_PAGE_NOCACHE;
@@ -229,7 +229,7 @@
 		if (count > (unsigned long) high_memory - p)
 			read = (unsigned long) high_memory - p;
 
-#if defined(__sparc__) || defined(__mc68000__)
+#if defined(__sparc__) || (defined(__mc68000__) && defined(CONFIG_MMU))
 		/* we don't have page 0 mapped on sparc and m68k.. */
 		if (p < PAGE_SIZE && read > 0) {
 			size_t tmp = PAGE_SIZE - p;
@@ -537,47 +537,47 @@
 #define open_kmem	open_mem
 
 static struct file_operations mem_fops = {
-	llseek:		memory_lseek,
-	read:		read_mem,
-	write:		write_mem,
-	mmap:		mmap_mem,
-	open:		open_mem,
+	.llseek		= memory_lseek,
+	.read		= read_mem,
+	.write		= write_mem,
+	.mmap		= mmap_mem,
+	.open		= open_mem,
 };
 
 static struct file_operations kmem_fops = {
-	llseek:		memory_lseek,
-	read:		read_kmem,
-	write:		write_kmem,
-	mmap:		mmap_kmem,
-	open:		open_kmem,
+	.llseek		= memory_lseek,
+	.read		= read_kmem,
+	.write		= write_kmem,
+	.mmap		= mmap_kmem,
+	.open		= open_kmem,
 };
 
 static struct file_operations null_fops = {
-	llseek:		null_lseek,
-	read:		read_null,
-	write:		write_null,
+	.llseek		= null_lseek,
+	.read		= read_null,
+	.write		= write_null,
 };
 
 #if defined(CONFIG_ISA) || !defined(__mc68000__)
 static struct file_operations port_fops = {
-	llseek:		memory_lseek,
-	read:		read_port,
-	write:		write_port,
-	open:		open_port,
+	.llseek		= memory_lseek,
+	.read		= read_port,
+	.write		= write_port,
+	.open		= open_port,
 };
 #endif
 
 static struct file_operations zero_fops = {
-	llseek:		zero_lseek,
-	read:		read_zero,
-	write:		write_zero,
-	mmap:		mmap_zero,
+	.llseek		= zero_lseek,
+	.read		= read_zero,
+	.write		= write_zero,
+	.mmap		= mmap_zero,
 };
 
 static struct file_operations full_fops = {
-	llseek:		full_lseek,
-	read:		read_full,
-	write:		write_full,
+	.llseek		= full_lseek,
+	.read		= read_full,
+	.write		= write_full,
 };
 
 static int memory_open(struct inode * inode, struct file * filp)
@@ -647,7 +647,7 @@
 }
 
 static struct file_operations memory_fops = {
-	open:		memory_open,	/* just a selector for the real open */
+	.open		= memory_open,	/* just a selector for the real open */
 };
 
 int __init chr_dev_init(void)
diff -Nru a/drivers/char/misc.c b/drivers/char/misc.c
--- a/drivers/char/misc.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/char/misc.c	Sun Nov 10 19:28:41 2002
@@ -146,8 +146,8 @@
 }
 
 static struct file_operations misc_fops = {
-	owner:		THIS_MODULE,
-	open:		misc_open,
+	.owner		= THIS_MODULE,
+	.open		= misc_open,
 };
 
 
diff -Nru a/drivers/char/mixcomwd.c b/drivers/char/mixcomwd.c
--- a/drivers/char/mixcomwd.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/char/mixcomwd.c	Sun Nov 10 19:28:38 2002
@@ -61,7 +61,7 @@
 
 static int watchdog_port;
 static int mixcomwd_timer_alive;
-static struct timer_list mixcomwd_timer;
+static struct timer_list mixcomwd_timer = TIMER_INITIALIZER(NULL, 0, 0);
 
 #ifdef CONFIG_WATCHDOG_NOWAYOUT
 static int nowayout = 1;
@@ -177,11 +177,11 @@
 
 static struct file_operations mixcomwd_fops=
 {
-	owner:		THIS_MODULE,
-	write:		mixcomwd_write,
-	ioctl:		mixcomwd_ioctl,
-	open:		mixcomwd_open,
-	release:	mixcomwd_release,
+	.owner		= THIS_MODULE,
+	.write		= mixcomwd_write,
+	.ioctl		= mixcomwd_ioctl,
+	.open		= mixcomwd_open,
+	.release	= mixcomwd_release,
 };
 
 static struct miscdevice mixcomwd_miscdev=
diff -Nru a/drivers/char/nvram.c b/drivers/char/nvram.c
--- a/drivers/char/nvram.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/nvram.c	Sun Nov 10 19:28:39 2002
@@ -438,13 +438,13 @@
 #endif /* CONFIG_PROC_FS */
 
 static struct file_operations nvram_fops = {
-	owner:		THIS_MODULE,
-	llseek:		nvram_llseek,
-	read:		nvram_read,
-	write:		nvram_write,
-	ioctl:		nvram_ioctl,
-	open:		nvram_open,
-	release:	nvram_release,
+	.owner		= THIS_MODULE,
+	.llseek		= nvram_llseek,
+	.read		= nvram_read,
+	.write		= nvram_write,
+	.ioctl		= nvram_ioctl,
+	.open		= nvram_open,
+	.release	= nvram_release,
 };
 
 static struct miscdevice nvram_dev = {
diff -Nru a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c
--- a/drivers/char/nwbutton.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/char/nwbutton.c	Sun Nov 10 19:28:41 2002
@@ -183,8 +183,8 @@
  */
 
 static struct file_operations button_fops = {
-	owner:		THIS_MODULE,
-	read:		button_read,
+	.owner		= THIS_MODULE,
+	.read		= button_read,
 };
 
 /* 
diff -Nru a/drivers/char/nwflash.c b/drivers/char/nwflash.c
--- a/drivers/char/nwflash.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/char/nwflash.c	Sun Nov 10 19:28:41 2002
@@ -652,11 +652,11 @@
 
 static struct file_operations flash_fops =
 {
-	owner:		THIS_MODULE,
-	llseek:		flash_llseek,
-	read:		flash_read,
-	write:		flash_write,
-	ioctl:		flash_ioctl,
+	.owner		= THIS_MODULE,
+	.llseek		= flash_llseek,
+	.read		= flash_read,
+	.write		= flash_write,
+	.ioctl		= flash_ioctl,
 };
 
 static struct miscdevice flash_miscdev =
diff -Nru a/drivers/char/pcwd.c b/drivers/char/pcwd.c
--- a/drivers/char/pcwd.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/char/pcwd.c	Sun Nov 10 19:28:37 2002
@@ -540,12 +540,12 @@
 }
 
 static struct file_operations pcwd_fops = {
-	owner:		THIS_MODULE,
-	read:		pcwd_read,
-	write:		pcwd_write,
-	ioctl:		pcwd_ioctl,
-	open:		pcwd_open,
-	release:	pcwd_close,
+	.owner		= THIS_MODULE,
+	.read		= pcwd_read,
+	.write		= pcwd_write,
+	.ioctl		= pcwd_ioctl,
+	.open		= pcwd_open,
+	.release	= pcwd_close,
 };
 
 static struct miscdevice pcwd_miscdev = {
diff -Nru a/drivers/char/ppdev.c b/drivers/char/ppdev.c
--- a/drivers/char/ppdev.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/char/ppdev.c	Sun Nov 10 19:28:41 2002
@@ -739,14 +739,14 @@
 }
 
 static struct file_operations pp_fops = {
-	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	read:		pp_read,
-	write:		pp_write,
-	poll:		pp_poll,
-	ioctl:		pp_ioctl,
-	open:		pp_open,
-	release:	pp_release,
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= pp_read,
+	.write		= pp_write,
+	.poll		= pp_poll,
+	.ioctl		= pp_ioctl,
+	.open		= pp_open,
+	.release	= pp_release,
 };
 
 static devfs_handle_t devfs_handle;
diff -Nru a/drivers/char/qtronix.c b/drivers/char/qtronix.c
--- a/drivers/char/qtronix.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/qtronix.c	Sun Nov 10 19:28:39 2002
@@ -568,12 +568,12 @@
 }
 
 struct file_operations psaux_fops = {
-	read:		read_aux,
-	write:		write_aux,
-	poll:		aux_poll,
-	open:		open_aux,
-	release:	release_aux,
-	fasync:		fasync_aux,
+	.read		= read_aux,
+	.write		= write_aux,
+	.poll		= aux_poll,
+	.open		= open_aux,
+	.release	= release_aux,
+	.fasync		= fasync_aux,
 };
 
 /*
diff -Nru a/drivers/char/random.c b/drivers/char/random.c
--- a/drivers/char/random.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/char/random.c	Sun Nov 10 19:28:37 2002
@@ -175,7 +175,7 @@
  *	chmod 600 $random_seed
  *	poolfile=/proc/sys/kernel/random/poolsize
  *	[ -r $poolfile ] && bytes=`cat $poolfile` || bytes=512
- *	dd if=/dev/urandom of=$random_seed count=1 bs=bytes
+ *	dd if=/dev/urandom of=$random_seed count=1 bs=$bytes
  *
  * and the following lines in an appropriate script which is run as
  * the system is shutdown:
@@ -188,7 +188,7 @@
  *	chmod 600 $random_seed
  *	poolfile=/proc/sys/kernel/random/poolsize
  *	[ -r $poolfile ] && bytes=`cat $poolfile` || bytes=512
- *	dd if=/dev/urandom of=$random_seed count=1 bs=bytes
+ *	dd if=/dev/urandom of=$random_seed count=1 bs=$bytes
  *
  * For example, on most modern systems using the System V init
  * scripts, such code fragments would be found in
@@ -1674,16 +1674,16 @@
 }
 
 struct file_operations random_fops = {
-	read:		random_read,
-	write:		random_write,
-	poll:		random_poll,
-	ioctl:		random_ioctl,
+	.read		= random_read,
+	.write		= random_write,
+	.poll		= random_poll,
+	.ioctl		= random_ioctl,
 };
 
 struct file_operations urandom_fops = {
-	read:		urandom_read,
-	write:		random_write,
-	ioctl:		random_ioctl,
+	.read		= urandom_read,
+	.write		= random_write,
+	.ioctl		= random_ioctl,
 };
 
 /***************************************************************
diff -Nru a/drivers/char/riscom8.c b/drivers/char/riscom8.c
--- a/drivers/char/riscom8.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/riscom8.c	Sun Nov 10 19:28:39 2002
@@ -102,16 +102,16 @@
 
 static struct riscom_board rc_board[RC_NBOARD] =  {
 	{
-		base:	RC_IOBASE1,
+		.base	= RC_IOBASE1,
 	},
 	{
-		base:	RC_IOBASE2,
+		.base	= RC_IOBASE2,
 	},
 	{
-		base:	RC_IOBASE3,
+		.base	= RC_IOBASE3,
 	},
 	{
-		base:	RC_IOBASE4,
+		.base	= RC_IOBASE4,
 	},
 };
 
diff -Nru a/drivers/char/rtc.c b/drivers/char/rtc.c
--- a/drivers/char/rtc.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/rtc.c	Sun Nov 10 19:28:39 2002
@@ -775,16 +775,16 @@
  */
 
 static struct file_operations rtc_fops = {
-	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	read:		rtc_read,
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= rtc_read,
 #if RTC_IRQ
-	poll:		rtc_poll,
+	.poll		= rtc_poll,
 #endif
-	ioctl:		rtc_ioctl,
-	open:		rtc_open,
-	release:	rtc_release,
-	fasync:		rtc_fasync,
+	.ioctl		= rtc_ioctl,
+	.open		= rtc_open,
+	.release	= rtc_release,
+	.fasync		= rtc_fasync,
 };
 
 static struct miscdevice rtc_dev=
diff -Nru a/drivers/char/sbc60xxwdt.c b/drivers/char/sbc60xxwdt.c
--- a/drivers/char/sbc60xxwdt.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/sbc60xxwdt.c	Sun Nov 10 19:28:40 2002
@@ -262,13 +262,13 @@
 }
 
 static struct file_operations wdt_fops = {
-	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	read:		fop_read,
-	write:		fop_write,
-	open:		fop_open,
-	release:	fop_close,
-	ioctl:		fop_ioctl
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= fop_read,
+	.write		= fop_write,
+	.open		= fop_open,
+	.release	= fop_close,
+	.ioctl		= fop_ioctl
 };
 
 static struct miscdevice wdt_miscdev = {
diff -Nru a/drivers/char/scx200_wdt.c b/drivers/char/scx200_wdt.c
--- a/drivers/char/scx200_wdt.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/scx200_wdt.c	Sun Nov 10 19:28:40 2002
@@ -128,7 +128,7 @@
 
 static struct notifier_block scx200_wdt_notifier =
 {
-        notifier_call: scx200_wdt_notify_sys
+        .notifier_call = scx200_wdt_notify_sys
 };
 
 static ssize_t scx200_wdt_write(struct file *file, const char *data, 
diff -Nru a/drivers/char/serial167.c b/drivers/char/serial167.c
--- a/drivers/char/serial167.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/serial167.c	Sun Nov 10 19:28:39 2002
@@ -2827,12 +2827,12 @@
 
 
 static struct console sercons = {
-	name:		"ttyS",
-	write:		serial167_console_write,
-	device:		serial167_console_device,
-	setup:		serial167_console_setup,
-	flags:		CON_PRINTBUFFER,
-	index:		-1,
+	.name		= "ttyS",
+	.write		= serial167_console_write,
+	.device		= serial167_console_device,
+	.setup		= serial167_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
 };
 
 
diff -Nru a/drivers/char/serial_tx3912.c b/drivers/char/serial_tx3912.c
--- a/drivers/char/serial_tx3912.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/serial_tx3912.c	Sun Nov 10 19:28:40 2002
@@ -48,16 +48,16 @@
  * Used by generic serial driver to access hardware
  */
 static struct real_driver rs_real_driver = { 
-	disable_tx_interrupts: rs_disable_tx_interrupts, 
-	enable_tx_interrupts:  rs_enable_tx_interrupts, 
-	disable_rx_interrupts: rs_disable_rx_interrupts, 
-	enable_rx_interrupts:  rs_enable_rx_interrupts, 
-	get_CD:                rs_get_CD, 
-	shutdown_port:         rs_shutdown_port,  
-	set_real_termios:      rs_set_real_termios,  
-	chars_in_buffer:       rs_chars_in_buffer, 
-	close:                 rs_close, 
-	hungup:                rs_hungup,
+	.disable_tx_interrupts = rs_disable_tx_interrupts, 
+	.enable_tx_interrupts  = rs_enable_tx_interrupts, 
+	.disable_rx_interrupts = rs_disable_rx_interrupts, 
+	.enable_rx_interrupts  = rs_enable_rx_interrupts, 
+	.get_CD                = rs_get_CD, 
+	.shutdown_port         = rs_shutdown_port,  
+	.set_real_termios      = rs_set_real_termios,  
+	.chars_in_buffer       = rs_chars_in_buffer, 
+	.close                 = rs_close, 
+	.hungup                = rs_hungup,
 }; 
 
 /*
@@ -1046,12 +1046,12 @@
 }
 
 static struct console sercons = {
-	name:     "ttyS",
-	write:    serial_console_write,
-	device:   serial_console_device,
-	setup:    serial_console_setup,
-	flags:    CON_PRINTBUFFER,
-	index:    -1
+	.name     = "ttyS",
+	.write    = serial_console_write,
+	.device   = serial_console_device,
+	.setup    = serial_console_setup,
+	.flags    = CON_PRINTBUFFER,
+	.index    = -1
 };
 
 void __init tx3912_console_init(void)
diff -Nru a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c
--- a/drivers/char/sh-sci.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/char/sh-sci.c	Sun Nov 10 19:28:41 2002
@@ -1259,12 +1259,12 @@
 }
 
 static struct console sercons = {
-	name:		"ttySC",
-	write:		serial_console_write,
-	device:		serial_console_device,
-	setup:		serial_console_setup,
-	flags:		CON_PRINTBUFFER,
-	index:		-1,
+	.name		= "ttySC",
+	.write		= serial_console_write,
+	.device		= serial_console_device,
+	.setup		= serial_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
 };
 
 /*
diff -Nru a/drivers/char/shwdt.c b/drivers/char/shwdt.c
--- a/drivers/char/shwdt.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/char/shwdt.c	Sun Nov 10 19:28:38 2002
@@ -325,12 +325,12 @@
 }
 
 static struct file_operations sh_wdt_fops = {
-	owner:		THIS_MODULE,
-	read:		sh_wdt_read,
-	write:		sh_wdt_write,
-	ioctl:		sh_wdt_ioctl,
-	open:		sh_wdt_open,
-	release:	sh_wdt_close,
+	.owner		= THIS_MODULE,
+	.read		= sh_wdt_read,
+	.write		= sh_wdt_write,
+	.ioctl		= sh_wdt_ioctl,
+	.open		= sh_wdt_open,
+	.release	= sh_wdt_close,
 };
 
 static struct watchdog_info sh_wdt_info = {
diff -Nru a/drivers/char/softdog.c b/drivers/char/softdog.c
--- a/drivers/char/softdog.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/softdog.c	Sun Nov 10 19:28:39 2002
@@ -67,9 +67,8 @@
  
 static void watchdog_fire(unsigned long);
 
-static struct timer_list watchdog_ticktock = {
-	function:	watchdog_fire,
-};
+static struct timer_list watchdog_ticktock =
+		TIMER_INITIALIZER(watchdog_fire, 0, 0);
 static int timer_alive;
 
 
diff -Nru a/drivers/char/sonypi.c b/drivers/char/sonypi.c
--- a/drivers/char/sonypi.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/sonypi.c	Sun Nov 10 19:28:40 2002
@@ -613,13 +613,13 @@
 }
 
 static struct file_operations sonypi_misc_fops = {
-	owner:		THIS_MODULE,
-	read:		sonypi_misc_read,
-	poll:		sonypi_misc_poll,
-	open:		sonypi_misc_open,
-	release:	sonypi_misc_release,
-	fasync: 	sonypi_misc_fasync,
-	ioctl:		sonypi_misc_ioctl,
+	.owner		= THIS_MODULE,
+	.read		= sonypi_misc_read,
+	.poll		= sonypi_misc_poll,
+	.open		= sonypi_misc_open,
+	.release	= sonypi_misc_release,
+	.fasync 	= sonypi_misc_fasync,
+	.ioctl		= sonypi_misc_ioctl,
 };
 
 struct miscdevice sonypi_misc_device = {
diff -Nru a/drivers/char/stallion.c b/drivers/char/stallion.c
--- a/drivers/char/stallion.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/stallion.c	Sun Nov 10 19:28:40 2002
@@ -170,8 +170,8 @@
  *	at 9600, 8 data bits, 1 stop bit.
  */
 static struct termios		stl_deftermios = {
-	c_cflag:	(B9600 | CS8 | CREAD | HUPCL | CLOCAL),
-	c_cc:		INIT_C_CC,
+	.c_cflag	= (B9600 | CS8 | CREAD | HUPCL | CLOCAL),
+	.c_cc		= INIT_C_CC,
 };
 
 /*
@@ -745,8 +745,8 @@
  *	to get at port stats - only not using the port device itself.
  */
 static struct file_operations	stl_fsiomem = {
-	owner:		THIS_MODULE,
-	ioctl:		stl_memioctl,
+	.owner		= THIS_MODULE,
+	.ioctl		= stl_memioctl,
 };
 
 /*****************************************************************************/
diff -Nru a/drivers/char/sx.c b/drivers/char/sx.c
--- a/drivers/char/sx.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/sx.c	Sun Nov 10 19:28:39 2002
@@ -419,8 +419,8 @@
  */
 
 static struct file_operations sx_fw_fops = {
-	owner:		THIS_MODULE,
-	ioctl:		sx_fw_ioctl,
+	.owner		= THIS_MODULE,
+	.ioctl		= sx_fw_ioctl,
 };
 
 static struct miscdevice sx_fw_device = {
diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c
--- a/drivers/char/synclink.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/synclink.c	Sun Nov 10 19:28:39 2002
@@ -932,10 +932,10 @@
 MODULE_LICENSE("GPL");
 
 static struct pci_driver synclink_pci_driver = {
-	name:		"synclink",
-	id_table:	synclink_pci_tbl,
-	probe:		synclink_init_one,
-	remove:		__devexit_p(synclink_remove_one),
+	.name		= "synclink",
+	.id_table	= synclink_pci_tbl,
+	.probe		= synclink_init_one,
+	.remove		= __devexit_p(synclink_remove_one),
 };
 
 static struct tty_driver serial_driver, callout_driver;
diff -Nru a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c
--- a/drivers/char/synclinkmp.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/char/synclinkmp.c	Sun Nov 10 19:28:37 2002
@@ -517,10 +517,10 @@
 MODULE_LICENSE("GPL");
 
 static struct pci_driver synclinkmp_pci_driver = {
-	name:		"synclinkmp",
-	id_table:	synclinkmp_pci_tbl,
-	probe:		synclinkmp_init_one,
-	remove:		__devexit_p(synclinkmp_remove_one),
+	.name		= "synclinkmp",
+	.id_table	= synclinkmp_pci_tbl,
+	.probe		= synclinkmp_init_one,
+	.remove		= __devexit_p(synclinkmp_remove_one),
 };
 
 
diff -Nru a/drivers/char/sysrq.c b/drivers/char/sysrq.c
--- a/drivers/char/sysrq.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/char/sysrq.c	Sun Nov 10 19:28:41 2002
@@ -59,9 +59,9 @@
 	console_loglevel = i;
 }	
 static struct sysrq_key_op sysrq_loglevel_op = {
-	handler:	sysrq_handle_loglevel,
-	help_msg:	"loglevel0-8",
-	action_msg:	"Changing Loglevel",
+	.handler	= sysrq_handle_loglevel,
+	.help_msg	= "loglevel0-8",
+	.action_msg	= "Changing Loglevel",
 };
 
 
@@ -75,9 +75,9 @@
 	reset_vc(fg_console);
 }
 static struct sysrq_key_op sysrq_SAK_op = {
-	handler:	sysrq_handle_SAK,
-	help_msg:	"saK",
-	action_msg:	"SAK",
+	.handler	= sysrq_handle_SAK,
+	.help_msg	= "saK",
+	.action_msg	= "SAK",
 };
 #endif
 
@@ -92,9 +92,9 @@
 		kbd->kbdmode = VC_XLATE;
 }
 static struct sysrq_key_op sysrq_unraw_op = {
-	handler:	sysrq_handle_unraw,
-	help_msg:	"unRaw",
-	action_msg:	"Keyboard mode set to XLATE",
+	.handler	= sysrq_handle_unraw,
+	.help_msg	= "unRaw",
+	.action_msg	= "Keyboard mode set to XLATE",
 };
 #endif /* CONFIG_VT */
 
@@ -105,9 +105,9 @@
 	machine_restart(NULL);
 }
 static struct sysrq_key_op sysrq_reboot_op = {
-	handler:	sysrq_handle_reboot,
-	help_msg:	"reBoot",
-	action_msg:	"Resetting",
+	.handler	= sysrq_handle_reboot,
+	.help_msg	= "reBoot",
+	.action_msg	= "Resetting",
 };
 
 
@@ -235,9 +235,9 @@
 	wakeup_bdflush(0);
 }
 static struct sysrq_key_op sysrq_sync_op = {
-	handler:	sysrq_handle_sync,
-	help_msg:	"Sync",
-	action_msg:	"Emergency Sync",
+	.handler	= sysrq_handle_sync,
+	.help_msg	= "Sync",
+	.action_msg	= "Emergency Sync",
 };
 
 static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
@@ -247,9 +247,9 @@
 	wakeup_bdflush(0);
 }
 static struct sysrq_key_op sysrq_mountro_op = {
-	handler:	sysrq_handle_mountro,
-	help_msg:	"Unmount",
-	action_msg:	"Emergency Remount R/O",
+	.handler	= sysrq_handle_mountro,
+	.help_msg	= "Unmount",
+	.action_msg	= "Emergency Remount R/O",
 };
 
 /* END SYNC SYSRQ HANDLERS BLOCK */
@@ -264,9 +264,9 @@
 		show_regs(pt_regs);
 }
 static struct sysrq_key_op sysrq_showregs_op = {
-	handler:	sysrq_handle_showregs,
-	help_msg:	"showPc",
-	action_msg:	"Show Regs",
+	.handler	= sysrq_handle_showregs,
+	.help_msg	= "showPc",
+	.action_msg	= "Show Regs",
 };
 
 
@@ -276,9 +276,9 @@
 	show_state();
 }
 static struct sysrq_key_op sysrq_showstate_op = {
-	handler:	sysrq_handle_showstate,
-	help_msg:	"showTasks",
-	action_msg:	"Show State",
+	.handler	= sysrq_handle_showstate,
+	.help_msg	= "showTasks",
+	.action_msg	= "Show State",
 };
 
 
@@ -288,9 +288,9 @@
 	show_mem();
 }
 static struct sysrq_key_op sysrq_showmem_op = {
-	handler:	sysrq_handle_showmem,
-	help_msg:	"showMem",
-	action_msg:	"Show Memory",
+	.handler	= sysrq_handle_showmem,
+	.help_msg	= "showMem",
+	.action_msg	= "Show Memory",
 };
 
 /* SHOW SYSRQ HANDLERS BLOCK */
@@ -318,16 +318,16 @@
 	console_loglevel = 8;
 }
 static struct sysrq_key_op sysrq_term_op = {
-	handler:	sysrq_handle_term,
-	help_msg:	"tErm",
-	action_msg:	"Terminate All Tasks",
+	.handler	= sysrq_handle_term,
+	.help_msg	= "tErm",
+	.action_msg	= "Terminate All Tasks",
 };
 
 #ifdef CONFIG_VOYAGER
 static struct sysrq_key_op sysrq_voyager_dump_op = {
-	handler:	voyager_dump,
-	help_msg:	"voyager",
-	action_msg:	"Dump Voyager Status\n",
+	.handler	= voyager_dump,
+	.help_msg	= "voyager",
+	.action_msg	= "Dump Voyager Status\n",
 };
 #endif
 
@@ -338,9 +338,9 @@
 	console_loglevel = 8;
 }
 static struct sysrq_key_op sysrq_kill_op = {
-	handler:	sysrq_handle_kill,
-	help_msg:	"kIll",
-	action_msg:	"Kill All Tasks",
+	.handler	= sysrq_handle_kill,
+	.help_msg	= "kIll",
+	.action_msg	= "Kill All Tasks",
 };
 
 /* END SIGNAL SYSRQ HANDLERS BLOCK */
diff -Nru a/drivers/char/tipar.c b/drivers/char/tipar.c
--- a/drivers/char/tipar.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/tipar.c	Sun Nov 10 19:28:40 2002
@@ -381,13 +381,13 @@
 /* ----- kernel module registering ------------------------------------ */
 
 static struct file_operations tipar_fops = {
-	owner:THIS_MODULE,
-	llseek:no_llseek,
-	read:tipar_read,
-	write:tipar_write,
-	ioctl:tipar_ioctl,
-	open:tipar_open,
-	release:tipar_close,
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.read = tipar_read,
+	.write = tipar_write,
+	.ioctl = tipar_ioctl,
+	.open = tipar_open,
+	.release = tipar_close,
 };
 
 /* --- initialisation code ------------------------------------- */
diff -Nru a/drivers/char/toshiba.c b/drivers/char/toshiba.c
--- a/drivers/char/toshiba.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/char/toshiba.c	Sun Nov 10 19:28:41 2002
@@ -91,8 +91,8 @@
 
 
 static struct file_operations tosh_fops = {
-	owner:		THIS_MODULE,
-	ioctl:		tosh_ioctl,
+	.owner		= THIS_MODULE,
+	.ioctl		= tosh_ioctl,
 };
 
 static struct miscdevice tosh_device = {
diff -Nru a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
--- a/drivers/char/tpqic02.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/char/tpqic02.c	Sun Nov 10 19:28:39 2002
@@ -2565,13 +2565,13 @@
 
 /* These are (most) of the interface functions: */
 static struct file_operations qic02_tape_fops = {
-	owner:THIS_MODULE,
-	llseek:no_llseek,
-	read:qic02_do_tape_read,
-	write:qic02_do_tape_write,
-	ioctl:qic02_do_tape_ioctl,
-	open:qic02_tape_open,
-	release:qic02_tape_release,
+	.owner = THIS_MODULE,
+	.llseek = no_llseek,
+	.read = qic02_do_tape_read,
+	.write = qic02_do_tape_write,
+	.ioctl = qic02_do_tape_ioctl,
+	.open = qic02_tape_open,
+	.release = qic02_tape_release,
 };
 
 
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/tty_io.c	Sun Nov 10 19:28:40 2002
@@ -404,23 +404,23 @@
 }
 
 static struct file_operations tty_fops = {
-	llseek:		no_llseek,
-	read:		tty_read,
-	write:		tty_write,
-	poll:		tty_poll,
-	ioctl:		tty_ioctl,
-	open:		tty_open,
-	release:	tty_release,
-	fasync:		tty_fasync,
+	.llseek		= no_llseek,
+	.read		= tty_read,
+	.write		= tty_write,
+	.poll		= tty_poll,
+	.ioctl		= tty_ioctl,
+	.open		= tty_open,
+	.release	= tty_release,
+	.fasync		= tty_fasync,
 };
 
 static struct file_operations hung_up_tty_fops = {
-	llseek:		no_llseek,
-	read:		hung_up_tty_read,
-	write:		hung_up_tty_write,
-	poll:		hung_up_tty_poll,
-	ioctl:		hung_up_tty_ioctl,
-	release:	tty_release,
+	.llseek		= no_llseek,
+	.read		= hung_up_tty_read,
+	.write		= hung_up_tty_write,
+	.poll		= hung_up_tty_poll,
+	.ioctl		= hung_up_tty_ioctl,
+	.release	= tty_release,
 };
 
 /*
diff -Nru a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
--- a/drivers/char/vc_screen.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/char/vc_screen.c	Sun Nov 10 19:28:38 2002
@@ -464,10 +464,10 @@
 }
 
 static struct file_operations vcs_fops = {
-	llseek:		vcs_lseek,
-	read:		vcs_read,
-	write:		vcs_write,
-	open:		vcs_open,
+	.llseek		= vcs_lseek,
+	.read		= vcs_read,
+	.write		= vcs_write,
+	.open		= vcs_open,
 };
 
 static devfs_handle_t devfs_handle;
diff -Nru a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
--- a/drivers/char/vme_scc.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/char/vme_scc.c	Sun Nov 10 19:28:36 2002
@@ -1094,12 +1094,12 @@
 
 
 static struct console sercons = {
-	name:		"ttyS",
-	write:		scc_console_write,
-	device:		scc_console_device,
-	setup:		scc_console_setup,
-	flags:		CON_PRINTBUFFER,
-	index:		-1,
+	.name		= "ttyS",
+	.write		= scc_console_write,
+	.device		= scc_console_device,
+	.setup		= scc_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
 };
 
 
diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c
--- a/drivers/char/vt.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/char/vt.c	Sun Nov 10 19:28:41 2002
@@ -2172,12 +2172,12 @@
 }
 
 struct console vt_console_driver = {
-	name:		"tty",
-	write:		vt_console_print,
-	device:		vt_console_device,
-	unblank:	unblank_screen,
-	flags:		CON_PRINTBUFFER,
-	index:		-1,
+	.name		= "tty",
+	.write		= vt_console_print,
+	.device		= vt_console_device,
+	.unblank	= unblank_screen,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
 };
 #endif
 
diff -Nru a/drivers/char/w83877f_wdt.c b/drivers/char/w83877f_wdt.c
--- a/drivers/char/w83877f_wdt.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/w83877f_wdt.c	Sun Nov 10 19:28:40 2002
@@ -269,13 +269,13 @@
 }
 
 static struct file_operations wdt_fops = {
-	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	read:		fop_read,
-	write:		fop_write,
-	open:		fop_open,
-	release:	fop_close,
-	ioctl:		fop_ioctl
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= fop_read,
+	.write		= fop_write,
+	.open		= fop_open,
+	.release	= fop_close,
+	.ioctl		= fop_ioctl
 };
 
 static struct miscdevice wdt_miscdev = {
diff -Nru a/drivers/char/wdt.c b/drivers/char/wdt.c
--- a/drivers/char/wdt.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/wdt.c	Sun Nov 10 19:28:40 2002
@@ -438,13 +438,13 @@
  
  
 static struct file_operations wdt_fops = {
-	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	read:		wdt_read,
-	write:		wdt_write,
-	ioctl:		wdt_ioctl,
-	open:		wdt_open,
-	release:	wdt_release,
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= wdt_read,
+	.write		= wdt_write,
+	.ioctl		= wdt_ioctl,
+	.open		= wdt_open,
+	.release	= wdt_release,
 };
 
 static struct miscdevice wdt_miscdev=
diff -Nru a/drivers/char/wdt285.c b/drivers/char/wdt285.c
--- a/drivers/char/wdt285.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/char/wdt285.c	Sun Nov 10 19:28:38 2002
@@ -150,11 +150,11 @@
 
 static struct file_operations watchdog_fops=
 {
-	owner:		THIS_MODULE,
-	write:		watchdog_write,
-	ioctl:		watchdog_ioctl,
-	open:		watchdog_open,
-	release:	watchdog_release,
+	.owner		= THIS_MODULE,
+	.write		= watchdog_write,
+	.ioctl		= watchdog_ioctl,
+	.open		= watchdog_open,
+	.release	= watchdog_release,
 };
 
 static struct miscdevice watchdog_miscdev=
diff -Nru a/drivers/char/wdt977.c b/drivers/char/wdt977.c
--- a/drivers/char/wdt977.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/wdt977.c	Sun Nov 10 19:28:40 2002
@@ -311,11 +311,11 @@
 
 static struct file_operations wdt977_fops=
 {
-	owner:		THIS_MODULE,
-	write:		wdt977_write,
-	ioctl:		wdt977_ioctl,
-	open:		wdt977_open,
-	release:	wdt977_release,
+	.owner		= THIS_MODULE,
+	.write		= wdt977_write,
+	.ioctl		= wdt977_ioctl,
+	.open		= wdt977_open,
+	.release	= wdt977_release,
 };
 
 static struct miscdevice wdt977_miscdev=
diff -Nru a/drivers/char/wdt_pci.c b/drivers/char/wdt_pci.c
--- a/drivers/char/wdt_pci.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/char/wdt_pci.c	Sun Nov 10 19:28:40 2002
@@ -472,13 +472,13 @@
  
  
 static struct file_operations wdtpci_fops = {
-	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	read:		wdtpci_read,
-	write:		wdtpci_write,
-	ioctl:		wdtpci_ioctl,
-	open:		wdtpci_open,
-	release:	wdtpci_release,
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= wdtpci_read,
+	.write		= wdtpci_write,
+	.ioctl		= wdtpci_ioctl,
+	.open		= wdtpci_open,
+	.release	= wdtpci_release,
 };
 
 static struct miscdevice wdtpci_miscdev=
@@ -601,10 +601,10 @@
 
 
 static struct pci_driver wdtpci_driver = {
-	name:		"wdt-pci",
-	id_table:	wdtpci_pci_tbl,
-	probe:		wdtpci_init_one,
-	remove:		__devexit_p(wdtpci_remove_one),
+	.name		= "wdt-pci",
+	.id_table	= wdtpci_pci_tbl,
+	.probe		= wdtpci_init_one,
+	.remove		= __devexit_p(wdtpci_remove_one),
 };
 
 
diff -Nru a/drivers/fc4/fc.c b/drivers/fc4/fc.c
--- a/drivers/fc4/fc.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/fc4/fc.c	Sun Nov 10 19:28:40 2002
@@ -553,6 +553,7 @@
 	l->count = count;
 	FCND(("FCP Init for %d channels\n", count))
 	init_MUTEX_LOCKED(&l->sem);
+	init_timer(&l->timer);
 	l->timer.function = fcp_login_timeout;
 	l->timer.data = (unsigned long)l;
 	atomic_set (&l->todo, count);
diff -Nru a/drivers/hotplug/Kconfig b/drivers/hotplug/Kconfig
--- a/drivers/hotplug/Kconfig	Sun Nov 10 19:28:39 2002
+++ b/drivers/hotplug/Kconfig	Sun Nov 10 19:28:39 2002
@@ -73,5 +73,48 @@
 
 	  When in doubt, say N.
 
+config HOTPLUG_PCI_CPCI
+	tristate "CompactPCI Hotplug driver"
+	depends on HOTPLUG_PCI
+	help
+	  Say Y here if you have a CompactPCI system card with CompactPCI
+	  hotswap support per the PICMG 2.1 specification.
+
+	  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 cpci_hotplug.o. If you want to compile it
+	  as a module, say M here and read <file:Documentation/modules.txt>.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_CPCI_ZT5550
+	tristate "Ziatech ZT5550 CompactPCI Hotplug driver"
+	depends on HOTPLUG_PCI_CPCI && X86
+	help
+	  Say Y here if you have an Performance Technologies (formerly Intel,
+          formerly just Ziatech) Ziatech ZT5550 CompactPCI system card.
+
+	  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 cpcihp_zt5550.o. If you want to compile it
+	  as a module, say M here and read <file:Documentation/modules.txt>.
+
+	  When in doubt, say N.
+
+config HOTPLUG_PCI_CPCI_GENERIC
+	tristate "Generic port I/O CompactPCI Hotplug driver"
+	depends on HOTPLUG_PCI_CPCI && X86
+	help
+	  Say Y here if you have a CompactPCI system card that exposes the #ENUM
+	  hotswap signal as a bit in a system register that can be read through
+	  standard port I/O.
+
+	  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 cpcihp_generic.o. If you want to compile it
+	  as a module, say M here and read <file:Documentation/modules.txt>.
+
+	  When in doubt, say N.
+
 endmenu
 
diff -Nru a/drivers/hotplug/Makefile b/drivers/hotplug/Makefile
--- a/drivers/hotplug/Makefile	Sun Nov 10 19:28:40 2002
+++ b/drivers/hotplug/Makefile	Sun Nov 10 19:28:40 2002
@@ -2,12 +2,15 @@
 # Makefile for the Linux kernel pci hotplug controller drivers.
 #
 
-export-objs	:= pci_hotplug_core.o pci_hotplug_util.o
+export-objs	:= pci_hotplug_core.o pci_hotplug_util.o cpci_hotplug_core.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)		+= acpiphp.o
+obj-$(CONFIG_HOTPLUG_PCI_CPCI)		+= cpci_hotplug.o
+obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550)	+= cpcihp_zt5550.o
+obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC)	+= cpcihp_generic.o
 
 pci_hotplug-objs	:=	pci_hotplug_core.o	\
 				pci_hotplug_util.o
@@ -27,6 +30,9 @@
 				acpiphp_glue.o	\
 				acpiphp_pci.o	\
 				acpiphp_res.o
+
+cpci_hotplug-objs	:=	cpci_hotplug_core.o	\
+				cpci_hotplug_pci.o
 
 ifdef CONFIG_HOTPLUG_PCI_ACPI
   EXTRA_CFLAGS  += -D_LINUX -I$(TOPDIR)/drivers/acpi
diff -Nru a/drivers/hotplug/acpiphp.h b/drivers/hotplug/acpiphp.h
--- a/drivers/hotplug/acpiphp.h	Sun Nov 10 19:28:41 2002
+++ b/drivers/hotplug/acpiphp.h	Sun Nov 10 19:28:41 2002
@@ -41,12 +41,12 @@
 #define dbg(format, arg...)					\
 	do {							\
 		if (acpiphp_debug)				\
-			printk (KERN_DEBUG "%s: " format "\n",	\
+			printk(KERN_DEBUG "%s: " format,	\
 				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 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)
 
 #define SLOT_MAGIC	0x67267322
 /* name size which is used for entries in pcihpfs */
diff -Nru a/drivers/hotplug/acpiphp_core.c b/drivers/hotplug/acpiphp_core.c
--- a/drivers/hotplug/acpiphp_core.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/hotplug/acpiphp_core.c	Sun Nov 10 19:28:40 2002
@@ -50,6 +50,7 @@
 	#define MY_NAME	THIS_MODULE->name
 #endif
 
+static int debug;
 int acpiphp_debug;
 
 /* local variables */
@@ -62,8 +63,8 @@
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-MODULE_PARM(acpiphp_debug, "i");
-MODULE_PARM_DESC(acpiphp_debug, "Debugging mode enabled or not");
+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);
@@ -95,15 +96,15 @@
 static inline int slot_paranoia_check (struct slot *slot, const char *function)
 {
 	if (!slot) {
-		dbg("%s - slot == NULL", function);
+		dbg("%s - slot == NULL\n", function);
 		return -1;
 	}
 	if (slot->magic != SLOT_MAGIC) {
-		dbg("%s - bad magic number for slot", function);
+		dbg("%s - bad magic number for slot\n", function);
 		return -1;
 	}
 	if (!slot->hotplug_slot) {
-		dbg("%s - slot->hotplug_slot == NULL!", function);
+		dbg("%s - slot->hotplug_slot == NULL!\n", function);
 		return -1;
 	}
 	return 0;
@@ -111,16 +112,16 @@
 
 
 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);
+		dbg("%s - hotplug_slot == NULL\n", function);
 		return NULL;
 	}
 
 	slot = (struct slot *)hotplug_slot->private;
-	if (slot_paranoia_check (slot, function))
+	if (slot_paranoia_check(slot, function))
                 return NULL;
 	return slot;
 }
@@ -135,16 +136,16 @@
  */
 static int enable_slot (struct hotplug_slot *hotplug_slot)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	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);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	/* enable the specified slot */
-	retval = acpiphp_enable_slot (slot->acpi_slot);
+	retval = acpiphp_enable_slot(slot->acpi_slot);
 
 	return retval;
 }
@@ -159,16 +160,16 @@
  */
 static int disable_slot (struct hotplug_slot *hotplug_slot)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	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);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	/* disable the specified slot */
-	retval = acpiphp_disable_slot (slot->acpi_slot);
+	retval = acpiphp_disable_slot(slot->acpi_slot);
 
 	return retval;
 }
@@ -185,8 +186,8 @@
 static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status)
 {
 	int retval = 0;
-	
-	dbg ("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	switch (status) {
 		case 0:
@@ -213,15 +214,15 @@
  */
 static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	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");
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	err("No hardware tests are defined for this driver\n");
 	retval = -ENODEV;
 
 	return retval;
@@ -239,15 +240,15 @@
  */
 static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	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);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_power_status(slot->acpi_slot);
 
 	return retval;
 }
@@ -263,8 +264,8 @@
 static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
 	int retval = 0;
-	
-	dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name);
+
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
 	*value = hotplug_slot->info->attention_status;
 
@@ -283,15 +284,15 @@
  */
 static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	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);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_latch_status(slot->acpi_slot);
 
 	return retval;
 }
@@ -308,15 +309,15 @@
  */
 static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
+	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);
+	dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+	*value = acpiphp_get_adapter_status(slot->acpi_slot);
 
 	return retval;
 }
@@ -325,11 +326,11 @@
 /* return dummy value because ACPI doesn't provide any method... */
 static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
 	if (slot == NULL)
 		return -ENODEV;
-	
+
 	*value = PCI_SPEED_UNKNOWN;
 
 	return 0;
@@ -339,11 +340,11 @@
 /* return dummy value because ACPI doesn't provide any method... */
 static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value)
 {
-	struct slot *slot = get_slot (hotplug_slot, __FUNCTION__);
-	
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
 	if (slot == NULL)
 		return -ENODEV;
-	
+
 	*value = PCI_SPEED_UNKNOWN;
 
 	return 0;
@@ -375,10 +376,10 @@
  */
 static void make_slot_name (struct slot *slot)
 {
-	snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x",
-		  slot->acpi_slot->sun,
-		  slot->acpi_slot->bridge->bus,
-		  slot->acpi_slot->device);
+	snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x",
+		 slot->acpi_slot->sun,
+		 slot->acpi_slot->bridge->bus,
+		 slot->acpi_slot->device);
 }
 
 /**
@@ -392,31 +393,31 @@
 	int i;
 
 	for (i = 0; i < num_slots; ++i) {
-		slot = kmalloc (sizeof (struct slot), GFP_KERNEL);
+		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);
+		slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
 		if (!slot->hotplug_slot) {
-			kfree (slot);
+			kfree(slot);
 			return -ENOMEM;
 		}
-		memset(slot->hotplug_slot, 0, sizeof (struct hotplug_slot));
+		memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot));
 
-		slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
 		if (!slot->hotplug_slot->info) {
-			kfree (slot->hotplug_slot);
-			kfree (slot);
+			kfree(slot->hotplug_slot);
+			kfree(slot);
 			return -ENOMEM;
 		}
-		memset(slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info));
+		memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info));
 
-		slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL);
+		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);
+			kfree(slot->hotplug_slot->info);
+			kfree(slot->hotplug_slot);
+			kfree(slot);
 			return -ENOMEM;
 		}
 
@@ -426,27 +427,27 @@
 		slot->hotplug_slot->private = slot;
 		slot->hotplug_slot->ops = &acpi_hotplug_slot_ops;
 
-		slot->acpi_slot = get_slot_from_id (i);
+		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);
+		make_slot_name(slot);
 
-		retval = pci_hp_register (slot->hotplug_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);
+			err("pci_hp_register failed with error %d\n", 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);
-		info("Slot [%s] registered", slot->hotplug_slot->name);
+		list_add(&slot->slot_list, &slot_list);
+		info("Slot [%s] registered\n", slot->hotplug_slot->name);
 	}
 
 	return retval;
@@ -459,13 +460,13 @@
 	struct slot *slot;
 
 	list_for_each_safe (tmp, n, &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);
+		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;
@@ -476,7 +477,9 @@
 {
 	int retval;
 
-	info (DRIVER_DESC " version: " DRIVER_VERSION);
+	info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+	acpiphp_debug = debug;
 
 	/* read all the ACPI info from the system */
 	retval = init_acpi();
diff -Nru a/drivers/hotplug/acpiphp_glue.c b/drivers/hotplug/acpiphp_glue.c
--- a/drivers/hotplug/acpiphp_glue.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/hotplug/acpiphp_glue.c	Sun Nov 10 19:28:38 2002
@@ -153,7 +153,7 @@
 	for (slot = bridge->slots; slot; slot = slot->next)
 		if (slot->device == device) {
 			if (slot->sun != sun)
-				warn("sibling found, but _SUN doesn't match!");
+				warn("sibling found, but _SUN doesn't match!\n");
 			break;
 		}
 
@@ -177,7 +177,7 @@
 
 		bridge->nr_slots++;
 
-		dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:0x%x",
+		dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n",
 		    slot->bridge->bus, slot->device, slot->sun);
 	}
 
@@ -202,7 +202,7 @@
 					     newfunc);
 
 	if (ACPI_FAILURE(status)) {
-		err("failed to register interrupt notify handler");
+		err("failed to register interrupt notify handler\n");
 		return status;
 	}
 
@@ -302,21 +302,21 @@
 			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);
+					dbg("resource type: prefetchable memory 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
 					res = acpiphp_make_resource(min_address_range,
 							    address_length);
 					if (!res) {
-						err("out of memory");
+						err("out of memory\n");
 						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);
+					dbg("resource type: memory 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
 					res = acpiphp_make_resource(min_address_range,
 							    address_length);
 					if (!res) {
-						err("out of memory");
+						err("out of memory\n");
 						return;
 					}
 					res->next = bridge->mem_head;
@@ -324,22 +324,22 @@
 				}
 				break;
 			case ACPI_IO_RANGE:
-				dbg("resource type: io 0x%x - 0x%x", (u32)min_address_range, (u32)max_address_range);
+				dbg("resource type: io 0x%x - 0x%x\n", (u32)min_address_range, (u32)max_address_range);
 				res = acpiphp_make_resource(min_address_range,
 						    address_length);
 				if (!res) {
-					err("out of memory");
+					err("out of memory\n");
 					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);
+				dbg("resource type: bus number %d - %d\n", (u32)min_address_range, (u32)max_address_range);
 				res = acpiphp_make_resource(min_address_range,
 						    address_length);
 				if (!res) {
-					err("out of memory");
+					err("out of memory\n");
 					return;
 				}
 				res->next = bridge->bus_head;
@@ -356,10 +356,9 @@
 	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:");
+
+	dbg("ACPI _CRS resource:\n");
 	acpiphp_dump_resource(bridge);
-#endif
 }
 
 
@@ -368,7 +367,7 @@
 {
 	const struct list_head *l;
 
-	list_for_each(l, list) {
+	list_for_each (l, list) {
 		struct pci_bus *b = pci_bus_b(l);
 		if (b->number == bus)
 			return b;
@@ -404,7 +403,7 @@
 	status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer);
 
 	if (ACPI_FAILURE(status)) {
-		dbg("_HPP evaluation failed");
+		dbg("_HPP evaluation failed\n");
 		return;
 	}
 
@@ -412,13 +411,13 @@
 
 	if (!package || package->type != ACPI_TYPE_PACKAGE ||
 	    package->package.count != 4 || !package->package.elements) {
-		err("invalid _HPP object; ignoring");
+		err("invalid _HPP object; ignoring\n");
 		goto err_exit;
 	}
 
 	for (i = 0; i < 4; i++) {
 		if (package->package.elements[i].type != ACPI_TYPE_INTEGER) {
-			err("invalid _HPP parameter type; ignoring");
+			err("invalid _HPP parameter type; ignoring\n");
 			goto err_exit;
 		}
 	}
@@ -428,7 +427,7 @@
 	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)",
+	dbg("_HPP parameter = (%02x, %02x, %02x, %02x)\n",
 	    bridge->hpp.cache_line_size,
 	    bridge->hpp.latency_timer,
 	    bridge->hpp.enable_SERR,
@@ -463,15 +462,13 @@
 					     bridge);
 
 	if (ACPI_FAILURE(status)) {
-		err("failed to register interrupt notify handler");
+		err("failed to register interrupt notify handler\n");
 	}
 
 	list_add(&bridge->list, &bridge_list);
 
-#if 1
-	dbg("Bridge resource:");
+	dbg("Bridge resource:\n");
 	acpiphp_dump_resource(bridge);
-#endif
 }
 
 
@@ -507,7 +504,7 @@
 	status = acpi_get_current_resources(handle, &buffer);
 
 	if (ACPI_FAILURE(status)) {
-		err("failed to decode bridge resources");
+		err("failed to decode bridge resources\n");
 		kfree(bridge);
 		return;
 	}
@@ -535,7 +532,7 @@
 
 	bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
 	if (bridge == NULL) {
-		err("out of memory");
+		err("out of memory\n");
 		return;
 	}
 
@@ -547,14 +544,14 @@
 
 	bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn));
 	if (!bridge->pci_dev) {
-		err("Can't get pci_dev");
+		err("Can't get pci_dev\n");
 		kfree(bridge);
 		return;
 	}
 
 	bridge->pci_bus = bridge->pci_dev->subordinate;
 	if (!bridge->pci_bus) {
-		err("This is not a PCI-to-PCI bridge!");
+		err("This is not a PCI-to-PCI bridge!\n");
 		kfree(bridge);
 		return;
 	}
@@ -580,10 +577,10 @@
 		limit = ((limit << 8) & 0xf000) + 0xfff;
 		bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
 		if (!bridge->io_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("16bit I/O range: %04x-%04x",
+		dbg("16bit I/O range: %04x-%04x\n",
 		    (u32)bridge->io_head->base,
 		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
 		break;
@@ -594,18 +591,18 @@
 		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");
+			err("out of memory\n");
 			return;
 		}
-		dbg("32bit I/O range: %08x-%08x",
+		dbg("32bit I/O range: %08x-%08x\n",
 		    (u32)bridge->io_head->base,
 		    (u32)(bridge->io_head->base + bridge->io_head->length - 1));
 		break;
 	case 0x0f:
-		dbg("I/O space unsupported");
+		dbg("I/O space unsupported\n");
 		break;
 	default:
-		warn("Unknown I/O range type");
+		warn("Unknown I/O range type\n");
 	}
 
 	/* Memory resources (mandatory for P2P bridge) */
@@ -615,10 +612,10 @@
 	limit = ((tmp16 & 0xfff0) << 16) | 0xfffff;
 	bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
 	if (!bridge->mem_head) {
-		err("out of memory");
+		err("out of memory\n");
 		return;
 	}
-	dbg("32bit Memory range: %08x-%08x",
+	dbg("32bit Memory range: %08x-%08x\n",
 	    (u32)bridge->mem_head->base,
 	    (u32)(bridge->mem_head->base + bridge->mem_head->length-1));
 
@@ -634,10 +631,10 @@
 		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");
+			err("out of memory\n");
 			return;
 		}
-		dbg("32bit Prefetchable memory range: %08x-%08x",
+		dbg("32bit Prefetchable memory range: %08x-%08x\n",
 		    (u32)bridge->p_mem_head->base,
 		    (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1));
 		break;
@@ -649,10 +646,10 @@
 
 		bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1);
 		if (!bridge->p_mem_head) {
-			err("out of memory");
+			err("out of memory\n");
 			return;
 		}
-		dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x",
+		dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n",
 		    (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),
@@ -661,7 +658,7 @@
 	case 0x0f:
 		break;
 	default:
-		warn("Unknown prefetchale memory type");
+		warn("Unknown prefetchale memory type\n");
 	}
 
 	init_bridge_misc(bridge);
@@ -689,7 +686,7 @@
 
 	status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp);
 	if (ACPI_FAILURE(status)) {
-		dbg("%s: _ADR evaluation failure", __FUNCTION__);
+		dbg("%s: _ADR evaluation failure\n", __FUNCTION__);
 		return AE_OK;
 	}
 
@@ -706,7 +703,7 @@
 
 	/* 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);
+		dbg("found PCI-to-PCI bridge at PCI %s\n", dev->slot_name);
 		add_p2p_bridge(handle, seg, bus, device, function);
 	}
 
@@ -727,7 +724,7 @@
 	if (ACPI_SUCCESS(status)) {
 		status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp);
 		if (ACPI_FAILURE(status)) {
-			dbg("%s: _STA evaluation failure", __FUNCTION__);
+			dbg("%s: _STA evaluation failure\n", __FUNCTION__);
 			return 0;
 		}
 		if ((tmp & ACPI_STA_FUNCTIONING) == 0)
@@ -746,13 +743,13 @@
 	if (ACPI_SUCCESS(status)) {
 		bus = tmp;
 	} else {
-		warn("can't get bus number, assuming 0");
+		warn("can't get bus number, assuming 0\n");
 		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");
+		dbg("found PCI host-bus bridge with hot-pluggable slots\n");
 		add_host_bridge(handle, seg, bus);
 		return 0;
 	}
@@ -764,7 +761,7 @@
 				     find_p2p_bridge, &tmp, NULL);
 
 	if (ACPI_FAILURE(status))
-		warn("find_p2p_bridge faied (error code = 0x%x)",status);
+		warn("find_p2p_bridge faied (error code = 0x%x)\n",status);
 
 	return 0;
 }
@@ -782,7 +779,7 @@
 
 	status = acpi_get_object_info(handle, &info);
 	if (ACPI_FAILURE(status)) {
-		dbg("%s: failed to get bridge information", __FUNCTION__);
+		dbg("%s: failed to get bridge information\n", __FUNCTION__);
 		return AE_OK;		/* continue */
 	}
 
@@ -793,7 +790,7 @@
 	    (info.valid & ACPI_VALID_HID) &&
 	    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);
+		dbg("checking PCI-hotplug capable bridges under [%s]\n", objname);
 		add_bridges(handle);
 	}
 	return AE_OK;
@@ -811,15 +808,15 @@
 	if (slot->flags & SLOT_POWEREDON)
 		goto err_exit;
 
-	list_for_each(l, &slot->funcs) {
+	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);
+			dbg("%s: executing _PS0 on %s\n", __FUNCTION__,
+			    func->pci_dev->slot_name);
 			status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS0 failed", __FUNCTION__);
+				warn("%s: _PS0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
 			}
@@ -849,27 +846,27 @@
 	if ((slot->flags & SLOT_POWEREDON) == 0)
 		goto err_exit;
 
-	list_for_each(l, &slot->funcs) {
+	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);
+			dbg("%s: executing _PS3 on %s\n", __FUNCTION__,
+			    func->pci_dev->slot_name);
 			status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
 			if (ACPI_FAILURE(status)) {
-				warn("%s: _PS3 failed", __FUNCTION__);
+				warn("%s: _PS3 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
 			}
 		}
 	}
 
-	list_for_each(l, &slot->funcs) {
+	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);
+			dbg("%s: executing _EJ0 on %s\n", __FUNCTION__,
+			    func->pci_dev->slot_name);
 
 			/* _EJ0 method take one argument */
 			arg_list.count = 1;
@@ -879,7 +876,7 @@
 
 			status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
 			if (ACPI_FAILURE(status)) {
-				warn("%s: _EJ0 failed", __FUNCTION__);
+				warn("%s: _EJ0 failed\n", __FUNCTION__);
 				retval = -1;
 				goto err_exit;
 			}
@@ -919,7 +916,7 @@
 	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.");
+		err("pci_dev structure already exists.\n");
 		retval = -1;
 		goto err_exit;
 	}
@@ -941,7 +938,7 @@
 	dev = pci_scan_slot (&dev0);
 
 	if (!dev) {
-		err("No new device found");
+		err("No new device found\n");
 		retval = -1;
 		goto err_exit;
 	}
@@ -953,7 +950,7 @@
 	}
 
 	/* associate pci_dev to our representation */
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		func->pci_dev = pci_find_slot(slot->bridge->bus,
@@ -970,10 +967,8 @@
 
 	slot->flags |= SLOT_ENABLED;
 
-#if 1
-	dbg("Available resources:");
+	dbg("Available resources:\n");
 	acpiphp_dump_resource(slot->bridge);
-#endif
 
  err_exit:
 	return retval;
@@ -993,14 +988,14 @@
 	if (!(slot->flags & SLOT_ENABLED))
 		goto err_exit;
 
-	list_for_each(l, &slot->funcs) {
+	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");
+				err("failed to unconfigure device\n");
 				retval = -1;
 				goto err_exit;
 			}
@@ -1033,7 +1028,7 @@
 	struct list_head *l;
 	struct acpiphp_func *func;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 
 		if (func->flags & FUNC_HAS_STA) {
@@ -1063,7 +1058,7 @@
 /**
  * handle_hotplug_event_bridge - handle ACPI event on bridges
  *
- * @handle: Notify()'ed acpi_handle 
+ * @handle: Notify()'ed acpi_handle
  * @type: Notify code
  * @context: pointer to acpiphp_bridge structure
  *
@@ -1084,28 +1079,28 @@
 	switch (type) {
 	case ACPI_NOTIFY_BUS_CHECK:
 		/* bus re-enumerate */
-		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_check_bridge(bridge);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_CHECK:
 		/* device check */
-		dbg("%s: Device check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device check notify on %s\n", __FUNCTION__, objname);
 		acpiphp_check_bridge(bridge);
 		break;
 
 	case ACPI_NOTIFY_DEVICE_WAKE:
 		/* wake event */
-		dbg("%s: Device wake notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
 		break;
 
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
-		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
 		break;
 
 	default:
-		warn("notify_handler: unknown event type 0x%x for %s", type, objname);
+		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
 		break;
 	}
 }
@@ -1114,7 +1109,7 @@
 /**
  * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
  *
- * @handle: Notify()'ed acpi_handle 
+ * @handle: Notify()'ed acpi_handle
  * @type: Notify code
  * @context: pointer to acpiphp_func structure
  *
@@ -1135,29 +1130,29 @@
 	switch (type) {
 	case ACPI_NOTIFY_BUS_CHECK:
 		/* bus re-enumerate */
-		dbg("%s: Bus check notify on %s", __FUNCTION__, objname);
+		dbg("%s: Bus check notify on %s\n", __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);
+		dbg("%s: Device check notify on %s\n", __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);
+		dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname);
 		break;
 
 	case ACPI_NOTIFY_EJECT_REQUEST:
 		/* request device eject */
-		dbg("%s: Device eject notify on %s", __FUNCTION__, objname);
+		dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
 		acpiphp_disable_slot(func->slot);
 		break;
 
 	default:
-		warn("notify_handler: unknown event type 0x%x for %s", type, objname);
+		warn("notify_handler: unknown event type 0x%x for %s\n", type, objname);
 		break;
 	}
 }
@@ -1179,7 +1174,7 @@
 				     NULL, NULL);
 
 	if (ACPI_FAILURE(status)) {
-		err("%s: acpi_walk_namespace() failed", __FUNCTION__);
+		err("%s: acpi_walk_namespace() failed\n", __FUNCTION__);
 		return -1;
 	}
 
@@ -1200,12 +1195,12 @@
 	struct acpiphp_func *func;
 	acpi_status status;
 
-	list_for_each_safe(l1, n1, &bridge_list) {
+	list_for_each_safe (l1, n1, &bridge_list) {
 		bridge = (struct acpiphp_bridge *)l1;
 		slot = bridge->slots;
 		while (slot) {
 			next = slot->next;
-			list_for_each_safe(l2, n2, &slot->funcs) {
+			list_for_each_safe (l2, n2, &slot->funcs) {
 				func = list_entry(l2, struct acpiphp_func, sibling);
 				acpiphp_free_resource(&func->io_head);
 				acpiphp_free_resource(&func->mem_head);
@@ -1215,7 +1210,7 @@
 								    ACPI_SYSTEM_NOTIFY,
 								    handle_hotplug_event_func);
 				if (ACPI_FAILURE(status))
-					err("failed to remove notify handler");
+					err("failed to remove notify handler\n");
 				kfree(func);
 			}
 			kfree(slot);
@@ -1224,7 +1219,7 @@
 		status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
 						    handle_hotplug_event_bridge);
 		if (ACPI_FAILURE(status))
-			err("failed to remove notify handler");
+			err("failed to remove notify handler\n");
 
 		acpiphp_free_resource(&bridge->io_head);
 		acpiphp_free_resource(&bridge->mem_head);
@@ -1247,13 +1242,13 @@
 
 	num_slots = 0;
 
-	list_for_each(node, &bridge_list) {
+	list_for_each (node, &bridge_list) {
 		bridge = (struct acpiphp_bridge *)node;
-		dbg("Bus%d %dslot(s)", bridge->bus, bridge->nr_slots);
+		dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots);
 		num_slots += bridge->nr_slots;
 	}
 
-	dbg("Total %dslots", num_slots);
+	dbg("Total %dslots\n", num_slots);
 	return num_slots;
 }
 
@@ -1271,7 +1266,7 @@
 	struct acpiphp_slot *slot;
 	int retval = 0;
 
-	list_for_each(node, &bridge_list) {
+	list_for_each (node, &bridge_list) {
 		bridge = (struct acpiphp_bridge *)node;
 		for (slot = bridge->slots; slot; slot = slot->next) {
 			retval = fn(slot, data);
@@ -1292,7 +1287,7 @@
 	struct acpiphp_bridge *bridge;
 	struct acpiphp_slot *slot;
 
-	list_for_each(node, &bridge_list) {
+	list_for_each (node, &bridge_list) {
 		bridge = (struct acpiphp_bridge *)node;
 		for (slot = bridge->slots; slot; slot = slot->next)
 			if (slot->id == id)
@@ -1300,7 +1295,7 @@
 	}
 
 	/* should never happen! */
-	err("%s: no object for id %d",__FUNCTION__, id);
+	err("%s: no object for id %d\n",__FUNCTION__, id);
 	return 0;
 }
 
@@ -1352,7 +1347,7 @@
 	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:");
+	dbg("Available resources:\n");
 	acpiphp_dump_resource(slot->bridge);
 
  err_exit:
@@ -1380,7 +1375,7 @@
 			if (sta != ACPI_STA_ALL) {
 				retval = acpiphp_disable_slot(slot);
 				if (retval) {
-					err("Error occured in enabling");
+					err("Error occured in enabling\n");
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
@@ -1391,7 +1386,7 @@
 			if (sta == ACPI_STA_ALL) {
 				retval = acpiphp_enable_slot(slot);
 				if (retval) {
-					err("Error occured in enabling");
+					err("Error occured in enabling\n");
 					up(&slot->crit_sect);
 					goto err_exit;
 				}
@@ -1400,7 +1395,7 @@
 		}
 	}
 
-	dbg("%s: %d enabled, %d disabled", __FUNCTION__, enabled, disabled);
+	dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled);
 
  err_exit:
 	return retval;
diff -Nru a/drivers/hotplug/acpiphp_pci.c b/drivers/hotplug/acpiphp_pci.c
--- a/drivers/hotplug/acpiphp_pci.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/hotplug/acpiphp_pci.c	Sun Nov 10 19:28:36 2002
@@ -77,7 +77,7 @@
 		if (!bar)	/* This BAR is not implemented */
 			continue;
 
-		dbg("Device %02x.%02x BAR %d wants %x", device, function, count, bar);
+		dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar);
 
 		if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
 			/* This is IO */
@@ -85,7 +85,7 @@
 			len = bar & 0xFFFFFFFC;
 			len = ~len + 1;
 
-			dbg ("len in IO %x, BAR %d", len, count);
+			dbg("len in IO %x, BAR %d\n", len, count);
 
 			spin_lock(&bridge->res_lock);
 			res = acpiphp_get_io_resource(&bridge->io_head, len);
@@ -110,7 +110,7 @@
 				len = bar & 0xFFFFFFF0;
 				len = ~len + 1;
 
-				dbg("len in PFMEM %x, BAR %d", len, count);
+				dbg("len in PFMEM %x, BAR %d\n", len, count);
 
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource(&bridge->p_mem_head, len);
@@ -127,7 +127,7 @@
 							   (u32)res->base);
 
 				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
-					dbg ("inside the pfmem 64 case, count %d", count);
+					dbg("inside the pfmem 64 case, count %d\n", count);
 					count += 1;
 					pci_bus_write_config_dword(pbus, devfn,
 								   address[count],
@@ -143,7 +143,7 @@
 				len = bar & 0xFFFFFFF0;
 				len = ~len + 1;
 
-				dbg("len in MEM %x, BAR %d", len, count);
+				dbg("len in MEM %x, BAR %d\n", len, count);
 
 				spin_lock(&bridge->res_lock);
 				res = acpiphp_get_resource(&bridge->mem_head, len);
@@ -161,7 +161,7 @@
 
 				if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
-					dbg ("inside mem 64 case, reg. mem, count %d", count);
+					dbg("inside mem 64 case, reg. mem, count %d\n", count);
 					count += 1;
 					pci_bus_write_config_dword(pbus, devfn,
 								   address[count],
@@ -212,16 +212,16 @@
 
 	//pci_proc_attach_device(dev);
 	//pci_announce_device_to_drivers(dev);
-	info("Device %s configured", dev->slot_name);
+	info("Device %s configured\n", dev->slot_name);
 
 	return 0;
 }
 
 
-static int is_pci_dev_in_use (struct pci_dev* dev) 
+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 
+	/*
+	 * 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
 	 */
@@ -263,13 +263,13 @@
 {
 	struct pci_dev *dev = wrapped_dev->dev;
 
-	dbg("attempting removal of driver for device %s", dev->slot_name);
+	dbg("attempting removal of driver for device %s\n", 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");
+			dbg("driver was properly removed\n");
 		}
 		dev->driver = NULL;
 	}
@@ -286,7 +286,7 @@
 	/* Now, remove the Linux Representation */
 	if (dev) {
 		if (pci_hp_remove_device(dev) == 0) {
-			info("Device %s removed", dev->slot_name);
+			info("Device %s removed\n", dev->slot_name);
 			kfree(dev); /* Now, remove */
 		} else {
 			return -1; /* problems while freeing, abort visitation */
@@ -338,7 +338,7 @@
 	int count;
 	struct pci_resource *res;
 
-	dbg("Device %s", dev->slot_name);
+	dbg("Device %s\n", dev->slot_name);
 
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
 		pci_read_config_dword(dev, address[count], &bar);
@@ -355,7 +355,7 @@
 			len &= 0xFFFFFFFC;
 			len = ~len + 1;
 
-			dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
+			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
 			spin_lock(&bridge->res_lock);
 			res = acpiphp_get_resource_with_base(&bridge->io_head, base, len);
@@ -372,10 +372,10 @@
 				len = ~len + 1;
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
-					dbg ("prefetch mem 64");
+					dbg("prefetch mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (PMEM)\n", 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);
@@ -389,10 +389,10 @@
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
-					dbg ("mem 64");
+					dbg("mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (MEM)\n", 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);
@@ -414,7 +414,7 @@
 	struct list_head *l;
 	struct pci_dev *dev;
 
-	list_for_each(l, &bus->devices) {
+	list_for_each (l, &bus->devices) {
 		dev = pci_dev_b(l);
 		detect_used_resource(bridge, dev);
 		/* XXX recursive call */
@@ -463,16 +463,16 @@
 	struct pci_dev *dev;
 
 	dev = func->pci_dev;
-	dbg("Hot-pluggable device %s", dev->slot_name);
+	dbg("Hot-pluggable device %s\n", dev->slot_name);
 
 	for (count = 0; address[count]; count++) {	/* for 6 BARs */
-		pci_read_config_dword (dev, address[count], &bar);
+		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);
+		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 */
@@ -480,7 +480,7 @@
 			len &= 0xFFFFFFFC;
 			len = ~len + 1;
 
-			dbg("BAR[%d] %08x - %08x (IO)", count, (u32)base, (u32)base + len - 1);
+			dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
 
 			res = acpiphp_make_resource(base, len);
 			if (!res)
@@ -499,10 +499,10 @@
 				len = ~len + 1;
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {	/* takes up another dword */
-					dbg ("prefetch mem 64");
+					dbg("prefetch mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (PMEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
 				res = acpiphp_make_resource(base, len);
 				if (!res)
 					goto no_memory;
@@ -518,10 +518,10 @@
 
 				if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
 					/* takes up another dword */
-					dbg ("mem 64");
+					dbg("mem 64\n");
 					count += 1;
 				}
-				dbg("BAR[%d] %08x - %08x (MEM)", count, (u32)base, (u32)base + len - 1);
+				dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
 				res = acpiphp_make_resource(base, len);
 				if (!res)
 					goto no_memory;
@@ -532,7 +532,7 @@
 			}
 		}
 
-		pci_write_config_dword (dev, address[count], bar);
+		pci_write_config_dword(dev, address[count], bar);
 	}
 #if 1
 	acpiphp_dump_func_resource(func);
@@ -541,7 +541,7 @@
 	return 0;
 
  no_memory:
-	err("out of memory");
+	err("out of memory\n");
 	acpiphp_free_resource(&func->io_head);
 	acpiphp_free_resource(&func->mem_head);
 	acpiphp_free_resource(&func->p_mem_head);
@@ -574,7 +574,7 @@
 	if (hdr & 0x80)
 		is_multi = 1;
 
-	list_for_each(l, &slot->funcs) {
+	list_for_each (l, &slot->funcs) {
 		func = list_entry(l, struct acpiphp_func, sibling);
 		if (is_multi || func->function == 0) {
 			pci_bus_read_config_dword(slot->bridge->pci_bus,
@@ -583,7 +583,6 @@
 						  PCI_VENDOR_ID, &dvid);
 			if (dvid != 0xffffffff) {
 				retval = init_config_space(func);
-
 				if (retval)
 					break;
 			}
diff -Nru a/drivers/hotplug/acpiphp_res.c b/drivers/hotplug/acpiphp_res.c
--- a/drivers/hotplug/acpiphp_res.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/hotplug/acpiphp_res.c	Sun Nov 10 19:28:39 2002
@@ -273,7 +273,7 @@
 
 	for (max = *head;max; max = max->next) {
 
-		/* If not big enough we could probably just bail, 
+		/* If not big enough we could probably just bail,
 		   instead we'll continue to the next. */
 		if (max->length < size)
 			continue;
@@ -370,13 +370,13 @@
 		return NULL;
 
 	for (node = *head; node; node = node->next) {
-		dbg("%s: req_size =%x node=%p, base=%x, length=%x",
+		dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
 		    __FUNCTION__, size, node, (u32)node->base, node->length);
 		if (node->length < size)
 			continue;
 
 		if (node->base & (size - 1)) {
-			dbg("%s: not aligned", __FUNCTION__);
+			dbg("%s: not aligned\n", __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;
@@ -400,7 +400,7 @@
 
 		/* Don't need to check if too small since we already did */
 		if (node->length > size) {
-			dbg("%s: too big", __FUNCTION__);
+			dbg("%s: too big\n", __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);
@@ -415,7 +415,7 @@
 			node->next = split_node;
 		}  /* End of too big on top end */
 
-		dbg("%s: got one!!!", __FUNCTION__);
+		dbg("%s: got one!!!\n", __FUNCTION__);
 		/* If we got here, then it is the right size
 		   Now take it out of the list */
 		if (*head == node) {
@@ -437,7 +437,7 @@
 /**
  * get_resource_with_base - get resource with specific base address
  *
- * this function 
+ * 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.
  *
@@ -458,7 +458,7 @@
 		return NULL;
 
 	for (node = *head; node; node = node->next) {
-		dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x",
+		dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
 		    (u32)base, size, node, (u32)node->base, node->length);
 		if (node->base > base)
 			continue;
@@ -467,7 +467,7 @@
 			continue;
 
 		if (node->base < base) {
-			dbg(": split 1");
+			dbg(": split 1\n");
 			/* this one isn't base aligned properly
 			   so we'll make a new entry and split it up */
 			temp_qword = base;
@@ -489,12 +489,12 @@
 			node->next = split_node;
 		}
 
-		dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x",
+		dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
 		    (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");
+			dbg(": split 2\n");
 			/* 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);
@@ -509,7 +509,7 @@
 			node->next = split_node;
 		}  /* End of too big on top end */
 
-		dbg(": got one!!!");
+		dbg(": got one!!!\n");
 		/* If we got here, then it is the right size
 		   Now take it out of the list */
 		if (*head == node) {
@@ -547,13 +547,13 @@
 	if (!(*head))
 		return 1;
 
-	dbg("*head->next = %p",(*head)->next);
+	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",(u32)(*head)->base);
-	dbg("*head->next->base = 0x%x", (u32)(*head)->next->base);
+	dbg("*head->base = 0x%x\n",(u32)(*head)->base);
+	dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base);
 	while (out_of_order) {
 		out_of_order = 0;
 
@@ -587,7 +587,7 @@
 	while (node1 && node1->next) {
 		if ((node1->base + node1->length) == node1->next->base) {
 			/* Combine */
-			dbg("8..");
+			dbg("8..\n");
 			node1->length += node1->next->length;
 			node2 = node1->next;
 			node1->next = node1->next->next;
@@ -668,7 +668,7 @@
 	cnt = 0;
 
 	while (p) {
-		dbg("[%02d] %08x - %08x",
+		dbg("[%02d] %08x - %08x\n",
 		    cnt++, (u32)p->base, (u32)p->base + p->length - 1);
 		p = p->next;
 	}
@@ -676,24 +676,24 @@
 
 void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
 {
-	dbg("I/O resource:");
+	dbg("I/O resource:\n");
 	dump_resource(bridge->io_head);
-	dbg("MEM resource:");
+	dbg("MEM resource:\n");
 	dump_resource(bridge->mem_head);
-	dbg("PMEM resource:");
+	dbg("PMEM resource:\n");
 	dump_resource(bridge->p_mem_head);
-	dbg("BUS resource:");
+	dbg("BUS resource:\n");
 	dump_resource(bridge->bus_head);
 }
 
 void acpiphp_dump_func_resource(struct acpiphp_func *func)
 {
-	dbg("I/O resource:");
+	dbg("I/O resource:\n");
 	dump_resource(func->io_head);
-	dbg("MEM resource:");
+	dbg("MEM resource:\n");
 	dump_resource(func->mem_head);
-	dbg("PMEM resource:");
+	dbg("PMEM resource:\n");
 	dump_resource(func->p_mem_head);
-	dbg("BUS resource:");
+	dbg("BUS resource:\n");
 	dump_resource(func->bus_head);
 }
diff -Nru a/drivers/hotplug/cpci_hotplug.h b/drivers/hotplug/cpci_hotplug.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/hotplug/cpci_hotplug.h	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,100 @@
+/*
+ * CompactPCI Hot Plug Core Functions
+ *
+ * Copyright (c) 2002 SOMA Networks, Inc.
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001 IBM Corp.
+ *
+ * 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 <scottm@somanetworks.com>
+ */
+
+#ifndef _CPCI_HOTPLUG_H
+#define _CPCI_HOTPLUG_H
+
+#include <linux/types.h>
+#include <linux/pci.h>
+
+/* PICMG 2.12 R2.0 HS CSR bits: */
+#define HS_CSR_INS	0x0080
+#define HS_CSR_EXT	0x0040
+#define HS_CSR_PI	0x0030
+#define HS_CSR_LOO	0x0008
+#define HS_CSR_PIE	0x0004
+#define HS_CSR_EIM	0x0002
+#define HS_CSR_DHA	0x0001
+
+#define SLOT_MAGIC	0x67267322
+struct slot {
+	u32 magic;
+	u8 number;
+	unsigned int devfn;
+	struct pci_bus *bus;
+	struct pci_dev *dev;
+	unsigned int extracting;
+	struct hotplug_slot *hotplug_slot;
+	struct list_head slot_list;
+};
+
+struct cpci_hp_controller_ops {
+	int (*query_enum) (void);
+	int (*enable_irq) (void);
+	int (*disable_irq) (void);
+	int (*check_irq) (void *dev_id);
+	int (*hardware_test) (struct slot* slot, u32 value);
+	u8  (*get_power) (struct slot* slot);
+	int (*set_power) (struct slot* slot, int value);
+};
+
+struct cpci_hp_controller {
+	unsigned int irq;
+	unsigned long irq_flags;
+	char *devname;
+	void *dev_id;
+	char *name;
+	struct cpci_hp_controller_ops *ops;
+};
+
+extern int cpci_hp_register_controller(struct cpci_hp_controller *controller);
+extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller);
+extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last);
+extern int cpci_hp_unregister_bus(struct pci_bus *bus);
+extern struct slot *cpci_find_slot(struct pci_bus *bus, unsigned int devfn);
+extern int cpci_hp_start(void);
+extern int cpci_hp_stop(void);
+
+/*
+ * Internal function prototypes, these functions should not be used by
+ * board/chassis drivers.
+ */
+extern u8 cpci_get_attention_status(struct slot *slot);
+extern u8 cpci_get_latch_status(struct slot *slot);
+extern u8 cpci_get_adapter_status(struct slot *slot);
+extern u16 cpci_get_hs_csr(struct slot * slot);
+extern u16 cpci_set_hs_csr(struct slot * slot, u16 hs_csr);
+extern int cpci_set_attention_status(struct slot *slot, int status);
+extern int cpci_check_and_clear_ins(struct slot * slot);
+extern int cpci_check_ext(struct slot * slot);
+extern int cpci_clear_ext(struct slot * slot);
+extern int cpci_led_on(struct slot * slot);
+extern int cpci_led_off(struct slot * slot);
+extern int cpci_configure_slot(struct slot *slot);
+extern int cpci_unconfigure_slot(struct slot *slot);
+
+#endif	/* _CPCI_HOTPLUG_H */
diff -Nru a/drivers/hotplug/cpci_hotplug_core.c b/drivers/hotplug/cpci_hotplug_core.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/hotplug/cpci_hotplug_core.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,927 @@
+/*
+ * CompactPCI Hot Plug Driver
+ *
+ * Copyright (c) 2002 SOMA Networks, Inc.
+ * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001 IBM Corp.
+ *
+ * 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 <scottm@somanetworks.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 <linux/interrupt.h>
+#include <linux/smp_lock.h>
+#include "pci_hotplug.h"
+#include "cpci_hotplug.h"
+
+#define DRIVER_VERSION	"0.2"
+#define DRIVER_AUTHOR	"Scott Murray <scottm@somanetworks.com>"
+#define DRIVER_DESC	"CompactPCI Hot Plug Core"
+
+#if !defined(CONFIG_HOTPLUG_CPCI_MODULE)
+#define MY_NAME	"cpci_hotplug"
+#else
+#define MY_NAME	THIS_MODULE->name
+#endif
+
+#define dbg(format, arg...)					\
+	do {							\
+		if(cpci_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)
+
+/* local variables */
+static spinlock_t list_lock;
+static LIST_HEAD(slot_list);
+static int slots;
+int cpci_debug;
+static struct cpci_hp_controller *controller;
+static struct semaphore event_semaphore;	/* mutex for process loop (up if something to process) */
+static struct semaphore thread_exit;		/* guard ensure thread has exited before calling it quits */
+static int thread_finished = 1;
+
+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 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 cpci_hotplug_slot_ops = {
+	.owner = THIS_MODULE,
+	.enable_slot = enable_slot,
+	.disable_slot = disable_slot,
+	.set_attention_status = set_attention_status,
+	.hardware_test = NULL,
+	.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
+update_latch_status(struct hotplug_slot *hotplug_slot, u8 value)
+{
+	struct hotplug_slot_info info;
+
+	if(!(hotplug_slot && hotplug_slot->info))
+		return -EINVAL;
+	memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
+	info.latch_status = value;
+	return pci_hp_change_slot_info(hotplug_slot->name, &info);
+}
+
+static int
+update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value)
+{
+	struct hotplug_slot_info info;
+
+	if(!(hotplug_slot && hotplug_slot->info))
+		return -EINVAL;
+	memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info));
+	info.adapter_status = value;
+	return pci_hp_change_slot_info(hotplug_slot->name, &info);
+}
+
+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);
+
+	if(controller->ops->set_power) {
+		retval = controller->ops->set_power(slot, 1);
+	}
+
+	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);
+
+	/* Unconfigure device */
+	dbg("%s - unconfiguring slot %s",
+	    __FUNCTION__, slot->hotplug_slot->name);
+	if((retval = cpci_unconfigure_slot(slot))) {
+		err("%s - could not unconfigure slot %s",
+		    __FUNCTION__, slot->hotplug_slot->name);
+		return retval;
+	}
+	dbg("%s - finished unconfiguring slot %s",
+	    __FUNCTION__, slot->hotplug_slot->name);
+
+	/* Clear EXT (by setting it) */
+	if(cpci_clear_ext(slot)) {
+		err("%s - could not clear EXT for slot %s",
+		    __FUNCTION__, slot->hotplug_slot->name);
+		retval = -ENODEV;
+	}
+	cpci_led_on(slot);
+
+	if(controller->ops->set_power) {
+		retval = controller->ops->set_power(slot, 0);
+	}
+
+	if(update_adapter_status(slot->hotplug_slot, 0)) {
+		warn("failure to update adapter file");
+	}
+
+	slot->extracting = 0;
+
+	return retval;
+}
+
+static u8
+cpci_get_power_status(struct slot *slot)
+{
+	u8 power = 1;
+
+	if(controller->ops->get_power) {
+		power = controller->ops->get_power(slot);
+	}
+	return power;
+}
+
+static int
+get_power_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if(slot == NULL)
+		return -ENODEV;
+	*value = cpci_get_power_status(slot);
+	return 0;
+}
+
+static int
+get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if(slot == NULL)
+		return -ENODEV;
+	*value = cpci_get_attention_status(slot);
+	return 0;
+}
+
+static int
+set_attention_status(struct hotplug_slot *hotplug_slot, u8 status)
+{
+	struct slot *slot = get_slot(hotplug_slot, __FUNCTION__);
+
+	if(slot == NULL)
+		return -ENODEV;
+	switch (status) {
+	case 0:
+		cpci_set_attention_status(slot, 0);
+		break;
+
+	case 1:
+	default:
+		cpci_set_attention_status(slot, 1);
+		break;
+	}
+
+	return 0;
+}
+
+static int
+get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	if(hotplug_slot == NULL || hotplug_slot->info == NULL)
+		return -ENODEV;
+	*value = hotplug_slot->info->latch_status;
+	return 0;
+}
+
+static int
+get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value)
+{
+	if(hotplug_slot == NULL || hotplug_slot->info == NULL)
+		return -ENODEV;
+	*value = hotplug_slot->info->adapter_status;
+	return 0;
+}
+
+#define SLOT_NAME_SIZE	6
+static void
+make_slot_name(struct slot *slot)
+{
+	snprintf(slot->hotplug_slot->name,
+		 SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number);
+}
+
+int
+cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last)
+{
+	struct slot *slot;
+	struct hotplug_slot *hotplug_slot;
+	struct hotplug_slot_info *info;
+	char *name;
+	int status = 0;
+	int i;
+
+	if(!(controller && bus)) {
+		return -ENODEV;
+	}
+	if(last < first) {
+		return -EINVAL;
+	}
+
+	/*
+	 * Create a structure for each slot, and register that slot
+	 * with the pci_hotplug subsystem.
+	 */
+	for (i = first; i <= last; ++i) {
+		slot = kmalloc(sizeof (struct slot), GFP_KERNEL);
+		if(!slot)
+			return -ENOMEM;
+		memset(slot, 0, sizeof (struct slot));
+
+		hotplug_slot =
+		    kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL);
+		if(!hotplug_slot) {
+			kfree(slot);
+			return -ENOMEM;
+		}
+		memset(hotplug_slot, 0, sizeof (struct hotplug_slot));
+		slot->hotplug_slot = hotplug_slot;
+
+		info = kmalloc(sizeof (struct hotplug_slot_info), GFP_KERNEL);
+		if(!info) {
+			kfree(hotplug_slot);
+			kfree(slot);
+			return -ENOMEM;
+		}
+		memset(info, 0, sizeof (struct hotplug_slot_info));
+		hotplug_slot->info = info;
+
+		name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
+		if(!name) {
+			kfree(info);
+			kfree(hotplug_slot);
+			kfree(slot);
+			return -ENOMEM;
+		}
+		hotplug_slot->name = name;
+
+		slot->magic = SLOT_MAGIC;
+		slot->bus = bus;
+		slot->number = i;
+		slot->devfn = PCI_DEVFN(i, 0);
+
+		hotplug_slot->private = slot;
+		make_slot_name(slot);
+		hotplug_slot->ops = &cpci_hotplug_slot_ops;
+
+		/*
+		 * Initialize the slot info structure with some known
+		 * good values.
+		 */
+		dbg("initializing slot %s", slot->hotplug_slot->name);
+		info->power_status = cpci_get_power_status(slot);
+		info->attention_status = cpci_get_attention_status(slot);
+
+		dbg("registering slot %s", slot->hotplug_slot->name);
+		status = pci_hp_register(slot->hotplug_slot);
+		if(status) {
+			err("pci_hp_register failed with error %d", status);
+			kfree(info);
+			kfree(name);
+			kfree(hotplug_slot);
+			kfree(slot);
+			return status;
+		}
+
+		/* Add slot to our internal list */
+		spin_lock(&list_lock);
+		list_add(&slot->slot_list, &slot_list);
+		slots++;
+		spin_unlock(&list_lock);
+	}
+	return status;
+}
+
+int
+cpci_hp_unregister_bus(struct pci_bus *bus)
+{
+	struct slot *slot;
+	struct list_head *tmp;
+	int status;
+
+	if(!bus) {
+		return -ENODEV;
+	}
+
+	spin_lock(&list_lock);
+	if(!slots) {
+		spin_unlock(&list_lock);
+		return -1;
+	}
+	list_for_each(tmp, &slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		if(slot->bus == bus) {
+			dbg("deregistering slot %s", slot->hotplug_slot->name);
+			status = pci_hp_deregister(slot->hotplug_slot);
+			if(status) {
+				err("pci_hp_deregister failed with error %d",
+				    status);
+				return status;
+			}
+
+			list_del(&slot->slot_list);
+			kfree(slot->hotplug_slot->info);
+			kfree(slot->hotplug_slot->name);
+			kfree(slot->hotplug_slot);
+			kfree(slot);
+
+			slots--;
+		}
+	}
+	spin_unlock(&list_lock);
+	return 0;
+}
+
+struct slot *
+cpci_find_slot(struct pci_bus *bus, unsigned int devfn)
+{
+	struct slot *slot;
+	struct slot *found;
+	struct list_head *tmp;
+
+	if(!bus) {
+		return NULL;
+	}
+
+	spin_lock(&list_lock);
+	if(!slots) {
+		spin_unlock(&list_lock);
+		return NULL;
+	}
+	found = NULL;
+	list_for_each(tmp, &slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		if(slot->bus == bus && slot->devfn == devfn) {
+			found = slot;
+			break;
+		}
+	}
+	spin_unlock(&list_lock);
+	return found;
+}
+
+/* This is the interrupt mode interrupt handler */
+void
+cpci_hp_intr(int irq, void *data, struct pt_regs *regs)
+{
+	dbg("entered cpci_hp_intr");
+
+	/* Check to see if it was our interrupt */
+	if((controller->irq_flags & SA_SHIRQ) &&
+	    !controller->ops->check_irq(controller->dev_id)) {
+		dbg("exited cpci_hp_intr, not our interrupt");
+		return;
+	}
+
+	/* Disable ENUM interrupt */
+	controller->ops->disable_irq();
+
+	/* Trigger processing by the event thread */
+	dbg("Signal event_semaphore");
+	up(&event_semaphore);
+	dbg("exited cpci_hp_intr");
+}
+
+/*
+ * According to PICMG 2.12 R2.0, section 6.3.2, upon
+ * initialization, the system driver shall clear the
+ * INS bits of the cold-inserted devices.
+ */
+static int
+init_slots(void)
+{
+	struct slot *slot;
+	struct list_head *tmp;
+	struct pci_dev* dev;
+
+	dbg("%s - enter", __FUNCTION__);
+	spin_lock(&list_lock);
+	if(!slots) {
+		spin_unlock(&list_lock);
+		return -1;
+	}
+	list_for_each(tmp, &slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		dbg("%s - looking at slot %s",
+		    __FUNCTION__, slot->hotplug_slot->name);
+		if(cpci_check_and_clear_ins(slot)) {
+			dbg("%s - cleared INS for slot %s",
+			    __FUNCTION__, slot->hotplug_slot->name);
+			dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0));
+			if(dev) {
+				if(update_adapter_status(slot->hotplug_slot, 1)) {
+					warn("failure to update adapter file");
+				}
+				if(update_latch_status(slot->hotplug_slot, 1)) {
+					warn("failure to update latch file");
+				}
+				slot->dev = dev;
+			} else {
+				err("%s - no driver attached to device in slot %s",
+				    __FUNCTION__, slot->hotplug_slot->name);
+			}
+		}
+	}
+	spin_unlock(&list_lock);
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+static int
+check_slots(void)
+{
+	struct slot *slot;
+	struct list_head *tmp;
+	int extracted;
+	int inserted;
+
+	spin_lock(&list_lock);
+	if(!slots) {
+		spin_unlock(&list_lock);
+		err("no slots registered, shutting down");
+		return -1;
+	}
+	extracted = inserted = 0;
+	list_for_each(tmp, &slot_list) {
+		slot = list_entry(tmp, struct slot, slot_list);
+		dbg("%s - looking at slot %s",
+		    __FUNCTION__, slot->hotplug_slot->name);
+		if(cpci_check_and_clear_ins(slot)) {
+			u16 hs_csr;
+
+			/* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */
+			if(slot->dev) {
+				warn("slot %s already inserted", slot->hotplug_slot->name);
+				inserted++;
+				continue;
+			}
+
+			/* Process insertion */
+			dbg("%s - slot %s inserted",
+			    __FUNCTION__, slot->hotplug_slot->name);
+
+			/* GSM, debug */
+			hs_csr = cpci_get_hs_csr(slot);
+			dbg("%s - slot %s HS_CSR (1) = %04x",
+			    __FUNCTION__, slot->hotplug_slot->name, hs_csr);
+
+			/* Configure device */
+			dbg("%s - configuring slot %s",
+			    __FUNCTION__, slot->hotplug_slot->name);
+			if(cpci_configure_slot(slot)) {
+				err("%s - could not configure slot %s",
+				    __FUNCTION__, slot->hotplug_slot->name);
+				continue;
+			}
+			dbg("%s - finished configuring slot %s",
+			    __FUNCTION__, slot->hotplug_slot->name);
+
+			/* GSM, debug */
+			hs_csr = cpci_get_hs_csr(slot);
+			dbg("%s - slot %s HS_CSR (2) = %04x",
+			    __FUNCTION__, slot->hotplug_slot->name, hs_csr);
+
+			if(update_latch_status(slot->hotplug_slot, 1)) {
+				warn("failure to update latch file");
+			}
+
+			if(update_adapter_status(slot->hotplug_slot, 1)) {
+				warn("failure to update adapter file");
+			}
+
+			cpci_led_off(slot);
+
+			/* GSM, debug */
+			hs_csr = cpci_get_hs_csr(slot);
+			dbg("%s - slot %s HS_CSR (3) = %04x",
+			    __FUNCTION__, slot->hotplug_slot->name, hs_csr);
+
+			inserted++;
+		} else if(cpci_check_ext(slot)) {
+			u16 hs_csr;
+
+			/* Process extraction request */
+			dbg("%s - slot %s extracted",
+			    __FUNCTION__, slot->hotplug_slot->name);
+
+			/* GSM, debug */
+			hs_csr = cpci_get_hs_csr(slot);
+			dbg("%s - slot %s HS_CSR = %04x",
+			    __FUNCTION__, slot->hotplug_slot->name, hs_csr);
+
+			if(!slot->extracting) {
+				if(update_latch_status(slot->hotplug_slot, 0)) {
+					warn("failure to update latch file");
+				}
+				slot->extracting = 1;
+			}
+			extracted++;
+		}
+	}
+	spin_unlock(&list_lock);
+	if(inserted || extracted) {
+		return extracted;
+	}
+	else {
+		err("cannot find ENUM# source, shutting down");
+		return -1;
+	}
+}
+
+/* This is the interrupt mode worker thread body */
+static int
+event_thread(void *data)
+{
+	int rc;
+	struct slot *slot;
+	struct list_head *tmp;
+
+	lock_kernel();
+	daemonize();
+	strcpy(current->comm, "cpci_hp_eventd");
+	unlock_kernel();
+
+	dbg("%s - event thread started", __FUNCTION__);
+	while(1) {
+		dbg("event thread sleeping");
+		down_interruptible(&event_semaphore);
+		dbg("event thread woken, thread_finished = %d",
+		    thread_finished);
+		if(thread_finished || signal_pending(current))
+			break;
+		while(controller->ops->query_enum()) {
+			rc = check_slots();
+			if(rc > 0) {
+				/* Give userspace a chance to handle extraction */
+				set_current_state(TASK_INTERRUPTIBLE);
+				schedule_timeout(HZ / 2);
+			} else if(rc < 0) {
+				dbg("%s - error checking slots", __FUNCTION__);
+				thread_finished = 1;
+				break;
+			}
+		}
+		/* Check for someone yanking out a board */
+		list_for_each(tmp, &slot_list) {
+			slot = list_entry(tmp, struct slot, slot_list);
+			if(slot->extracting) {
+				/*
+				 * Hmmm, we're likely hosed at this point, should we
+				 * bother trying to tell the driver or not?
+				 */
+				err("card in slot %s was improperly removed",
+				    slot->hotplug_slot->name);
+				if(update_adapter_status(slot->hotplug_slot, 0)) {
+					warn("failure to update adapter file");
+				}
+				slot->extracting = 0;
+			}
+		}
+
+		/* Re-enable ENUM# interrupt */
+		dbg("%s - re-enabling irq", __FUNCTION__);
+		controller->ops->enable_irq();
+	}
+
+	dbg("%s - event thread signals exit", __FUNCTION__);
+	up(&thread_exit);
+	return 0;
+}
+
+/* This is the polling mode worker thread body */
+static int
+poll_thread(void *data)
+{
+	int rc;
+	struct slot *slot;
+	struct list_head *tmp;
+
+	lock_kernel();
+	daemonize();
+	strcpy(current->comm, "cpci_hp_polld");
+	unlock_kernel();
+
+	while(1) {
+		if(thread_finished || signal_pending(current))
+			break;
+
+		while(controller->ops->query_enum()) {
+			rc = check_slots();
+			if(rc > 0) {
+				/* Give userspace a chance to handle extraction */
+				set_current_state(TASK_INTERRUPTIBLE);
+				schedule_timeout(HZ / 2);
+			} else if(rc < 0) {
+				dbg("%s - error checking slots", __FUNCTION__);
+				thread_finished = 1;
+				break;
+			}
+		}
+		/* Check for someone yanking out a board */
+		list_for_each(tmp, &slot_list) {
+			slot = list_entry(tmp, struct slot, slot_list);
+			if(slot->extracting) {
+				/*
+				 * Hmmm, we're likely hosed at this point, should we
+				 * bother trying to tell the driver or not?
+				 */
+				err("card in slot %s was improperly removed",
+				    slot->hotplug_slot->name);
+				if(update_adapter_status(slot->hotplug_slot, 0)) {
+					warn("failure to update adapter file");
+				}
+				slot->extracting = 0;
+			}
+		}
+
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ / 10);
+	}
+	dbg("poll thread signals exit");
+	up(&thread_exit);
+	return 0;
+}
+
+static int
+cpci_start_thread(void)
+{
+	int pid;
+
+	/* initialize our semaphores */
+	init_MUTEX_LOCKED(&event_semaphore);
+	init_MUTEX_LOCKED(&thread_exit);
+	thread_finished = 0;
+
+	if(controller->irq) {
+		pid = kernel_thread(event_thread, 0, 0);
+	} else {
+		pid = kernel_thread(poll_thread, 0, 0);
+	}
+	if(pid < 0) {
+		err("Can't start up our thread");
+		return -1;
+	}
+	dbg("Our thread pid = %d", pid);
+	return 0;
+}
+
+static void
+cpci_stop_thread(void)
+{
+	thread_finished = 1;
+	dbg("thread finish command given");
+	if(controller->irq) {
+		up(&event_semaphore);
+	}
+	dbg("wait for thread to exit");
+	down(&thread_exit);
+}
+
+int
+cpci_hp_register_controller(struct cpci_hp_controller *new_controller)
+{
+	int status = 0;
+
+	if(!controller) {
+		controller = new_controller;
+		if(controller->irq) {
+			if(request_irq(controller->irq,
+					cpci_hp_intr,
+					controller->irq_flags,
+					MY_NAME, controller->dev_id)) {
+				err("Can't get irq %d for the hotplug cPCI controller", controller->irq);
+				status = -ENODEV;
+			}
+			dbg("%s - acquired controller irq %d", __FUNCTION__,
+			    controller->irq);
+		}
+	} else {
+		err("cPCI hotplug controller already registered");
+		status = -1;
+	}
+	return status;
+}
+
+int
+cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller)
+{
+	int status = 0;
+
+	if(controller) {
+		if(!thread_finished) {
+			cpci_stop_thread();
+		}
+		if(controller->irq) {
+			free_irq(controller->irq, controller->dev_id);
+		}
+		controller = NULL;
+	} else {
+		status = -ENODEV;
+	}
+	return status;
+}
+
+int
+cpci_hp_start(void)
+{
+	static int first = 1;
+	int status;
+
+	dbg("%s - enter", __FUNCTION__);
+	if(!controller) {
+		return -ENODEV;
+	}
+
+	spin_lock(&list_lock);
+	if(!slots) {
+		spin_unlock(&list_lock);
+		return -ENODEV;
+	}
+	spin_unlock(&list_lock);
+
+	if(first) {
+		status = init_slots();
+		if(status) {
+			return status;
+		}
+		first = 0;
+	}
+
+	status = cpci_start_thread();
+	if(status) {
+		return status;
+	}
+	dbg("%s - thread started", __FUNCTION__);
+
+	if(controller->irq) {
+		/* Start enum interrupt processing */
+		dbg("%s - enabling irq", __FUNCTION__);
+		controller->ops->enable_irq();
+	}
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+int
+cpci_hp_stop(void)
+{
+	if(!controller) {
+		return -ENODEV;
+	}
+
+	if(controller->irq) {
+		/* Stop enum interrupt processing */
+		dbg("%s - disabling irq", __FUNCTION__);
+		controller->ops->disable_irq();
+	}
+	cpci_stop_thread();
+	return 0;
+}
+
+static void __exit
+cleanup_slots(void)
+{
+	struct list_head *tmp;
+	struct slot *slot;
+
+	/*
+	 * Unregister all of our slots with the pci_hotplug subsystem,
+	 * and free up all memory that we had allocated.
+	 */
+	spin_lock(&list_lock);
+	if(!slots) {
+		goto null_cleanup;
+	}
+	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);
+	}
+      null_cleanup:
+	spin_unlock(&list_lock);
+	return;
+}
+
+static int __init
+cpci_hotplug_init(void)
+{
+	spin_lock_init(&list_lock);
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION);
+	return 0;
+}
+
+static void __exit
+cpci_hotplug_exit(void)
+{
+	/*
+	 * Clean everything up.
+	 */
+	cleanup_slots();
+}
+
+module_init(cpci_hotplug_init);
+module_exit(cpci_hotplug_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_PARM(cpci_debug, "i");
+MODULE_PARM_DESC(cpci_debug, "Debugging mode");
+
+EXPORT_SYMBOL_GPL(cpci_hp_register_controller);
+EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller);
+EXPORT_SYMBOL_GPL(cpci_hp_register_bus);
+EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus);
+EXPORT_SYMBOL_GPL(cpci_find_slot);
+EXPORT_SYMBOL_GPL(cpci_hp_start);
+EXPORT_SYMBOL_GPL(cpci_hp_stop);
diff -Nru a/drivers/hotplug/cpci_hotplug_pci.c b/drivers/hotplug/cpci_hotplug_pci.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/hotplug/cpci_hotplug_pci.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,685 @@
+/*
+ * CompactPCI Hot Plug Driver PCI functions
+ *
+ * Copyright (c) 2002 by SOMA Networks, Inc.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, 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 <scottm@somanetworks.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include "pci_hotplug.h"
+#include "cpci_hotplug.h"
+
+#if !defined(CONFIG_HOTPLUG_CPCI_MODULE)
+#define MY_NAME	"cpci_hotplug"
+#else
+#define MY_NAME	THIS_MODULE->name
+#endif
+
+extern int cpci_debug;
+
+#define dbg(format, arg...)					\
+	do {							\
+		if(cpci_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 ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
+
+
+u8 cpci_get_attention_status(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return 0;
+	}
+
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return 0;
+	}
+	return hs_csr & 0x0008 ? 1 : 0;
+}
+
+int cpci_set_attention_status(struct slot* slot, int status)
+{
+	int hs_cap;
+	u16 hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return 0;
+	}
+
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return 0;
+	}
+	if(status) {
+		hs_csr |= HS_CSR_LOO;
+	} else {
+		hs_csr &= ~HS_CSR_LOO;
+	}
+	if(pci_bus_write_config_word(slot->bus,
+				      slot->devfn,
+				      hs_cap + 2,
+				      hs_csr)) {
+		return 0;
+	}
+	return 1;
+}
+
+u16 cpci_get_hs_csr(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return 0xFFFF;
+	}
+
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return 0xFFFF;
+	}
+	return hs_csr;
+}
+
+u16 cpci_set_hs_csr(struct slot* slot, u16 hs_csr)
+{
+	int hs_cap;
+	u16 new_hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return 0xFFFF;
+	}
+
+	/* Write out the new value */
+	if(pci_bus_write_config_word(slot->bus,
+				      slot->devfn,
+				      hs_cap + 2,
+				      hs_csr)) {
+		return 0xFFFF;
+	}
+
+	/* Read back what we just wrote out */
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &new_hs_csr)) {
+		return 0xFFFF;
+	}
+	return new_hs_csr;
+}
+
+int cpci_check_and_clear_ins(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+	int ins = 0;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return 0;
+	}
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return 0;
+	}
+	if(hs_csr & HS_CSR_INS) {
+		/* Clear INS (by setting it) */
+		if(pci_bus_write_config_word(slot->bus,
+					      slot->devfn,
+					      hs_cap + 2,
+					      hs_csr)) {
+			ins = 0;
+		}
+		ins = 1;
+	}
+	return ins;
+}
+
+int cpci_check_ext(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+	int ext = 0;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return 0;
+	}
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return 0;
+	}
+	if(hs_csr & HS_CSR_EXT) {
+		ext = 1;
+	}
+	return ext;
+}
+
+int cpci_clear_ext(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return -ENODEV;
+	}
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return -ENODEV;
+	}
+	if(hs_csr & HS_CSR_EXT) {
+		/* Clear EXT (by setting it) */
+		if(pci_bus_write_config_word(slot->bus,
+					      slot->devfn,
+					      hs_cap + 2,
+					      hs_csr)) {
+			return -ENODEV;
+		}
+	}
+	return 0;
+}
+
+int cpci_led_on(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return -ENODEV;
+	}
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return -ENODEV;
+	}
+	if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) {
+		/* Set LOO */
+		hs_csr |= HS_CSR_LOO;
+		if(pci_bus_write_config_word(slot->bus,
+					      slot->devfn,
+					      hs_cap + 2,
+					      hs_csr)) {
+			err("Could not set LOO for slot %s",
+			    slot->hotplug_slot->name);
+			return -ENODEV;
+		}
+	}
+	return 0;
+}
+
+int cpci_led_off(struct slot* slot)
+{
+	int hs_cap;
+	u16 hs_csr;
+
+	hs_cap = pci_bus_find_capability(slot->bus,
+					 slot->devfn,
+					 PCI_CAP_ID_CHSWP);
+	if(!hs_cap) {
+		return -ENODEV;
+	}
+	if(pci_bus_read_config_word(slot->bus,
+				     slot->devfn,
+				     hs_cap + 2,
+				     &hs_csr)) {
+		return -ENODEV;
+	}
+	if(hs_csr & HS_CSR_LOO) {
+		/* Clear LOO */
+		hs_csr &= ~HS_CSR_LOO;
+		if(pci_bus_write_config_word(slot->bus,
+					      slot->devfn,
+					      hs_cap + 2,
+					      hs_csr)) {
+			err("Could not clear LOO for slot %s",
+			    slot->hotplug_slot->name);
+			return -ENODEV;
+		}
+	}
+	return 0;
+}
+
+
+/*
+ * Device configuration functions
+ */
+
+static int cpci_configure_dev(struct pci_bus *bus, struct pci_dev *dev)
+{
+	u8 irq_pin;
+	int r;
+
+	dbg("%s - enter", __FUNCTION__);
+
+	/* NOTE: device already setup from prior scan */
+
+	/* FIXME: How would we know if we need to enable the expansion ROM? */
+	pci_write_config_word(dev, PCI_ROM_ADDRESS, 0x00L);
+
+	/* Assign resources */
+	dbg("assigning resources for %02x:%02x.%x",
+	    dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	for (r = 0; r < 6; r++) {
+		struct resource *res = dev->resource + r;
+		if(res->flags)
+			pci_assign_resource(dev, r);
+	}
+	dbg("finished assigning resources for %02x:%02x.%x",
+	    dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+
+	/* Does this function have an interrupt at all? */
+	dbg("checking for function interrupt");
+	pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
+	if(irq_pin) {
+		dbg("function uses interrupt pin %d", irq_pin);
+	}
+
+	/*
+	 * Need to explicitly set irq field to 0 so that it'll get assigned
+	 * by the pcibios platform dependant code called by pci_enable_device.
+	 */
+	dev->irq = 0;
+
+	dbg("enabling device");
+	pci_enable_device(dev);	/* XXX check return */
+	dbg("now dev->irq = %d", dev->irq);
+	if(irq_pin && dev->irq) {
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	}
+
+	/* Can't use pci_insert_device at the moment, do it manually for now */
+	pci_proc_attach_device(dev);
+	dbg("notifying drivers");
+	//pci_announce_device_to_drivers(dev);
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev)
+{
+	int rc;
+	struct pci_bus* child;
+	struct resource* r;
+	u8 max, n;
+	u16 command;
+
+	dbg("%s - enter", __FUNCTION__);
+
+	/* Do basic bridge initialization */
+	rc = pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40);
+	if(rc) {
+		printk(KERN_ERR "%s - write of PCI_LATENCY_TIMER failed\n", __FUNCTION__);
+	}
+	rc = pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40);
+	if(rc) {
+		printk(KERN_ERR "%s - write of PCI_SEC_LATENCY_TIMER failed\n", __FUNCTION__);
+	}
+	rc = pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4);
+	if(rc) {
+		printk(KERN_ERR "%s - write of PCI_CACHE_LINE_SIZE failed\n", __FUNCTION__);
+	}
+
+	/*
+	 * Set parent bridge's subordinate field so that configuration space
+	 * access will work in pci_scan_bridge and friends.
+	 */
+	max = pci_max_busnr();
+	bus->subordinate = max + 1;
+	pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, max + 1);
+
+	/* Scan behind bridge */
+	n = pci_scan_bridge(bus, dev, max, 2);
+	child = pci_find_bus(max + 1);
+#ifdef CONFIG_PROC_FS
+	pci_proc_attach_bus(child);
+#endif
+	/*
+	 * Update parent bridge's subordinate field if there were more bridges
+	 * behind the bridge that was scanned.
+	 */
+	if(n > max) {
+		bus->subordinate = n;
+		pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, n);
+	}
+
+	/*
+	 * Update the bridge resources of the bridge to accommodate devices
+	 * behind it.
+	 */
+	pbus_size_bridges(child);
+	pbus_assign_resources(child);
+
+	/* Enable resource mapping via command register */
+	command = PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
+	r = child->resource[0];
+	if(r && r->start) {
+		command |= PCI_COMMAND_IO;
+	}
+	r = child->resource[1];
+	if(r && r->start) {
+		command |= PCI_COMMAND_MEMORY;
+	}
+	r = child->resource[2];
+	if(r && r->start) {
+		command |= PCI_COMMAND_MEMORY;
+	}
+	rc = pci_write_config_word(dev, PCI_COMMAND, command);
+	if(rc) {
+		err("Error setting command register");
+		return rc;
+	}
+
+	/* Set bridge control register */
+	command = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA;
+	rc = pci_write_config_word(dev, PCI_BRIDGE_CONTROL, command);
+	if(rc) {
+		err("Error setting bridge control register");
+		return rc;
+	}
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+static int configure_visit_pci_dev(struct pci_dev_wrapped *wrapped_dev,
+			struct pci_bus_wrapped *wrapped_bus)
+{
+	int rc;
+	struct pci_dev *dev = wrapped_dev->dev;
+	struct pci_bus *bus = wrapped_bus->bus;
+	struct slot* slot;
+
+	dbg("%s - enter", __FUNCTION__);
+
+	/*
+	 * We need to fix up the hotplug representation with the Linux
+	 * representation.
+	 */
+	slot = cpci_find_slot(dev->bus, dev->devfn);
+	if(slot) {
+		slot->dev = dev;
+	}
+
+	/* If it's a bridge, scan behind it for devices */
+	if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+		rc = cpci_configure_bridge(bus, dev);
+		if(rc)
+			return rc;
+	}
+
+	/* Actually configure device */
+	if(dev) {
+		rc = cpci_configure_dev(bus, dev);
+		if(rc)
+			return rc;
+	}
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+static int unconfigure_visit_pci_dev_phase1(struct pci_dev_wrapped *wrapped_dev,
+				 struct pci_bus_wrapped *wrapped_bus)
+{
+	struct pci_dev *dev = wrapped_dev->dev;
+
+	dbg("%s - enter", __FUNCTION__);
+
+	dbg("attempting removal of driver for device %02x:%02x.%x",
+	    dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+
+	/* Now, remove the Linux Driver representation */
+	if(dev->driver) {
+		dbg("device is attached to a driver");
+		if(dev->driver->remove) {
+			dev->driver->remove(dev);
+			dbg("driver was removed");
+		}
+		dev->driver = NULL;
+	}
+	dbg("%s - exit", __FUNCTION__);
+	return pci_is_dev_in_use(dev);
+}
+
+static int unconfigure_visit_pci_dev_phase2(struct pci_dev_wrapped *wrapped_dev,
+					    struct pci_bus_wrapped *wrapped_bus)
+{
+	struct pci_dev *dev = wrapped_dev->dev;
+	struct slot* slot;
+
+	dbg("%s - enter", __FUNCTION__);
+	if(!dev)
+		return -ENODEV;
+
+	/* Remove the Linux representation */
+	if(pci_remove_device_safe(dev) == 0) {
+		kfree(dev);
+	} else {
+		err("Could not remove device\n");
+		return -1;
+	}
+
+	/*
+	 * Now remove the hotplug representation.
+	 */
+	slot = cpci_find_slot(dev->bus, dev->devfn);
+	if(slot) {
+		slot->dev = NULL;
+	} else {
+		dbg("No hotplug representation for %02x:%02x.%x",
+		    dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	}
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+static int unconfigure_visit_pci_bus_phase2(struct pci_bus_wrapped *wrapped_bus,
+					    struct pci_dev_wrapped *wrapped_dev)
+{
+	struct pci_bus *bus = wrapped_bus->bus;
+	struct pci_bus *parent = bus->self->bus;
+
+	dbg("%s - enter", __FUNCTION__);
+
+	/* The cleanup code for proc entries regarding buses should be in the kernel... */
+	if(bus->procdir)
+		dbg("detach_pci_bus %s", bus->procdir->name);
+	pci_proc_detach_bus(bus);
+
+	/* 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);
+
+	/* Update parent's subordinate field */
+	if(parent) {
+		u8 n = pci_bus_max_busnr(parent);
+		if(n < parent->subordinate) {
+			parent->subordinate = n;
+			pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, n);
+		}
+	}
+	dbg("%s - exit", __FUNCTION__);
+	return 0;
+}
+
+static struct pci_visit configure_functions = {
+	visit_pci_dev:configure_visit_pci_dev,
+};
+
+static struct pci_visit unconfigure_functions_phase1 = {
+	post_visit_pci_dev:unconfigure_visit_pci_dev_phase1
+};
+
+static struct pci_visit unconfigure_functions_phase2 = {
+	post_visit_pci_bus:unconfigure_visit_pci_bus_phase2,
+	post_visit_pci_dev:unconfigure_visit_pci_dev_phase2
+};
+
+
+int cpci_configure_slot(struct slot* slot)
+{
+	int rc = 0;
+
+	dbg("%s - enter", __FUNCTION__);
+
+	if(slot->dev == NULL) {
+		dbg("pci_dev null, finding %02x:%02x:%x",
+		    slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn));
+		slot->dev = pci_find_slot(slot->bus->number, slot->devfn);
+	}
+
+	/* Still NULL? Well then scan for it! */
+	if(slot->dev == NULL) {
+		struct pci_dev dev0;
+
+		dbg("pci_dev still null");
+		memset(&dev0, 0, sizeof (struct pci_dev));
+		dev0.bus = slot->bus;
+		dev0.devfn = slot->devfn;
+		dev0.sysdata = slot->bus->self->sysdata;
+
+		/*
+		 * This will generate pci_dev structures for all functions, but
+		 * we will only call this case when lookup fails.
+		 */
+		slot->dev = pci_scan_slot(&dev0);
+		if(slot->dev == NULL) {
+			err("Could not find PCI device for slot %02x", slot->number);
+			return 0;
+		}
+	}
+	dbg("slot->dev = %p", slot->dev);
+	if(slot->dev) {
+		struct pci_dev *dev;
+		struct pci_dev_wrapped wrapped_dev;
+		struct pci_bus_wrapped wrapped_bus;
+		int i;
+
+		memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
+		memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
+
+		for (i = 0; i < 8; i++) {
+			dev = pci_find_slot(slot->bus->number,
+					    PCI_DEVFN(PCI_SLOT(slot->dev->devfn), i));
+			if(!dev)
+				continue;
+			wrapped_dev.dev = dev;
+			wrapped_bus.bus = slot->dev->bus;
+			rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus);
+		}
+	}
+
+	dbg("%s - exit, rc = %d", __FUNCTION__, rc);
+	return rc;
+}
+
+int cpci_unconfigure_slot(struct slot* slot)
+{
+	int rc = 0;
+	int i;
+	struct pci_dev_wrapped wrapped_dev;
+	struct pci_bus_wrapped wrapped_bus;
+	struct pci_dev *dev;
+
+	dbg("%s - enter", __FUNCTION__);
+
+	if(!slot->dev) {
+		err("No device for slot %02x\n", slot->number);
+		return -ENODEV;
+	}
+
+	memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped));
+	memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped));
+
+	for (i = 0; i < 8; i++) {
+		dev = pci_find_slot(slot->bus->number,
+				    PCI_DEVFN(PCI_SLOT(slot->devfn), i));
+		if(dev) {
+			wrapped_dev.dev = dev;
+			wrapped_bus.bus = dev->bus;
+			dbg("%s - unconfigure phase 1", __FUNCTION__);
+			rc = pci_visit_dev(&unconfigure_functions_phase1,
+					   &wrapped_dev, &wrapped_bus);
+			if(rc) {
+				break;
+			}
+
+			dbg("%s - unconfigure phase 2", __FUNCTION__);
+			rc = pci_visit_dev(&unconfigure_functions_phase2,
+					   &wrapped_dev, &wrapped_bus);
+			if(rc)
+				break;
+		}
+	}
+	dbg("%s - exit, rc = %d", __FUNCTION__, rc);
+	return rc;
+}
diff -Nru a/drivers/hotplug/cpcihp_generic.c b/drivers/hotplug/cpcihp_generic.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/hotplug/cpcihp_generic.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,290 @@
+/*
+ * cpcihp_generic.c
+ *
+ * Generic port I/O CompactPCI driver
+ *
+ * Copyright 2002 SOMA Networks, Inc.
+ * Copyright 2001 Intel San Luis Obispo
+ * Copyright 2000,2001 MontaVista Software 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 SOFTWARE IS PROVIDED "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 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 OUT OF THE USE OF THIS 
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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 generic CompactPCI hotplug driver should allow using the PCI hotplug
+ * mechanism on any CompactPCI board that exposes the #ENUM signal as a bit
+ * in a system register that can be read through standard port I/O.
+ *
+ * Send feedback to <scottm@somanetworks.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include "cpci_hotplug.h"
+
+#define DRIVER_VERSION	"0.1"
+#define DRIVER_AUTHOR	"Scott Murray <scottm@somanetworks.com>"
+#define DRIVER_DESC	"Generic port I/O CompactPCI Hot Plug Driver"
+
+#if !defined(CONFIG_HOTPLUG_CPCI_GENERIC_MODULE)
+#define MY_NAME	"cpcihp_generic"
+#else
+#define MY_NAME	THIS_MODULE->name
+#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)
+
+/* local variables */
+static int debug;
+static char* bridge;
+static u8 bridge_busnr;
+static u8 bridge_slot;
+static struct pci_bus *bus;
+static u8 first_slot;
+static u8 last_slot;
+static u16 port;
+static unsigned int enum_bit;
+static u8 enum_mask;
+
+static struct cpci_hp_controller_ops generic_hpc_ops;
+static struct cpci_hp_controller generic_hpc;
+
+/* The following allows configuring the driver when it's compiled into the kernel */
+#ifndef MODULE
+static int __init cpcihp_generic_setup(char* str)
+{
+	char* p;
+	unsigned long tmp;
+
+	if(!str)
+		return -EINVAL;
+	bridge = str;
+
+	p = strchr(str, ',');
+	str = p + 1;
+	if(!(p && *str && *p == ','))
+		goto setup_error;
+	tmp = simple_strtoul(str, &p, 0);
+	if(p == str || tmp > 0xff) {
+		err("hotplug bus first slot number out of range");
+		goto setup_error;
+	}
+	first_slot = (u8) tmp;
+
+	str = p + 1;		
+	if(!(*str && *p == ','))
+		return -EINVAL;
+	tmp = simple_strtoul(str, &p, 0);
+	if(p == str || tmp > 0xff) {
+		err("hotplug bus last slot number out of range");
+		goto setup_error;
+	}
+	last_slot = (u8) tmp;
+
+	str = p + 1;
+	if(!(*str && *p == ','))
+		goto setup_error;
+	tmp = simple_strtoul(str, &p, 0);
+	if(p == str || tmp > 0xffff) {
+		err("port number out of range");
+		goto setup_error;
+	}
+	port = (u16) tmp;
+
+	str = p + 1;
+	if(!(*str && *p == ','))
+		goto setup_error;
+	tmp = simple_strtoul(str, &p, 0);
+	if(p == str) {
+		err("invalid #ENUM bit number");
+		goto setup_error;
+	}
+	enum_bit = (u8) tmp;
+
+	str = p + 1;
+	if(*str && *p == ',') {
+		tmp = simple_strtoul(str, &p, 0);
+		if(p != str)
+			debug = (int) tmp;
+	}
+	return 0;
+setup_error:
+	bridge = NULL;
+	return -EINVAL;
+}
+
+__setup("cpcihp_generic=", cpcihp_generic_setup);
+#endif
+
+static int __init validate_parameters(void)
+{
+	char* str;
+	char* p;
+	unsigned long tmp;
+
+	if(!bridge) {
+		info("not configured, disabling.");
+		return 1;
+	}
+	str = bridge;
+	if(!*str)
+		return -EINVAL;
+
+	tmp = simple_strtoul(str, &p, 16);
+	if(p == str || tmp > 0xff) {
+		err("Invalid hotplug bus bridge device bus number");
+		return -EINVAL;
+	}
+	bridge_busnr = (u8) tmp;
+	dbg("bridge_busnr = 0x%02x", bridge_busnr);
+	if(*p != ':') {
+		err("Invalid hotplug bus bridge device");
+		return -EINVAL;
+	}
+	str = p + 1;
+	tmp = simple_strtoul(str, &p, 16);
+	if(p == str || tmp > 0x1f) {
+		err("Invalid hotplug bus bridge device slot number");
+		return -EINVAL;
+	}
+	bridge_slot = (u8) tmp;
+	dbg("bridge_slot = 0x%02x", bridge_slot);
+
+	dbg("first_slot = 0x%02x", first_slot);
+	dbg("last_slot = 0x%02x", last_slot);
+	if(!(first_slot && last_slot)) {
+		err("Need to specify first_slot and last_slot");
+		return -EINVAL;
+	}
+	if(last_slot < first_slot) {
+		err("first_slot must be less than last_slot");
+		return -EINVAL;
+	}
+
+	dbg("port = 0x%04x", port);
+	dbg("enum_bit = 0x%02x", enum_bit);
+	if(enum_bit > 7) {
+		err("Invalid #ENUM bit");
+		return -EINVAL;
+	}
+	enum_mask = 1 << enum_bit;
+	return 0;
+}
+
+static int query_enum(void)
+{
+	u8 value;
+
+	value = inb_p(port);
+	return ((value & enum_mask) == enum_mask);
+}
+
+static int __init cpcihp_generic_init(void)
+{
+	int status;
+	struct resource* r;
+	struct pci_dev* dev;
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION);
+	status = validate_parameters();
+	if(status != 0)
+		return status;
+
+	r = request_region(port, 1, "#ENUM hotswap signal register");
+	if(!r)
+		return -EBUSY;
+
+	dev = pci_find_slot(bridge_busnr, PCI_DEVFN(bridge_slot, 0));
+	if(!dev || dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
+		err("Invalid bridge device %s", bridge);
+		return -EINVAL;
+	}
+	bus = dev->subordinate;
+
+	memset(&generic_hpc, 0, sizeof (struct cpci_hp_controller));
+	generic_hpc_ops.query_enum = query_enum;
+	generic_hpc.ops = &generic_hpc_ops;
+
+	status = cpci_hp_register_controller(&generic_hpc);
+	if(status != 0) {
+		err("Could not register cPCI hotplug controller");
+		return -ENODEV;
+	}
+	dbg("registered controller");
+
+	status = cpci_hp_register_bus(bus, first_slot, last_slot);
+	if(status != 0) {
+		err("Could not register cPCI hotplug bus");
+		goto init_bus_register_error;
+	}
+	dbg("registered bus");
+
+	status = cpci_hp_start();
+	if(status != 0) {
+		err("Could not started cPCI hotplug system");
+		goto init_start_error;
+	}
+	dbg("started cpci hp system");
+	return 0;
+init_start_error:
+	cpci_hp_unregister_bus(bus);
+init_bus_register_error:
+	cpci_hp_unregister_controller(&generic_hpc);
+	err("status = %d", status);
+	return status;
+
+}
+
+static void __exit cpcihp_generic_exit(void)
+{
+	cpci_hp_stop();
+	cpci_hp_unregister_bus(bus);
+	cpci_hp_unregister_controller(&generic_hpc);
+	release_region(port, 1);
+}
+
+module_init(cpcihp_generic_init);
+module_exit(cpcihp_generic_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+MODULE_PARM(bridge, "s");
+MODULE_PARM_DESC(bridge, "Hotswap bus bridge device, <bus>:<slot> (bus and slot are in hexadecimal)");
+MODULE_PARM(first_slot, "b");
+MODULE_PARM_DESC(first_slot, "Hotswap bus first slot number");
+MODULE_PARM(last_slot, "b");
+MODULE_PARM_DESC(last_slot, "Hotswap bus last slot number");
+MODULE_PARM(port, "h");
+MODULE_PARM_DESC(port, "#ENUM signal I/O port");
+MODULE_PARM(enum_bit, "i");
+MODULE_PARM_DESC(enum_bit, "#ENUM signal bit (0-7)");
diff -Nru a/drivers/hotplug/cpcihp_zt5550.c b/drivers/hotplug/cpcihp_zt5550.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/hotplug/cpcihp_zt5550.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,306 @@
+/*
+ * cpcihp_zt5550.c
+ *
+ * Intel/Ziatech ZT5550 CompactPCI Host Controller driver
+ *
+ * Copyright 2002 SOMA Networks, Inc.
+ * Copyright 2001 Intel San Luis Obispo
+ * Copyright 2000,2001 MontaVista Software 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 SOFTWARE IS PROVIDED "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 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 OUT OF THE USE OF THIS 
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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 <scottm@somanetworks.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include "cpci_hotplug.h"
+#include "cpcihp_zt5550.h"
+
+#define DRIVER_VERSION	"0.2"
+#define DRIVER_AUTHOR	"Scott Murray <scottm@somanetworks.com>"
+#define DRIVER_DESC	"ZT5550 CompactPCI Hot Plug Driver"
+
+#if !defined(CONFIG_HOTPLUG_PCI_CPCI_ZT5550_MODULE)
+#define MY_NAME	"cpcihp_zt5550"
+#else
+#define MY_NAME	THIS_MODULE->name
+#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)
+
+/* local variables */
+static int debug;
+static int poll;
+static struct cpci_hp_controller_ops zt5550_hpc_ops;
+static struct cpci_hp_controller zt5550_hpc;
+
+/* Primary cPCI bus bridge device */
+static struct pci_dev *bus0_dev;
+static struct pci_bus *bus0;
+
+/* Host controller device */
+static struct pci_dev *hc_dev;
+
+/* Host controller register addresses */
+static void *hc_registers;
+static void *csr_hc_index;
+static void *csr_hc_data;
+static void *csr_int_status;
+static void *csr_int_mask;
+
+
+static int zt5550_hc_config(struct pci_dev *pdev)
+{
+	/* Since we know that no boards exist with two HC chips, treat it as an error */
+	if(hc_dev) {
+		err("too many host controller devices?");
+		return -EBUSY;
+	}
+	hc_dev = pdev;
+	dbg("hc_dev = %p", hc_dev);
+	dbg("pci resource start %lx", pci_resource_start(hc_dev, 1));
+	dbg("pci resource len %lx", pci_resource_len(hc_dev, 1));
+
+	if(!request_mem_region(pci_resource_start(hc_dev, 1),
+				pci_resource_len(hc_dev, 1), MY_NAME)) {
+		err("cannot reserve MMIO region");
+		return -ENOMEM;
+	}
+
+	hc_registers =
+	    ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1));
+	if(!hc_registers) {
+		err("cannot remap MMIO region %lx @ %lx",
+		    pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1));
+		release_mem_region(pci_resource_start(hc_dev, 1),
+				   pci_resource_len(hc_dev, 1));
+		return -ENODEV;
+	}
+
+	csr_hc_index = hc_registers + CSR_HCINDEX;
+	csr_hc_data = hc_registers + CSR_HCDATA;
+	csr_int_status = hc_registers + CSR_INTSTAT;
+	csr_int_mask = hc_registers + CSR_INTMASK;
+
+	/*
+	 * Disable host control, fault and serial interrupts
+	 */
+	dbg("disabling host control, fault and serial interrupts");
+	writeb((u8) HC_INT_MASK_REG, csr_hc_index);
+	writeb((u8) ALL_INDEXED_INTS_MASK, csr_hc_data);
+	dbg("disabled host control, fault and serial interrupts");
+
+	/*
+	 * Disable timer0, timer1 and ENUM interrupts
+	 */
+	dbg("disabling timer0, timer1 and ENUM interrupts");
+	writeb((u8) ALL_DIRECT_INTS_MASK, csr_int_mask);
+	dbg("disabled timer0, timer1 and ENUM interrupts");
+	return 0;
+}
+
+static int zt5550_hc_cleanup(void)
+{
+	if(!hc_dev)
+		return -ENODEV;
+	release_mem_region(pci_resource_start(hc_dev, 1),
+			   pci_resource_len(hc_dev, 1));
+	return 0;
+}
+
+static int zt5550_hc_query_enum(void)
+{
+	u8 value;
+
+	value = inb_p(ENUM_PORT);
+	return ((value & ENUM_MASK) == ENUM_MASK);
+}
+
+static int zt5550_hc_check_irq(void *dev_id)
+{
+	int ret;
+	u8 reg;
+
+	ret = 0;
+	if(dev_id == zt5550_hpc.dev_id) {
+		reg = readb(csr_int_status);
+		if(reg)
+			ret = 1;
+	}
+	return ret;
+}
+
+static int zt5550_hc_enable_irq(void)
+{
+	u8 reg;
+
+	if(hc_dev == NULL) {
+		return -ENODEV;
+	}
+	reg = readb(csr_int_mask);
+	reg = reg & ~ENUM_INT_MASK;
+	writeb(reg, csr_int_mask);
+	return 0;
+}
+
+int zt5550_hc_disable_irq(void)
+{
+	u8 reg;
+
+	if(hc_dev == NULL) {
+		return -ENODEV;
+	}
+
+	reg = readb(csr_int_mask);
+	reg = reg | ENUM_INT_MASK;
+	writeb(reg, csr_int_mask);
+	return 0;
+}
+
+static int __devinit zt5550_hc_init_one (struct pci_dev *pdev,
+					 const struct pci_device_id *ent)
+{
+	int status;
+
+	status = zt5550_hc_config(pdev);
+	if(status != 0) {
+		return status;
+	}
+	dbg("returned from zt5550_hc_config");
+
+	memset(&zt5550_hpc, 0, sizeof (struct cpci_hp_controller));
+	zt5550_hpc_ops.query_enum = zt5550_hc_query_enum;
+	zt5550_hpc.ops = &zt5550_hpc_ops;
+	if(!poll) {
+		zt5550_hpc.irq = hc_dev->irq;
+		zt5550_hpc.irq_flags = SA_SHIRQ;
+		zt5550_hpc.dev_id = hc_dev;
+
+		zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq;
+		zt5550_hpc_ops.disable_irq = zt5550_hc_disable_irq;
+		zt5550_hpc_ops.check_irq = zt5550_hc_check_irq;
+	} else {
+		info("using ENUM# polling mode");
+	}
+
+	status = cpci_hp_register_controller(&zt5550_hpc);
+	if(status != 0) {
+		err("could not register cPCI hotplug controller");
+		goto init_hc_error;
+	}
+	dbg("registered controller");
+
+	/* Look for first device matching cPCI bus's bridge vendor and device IDs */
+	if(!(bus0_dev = pci_find_device(PCI_VENDOR_ID_DEC,
+					 PCI_DEVICE_ID_DEC_21154, NULL))) {
+		status = -ENODEV;
+		goto init_register_error;
+	}
+	bus0 = bus0_dev->subordinate;
+
+	status = cpci_hp_register_bus(bus0, 0x0a, 0x0f);
+	if(status != 0) {
+		err("could not register cPCI hotplug bus");
+		goto init_register_error;
+	}
+	dbg("registered bus");
+
+	status = cpci_hp_start();
+	if(status != 0) {
+		err("could not started cPCI hotplug system");
+		cpci_hp_unregister_bus(bus0);
+		goto init_register_error;
+	}
+	dbg("started cpci hp system");
+
+	return 0;
+init_register_error:
+	cpci_hp_unregister_controller(&zt5550_hpc);
+init_hc_error:
+	err("status = %d", status);
+	zt5550_hc_cleanup();
+	return status;
+
+}
+
+static void __devexit zt5550_hc_remove_one(struct pci_dev *pdev)
+{
+	cpci_hp_stop();
+	cpci_hp_unregister_bus(bus0);
+	cpci_hp_unregister_controller(&zt5550_hpc);
+	zt5550_hc_cleanup();
+}
+
+
+static struct pci_device_id zt5550_hc_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_ZIATECH, PCI_DEVICE_ID_ZIATECH_5550_HC, PCI_ANY_ID, PCI_ANY_ID, },
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci, zt5550_hc_pci_tbl);
+	
+static struct pci_driver zt5550_hc_driver = {
+	.name		= "zt5550_hc",
+	.id_table	= zt5550_hc_pci_tbl,
+	.probe		= zt5550_hc_init_one,
+	.remove		= __devexit_p(zt5550_hc_remove_one),
+};
+
+static int __init zt5550_init(void)
+{
+	struct resource* r;
+
+	info(DRIVER_DESC " version: " DRIVER_VERSION);
+	r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register");
+	if(!r)
+		return -EBUSY;
+
+	return pci_module_init(&zt5550_hc_driver);
+}
+
+static void __exit
+zt5550_exit(void)
+{
+	pci_unregister_driver(&zt5550_hc_driver);
+	release_region(ENUM_PORT, 1);
+}
+
+module_init(zt5550_init);
+module_exit(zt5550_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+MODULE_PARM(poll, "i");
+MODULE_PARM_DESC(poll, "#ENUM polling mode enabled or not");
diff -Nru a/drivers/hotplug/cpcihp_zt5550.h b/drivers/hotplug/cpcihp_zt5550.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/hotplug/cpcihp_zt5550.h	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,79 @@
+/*
+ * cpcihp_zt5550.h
+ *
+ * Intel/Ziatech ZT5550 CompactPCI Host Controller driver definitions
+ *
+ * Copyright 2002 SOMA Networks, Inc.
+ * Copyright 2001 Intel San Luis Obispo
+ * Copyright 2000,2001 MontaVista Software 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 SOFTWARE IS PROVIDED "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 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 OUT OF THE USE OF THIS 
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * 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 <scottm@somanetworks.com>
+ */
+
+#ifndef _CPCIHP_ZT5550_H
+#define _CPCIHP_ZT5550_H
+
+/* Direct registers */
+#define CSR_HCINDEX		0x00
+#define CSR_HCDATA		0x04
+#define CSR_INTSTAT		0x08
+#define CSR_INTMASK		0x09
+#define CSR_CNT0CMD		0x0C
+#define CSR_CNT1CMD		0x0E
+#define CSR_CNT0		0x10
+#define CSR_CNT1		0x14
+
+/* Masks for interrupt bits in CSR_INTMASK direct register */
+#define CNT0_INT_MASK		0x01
+#define CNT1_INT_MASK		0x02
+#define ENUM_INT_MASK		0x04
+#define ALL_DIRECT_INTS_MASK	0x07
+
+/* Indexed registers (through CSR_INDEX, CSR_DATA) */
+#define HC_INT_MASK_REG		0x04
+#define HC_STATUS_REG		0x08
+#define HC_CMD_REG		0x0C
+#define ARB_CONFIG_GNT_REG	0x10
+#define ARB_CONFIG_CFG_REG	0x12
+#define ARB_CONFIG_REG	 	0x10
+#define ISOL_CONFIG_REG		0x18
+#define FAULT_STATUS_REG	0x20
+#define FAULT_CONFIG_REG	0x24
+#define WD_CONFIG_REG		0x2C
+#define HC_DIAG_REG		0x30
+#define SERIAL_COMM_REG		0x34
+#define SERIAL_OUT_REG		0x38
+#define SERIAL_IN_REG		0x3C
+
+/* Masks for interrupt bits in HC_INT_MASK_REG indexed register */
+#define SERIAL_INT_MASK		0x01
+#define FAULT_INT_MASK		0x02
+#define HCF_INT_MASK		0x04
+#define ALL_INDEXED_INTS_MASK	0x07
+
+/* Digital I/O port storing ENUM# */
+#define ENUM_PORT	0xE1
+/* Mask to get to the ENUM# bit on the bus */
+#define ENUM_MASK	0x40
+
+#endif				/* _CPCIHP_ZT5550_H */
diff -Nru a/drivers/hotplug/pci_hotplug.h b/drivers/hotplug/pci_hotplug.h
--- a/drivers/hotplug/pci_hotplug.h	Sun Nov 10 19:28:39 2002
+++ b/drivers/hotplug/pci_hotplug.h	Sun Nov 10 19:28:39 2002
@@ -167,5 +167,9 @@
 				 struct pci_dev_wrapped *wrapped_dev,
 				 struct pci_bus_wrapped *wrapped_parent);
 
+int pci_is_dev_in_use(struct pci_dev *dev);
+
+int pci_remove_device_safe(struct pci_dev *dev);
+
 #endif
 
diff -Nru a/drivers/hotplug/pci_hotplug_util.c b/drivers/hotplug/pci_hotplug_util.c
--- a/drivers/hotplug/pci_hotplug_util.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/hotplug/pci_hotplug_util.c	Sun Nov 10 19:28:40 2002
@@ -94,15 +94,12 @@
 
 static int pci_visit_bridge (struct pci_visit * fn, struct pci_dev_wrapped *wrapped_dev, struct pci_bus_wrapped *wrapped_parent)
 {
-	struct pci_bus *bus = wrapped_dev->dev->subordinate;
+	struct pci_bus *bus;
 	struct pci_bus_wrapped wrapped_bus;
-	int result;
-
-	memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
-	wrapped_bus.bus = bus;
+	int result = 0;
 
-	dbg("scanning bridge %02x, %02x\n", wrapped_dev->dev->devfn >> 3,
-	    wrapped_dev->dev->devfn & 0x7);
+	dbg("scanning bridge %02x, %02x\n", PCI_SLOT(wrapped_dev->dev->devfn),
+	    PCI_FUNC(wrapped_dev->dev->devfn));
 
 	if (fn->visit_pci_dev) {
 		result = fn->visit_pci_dev(wrapped_dev, wrapped_parent);
@@ -110,7 +107,13 @@
 			return result;
 	}
 
-	result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
+	bus = wrapped_dev->dev->subordinate;
+	if(bus) {
+		memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
+		wrapped_bus.bus = bus;
+
+		result = pci_visit_bus(fn, &wrapped_bus, wrapped_dev);
+	}
 	return result;
 }
 
@@ -153,6 +156,62 @@
 	return result;
 }
 
+/**
+ * pci_is_dev_in_use - query devices' usage
+ * @dev: PCI device to query
+ *
+ * Queries whether a given PCI device is in use by a driver or not.
+ * Returns 1 if the device is in use, 0 if it is not.
+ */
+int pci_is_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;
+	int inuse = 0;
+
+	if (dev->driver) {
+		/* Assume driver feels responsible */
+		return 1;
+	}
+
+	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;
+}
+
+/**
+ * pci_remove_device_safe - remove an unused hotplug device
+ * @dev: the device to remove
+ *
+ * Delete the device structure from the device lists and 
+ * notify userspace (/sbin/hotplug), but only if the device
+ * in question is not being used by a driver.
+ * Returns 0 on success.
+ */
+int pci_remove_device_safe(struct pci_dev *dev)
+{
+	if (pci_is_dev_in_use(dev)) {
+		return -EBUSY;
+	}
+	pci_remove_device(dev);
+	return 0;
+}
 
 EXPORT_SYMBOL(pci_visit_dev);
+EXPORT_SYMBOL(pci_is_dev_in_use);
+EXPORT_SYMBOL(pci_remove_device_safe);
 
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/ide/ide-cd.c	Sun Nov 10 19:28:39 2002
@@ -1469,7 +1469,7 @@
 	} else {
 confused:
 		printk ("%s: cdrom_pc_intr: The drive "
-			"appears confused (ireason = 0x%2x)\n",
+			"appears confused (ireason = 0x%02x)\n",
 			drive->name, ireason);
 		rq->flags |= REQ_FAILED;
 	}
@@ -1722,6 +1722,11 @@
 			blen = bio_iovec(rq->bio)->bv_len;
 		}
 
+		if (!ptr) {
+			printk("%s: confused, missing data\n", drive->name);
+			break;
+		}
+
 		if (blen > thislen)
 			blen = thislen;
 
@@ -1741,8 +1746,6 @@
 	 * pad, if necessary
 	 */
 	if (len) {
-		printk("%s: padding %u bytes\n", drive->name, len);
-
 		while (len) {
 			int pad = 0;
 
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/ide/ide-disk.c	Sun Nov 10 19:28:39 2002
@@ -68,7 +68,7 @@
 #include <asm/uaccess.h>
 #include <asm/io.h>
 
-/* FIXME: soem day we shouldnt need to look in here! */
+/* FIXME: some day we shouldnt need to look in here! */
 
 #include "legacy/pdc4030.h"
 
diff -Nru a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
--- a/drivers/ide/ide-dma.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/ide/ide-dma.c	Sun Nov 10 19:28:40 2002
@@ -1028,9 +1028,18 @@
 
 	if (hwif->chipset != ide_trm290) {
 		u8 dma_stat = hwif->INB(hwif->dma_status);
-		printk(", BIOS settings: %s:%s, %s:%s",
+		printk(", BIOS settings: %s:%s%s, %s:%s%s",
 		       hwif->drives[0].name, (dma_stat & 0x20) ? "DMA" : "pio",
-		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio");
+		       hwif->drives[0].autotune == IDE_TUNE_BIOS ? 
+		       		" (used)" : "",
+		       hwif->drives[1].name, (dma_stat & 0x40) ? "DMA" : "pio",
+		       hwif->drives[1].autotune == IDE_TUNE_BIOS ? 
+		       		" (used)" : "");
+
+		if (hwif->drives[0].autotune == IDE_TUNE_BIOS)
+			hwif->drives[0].using_dma = (dma_stat & 0x20);
+		if (hwif->drives[1].autotune == IDE_TUNE_BIOS)
+			hwif->drives[1].using_dma = (dma_stat & 0x40);
 	}
 	printk("\n");
 
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/ide/ide-probe.c	Sun Nov 10 19:28:40 2002
@@ -434,7 +434,9 @@
 		if (hwif->INB(IDE_STATUS_REG) == (BUSY_STAT|READY_STAT))
 			return 4;
 
-		if (rc == 1 && cmd == WIN_PIDENTIFY && drive->autotune != 2) {
+		if ((rc == 1 && cmd == WIN_PIDENTIFY) &&
+			((drive->autotune == IDE_TUNE_DEFAULT) ||
+			(drive->autotune == IDE_TUNE_AUTO))) {
 			unsigned long timeout;
 			printk("%s: no response (status = 0x%02x), "
 				"resetting drive\n", drive->name,
@@ -699,7 +701,8 @@
 	for (unit = 0; unit < MAX_DRIVES; ++unit) {
 		ide_drive_t *drive = &hwif->drives[unit];
 		if (drive->present) {
-			if (hwif->tuneproc != NULL && drive->autotune == 1)
+			if (hwif->tuneproc != NULL && 
+				drive->autotune == IDE_TUNE_AUTO)
 				/* auto-tune PIO mode */
 				hwif->tuneproc(drive, 255);
 			/*
@@ -711,7 +714,9 @@
 			 * Move here to prevent module loading clashing.
 			 */
 	//		drive->autodma = hwif->autodma;
-			if ((drive->autotune != 2) && (hwif->ide_dma_check)) {
+			if ((hwif->ide_dma_check) &&
+				((drive->autotune == IDE_TUNE_DEFAULT) ||
+				(drive->autotune == IDE_TUNE_AUTO))) {
 				/*
 				 * Force DMAing for the beginning of the check.
 				 * Some chipsets appear to do interesting
diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c
--- a/drivers/ide/ide-proc.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/ide/ide-proc.c	Sun Nov 10 19:28:40 2002
@@ -590,7 +590,7 @@
 	(char *page, char **start, off_t off, int count, int *eof, void *data)
 {
 	ide_drive_t	*drive = (ide_drive_t *) data;
-	ide_driver_t	*driver = (ide_driver_t *) drive->driver;
+	ide_driver_t	*driver = drive->driver;
 	int		len;
 
 	if (!driver)
@@ -720,7 +720,6 @@
 	struct proc_dir_entry *ent;
 	struct proc_dir_entry *parent = hwif->proc;
 	char name[64];
-//	ide_driver_t *driver = drive->driver;
 
 	if (drive->present && !drive->proc) {
 		drive->proc = proc_mkdir(drive->name, parent);
diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c
--- a/drivers/ide/ide.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/ide/ide.c	Sun Nov 10 19:28:38 2002
@@ -153,6 +153,7 @@
 #include <linux/cdrom.h>
 #include <linux/seq_file.h>
 #include <linux/device.h>
+#include <linux/kmod.h>
 
 #include <asm/byteorder.h>
 #include <asm/irq.h>
@@ -162,7 +163,6 @@
 
 #include "ide_modes.h"
 
-#include <linux/kmod.h>
 
 /* default maximum number of failures */
 #define IDE_DEFAULT_MAX_FAILURES 	1
@@ -2621,7 +2621,8 @@
  *				Not fully supported by all chipset types,
  *				and quite likely to cause trouble with
  *				older/odd IDE drives.
- *
+ * "hdx=biostimings"	: driver will NOT attempt to tune interface speed 
+ * 				(DMA/PIO) but always honour BIOS timings.
  * "hdx=slow"		: insert a huge pause after each access to the data
  *				port. Should be used only as a last resort.
  *
@@ -2658,6 +2659,8 @@
  * "idex=noautotune"	: driver will NOT attempt to tune interface speed
  *				This is the default for most chipsets,
  *				except the cmd640.
+ * "idex=biostimings"	: driver will NOT attempt to tune interface speed 
+ * 				(DMA/PIO) but always honour BIOS timings.
  * "idex=serialize"	: do not overlap operations on idex and ide(x^1)
  * "idex=four"		: four drives on idex and ide(x^1) share same ports
  * "idex=reset"		: reset interface before first use
@@ -2733,7 +2736,8 @@
 		const char *hd_words[] = {"none", "noprobe", "nowerr", "cdrom",
 				"serialize", "autotune", "noautotune",
 				"slow", "swapdata", "bswap", "flash",
-				"remap", "noremap", "scsi", NULL};
+				"remap", "noremap", "scsi", "biostimings",
+				NULL};
 		unit = s[2] - 'a';
 		hw   = unit / MAX_DRIVES;
 		unit = unit % MAX_DRIVES;
@@ -2775,10 +2779,10 @@
 				printk(" -- USE \"ide%d=serialize\" INSTEAD", hw);
 				goto do_serialize;
 			case -6: /* "autotune" */
-				drive->autotune = 1;
+				drive->autotune = IDE_TUNE_AUTO;
 				goto done;
 			case -7: /* "noautotune" */
-				drive->autotune = 2;
+				drive->autotune = IDE_TUNE_NOAUTO;
 				goto done;
 			case -8: /* "slow" */
 				drive->slow = 1;
@@ -2804,6 +2808,9 @@
 				drive->scsi = 0;
 				goto bad_option;
 #endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */
+			case -15: /* "biostimings" */
+				drive->autotune = IDE_TUNE_BIOS;
+				goto done;
 			case 3: /* cyl,head,sect */
 				drive->media	= ide_disk;
 				drive->cyl	= drive->bios_cyl  = vals[0];
@@ -2841,9 +2848,10 @@
 		 * -8,-9,-10 : are reserved for future idex calls to ease the hardcoding.
 		 */
 		const char *ide_words[] = {
-			"noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66",
-			"minus8", "minus9", "minus10",
-			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL };
+			"noprobe", "serialize", "autotune", "noautotune", 
+			"reset", "dma", "ata66", "minus8", "minus9", "minus10",
+			"four", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", 
+			"umc8672", "ali14xx", "dc4030", "biostimings", NULL };
 		hw = s[3] - '0';
 		hwif = &ide_hwifs[hw];
 		i = match_parm(&s[4], ide_words, vals, 3);
@@ -2862,6 +2870,10 @@
 		}
 
 		switch (i) {
+			case -19: /* "biostimings" */
+				hwif->drives[0].autotune = IDE_TUNE_BIOS;
+				hwif->drives[1].autotune = IDE_TUNE_BIOS;
+				goto done;
 #ifdef CONFIG_BLK_DEV_PDC4030
 			case -18: /* "dc4030" */
 			{
@@ -2949,12 +2961,12 @@
 				hwif->reset = 1;
 				goto done;
 			case -4: /* "noautotune" */
-				hwif->drives[0].autotune = 2;
-				hwif->drives[1].autotune = 2;
+				hwif->drives[0].autotune = IDE_TUNE_NOAUTO;
+				hwif->drives[1].autotune = IDE_TUNE_NOAUTO;
 				goto done;
 			case -3: /* "autotune" */
-				hwif->drives[0].autotune = 1;
-				hwif->drives[1].autotune = 1;
+				hwif->drives[0].autotune = IDE_TUNE_AUTO;
+				hwif->drives[1].autotune = IDE_TUNE_AUTO;
 				goto done;
 			case -2: /* "serialize" */
 			do_serialize:
@@ -3211,7 +3223,8 @@
 	spin_lock(&drives_lock);
 	list_add(&drive->list, &driver->drives);
 	spin_unlock(&drives_lock);
-	if (drive->autotune != 2) {
+	if ((drive->autotune == IDE_TUNE_DEFAULT) ||
+		(drive->autotune == IDE_TUNE_AUTO)) {
 		/* DMA timings and setup moved to ide-probe.c */
 		if (!driver->supports_dma && HWIF(drive)->ide_dma_off_quietly)
 //			HWIF(drive)->ide_dma_off_quietly(drive);
diff -Nru a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
--- a/drivers/ide/legacy/ide-cs.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/ide/legacy/ide-cs.c	Sun Nov 10 19:28:40 2002
@@ -2,7 +2,7 @@
 
     A driver for PCMCIA IDE/ATA disk cards
 
-    ide_cs.c 1.26 1999/11/16 02:10:49
+    ide-cs.c 1.3 2002/10/26 05:45:31
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -15,12 +15,12 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
-    terms of the GNU General Public License version 2 (the "GPL"), in which
-    case the provisions of the GPL are applicable instead of the
+    terms of the GNU General Public License version 2 (the "GPL"), in
+    which case the provisions of the GPL are applicable instead of the
     above.  If you wish to allow the use of your version of this file
     only under the terms of the GPL and not to allow others to use
     your version of this file under the MPL, indicate your decision
@@ -40,10 +40,9 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/ioport.h>
+#include <linux/ide.h>
 #include <linux/hdreg.h>
 #include <linux/major.h>
-#include <linux/ide.h>
-
 #include <asm/io.h>
 #include <asm/system.h>
 
@@ -53,38 +52,37 @@
 #include <pcmcia/cistpl.h>
 #include <pcmcia/ds.h>
 #include <pcmcia/cisreg.h>
-
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"ide_cs.c 1.26 1999/11/16 02:10:49 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
+#include <pcmcia/ciscode.h>
 
 /*====================================================================*/
 
-/* Parameters that can be set with 'insmod' */
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("PCMCIA ATA/IDE card driver");
+MODULE_LICENSE("Dual MPL/GPL");
+
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 /* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
+INT_MODULE_PARM(irq_mask, 0xdeb8);
 static int irq_list[4] = { -1 };
-
-MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
 
-MODULE_LICENSE("GPL");
-
+#ifdef PCMCIA_DEBUG
+INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"ide-cs.c 1.3 2002/10/26 05:45:31 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
 
 /*====================================================================*/
 
 static const char ide_major[] = {
     IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
-#ifdef IDE4_MAJOR
     IDE4_MAJOR, IDE5_MAJOR
-#endif
 };
 
 typedef struct ide_info_t {
@@ -94,7 +92,6 @@
     int		hd;
 } ide_info_t;
 
-static void ide_config(dev_link_t *link);
 static void ide_release(u_long arg);
 static int ide_event(event_t event, int priority,
 		     event_callback_args_t *args);
@@ -227,13 +224,13 @@
 #define CFG_CHECK(fn, args...) \
 if (CardServices(fn, args) != 0) goto next_entry
 
-int idecs_register (int arg1, int arg2, int irq)
+static int idecs_register(int io, int ctl, int irq)
 {
-        hw_regs_t hw;
-        ide_init_hwif_ports(&hw, (ide_ioreg_t) arg1, (ide_ioreg_t) arg2, NULL);
-        hw.irq = irq;
-        hw.chipset = ide_pci; /* this enables IRQ sharing w/ PCI irqs */
-        return ide_register_hw(&hw, NULL);
+    hw_regs_t hw;
+    ide_init_hwif_ports(&hw, (ide_ioreg_t)io, (ide_ioreg_t)ctl, NULL);
+    hw.irq = irq;
+    hw.chipset = ide_pci;
+    return ide_register_hw(&hw, NULL);
 }
 
 void ide_config(dev_link_t *link)
@@ -246,7 +243,7 @@
     config_info_t conf;
     cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
     cistpl_cftable_entry_t dflt = { 0 };
-    int i, pass, last_ret, last_fn, hd=-1, io_base, ctl_base;
+    int i, pass, last_ret, last_fn, hd, io_base, ctl_base, is_kme = 0;
 
     DEBUG(0, "ide_config(0x%p)\n", link);
     
@@ -259,7 +256,15 @@
     CS_CHECK(ParseTuple, handle, &tuple, &parse);
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
-    
+
+    tuple.DesiredTuple = CISTPL_MANFID;
+    if (!CardServices(GetFirstTuple, handle, &tuple) &&
+	!CardServices(GetTupleData, handle, &tuple) &&
+	!CardServices(ParseTuple, handle, &tuple, &parse))
+	is_kme = ((parse.manfid.manf == MANFID_KME) &&
+		  ((parse.manfid.card == PRODID_KME_KXLC005_A) ||
+		   (parse.manfid.card == PRODID_KME_KXLC005_B)));
+
     /* Configure card */
     link->state |= DEV_CONFIG;
 
@@ -303,7 +308,7 @@
 	    if (io->nwin == 2) {
 		link->io.NumPorts1 = 8;
 		link->io.BasePort2 = io->win[1].base;
-		link->io.NumPorts2 = 1;
+		link->io.NumPorts2 = (is_kme) ? 2 : 1;
 		CFG_CHECK(RequestIO, link->handle, &link->io);
 		io_base = link->io.BasePort1;
 		ctl_base = link->io.BasePort2;
@@ -337,17 +342,20 @@
     if (link->io.NumPorts2)
 	release_region(link->io.BasePort2, link->io.NumPorts2);
 
+    /* disable drive interrupts during IDE probe */
+    outb(0x02, ctl_base);
+
+    /* special setup for KXLC005 card */
+    if (is_kme) outb(0x81, ctl_base+1);
+
     /* retry registration in case device is still spinning up */
-    for (i = 0; i < 10; i++) {
-	if (ctl_base)
-	    outb(0x02, ctl_base); /* Set nIEN = disable device interrupts */
+    for (hd = -1, i = 0; i < 10; i++) {
 	hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ);
 	if (hd >= 0) break;
 	if (link->io.NumPorts1 == 0x20) {
-	    if (ctl_base)
-		outb(0x02, ctl_base+0x10);
+	    outb(0x02, ctl_base+0x10);
 	    hd = idecs_register(io_base+0x10, ctl_base+0x10,
-			      link->irq.AssignedIRQ);
+				link->irq.AssignedIRQ);
 	    if (hd >= 0) {
 		io_base += 0x10; ctl_base += 0x10;
 		break;
@@ -358,7 +366,7 @@
     }
     
     if (hd < 0) {
-	printk(KERN_NOTICE "ide_cs: ide_register() at 0x%03x & 0x%03x"
+	printk(KERN_NOTICE "ide-cs: ide_register() at 0x%3x & 0x%3x"
 	       ", irq %u failed\n", io_base, ctl_base,
 	       link->irq.AssignedIRQ);
 	goto failed;
@@ -371,7 +379,7 @@
     info->node.minor = 0;
     info->hd = hd;
     link->dev = &info->node;
-    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
+    printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
 	   info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
 	   link->conf.Vpp1/10, link->conf.Vpp1%10);
 
@@ -382,6 +390,7 @@
     cs_error(link->handle, last_fn, last_ret);
 failed:
     ide_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
 
 } /* ide_config */
 
@@ -402,13 +411,14 @@
 
     if (info->ndev) {
 	ide_unregister(info->hd);
+	/* deal with brain dead IDE resource management */
+	request_region(link->io.BasePort1, link->io.NumPorts1,
+		       info->node.dev_name);
+	if (link->io.NumPorts2)
+	    request_region(link->io.BasePort2, link->io.NumPorts2,
+			   info->node.dev_name);
 	MOD_DEC_USE_COUNT;
     }
-
-    request_region(link->io.BasePort1, link->io.NumPorts1,"ide-cs");
-    if (link->io.NumPorts2)
-	request_region(link->io.BasePort2, link->io.NumPorts2,"ide-cs");
-    
     info->ndev = 0;
     link->dev = NULL;
     
@@ -472,9 +482,9 @@
     DEBUG(0, "%s\n", version);
     CardServices(GetCardServicesInfo, &serv);
     if (serv.Revision != CS_RELEASE_CODE) {
-	printk(KERN_NOTICE "ide_cs: Card Services release "
+	printk(KERN_NOTICE "ide-cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
     return 0;
@@ -482,7 +492,7 @@
 
 static void __exit exit_ide_cs(void)
 {
-    DEBUG(0, "ide_cs: unloading\n");
+    DEBUG(0, "ide-cs: unloading\n");
     unregister_pccard_driver(&dev_info);
     while (dev_list != NULL)
 	ide_detach(dev_list);
diff -Nru a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
--- a/drivers/ide/pci/sl82c105.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/ide/pci/sl82c105.c	Sun Nov 10 19:28:38 2002
@@ -284,7 +284,7 @@
 
 static int __devinit sl82c105_init_one(struct pci_dev *dev, const struct pci_device_id *id)
 {
-	ide_pci_device_t *d = &slc82c105_chipsets[id->driver_data];
+	ide_pci_device_t *d = &sl82c105_chipsets[id->driver_data];
 	if (dev->device != d->device)
 		BUG();
 	ide_setup_pci_device(dev, d);
diff -Nru a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
--- a/drivers/ide/ppc/pmac.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/ide/ppc/pmac.c	Sun Nov 10 19:28:37 2002
@@ -717,11 +717,11 @@
 		name = pmac_ide[i].node->full_name;
 		if (memcmp(name, bootdevice, n) == 0 && name[n] == 0) {
 			/* XXX should cope with the 2nd drive as well... */
-			return MKDEV(ide_majors[i], 0);
+			return mk_kdev(ide_majors[i], 0);
 		}
 	}
 
-	return 0;
+	return NODEV;
 }
 
 void __init
@@ -932,47 +932,32 @@
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 
 static int
-pmac_ide_build_sglist(ide_hwif_t *hwif, struct request *rq)
+pmac_ide_build_sglist(ide_drive_t *drive, struct request *rq)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
-	struct buffer_head *bh;
 	struct scatterlist *sg = pmif->sg_table;
-	int nents = 0;
+	int nents;
 
 	if (hwif->sg_dma_active)
 		BUG();
 		
-	if (rq->cmd == READ)
+	nents = blk_rq_map_sg(&drive->queue, rq, sg);
+		
+	if (rq_data_dir(rq) == READ)
 		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
 	else
 		pmif->sg_dma_direction = PCI_DMA_TODEVICE;
-	bh = rq->bh;
-	do {
-		unsigned char *virt_addr = bh->b_data;
-		unsigned int size = bh->b_size;
-
-		if (nents >= MAX_DCMDS)
-			return 0;
-
-		while ((bh = bh->b_reqnext) != NULL) {
-			if ((virt_addr + size) != (unsigned char *) bh->b_data)
-				break;
-			size += bh->b_size;
-		}
-		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = size;
-		nents++;
-	} while (bh != NULL);
 
 	return pci_map_sg(hwif->pci_dev, sg, nents, pmif->sg_dma_direction);
 }
 
 static int
-pmac_ide_raw_build_sglist(ide_hwif_t *hwif, struct request *rq)
+pmac_ide_raw_build_sglist(ide_drive_t *drive, struct request *rq)
 {
+	ide_hwif_t *hwif = HWIF(drive);
 	pmac_ide_hwif_t *pmif = (pmac_ide_hwif_t *)hwif->hwif_data;
-	struct scatterlist *sg = hwif->sg_table;
+	struct scatterlist *sg = pmif->sg_table;
 	int nents = 0;
 	ide_task_t *args = rq->special;
 	unsigned char *virt_addr = rq->buffer;
@@ -983,16 +968,18 @@
 	else
 		pmif->sg_dma_direction = PCI_DMA_FROMDEVICE;
 	
-	if (sector_count > 128) {
+	if (sector_count > 127) {
 		memset(&sg[nents], 0, sizeof(*sg));
-		sg[nents].address = virt_addr;
-		sg[nents].length = 128  * SECTOR_SIZE;
+		sg[nents].page = virt_to_page(virt_addr);
+		sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
+		sg[nents].length = 127  * SECTOR_SIZE;
 		nents++;
-		virt_addr = virt_addr + (128 * SECTOR_SIZE);
-		sector_count -= 128;
+		virt_addr = virt_addr + (127 * SECTOR_SIZE);
+		sector_count -= 127;
 	}
 	memset(&sg[nents], 0, sizeof(*sg));
-	sg[nents].address = virt_addr;
+	sg[nents].page = virt_to_page(virt_addr);
+	sg[nents].offset = (unsigned long) virt_addr & ~PAGE_MASK;
 	sg[nents].length =  sector_count  * SECTOR_SIZE;
 	nents++;
    
@@ -1023,10 +1010,10 @@
 		udelay(1);
 
 	/* Build sglist */
-	if (rq->cmd == IDE_DRIVE_TASKFILE)
-		pmif->sg_nents = i = pmac_ide_raw_build_sglist(hwif, rq);
+	if (HWGROUP(drive)->rq->flags & REQ_DRIVE_TASKFILE)
+		pmif->sg_nents = i = pmac_ide_raw_build_sglist(drive, rq);
 	else
-		pmif->sg_nents = i = pmac_ide_build_sglist(hwif, rq);
+		pmif->sg_nents = i = pmac_ide_build_sglist(drive, rq);
 	if (!i)
 		return 0;
 
@@ -1045,7 +1032,7 @@
 			if (++count >= MAX_DCMDS) {
 				printk(KERN_WARNING "%s: DMA table too small\n",
 				       drive->name);
-				return 0; /* revert to PIO for this request */
+				goto use_pio_instead;
 			}
 			st_le16(&table->command, wr? OUTPUT_MORE: INPUT_MORE);
 			st_le16(&table->req_count, tc);
@@ -1062,17 +1049,24 @@
 	}
 
 	/* convert the last command to an input/output last command */
-	if (count)
+	if (count) {
 		st_le16(&table[-1].command, wr? OUTPUT_LAST: INPUT_LAST);
-	else
-		printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
+		/* add the stop command to the end of the list */
+		memset(table, 0, sizeof(struct dbdma_cmd));
+		st_le16(&table->command, DBDMA_STOP);
+		mb();
+		writel(pmif->dma_table_dma, &dma->cmdptr);
+		return 1;
+	}
 
-	/* add the stop command to the end of the list */
-	memset(table, 0, sizeof(struct dbdma_cmd));
-	st_le16(&table->command, DBDMA_STOP);
-	mb();
-	writel(pmif->dma_table_dma, &dma->cmdptr);
-	return 1;
+	printk(KERN_DEBUG "%s: empty DMA table?\n", drive->name);
+ use_pio_instead:
+	pci_unmap_sg(hwif->pci_dev,
+		     pmif->sg_table,
+		     pmif->sg_nents,
+		     pmif->sg_dma_direction);
+	hwif->sg_dma_active = 0;
+	return 0; /* revert to PIO for this request */
 }
 
 /* Teardown mappings after DMA has completed.  */
@@ -1279,7 +1273,7 @@
 	}
 #else
 	command = (lba48) ? WIN_READDMA_EXT : WIN_READDMA;
-	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
 		ide_task_t *args = rq->special;
 		command = args->tfRegister[IDE_COMMAND_OFFSET];
 	}
@@ -1332,7 +1326,7 @@
 	}
 #else
 	command = (lba48) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;
-	if (rq->cmd == IDE_DRIVE_TASKFILE) {
+	if (rq->flags & REQ_DRIVE_TASKFILE) {
 		ide_task_t *args = rq->special;
 		command = args->tfRegister[IDE_COMMAND_OFFSET];
 	}
@@ -1579,8 +1573,8 @@
 	 * Problem: This can schedule. I moved the block device
 	 * wakeup almost late by priority because of that.
 	 */
-	if (DRIVER(drive))
-		check_disk_change(MKDEV(drive->disk->major, drive->disk->first_minor));
+	//if (DRIVER(drive))
+	//	check_disk_change(MKDEV(drive->disk->major, drive->disk->first_minor));
 	
 #ifdef CONFIG_BLK_DEV_IDEDMA_PMAC
 	/* We re-enable DMA on the drive if it was active. */
@@ -1595,7 +1589,7 @@
 		HWGROUP(drive)->busy = 0;
 		if (!list_empty(&drive->queue.queue_head))
 			ide_do_request(HWGROUP(drive), 0);
-		spin_unlock_irq(&io_request_lock);
+		spin_unlock_irq(&ide_lock);
 	}
 #endif /* CONFIG_BLK_DEV_IDEDMA_PMAC */
 }
@@ -1648,7 +1642,7 @@
 		idepmac_sleep_device(drive, base);
 	}
 	if (unlock)
-		spin_unlock_irq(&io_request_lock);
+		spin_unlock_irq(&ide_lock);
 }
 
 static void
@@ -1675,11 +1669,11 @@
 	}
 
 	/* We resume processing on the HW group */
-	spin_lock_irqsave(&io_request_lock, flags);
+	spin_lock_irqsave(&ide_lock, flags);
 	HWGROUP(drive)->busy = 0;
 	if (!list_empty(&drive->queue.queue_head))
 		ide_do_request(HWGROUP(drive), 0);
-	spin_unlock_irqrestore(&io_request_lock, flags);			
+	spin_unlock_irqrestore(&ide_lock, flags);
 }
 
 /* Note: We support only master drives for now. This will have to be
diff -Nru a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
--- a/drivers/ide/setup-pci.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/ide/setup-pci.c	Sun Nov 10 19:28:39 2002
@@ -590,6 +590,7 @@
 	u32 port, at_least_one_hwif_enabled = 0, autodma = 0;
 	int pciirq = 0;
 	int tried_config = 0;
+	int drive0_tune, drive1_tune;
 	ata_index_t index;
 	u8 tmp = 0;
 	ide_hwif_t *hwif, *mate = NULL;
@@ -698,11 +699,20 @@
 		ide_hwif_setup_dma(dev, d, hwif);
 bypass_legacy_dma:
 #endif	/* CONFIG_BLK_DEV_IDEDMA */
+
+		drive0_tune = hwif->drives[0].autotune;
+		drive1_tune = hwif->drives[1].autotune;
+
 		if (d->init_hwif)
 			/* Call chipset-specific routine
 			 * for each enabled hwif
 			 */
 			d->init_hwif(hwif);
+		
+		if (drive0_tune == IDE_TUNE_BIOS) /* biostimings */
+			hwif->drives[0].autotune = IDE_TUNE_BIOS;
+		if (drive1_tune == IDE_TUNE_BIOS)
+			hwif->drives[1].autotune = IDE_TUNE_BIOS;
 
 		mate = hwif;
 		at_least_one_hwif_enabled = 1;
diff -Nru a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
--- a/drivers/ieee1394/sbp2.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/ieee1394/sbp2.c	Sun Nov 10 19:28:37 2002
@@ -3137,14 +3137,14 @@
 /*
  * Called by scsi stack to get bios parameters (used by fdisk, and at boot).
  */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,44)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,43)
 static int sbp2scsi_biosparam (struct scsi_device *sdev,
-		struct block_device *dev, sector_t capacy, int geom[]) 
+		struct block_device *dev, sector_t capacity, int geom[]) 
 {
 #else
 static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]) 
 {
-	sector_t capacy = disk->capacity;
+	sector_t capacity = disk->capacity;
 #endif
 	int heads, sectors, cylinders;
 
diff -Nru a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
--- a/drivers/ieee1394/sbp2.h	Sun Nov 10 19:28:37 2002
+++ b/drivers/ieee1394/sbp2.h	Sun Nov 10 19:28:37 2002
@@ -549,10 +549,11 @@
 static int sbp2scsi_detect (Scsi_Host_Template *tpnt);
 static const char *sbp2scsi_info (struct Scsi_Host *host);
 void sbp2scsi_setup(char *str, int *ints);
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28)
-static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[]);
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,44)
+static int sbp2scsi_biosparam (struct scsi_device *sdev, struct block_device *dev, sector_t capacity, int geom[]);
 #else
-static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[]);
+static int sbp2scsi_biosparam (struct scsi_device *sdev, 
+			struct block_device *dev, sector_t capacy, int geom[]);
 #endif
 static int sbp2scsi_abort (Scsi_Cmnd *SCpnt); 
 static int sbp2scsi_reset (Scsi_Cmnd *SCpnt); 
diff -Nru a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
--- a/drivers/ieee1394/video1394.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/ieee1394/video1394.c	Sun Nov 10 19:28:37 2002
@@ -1367,8 +1367,7 @@
 
 	sprintf(name, "%d", video->id);
 	minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + video->id;
-	video->devfs = devfs_register(devfs_handle, name,
-				      DEVFS_FL_AUTO_OWNER,
+	video->devfs = devfs_register(devfs_handle, name, DEVFS_FL_DEFAULT,
 				      IEEE1394_MAJOR, minor,
 				      S_IFCHR | S_IRUSR | S_IWUSR,
 				      &video1394_fops, NULL);
diff -Nru a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
--- a/drivers/input/mouse/Kconfig	Sun Nov 10 19:28:41 2002
+++ b/drivers/input/mouse/Kconfig	Sun Nov 10 19:28:41 2002
@@ -107,7 +107,7 @@
 	  The module will be called amimouse.o. If you want to compile it as a
 	  module, say M here and read <file.:Documentation/modules.txt>.
 
-config MOUSE_ACORN
+config MOUSE_RISCPC
 	tristate "Acorn RiscPC mouse"
 	depends on ARCH_ACORN && INPUT && INPUT_MOUSE
 	help
diff -Nru a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
--- a/drivers/input/mouse/Makefile	Sun Nov 10 19:28:37 2002
+++ b/drivers/input/mouse/Makefile	Sun Nov 10 19:28:37 2002
@@ -5,7 +5,7 @@
 # Each configuration option enables a list of files.
 
 obj-$(CONFIG_MOUSE_AMIGA)	+= amimouse.o
-obj-$(CONFIG_MOUSE_ACORN)	+= rpcmouse.o
+obj-$(CONFIG_MOUSE_RISCPC)	+= rpcmouse.o
 obj-$(CONFIG_MOUSE_INPORT)	+= inport.o
 obj-$(CONFIG_MOUSE_LOGIBM)	+= logibm.o
 obj-$(CONFIG_MOUSE_MAPLE)	+= maplemouse.o
diff -Nru a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
--- a/drivers/input/mouse/rpcmouse.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/input/mouse/rpcmouse.c	Sun Nov 10 19:28:39 2002
@@ -51,11 +51,12 @@
 
 static void rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
+	struct input_dev *dev = dev_id;
 	short x, y, dx, dy, b;
 
 	x = (short) iomd_readl(IOMD_MOUSEX);
 	y = (short) iomd_readl(IOMD_MOUSEY);
-	b = (short) (__raw_readl(0xe0310000) >> 4) & 7;
+	b = (short) (__raw_readl(0xe0310000) ^ 0x70);
 
 	dx = x - rpcmouse_lastx;
 	dy = y - rpcmouse_lasty; 
@@ -63,14 +64,14 @@
 	rpcmouse_lastx = x;
 	rpcmouse_lasty = y;
 
-	input_report_rel(&rpcmouse_dev, REL_X, dx);
-	input_report_rel(&rpcmouse_dev, REL_Y, dy);
+	input_report_rel(dev, REL_X, dx);
+	input_report_rel(dev, REL_Y, -dy);
 
-	input_report_key(&rpcmouse_dev, BTN_LEFT,   b & 0x10);
-	input_report_key(&rpcmouse_dev, BTN_MIDDLE, b & 0x20);
-	input_report_key(&rpcmouse_dev, BTN_RIGHT,  b & 0x40);
+	input_report_key(dev, BTN_LEFT,   b & 0x40);
+	input_report_key(dev, BTN_MIDDLE, b & 0x20);
+	input_report_key(dev, BTN_RIGHT,  b & 0x10);
 
-	input_sync(&rpcmouse_dev);
+	input_sync(dev);
 }
 
 static int __init rpcmouse_init(void)
@@ -80,7 +81,7 @@
 	rpcmouse_lastx = (short) iomd_readl(IOMD_MOUSEX);
 	rpcmouse_lasty = (short) iomd_readl(IOMD_MOUSEY);
 
-	if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", NULL)) {
+	if (request_irq(IRQ_VSYNCPULSE, rpcmouse_irq, SA_SHIRQ, "rpcmouse", &rpcmouse_dev)) {
 		printk(KERN_ERR "rpcmouse: unable to allocate VSYNC interrupt\n");
 		return -1;
 	}
@@ -95,7 +96,7 @@
 static void __exit rpcmouse_exit(void)
 {
 	input_unregister_device(&rpcmouse_dev);
-	free_irq(IRQ_VSYNCPULSE, NULL);
+	free_irq(IRQ_VSYNCPULSE, &rpcmouse_dev);
 }
 
 module_init(rpcmouse_init);
diff -Nru a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
--- a/drivers/input/serio/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/drivers/input/serio/Kconfig	Sun Nov 10 19:28:40 2002
@@ -83,7 +83,7 @@
 	  The module will be called parkbd.o. If you want to compile it as a
 	  module, say M here and read <file:Documentation/modules.txt>.
 
-config SERIO_ACORN
+config SERIO_RPCKBD
 	tristate "Acorn RiscPC keyboard controller"
 	depends on ARCH_ACORN && SERIO
 	help
diff -Nru a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
--- a/drivers/input/serio/ambakmi.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/input/serio/ambakmi.c	Sun Nov 10 19:28:40 2002
@@ -22,7 +22,6 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/hardware/amba_kmi.h>
-#include <asm/mach/amba_kmi.h>
 
 extern struct pt_regs *kbd_pt_regs;
 
diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
--- a/drivers/input/serio/i8042.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/input/serio/i8042.c	Sun Nov 10 19:28:37 2002
@@ -844,6 +844,7 @@
 
 	i8042_port_register(&i8042_kbd_values, &i8042_kbd_port);
 
+	init_timer(&i8042_timer);
 	i8042_timer.function = i8042_timer_func;
 	mod_timer(&i8042_timer, jiffies + I8042_POLL_PERIOD);
 
diff -Nru a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
--- a/drivers/input/serio/rpckbd.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/input/serio/rpckbd.c	Sun Nov 10 19:28:36 2002
@@ -4,7 +4,9 @@
  *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
  *  Based on the work of:
- *	unknown author
+ *	Russell King
+ *
+ * Fixes by Russell King.
  */
 
 /*
@@ -32,44 +34,42 @@
  */
 
 #include <linux/module.h>
+#include <linux/interrupt.h>
 #include <linux/init.h>
 #include <linux/serio.h>
 
 #include <asm/irq.h>
 #include <asm/hardware.h>
 #include <asm/io.h>
-#include <asm/iomd.h>
+#include <asm/hardware/iomd.h>
 #include <asm/system.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
 MODULE_DESCRIPTION("Acorn RiscPC PS/2 keyboard controller driver");
 MODULE_LICENSE("GPL");
 
-static inline void rpckbd_write(unsigned char val)
+extern struct pt_regs *kbd_pt_regs;
+
+static int rpckbd_write(struct serio *port, unsigned char val)
 {
 	while (!(iomd_readb(IOMD_KCTRL) & (1 << 7)))
 		cpu_relax();
 
 	iomd_writeb(val, IOMD_KARTTX);
-}
 
-static struct serio rpckbd_port =
-{
-	.type	= SERIO_8042,
-	.write	= rpckbd_write,
-	.name	= "RiscPC PS/2 kbd port",
-	.phys	= "rpckbd/serio0",
-};
+	return 0;
+}
 
 static void rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs)
 {
+	struct serio *port = dev_id;
 	unsigned int byte;
 	kbd_pt_regs = regs;
 
 	while (iomd_readb(IOMD_KCTRL) & (1 << 5)) {
 		byte = iomd_readb(IOMD_KARTRX);
 
-		serio_interrupt(&rpckbd_port, byte, 0);
+		serio_interrupt(port, byte, 0);
 	}
 }
 
@@ -77,34 +77,52 @@
 {
 }
 
-static int __init rpckbd_init(void)
+static int rpckbd_open(struct serio *port)
 {
 	/* Reset the keyboard state machine. */
 	iomd_writeb(0, IOMD_KCTRL);
 	iomd_writeb(8, IOMD_KCTRL);
 	iomd_readb(IOMD_KARTRX);
 
-	if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", NULL) != 0) {
-		printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ!\n")
+	if (request_irq(IRQ_KEYBOARDRX, rpckbd_rx, 0, "rpckbd", port) != 0) {
+		printk(KERN_ERR "rpckbd.c: Could not allocate keyboard receive IRQ\n");
 		return -EBUSY;
 	}
 
-	if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", NULL) != 0) {
-		printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ!\n")
+	if (request_irq(IRQ_KEYBOARDTX, rpckbd_tx, 0, "rpckbd", port) != 0) {
+		printk(KERN_ERR "rpckbd.c: Could not allocate keyboard transmit IRQ\n");
 		free_irq(IRQ_KEYBOARDRX, NULL);
 		return -EBUSY;
 	}
 
-	register_serio_port(&rpckbd_port);
 	return 0;
 }
 
-static void __exit rpckbd_exit(void)
+static void rpckbd_close(struct serio *port)
+{
+	free_irq(IRQ_KEYBOARDRX, port);
+	free_irq(IRQ_KEYBOARDTX, port);	
+}
+
+static struct serio rpckbd_port =
 {
-	free_irq(IRQ_KEYBOARDRX, NULL);
-	free_irq(IRQ_KEYBOARDTX, NULL);	
+	.type	= SERIO_8042,
+	.open	= rpckbd_open,
+	.close	= rpckbd_close,
+	.write	= rpckbd_write,
+	.name	= "RiscPC PS/2 kbd port",
+	.phys	= "rpckbd/serio0",
+};
 
-	unregister_serio_port(&rpckbd_port);
+static int __init rpckbd_init(void)
+{
+	serio_register_port(&rpckbd_port);
+	return 0;
+}
+
+static void __exit rpckbd_exit(void)
+{
+	serio_unregister_port(&rpckbd_port);
 }
 
 module_init(rpckbd_init);
diff -Nru a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
--- a/drivers/macintosh/Makefile	Sun Nov 10 19:28:41 2002
+++ b/drivers/macintosh/Makefile	Sun Nov 10 19:28:41 2002
@@ -22,7 +22,6 @@
 endif
 obj-$(CONFIG_MAC_EMUMOUSEBTN)	+= mac_hid.o
 obj-$(CONFIG_INPUT_ADBHID)	+= adbhid.o
-obj-$(CONFIG_PPC_RTC)		+= rtc.o
 obj-$(CONFIG_ANSLCD)		+= ans-lcd.o
 
 obj-$(CONFIG_ADB_PMU)		+= via-pmu.o
@@ -30,7 +29,6 @@
 obj-$(CONFIG_PMAC_APM_EMU)	+= apm_emu.o
 
 obj-$(CONFIG_ADB)		+= adb.o
-obj-$(CONFIG_ADB_KEYBOARD)	+= mac_keyb.o
 obj-$(CONFIG_ADB_MACII)		+= via-macii.o
 obj-$(CONFIG_ADB_MACIISI)	+= via-maciisi.o
 obj-$(CONFIG_ADB_IOP)		+= adb-iop.o
diff -Nru a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
--- a/drivers/macintosh/adb.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/macintosh/adb.c	Sun Nov 10 19:28:41 2002
@@ -34,8 +34,10 @@
 #include <linux/wait.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <asm/uaccess.h>
+#include <asm/semaphore.h>
 #ifdef CONFIG_PPC
 #include <asm/prom.h>
 #include <asm/hydra.h>
@@ -75,8 +77,8 @@
 
 struct adb_driver *adb_controller;
 struct notifier_block *adb_client_list = NULL;
-static int adb_got_sleep = 0;
-static int adb_inited = 0;
+static int adb_got_sleep;
+static int adb_inited;
 static pid_t adb_probe_task_pid;
 static DECLARE_MUTEX(adb_probe_mutex);
 static struct completion adb_probe_task_comp;
@@ -94,7 +96,7 @@
 static int adb_scan_bus(void);
 static int do_adb_reset_bus(void);
 static void adbdev_init(void);
-
+static int try_handler_change(int, int);
 
 static struct adb_handler {
 	void (*handler)(unsigned char *, int, struct pt_regs *, int);
@@ -102,6 +104,18 @@
 	int handler_id;
 } adb_handler[16];
 
+/*
+ * The adb_handler_sem mutex protects all accesses to the original_address
+ * and handler_id fields of adb_handler[i] for all i, and changes to the
+ * handler field.
+ * Accesses to the handler field are protected by the adb_handler_lock
+ * rwlock.  It is held across all calls to any handler, so that by the
+ * time adb_unregister returns, we know that the old handler isn't being
+ * called.
+ */
+static DECLARE_MUTEX(adb_handler_sem);
+static rwlock_t adb_handler_lock = RW_LOCK_UNLOCKED;
+
 #if 0
 static void printADBreply(struct adb_request *req)
 {
@@ -254,25 +268,18 @@
 		SIGCHLD | CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 }
 
+static DECLARE_WORK(adb_reset_work, __adb_probe_task, NULL);
+
 int
 adb_reset_bus(void)
 {
-	static struct tq_struct tqs = {
-		routine:	__adb_probe_task,
-	};
-
 	if (__adb_probe_sync) {
 		do_adb_reset_bus();
 		return 0;
 	}
 
 	down(&adb_probe_mutex);
-
-	/* Create probe thread as a child of keventd */
-	if (current_is_keventd())
-		__adb_probe_task(NULL);
-	else
-		schedule_task(&tqs);
+	schedule_work(&adb_reset_work);
 	return 0;
 }
 
@@ -372,7 +379,6 @@
 do_adb_reset_bus(void)
 {
 	int ret, nret, devs;
-	unsigned long flags;
 	
 	if (adb_controller == NULL)
 		return -ENXIO;
@@ -391,11 +397,11 @@
 		/* Let the trackpad settle down */
 		adb_wait_ms(500);
 	}
-	
-	save_flags(flags);
-	cli();
+
+	down(&adb_handler_sem);
+	write_lock_irq(&adb_handler_lock);
 	memset(adb_handler, 0, sizeof(adb_handler));
-	restore_flags(flags);
+	write_unlock_irq(&adb_handler_lock);
 
 	/* That one is still a bit synchronous, oh well... */
 	if (adb_controller->reset_bus)
@@ -413,6 +419,7 @@
 		if (adb_controller->autopoll)
 			adb_controller->autopoll(devs);
 	}
+	up(&adb_handler_sem);
 
 	nret = notifier_call_chain(&adb_client_list, ADB_MSG_POST_RESET, NULL);
 	if (nret & NOTIFY_STOP_MASK)
@@ -512,30 +519,41 @@
 {
 	int i;
 
+	down(&adb_handler_sem);
 	ids->nids = 0;
 	for (i = 1; i < 16; i++) {
 		if ((adb_handler[i].original_address == default_id) &&
 		    (!handler_id || (handler_id == adb_handler[i].handler_id) || 
-		    adb_try_handler_change(i, handler_id))) {
+		    try_handler_change(i, handler_id))) {
 			if (adb_handler[i].handler != 0) {
 				printk(KERN_ERR
 				       "Two handlers for ADB device %d\n",
 				       default_id);
 				continue;
 			}
+			write_lock_irq(&adb_handler_lock);
 			adb_handler[i].handler = handler;
+			write_unlock_irq(&adb_handler_lock);
 			ids->id[ids->nids++] = i;
 		}
 	}
+	up(&adb_handler_sem);
 	return ids->nids;
 }
 
 int
 adb_unregister(int index)
 {
-	if (!adb_handler[index].handler)
-		return -ENODEV;
-	adb_handler[index].handler = 0;
+	int ret = -ENODEV;
+
+	down(&adb_handler_sem);
+	write_lock_irq(&adb_handler_lock);
+	if (adb_handler[index].handler) {
+		ret = 0;
+		adb_handler[index].handler = 0;
+	}
+	write_unlock_irq(&adb_handler_lock);
+	up(&adb_handler_sem);
 	return 0;
 }
 
@@ -544,6 +562,7 @@
 {
 	int i, id;
 	static int dump_adb_input = 0;
+	void (*handler)(unsigned char *, int, struct pt_regs *, int);
 
 	/* We skip keystrokes and mouse moves when the sleep process
 	 * has been started. We stop autopoll, but this is another security
@@ -558,14 +577,15 @@
 			printk(" %x", buf[i]);
 		printk(", id = %d\n", id);
 	}
-	if (adb_handler[id].handler != 0) {
-		(*adb_handler[id].handler)(buf, nb, regs, autopoll);
-	}
+	read_lock(&adb_handler_lock);
+	handler = adb_handler[id].handler;
+	if (handler != 0)
+		(*handler)(buf, nb, regs, autopoll);
+	read_unlock(&adb_handler_lock);
 }
 
-/* Try to change handler to new_id. Will return 1 if successful */
-int
-adb_try_handler_change(int address, int new_id)
+/* Try to change handler to new_id. Will return 1 if successful. */
+static int try_handler_change(int address, int new_id)
 {
 	struct adb_request req;
 
@@ -585,11 +605,24 @@
 }
 
 int
+adb_try_handler_change(int address, int new_id)
+{
+	int ret;
+
+	down(&adb_handler_sem);
+	ret = try_handler_change(address, new_id);
+	up(&adb_handler_sem);
+	return ret;
+}
+
+int
 adb_get_infos(int address, int *original_address, int *handler_id)
 {
+	down(&adb_handler_sem);
 	*original_address = adb_handler[address].original_address;
 	*handler_id = adb_handler[address].handler_id;
-	
+	up(&adb_handler_sem);
+
 	return (*original_address != 0);
 }
 
diff -Nru a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c
--- a/drivers/macintosh/mac_keyb.c	Sun Nov 10 19:28:39 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,834 +0,0 @@
-/*
- * drivers/char/mac_keyb.c
- *
- * Keyboard driver for Power Macintosh computers.
- *
- * Adapted from drivers/char/keyboard.c by Paul Mackerras
- * (see that file for its authors and contributors).
- *
- * Copyright (C) 1996 Paul Mackerras.
- *
- * Adapted to ADB changes and support for more devices by
- * Benjamin Herrenschmidt. Adapted from code in MkLinux
- * and reworked.
- *
- * Supported devices:
- *
- * - Standard 1 button mouse
- * - All standard Apple Extended protocol (handler ID 4)
- * - mouseman and trackman mice & trackballs
- * - PowerBook Trackpad (default setup: enable tapping)
- * - MicroSpeed mouse & trackball (needs testing)
- * - CH Products Trackball Pro (needs testing)
- * - Contour Design (Contour Mouse)
- * - Hunter digital (NoHandsMouse)
- * - Kensignton TurboMouse 5 (needs testing)
- * - Mouse Systems A3 mice and trackballs <aidan@kublai.com>
- * - MacAlly 2-buttons mouse (needs testing) <pochini@denise.shiny.it>
- *
- * To do:
- *
- * Improve Kensignton support, add MacX support as a dynamic
- * option (not a compile-time option).
- */
-
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/tty.h>
-#include <linux/mm.h>
-#include <linux/signal.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/tty_flip.h>
-#include <linux/config.h>
-#include <linux/notifier.h>
-
-#include <asm/bitops.h>
-
-#include <linux/adb.h>
-#include <linux/cuda.h>
-#include <linux/pmu.h>
-#include <linux/kbd_kern.h>
-#include <linux/kbd_ll.h>
-
-#ifdef CONFIG_PMAC_BACKLIGHT
-#include <asm/backlight.h>
-#endif
-
-#define KEYB_KEYREG	0	/* register # for key up/down data */
-#define KEYB_LEDREG	2	/* register # for leds on ADB keyboard */
-#define MOUSE_DATAREG	0	/* reg# for movement/button codes from mouse */
-
-static int adb_message_handler(struct notifier_block *, unsigned long, void *);
-static struct notifier_block mackeyb_adb_notifier = {
-	adb_message_handler,
-	NULL,
-	0
-};
-
-/* this map indicates which keys shouldn't autorepeat. */
-static unsigned char dont_repeat[128] = {
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,	/* esc...option */
-	0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, /* fn, num lock */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, /* scroll lock */
-	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, /* R modifiers */
-};
-
-/* Simple translation table for the SysRq keys */
-
-#ifdef CONFIG_MAGIC_SYSRQ
-unsigned char mackbd_sysrq_xlate[128] =
-	"asdfhgzxcv\000bqwer"				/* 0x00 - 0x0f */
-	"yt123465=97-80o]"				/* 0x10 - 0x1f */
-	"u[ip\rlj'k;\\,/nm."				/* 0x20 - 0x2f */
-	"\t `\177\000\033\000\000\000\000\000\000\000\000\000\000"
-							/* 0x30 - 0x3f */
-	"\000\000\000*\000+\000\000\000\000\000/\r\000-\000"
-							/* 0x40 - 0x4f */
-	"\000\0000123456789\000\000\000"		/* 0x50 - 0x5f */
-	"\205\206\207\203\210\211\000\213\000\215\000\000\000\000\000\212\000\214";
-							/* 0x60 - 0x6f */
-#endif
-
-static u_short macplain_map[NR_KEYS] __initdata = {
-	0xfb61,	0xfb73,	0xfb64,	0xfb66,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
-	0xfb63,	0xfb76,	0xf200,	0xfb62,	0xfb71,	0xfb77,	0xfb65,	0xfb72,
-	0xfb79,	0xfb74,	0xf031,	0xf032,	0xf033,	0xf034,	0xf036,	0xf035,
-	0xf03d,	0xf039,	0xf037,	0xf02d,	0xf038,	0xf030,	0xf05d,	0xfb6f,
-	0xfb75,	0xf05b,	0xfb69,	0xfb70,	0xf201,	0xfb6c,	0xfb6a,	0xf027,
-	0xfb6b,	0xf03b,	0xf05c,	0xf02c,	0xf02f,	0xfb6e,	0xfb6d,	0xf02e,
-	0xf009,	0xf020,	0xf060,	0xf07f,	0xf200,	0xf01b,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf104,	0xf105,	0xf106,	0xf102,	0xf107,	0xf108,	0xf200,	0xf10a,
-	0xf200,	0xf10c,	0xf200,	0xf209,	0xf200,	0xf109,	0xf200,	0xf10b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf103,	0xf117,
-	0xf101,	0xf119,	0xf100,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
-};
-
-static u_short macshift_map[NR_KEYS] __initdata = {
-	0xfb41,	0xfb53,	0xfb44,	0xfb46,	0xfb48,	0xfb47,	0xfb5a,	0xfb58,
-	0xfb43,	0xfb56,	0xf200,	0xfb42,	0xfb51,	0xfb57,	0xfb45,	0xfb52,
-	0xfb59,	0xfb54,	0xf021,	0xf040,	0xf023,	0xf024,	0xf05e,	0xf025,
-	0xf02b,	0xf028,	0xf026,	0xf05f,	0xf02a,	0xf029,	0xf07d,	0xfb4f,
-	0xfb55,	0xf07b,	0xfb49,	0xfb50,	0xf201,	0xfb4c,	0xfb4a,	0xf022,
-	0xfb4b,	0xf03a,	0xf07c,	0xf03c,	0xf03f,	0xfb4e,	0xfb4d,	0xf03e,
-	0xf009,	0xf020,	0xf07e,	0xf07f,	0xf200,	0xf01b,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf10e,	0xf10f,	0xf110,	0xf10c,	0xf111,	0xf112,	0xf200,	0xf10a,
-	0xf200,	0xf10c,	0xf200,	0xf203,	0xf200,	0xf113,	0xf200,	0xf10b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf20b,	0xf116,	0xf10d,	0xf117,
-	0xf10b,	0xf20a,	0xf10a,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
-};
-
-static u_short macaltgr_map[NR_KEYS] __initdata = {
-	0xf914,	0xfb73,	0xf917,	0xf919,	0xfb68,	0xfb67,	0xfb7a,	0xfb78,
-	0xf916,	0xfb76,	0xf200,	0xf915,	0xfb71,	0xfb77,	0xf918,	0xfb72,
-	0xfb79,	0xfb74,	0xf200,	0xf040,	0xf200,	0xf024,	0xf200,	0xf200,
-	0xf200,	0xf05d,	0xf07b,	0xf05c,	0xf05b,	0xf07d,	0xf07e,	0xfb6f,
-	0xfb75,	0xf200,	0xfb69,	0xfb70,	0xf201,	0xfb6c,	0xfb6a,	0xf200,
-	0xfb6b,	0xf200,	0xf200,	0xf200,	0xf200,	0xfb6e,	0xfb6d,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf90a,	0xf90b,	0xf90c,	0xf90d,	0xf90e,	0xf90f,
-	0xf910,	0xf911,	0xf200,	0xf912,	0xf913,	0xf200,	0xf200,	0xf200,
-	0xf510,	0xf511,	0xf512,	0xf50e,	0xf513,	0xf514,	0xf200,	0xf516,
-	0xf200,	0xf10c,	0xf200,	0xf202,	0xf200,	0xf515,	0xf200,	0xf517,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf50f,	0xf117,
-	0xf50d,	0xf119,	0xf50c,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
-};
-
-static u_short macctrl_map[NR_KEYS] __initdata = {
-	0xf001,	0xf013,	0xf004,	0xf006,	0xf008,	0xf007,	0xf01a,	0xf018,
-	0xf003,	0xf016,	0xf200,	0xf002,	0xf011,	0xf017,	0xf005,	0xf012,
-	0xf019,	0xf014,	0xf200,	0xf000,	0xf01b,	0xf01c,	0xf01e,	0xf01d,
-	0xf200,	0xf200,	0xf01f,	0xf01f,	0xf07f,	0xf200,	0xf01d,	0xf00f,
-	0xf015,	0xf01b,	0xf009,	0xf010,	0xf201,	0xf00c,	0xf00a,	0xf007,
-	0xf00b,	0xf200,	0xf01c,	0xf200,	0xf07f,	0xf00e,	0xf00d,	0xf20e,
-	0xf200,	0xf000,	0xf000,	0xf008,	0xf200,	0xf200,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf104,	0xf105,	0xf106,	0xf102,	0xf107,	0xf108,	0xf200,	0xf10a,
-	0xf200,	0xf10c,	0xf200,	0xf204,	0xf200,	0xf109,	0xf200,	0xf10b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf103,	0xf117,
-	0xf101,	0xf119,	0xf100,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
-};
-
-static u_short macshift_ctrl_map[NR_KEYS] __initdata = {
-	0xf001,	0xf013,	0xf004,	0xf006,	0xf008,	0xf007,	0xf01a,	0xf018,
-	0xf003,	0xf016,	0xf200,	0xf002,	0xf011,	0xf017,	0xf005,	0xf012,
-	0xf019,	0xf014,	0xf200,	0xf000,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf01f,	0xf200,	0xf200,	0xf200,	0xf00f,
-	0xf015,	0xf200,	0xf009,	0xf010,	0xf201,	0xf00c,	0xf00a,	0xf200,
-	0xf00b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf00e,	0xf00d,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf10c,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf200,	0xf117,
-	0xf200,	0xf119,	0xf200,	0xf700,	0xf701,	0xf702,	0xf200,	0xf20c,
-};
-
-static u_short macalt_map[NR_KEYS] __initdata = {
-	0xf861,	0xf873,	0xf864,	0xf866,	0xf868,	0xf867,	0xf87a,	0xf878,
-	0xf863,	0xf876,	0xf200,	0xf862,	0xf871,	0xf877,	0xf865,	0xf872,
-	0xf879,	0xf874,	0xf831,	0xf832,	0xf833,	0xf834,	0xf836,	0xf835,
-	0xf83d,	0xf839,	0xf837,	0xf82d,	0xf838,	0xf830,	0xf85d,	0xf86f,
-	0xf875,	0xf85b,	0xf869,	0xf870,	0xf80d,	0xf86c,	0xf86a,	0xf827,
-	0xf86b,	0xf83b,	0xf85c,	0xf82c,	0xf82f,	0xf86e,	0xf86d,	0xf82e,
-	0xf809,	0xf820,	0xf860,	0xf87f,	0xf200,	0xf81b,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf210,	0xf211,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf900,	0xf901,	0xf902,	0xf903,	0xf904,	0xf905,
-	0xf906,	0xf907,	0xf200,	0xf908,	0xf909,	0xf200,	0xf200,	0xf200,
-	0xf504,	0xf505,	0xf506,	0xf502,	0xf507,	0xf508,	0xf200,	0xf50a,
-	0xf200,	0xf10c,	0xf200,	0xf209,	0xf200,	0xf509,	0xf200,	0xf50b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf503,	0xf117,
-	0xf501,	0xf119,	0xf500,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
-};
-
-static u_short macctrl_alt_map[NR_KEYS] __initdata = {
-	0xf801,	0xf813,	0xf804,	0xf806,	0xf808,	0xf807,	0xf81a,	0xf818,
-	0xf803,	0xf816,	0xf200,	0xf802,	0xf811,	0xf817,	0xf805,	0xf812,
-	0xf819,	0xf814,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf80f,
-	0xf815,	0xf200,	0xf809,	0xf810,	0xf201,	0xf80c,	0xf80a,	0xf200,
-	0xf80b,	0xf200,	0xf200,	0xf200,	0xf200,	0xf80e,	0xf80d,	0xf200,
-	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf200,	0xf702,	0xf703,
-	0xf700,	0xf207,	0xf701,	0xf601,	0xf602,	0xf600,	0xf603,	0xf200,
-	0xf200,	0xf310,	0xf200,	0xf30c,	0xf200,	0xf30a,	0xf200,	0xf208,
-	0xf200,	0xf200,	0xf200,	0xf30d,	0xf30e,	0xf200,	0xf30b,	0xf200,
-	0xf200,	0xf200,	0xf300,	0xf301,	0xf302,	0xf303,	0xf304,	0xf305,
-	0xf306,	0xf307,	0xf200,	0xf308,	0xf309,	0xf200,	0xf200,	0xf200,
-	0xf504,	0xf505,	0xf506,	0xf502,	0xf507,	0xf508,	0xf200,	0xf50a,
-	0xf200,	0xf10c,	0xf200,	0xf200,	0xf200,	0xf509,	0xf200,	0xf50b,
-	0xf200,	0xf11d,	0xf115,	0xf114,	0xf118,	0xf116,	0xf503,	0xf117,
-	0xf501,	0xf119,	0xf500,	0xf700,	0xf701,	0xf702,	0xf200,	0xf200,
-};
-
-
-static void kbd_repeat(unsigned long);
-static struct timer_list repeat_timer = { function: kbd_repeat };
-static int last_keycode;
-
-static void mackeyb_probe(void);
-
-static void keyboard_input(unsigned char *, int, struct pt_regs *, int);
-static void input_keycode(int, int);
-static void leds_done(struct adb_request *);
-static void mac_put_queue(int);
-
-static void buttons_input(unsigned char *, int, struct pt_regs *, int);
-
-static void init_trackpad(int id);
-static void init_trackball(int id);
-static void init_turbomouse(int id);
-static void init_microspeed(int id);
-static void init_ms_a3(int id);
-
-extern struct kbd_struct kbd_table[];
-
-extern void handle_scancode(unsigned char, int);
-
-static struct adb_ids keyboard_ids;
-static struct adb_ids mouse_ids;
-static struct adb_ids buttons_ids;
-
-/* Kind of mouse  */
-#define ADBMOUSE_STANDARD_100	0	/* Standard 100cpi mouse (handler 1) */
-#define ADBMOUSE_STANDARD_200	1	/* Standard 200cpi mouse (handler 2) */
-#define ADBMOUSE_EXTENDED	2	/* Apple Extended mouse (handler 4) */
-#define ADBMOUSE_TRACKBALL	3	/* TrackBall (handler 4) */
-#define ADBMOUSE_TRACKPAD       4	/* Apple's PowerBook trackpad (handler 4) */
-#define ADBMOUSE_TURBOMOUSE5    5	/* Turbomouse 5 (previously req. mousehack) */
-#define ADBMOUSE_MICROSPEED	6	/* Microspeed mouse (&trackball ?), MacPoint */
-#define ADBMOUSE_TRACKBALLPRO	7	/* Trackball Pro (special buttons) */
-#define ADBMOUSE_MS_A3		8	/* Mouse systems A3 trackball (handler 3) */
-#define ADBMOUSE_MACALLY2	9	/* MacAlly 2-button mouse */
-
-static int adb_mouse_kinds[16];
-
-int mackbd_setkeycode(unsigned int scancode, unsigned int keycode)
-{
-	return -EINVAL;
-}
-
-int mackbd_getkeycode(unsigned int scancode)
-{
-	return -EINVAL;
-}
-
-int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
-		     char raw_mode)
-{
-	if (!raw_mode) {
-		/*
-		 * Convert R-shift/control/option to L version.
-		 */
-		switch (keycode) {
-		case 0x7b: keycode = 0x38; break; /* R-shift */
-		case 0x7c: keycode = 0x3a; break; /* R-option */
-		case 0x7d: keycode = 0x36; break; /* R-control */
-		}
-	}
-	*keycodep = keycode;
-	return 1;
-}
-
-char mackbd_unexpected_up(unsigned char keycode)
-{
-	return 0x80;
-}
-
-static void
-keyboard_input(unsigned char *data, int nb, struct pt_regs *regs, int apoll)
-{
-	/* first check this is from register 0 */
-	if (nb != 3 || (data[0] & 3) != KEYB_KEYREG)
-		return;		/* ignore it */
-	kbd_pt_regs = regs;
-	input_keycode(data[1], 0);
-	if (!(data[2] == 0xff || (data[2] == 0x7f && data[1] == 0x7f)))
-		input_keycode(data[2], 0);
-}
-
-static void
-input_keycode(int keycode, int repeat)
-{
-	struct kbd_struct *kbd;
-	int up_flag;
-
- 	kbd = kbd_table + fg_console;
-	up_flag = (keycode & 0x80);
-	keycode &= 0x7f;
-
-	/* on the powerbook 3400, the power key gives code 0x7e */
-	if (keycode == 0x7e)
-		keycode = 0x7f;
-	/* remap the "Fn" key of the PowerBook G3 Series to 0x48
-	   to avoid conflict with button emulation */
-	if (keycode == 0x3f)
-		keycode = 0x48;
-
-	if (!repeat)
-		del_timer(&repeat_timer);
-
-	if (kbd->kbdmode != VC_RAW) {
-		if (!up_flag && !dont_repeat[keycode]) {
-			last_keycode = keycode;
-			repeat_timer.expires = jiffies + (repeat? HZ/15: HZ/2);
-			add_timer(&repeat_timer);
-		}
-
-		/*
-		 * adb kludge!! Imitate pc caps lock behaviour by
-		 * generating an up/down event for each time caps
-		 * is pressed/released. Also, makes sure that the
-		 * LED are handled.  atong@uiuc.edu
-		 */
-		 switch (keycode) {
-		 /*case 0xb9:*/
-		 case 0x39:
-			handle_scancode(0x39, 1);
-			handle_scancode(0x39, 0);
-		 	tasklet_schedule(&keyboard_tasklet);
-		 	return;
-		 case 0x47:
-		 /*case 0xc7:*/
-		 	tasklet_schedule(&keyboard_tasklet);
-		 	break;
-		 }
-	}
-
-	handle_scancode(keycode, !up_flag);
-	tasklet_schedule(&keyboard_tasklet);
-}
-
-static void
-kbd_repeat(unsigned long xxx)
-{
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	input_keycode(last_keycode, 1);
-	restore_flags(flags);
-}
-
-static void mac_put_queue(int ch)
-{
-	extern struct tty_driver console_driver;
-	struct tty_struct *tty;
-
-	tty = console_driver.table? console_driver.table[fg_console]: NULL;
-	if (tty) {
-		tty_insert_flip_char(tty, ch, 0);
-		con_schedule_flip(tty);
-	}
-}
-
-static void
-buttons_input(unsigned char *data, int nb, struct pt_regs *regs, int autopoll)
-{
-#ifdef CONFIG_PMAC_BACKLIGHT
-	int backlight = get_backlight_level();
-
-	/*
-	 * XXX: Where is the contrast control for the passive?
-	 *  -- Cort
-	 */
-
-	/* Ignore data from register other than 0 */
-	if ((data[0] & 0x3) || (nb < 2))
-		return;
-
-	switch (data[1]) {
-	case 0x8:		/* mute */
-		break;
-
-	case 0x7:		/* contrast decrease */
-		break;
-
-	case 0x6:		/* contrast increase */
-		break;
-
-	case 0xa:		/* brightness decrease */
-		if (backlight < 0)
-			break;
-		if (backlight > BACKLIGHT_OFF)
-			set_backlight_level(backlight-1);
-		else
-			set_backlight_level(BACKLIGHT_OFF);
-		break;
-
-	case 0x9:		/* brightness increase */
-		if (backlight < 0)
-			break;
-		if (backlight < BACKLIGHT_MAX)
-			set_backlight_level(backlight+1);
-		else 
-			set_backlight_level(BACKLIGHT_MAX);
-		break;
-	}
-#endif /* CONFIG_PMAC_BACKLIGHT */
-}
-
-/* Map led flags as defined in kbd_kern.h to bits for Apple keyboard. */
-static unsigned char mac_ledmap[8] = {
-    0,		/* none */
-    4,		/* scroll lock */
-    1,		/* num lock */
-    5,		/* scroll + num lock */
-    2,		/* caps lock */
-    6,		/* caps + scroll lock */
-    3,		/* caps + num lock */
-    7,		/* caps + num + scroll lock */
-};
-
-static struct adb_request led_request;
-static int leds_pending[16];
-static int pending_devs[16];
-static int pending_led_start=0;
-static int pending_led_end=0;
-
-static void real_mackbd_leds(unsigned char leds, int device)
-{
-    if (led_request.complete) {
-	adb_request(&led_request, leds_done, 0, 3,
-		    ADB_WRITEREG(device, KEYB_LEDREG), 0xff,
-		    ~mac_ledmap[leds]);
-    } else {
-	if (!(leds_pending[device] & 0x100)) {
-	    pending_devs[pending_led_end] = device;
-	    pending_led_end++;
-	    pending_led_end = (pending_led_end < 16) ? pending_led_end : 0;
-	}
-	leds_pending[device] = leds | 0x100;
-    }
-}
-
-void mackbd_leds(unsigned char leds)
-{
-    int i;
-
-    for(i = 0; i < keyboard_ids.nids; i++)
-	real_mackbd_leds(leds,keyboard_ids.id[i]);
-}
-
-static void leds_done(struct adb_request *req)
-{
-    int leds,device;
-
-    if (pending_led_start != pending_led_end) {
-	device = pending_devs[pending_led_start];
-	leds = leds_pending[device] & 0xff;
-	leds_pending[device] = 0;
-	pending_led_start++;
-	pending_led_start = (pending_led_start < 16) ? pending_led_start : 0;
-	real_mackbd_leds(leds,device);
-    }
-
-}
-
-void __init mackbd_init_hw(void)
-{
-#ifdef CONFIG_PPC
-	if ( (_machine != _MACH_chrp) && (_machine != _MACH_Pmac) )
-		return;
-#endif
-#ifdef CONFIG_MAC
-	if (!MACH_IS_MAC)
-		return;
-#endif
-
-	/* setup key map */
-	memcpy(key_maps[0], macplain_map, sizeof(plain_map));
-	memcpy(key_maps[1], macshift_map, sizeof(plain_map));
-	memcpy(key_maps[2], macaltgr_map, sizeof(plain_map));
-	memcpy(key_maps[4], macctrl_map, sizeof(plain_map));
-	memcpy(key_maps[5], macshift_ctrl_map, sizeof(plain_map));
-	memcpy(key_maps[8], macalt_map, sizeof(plain_map));
-	memcpy(key_maps[12], macctrl_alt_map, sizeof(plain_map));
-
-	led_request.complete = 1;
-
-	mackeyb_probe();
-
-	notifier_chain_register(&adb_client_list, &mackeyb_adb_notifier);
-}
-
-static int
-adb_message_handler(struct notifier_block *this, unsigned long code, void *x)
-{
-	unsigned long flags;
-
-	switch (code) {
-	case ADB_MSG_PRE_RESET:
-	case ADB_MSG_POWERDOWN:
-		/* Stop the repeat timer. Autopoll is already off at this point */
-		save_flags(flags);
-		cli();
-		del_timer(&repeat_timer);
-		restore_flags(flags);
-
-		/* Stop pending led requests */
-		while(!led_request.complete)
-			adb_poll();
-		break;
-
-	case ADB_MSG_POST_RESET:
-		mackeyb_probe();
-		break;
-	}
-	return NOTIFY_DONE;
-}
-
-static void
-mackeyb_probe(void)
-{
-	struct adb_request req;
-	int i;
-
-	adb_register(ADB_KEYBOARD, 0, &keyboard_ids, keyboard_input);
-	adb_register(0x07, 0x1F, &buttons_ids, buttons_input);
-
-	for (i = 0; i < keyboard_ids.nids; i++) {
-		int id = keyboard_ids.id[i];
-
-		/* turn off all leds */
-		adb_request(&req, NULL, ADBREQ_SYNC, 3,
-			    ADB_WRITEREG(id, KEYB_LEDREG), 0xff, 0xff);
-
-		/* Enable full feature set of the keyboard
-		   ->get it to send separate codes for left and right shift,
-		   control, option keys */
-#if 0		/* handler 5 doesn't send separate codes for R modifiers */
-		if (adb_try_handler_change(id, 5))
-			printk("ADB keyboard at %d, handler set to 5\n", id);
-		else
-#endif
-		if (adb_try_handler_change(id, 3))
-			printk("ADB keyboard at %d, handler set to 3\n", id);
-		else
-			printk("ADB keyboard at %d, handler 1\n", id);
-	}
-
-	/* Try to switch all mice to handler 4, or 2 for three-button
-	   mode and full resolution. */
-	for (i = 0; i < mouse_ids.nids; i++) {
-		int id = mouse_ids.id[i];
-		if (adb_try_handler_change(id, 4)) {
-			printk("ADB mouse at %d, handler set to 4", id);
-			adb_mouse_kinds[id] = ADBMOUSE_EXTENDED;
-		}
-		else if (adb_try_handler_change(id, 0x2F)) {
-			printk("ADB mouse at %d, handler set to 0x2F", id);
-			adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED;
-		}
-		else if (adb_try_handler_change(id, 0x42)) {
-			printk("ADB mouse at %d, handler set to 0x42", id);
-			adb_mouse_kinds[id] = ADBMOUSE_TRACKBALLPRO;
-		}
-		else if (adb_try_handler_change(id, 0x66)) {
-			printk("ADB mouse at %d, handler set to 0x66", id);
-			adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED;
-		}
-		else if (adb_try_handler_change(id, 0x5F)) {
-			printk("ADB mouse at %d, handler set to 0x5F", id);
-			adb_mouse_kinds[id] = ADBMOUSE_MICROSPEED;
-		}
-		else if (adb_try_handler_change(id, 3)) {
-			printk("ADB mouse at %d, handler set to 3", id);
-			adb_mouse_kinds[id] = ADBMOUSE_MS_A3;
-		}
-		else if (adb_try_handler_change(id, 2)) {
-			printk("ADB mouse at %d, handler set to 2", id);
-			adb_mouse_kinds[id] = ADBMOUSE_STANDARD_200;
-		}
-		else {
-			printk("ADB mouse at %d, handler 1", id);
-			adb_mouse_kinds[id] = ADBMOUSE_STANDARD_100;
-		}
-
-		if ((adb_mouse_kinds[id] == ADBMOUSE_TRACKBALLPRO)
-		    || (adb_mouse_kinds[id] == ADBMOUSE_MICROSPEED)) {
-			init_microspeed(id);
-		} else if (adb_mouse_kinds[id] == ADBMOUSE_MS_A3) {
-			init_ms_a3(id);
-		}  else if (adb_mouse_kinds[id] ==  ADBMOUSE_EXTENDED) {
-			/*
-			 * Register 1 is usually used for device
-			 * identification.  Here, we try to identify
-			 * a known device and call the appropriate
-			 * init function.
-			 */
-			adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
-				    ADB_READREG(id, 1));
-
-			if ((req.reply_len) &&
-			    (req.reply[1] == 0x9a) && ((req.reply[2] == 0x21)
-				|| (req.reply[2] == 0x20)))
-				init_trackball(id);
-			else if ((req.reply_len >= 4) &&
-			    (req.reply[1] == 0x74) && (req.reply[2] == 0x70) &&
-			    (req.reply[3] == 0x61) && (req.reply[4] == 0x64))
-				init_trackpad(id);
-			else if ((req.reply_len >= 4) &&
-			    (req.reply[1] == 0x4b) && (req.reply[2] == 0x4d) &&
-			    (req.reply[3] == 0x4c) && (req.reply[4] == 0x31))
-				init_turbomouse(id);
-			else if ((req.reply_len == 9) &&
-			    (req.reply[1] == 0x4b) && (req.reply[2] == 0x4f) &&
-			    (req.reply[3] == 0x49) && (req.reply[4] == 0x54)){
-				if (adb_try_handler_change(id, 0x42)) {
-					printk("\nADB MacAlly 2-button mouse at %d, handler set to 0x42", id);
-					adb_mouse_kinds[id] = ADBMOUSE_MACALLY2;
-				}
-			}
-		}
-		printk("\n");
-        }
-}
-
-static void
-init_trackpad(int id)
-{
-	struct adb_request req;
-	unsigned char r1_buffer[8];
-
-	printk(" (trackpad)");
-
-	adb_mouse_kinds[id] = ADBMOUSE_TRACKPAD;
-
-	adb_request(&req, NULL, ADBREQ_SYNC | ADBREQ_REPLY, 1,
-	ADB_READREG(id,1));
-	if (req.reply_len < 8)
-	    printk("bad length for reg. 1\n");
-	else
-	{
-	    memcpy(r1_buffer, &req.reply[1], 8);
-	    adb_request(&req, NULL, ADBREQ_SYNC, 9,
-	        ADB_WRITEREG(id,1),
-	            r1_buffer[0],
-	            r1_buffer[1],
-	            r1_buffer[2],
-	            r1_buffer[3],
-	            r1_buffer[4],
-	            r1_buffer[5],
-	            0x0d, /*r1_buffer[6],*/
-	            r1_buffer[7]);
-
-            adb_request(&req, NULL, ADBREQ_SYNC, 9,
-	        ADB_WRITEREG(id,2),
-		    0x99,
-		    0x94,
-		    0x19,
-		    0xff,
-		    0xb2,
-		    0x8a,
-		    0x1b,
-		    0x50);
-
-	    adb_request(&req, NULL, ADBREQ_SYNC, 9,
-	        ADB_WRITEREG(id,1),
-	            r1_buffer[0],
-	            r1_buffer[1],
-	            r1_buffer[2],
-	            r1_buffer[3],
-	            r1_buffer[4],
-	            r1_buffer[5],
-	            0x03, /*r1_buffer[6],*/
-	            r1_buffer[7]);
-
-	    /* Without this flush, the trackpad may be locked up */	    
-	    adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
-        }
-}
-
-static void
-init_trackball(int id)
-{
-	struct adb_request req;
-
-	printk(" (trackman/mouseman)");
-
-	adb_mouse_kinds[id] = ADBMOUSE_TRACKBALL;
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	ADB_WRITEREG(id,1), 00,0x81);
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	ADB_WRITEREG(id,1), 01,0x81);
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	ADB_WRITEREG(id,1), 02,0x81);
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	ADB_WRITEREG(id,1), 03,0x38);
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	ADB_WRITEREG(id,1), 00,0x81);
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	ADB_WRITEREG(id,1), 01,0x81);
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	ADB_WRITEREG(id,1), 02,0x81);
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	ADB_WRITEREG(id,1), 03,0x38);
-}
-
-static void
-init_turbomouse(int id)
-{
-	struct adb_request req;
-
-        printk(" (TurboMouse 5)");
-
-	adb_mouse_kinds[id] = ADBMOUSE_TURBOMOUSE5;
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 9,
-	ADB_WRITEREG(3,2),
-	    0xe7,
-	    0x8c,
-	    0,
-	    0,
-	    0,
-	    0xff,
-	    0xff,
-	    0x94);
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(3));
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 9,
-	ADB_WRITEREG(3,2),
-	    0xa5,
-	    0x14,
-	    0,
-	    0,
-	    0x69,
-	    0xff,
-	    0xff,
-	    0x27);
-}
-
-static void
-init_microspeed(int id)
-{
-	struct adb_request req;
-
-        printk(" (Microspeed/MacPoint or compatible)");
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
-
-	/* This will initialize mice using the Microspeed, MacPoint and
-	   other compatible firmware. Bit 12 enables extended protocol.
-
-	   Register 1 Listen (4 Bytes)
-            0 -  3     Button is mouse (set also for double clicking!!!)
-            4 -  7     Button is locking (affects change speed also)
-            8 - 11     Button changes speed
-           12          1 = Extended mouse mode, 0 = normal mouse mode
-           13 - 15     unused 0
-           16 - 23     normal speed
-           24 - 31     changed speed
-
-       Register 1 talk holds version and product identification information.
-       Register 1 Talk (4 Bytes):
-            0 -  7     Product code
-            8 - 23     undefined, reserved
-           24 - 31     Version number
-
-       Speed 0 is max. 1 to 255 set speed in increments of 1/256 of max.
- */
-	adb_request(&req, NULL, ADBREQ_SYNC, 5,
-	ADB_WRITEREG(id,1),
-	    0x20,	/* alt speed = 0x20 (rather slow) */
-	    0x00,	/* norm speed = 0x00 (fastest) */
-	    0x10,	/* extended protocol, no speed change */
-	    0x07);	/* all buttons enabled as mouse buttons, no locking */
-
-
-	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
-}
-
-static void
-init_ms_a3(int id)
-{
-	struct adb_request req;
-
-	printk(" (Mouse Systems A3 Mouse, or compatible)");
-	adb_request(&req, NULL, ADBREQ_SYNC, 3,
-	ADB_WRITEREG(id, 0x2),
-	    0x00,
-	    0x07);
-
- 	adb_request(&req, NULL, ADBREQ_SYNC, 1, ADB_FLUSH(id));
- }
-
diff -Nru a/drivers/macintosh/macio-adb.c b/drivers/macintosh/macio-adb.c
--- a/drivers/macintosh/macio-adb.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/macintosh/macio-adb.c	Sun Nov 10 19:28:41 2002
@@ -7,6 +7,7 @@
 #include <linux/kernel.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
+#include <linux/spinlock.h>
 #include <asm/prom.h>
 #include <linux/adb.h>
 #include <asm/io.h>
@@ -57,7 +58,7 @@
 
 static volatile struct adb_regs *adb;
 static struct adb_request *current_req, *last_req;
-static unsigned char adb_rbuf[16];
+static spinlock_t macio_lock = SPIN_LOCK_UNLOCKED;
 
 static int macio_probe(void);
 static int macio_init(void);
@@ -66,7 +67,6 @@
 static int macio_adb_autopoll(int devs);
 static void macio_adb_poll(void);
 static int macio_adb_reset_bus(void);
-static void completed(void);
 
 struct adb_driver macio_adb_driver = {
 	"MACIO",
@@ -107,19 +107,19 @@
 	adb = (volatile struct adb_regs *)
 		ioremap(adbs->addrs->address, sizeof(struct adb_regs));
 
-	if (request_irq(adbs->intrs[0].line, macio_adb_interrupt,
-			0, "ADB", (void *)0)) {
-		printk(KERN_ERR "ADB: can't get irq %d\n",
-		       adbs->intrs[0].line);
-		return -EAGAIN;
-	}
-
 	out_8(&adb->ctrl.r, 0);
 	out_8(&adb->intr.r, 0);
 	out_8(&adb->error.r, 0);
 	out_8(&adb->active_hi.r, 0xff); /* for now, set all devices active */
 	out_8(&adb->active_lo.r, 0xff);
 	out_8(&adb->autopoll.r, APE);
+
+	if (request_irq(adbs->intrs[0].line, macio_adb_interrupt,
+			0, "ADB", (void *)0)) {
+		printk(KERN_ERR "ADB: can't get irq %d\n",
+		       adbs->intrs[0].line);
+		return -EAGAIN;
+	}
 	out_8(&adb->intr_enb.r, DFB | TAG);
 
 	printk("adb: mac-io driver 1.0 for unified ADB\n");
@@ -129,16 +129,27 @@
 
 static int macio_adb_autopoll(int devs)
 {
+	unsigned long flags;
+	
+	spin_lock_irqsave(&macio_lock, flags);
 	out_8(&adb->active_hi.r, devs >> 8);
 	out_8(&adb->active_lo.r, devs);
 	out_8(&adb->autopoll.r, devs? APE: 0);
+	spin_unlock_irqrestore(&macio_lock, flags);
 	return 0;
 }
 
 static int macio_adb_reset_bus(void)
 {
+	unsigned long flags;
 	int timeout = 1000000;
 
+	/* Hrm... we may want to not lock interrupts for so
+	 * long ... oh well, who uses that chip anyway ? :)
+	 * That function will be seldomly used during boot
+	 * on rare machines, so...
+	 */
+	spin_lock_irqsave(&macio_lock, flags);
 	out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | ADB_RST);
 	while ((in_8(&adb->ctrl.r) & ADB_RST) != 0) {
 		if (--timeout == 0) {
@@ -146,13 +157,14 @@
 			return -1;
 		}
 	}
+	spin_unlock_irqrestore(&macio_lock, flags);
 	return 0;
 }
 
 /* Send an ADB command */
 static int macio_send_request(struct adb_request *req, int sync)
 {
-	unsigned long mflags;
+	unsigned long flags;
 	int i;
 	
 	if (req->data[0] != ADB_PACKET)
@@ -167,8 +179,7 @@
 	req->complete = 0;
 	req->reply_len = 0;
 
-	save_flags(mflags);
-	cli();
+	spin_lock_irqsave(&macio_lock, flags);
 	if (current_req != 0) {
 		last_req->next = req;
 		last_req = req;
@@ -176,7 +187,7 @@
 		current_req = last_req = req;
 		out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
 	}
-	restore_flags(mflags);
+	spin_unlock_irqrestore(&macio_lock, flags);
 	
 	if (sync) {
 		while (!req->complete)
@@ -190,7 +201,12 @@
 {
 	int i, n, err;
 	struct adb_request *req;
-
+	unsigned char ibuf[16];
+	int ibuf_len = 0;
+	int complete = 0;
+	int autopoll = 0;
+	
+	spin_lock(&macio_lock);
 	if (in_8(&adb->intr.r) & TAG) {
 		if ((req = current_req) != 0) {
 			/* put the current request in */
@@ -202,7 +218,10 @@
 				out_8(&adb->ctrl.r, DTB + CRE);
 			} else {
 				out_8(&adb->ctrl.r, DTB);
-				completed();
+				current_req = req->next;
+				complete = 1;
+				if (current_req)
+					out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
 			}
 		}
 		out_8(&adb->intr.r, 0);
@@ -218,39 +237,42 @@
 				for (i = 0; i < req->reply_len; ++i)
 					req->reply[i] = in_8(&adb->data[i].r);
 			}
-			completed();
+			current_req = req->next;
+			complete = 1;
+			if (current_req)
+				out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
 		} else if (err == 0) {
 			/* autopoll data */
 			n = in_8(&adb->dcount.r) & HMB;
 			for (i = 0; i < n; ++i)
-				adb_rbuf[i] = in_8(&adb->data[i].r);
-			adb_input(adb_rbuf, n, regs,
-				  in_8(&adb->dcount.r) & APD);
+				ibuf[i] = in_8(&adb->data[i].r);
+			ibuf_len = n;
+			autopoll = (in_8(&adb->dcount.r) & APD) != 0;
 		}
 		out_8(&adb->error.r, 0);
 		out_8(&adb->intr.r, 0);
 	}
-}
-
-static void completed(void)
-{
-	struct adb_request *req = current_req;
-
-	req->complete = 1;
-	current_req = req->next;
-	if (current_req)
-		out_8(&adb->ctrl.r, in_8(&adb->ctrl.r) | TAR);
-	if (req->done)
-		(*req->done)(req);
+	spin_unlock(&macio_lock);
+	if (complete && req) {
+	    void (*done)(struct adb_request *) = req->done;
+	    mb();
+	    req->complete = 1;
+	    /* Here, we assume that if the request has a done member, the
+    	     * struct request will survive to setting req->complete to 1
+	     */
+	    if (done)
+		(*done)(req);
+	}
+	if (ibuf_len)
+		adb_input(ibuf, ibuf_len, regs, autopoll);
 }
 
 static void macio_adb_poll(void)
 {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	local_irq_save(flags);
 	if (in_8(&adb->intr.r) != 0)
 		macio_adb_interrupt(0, 0, 0);
-	restore_flags(flags);
+	local_irq_restore(flags);
 }
diff -Nru a/drivers/macintosh/mackeymap.map b/drivers/macintosh/mackeymap.map
--- a/drivers/macintosh/mackeymap.map	Sun Nov 10 19:28:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,344 +0,0 @@
-# Kernel keymap for Macintoshes. This uses 7 modifier combinations.
-keymaps 0-2,4-5,8,12
-# We use the Command (pretzel) key as Alt, and the Option key as AltGr.
-#
-keycode 0x00 = a
-	altgr   keycode 0x00 = Hex_A
-keycode 0x01 = s               
-keycode 0x02 = d
-	altgr   keycode 0x02 = Hex_D   
-keycode 0x03 = f
-	altgr   keycode 0x03 = Hex_F               
-keycode 0x04 = h               
-keycode 0x05 = g  
-keycode 0x06 = z
-keycode 0x07 = x               
-keycode 0x08 = c
-	altgr   keycode 0x08 = Hex_C   
-keycode 0x09 = v
-keycode 0x0a =
-keycode 0x0b = b
-	altgr   keycode 0x0b = Hex_B
-keycode 0x0c = q               
-keycode 0x0d = w               
-keycode 0x0e = e
-	altgr   keycode 0x0e = Hex_E   
-keycode 0x0f = r               
-keycode 0x10 = y               
-keycode 0x11 = t               
-keycode 0x12 = one              exclam          
-	alt     keycode 0x12 = Meta_one        
-keycode 0x13 = two              at               at              
-	control	keycode 0x13 = nul             
-	shift	control	keycode 0x13 = nul             
-	alt	keycode 0x13 = Meta_two        
-keycode 0x14 = three            numbersign      
-	control keycode 0x14 = Escape          
-	alt     keycode 0x14 = Meta_three      
-keycode 0x15 = four             dollar           dollar          
-	control keycode 0x15 = Control_backslash
-	alt     keycode 0x15 = Meta_four       
-keycode 0x16 = six              asciicircum     
-	control keycode 0x16 = Control_asciicircum
-	alt     keycode 0x16 = Meta_six        
-keycode 0x17 = five             percent         
-	control keycode 0x17 = Control_bracketright
-	alt     keycode 0x17 = Meta_five       
-keycode 0x18 = equal            plus            
-	alt     keycode 0x18 = Meta_equal      
-keycode 0x19 = nine             parenleft        bracketright    
-	alt     keycode 0x19 = Meta_nine       
-keycode 0x1a = seven            ampersand        braceleft       
-	control keycode 0x1a = Control_underscore
-	alt     keycode 0x1a = Meta_seven      
-keycode 0x1b = minus            underscore       backslash       
-	control	keycode 0x1b = Control_underscore
-	shift	control	keycode 0x1b = Control_underscore
-	alt	keycode 0x1b = Meta_minus      
-keycode 0x1c = eight            asterisk         bracketleft     
-	control keycode 0x1c = Delete          
-	alt     keycode 0x1c = Meta_eight      
-keycode 0x1d = zero             parenright       braceright      
-	alt     keycode 0x1d = Meta_zero       
-keycode 0x1e = bracketright     braceright       asciitilde      
-	control keycode 0x1e = Control_bracketright
-	alt     keycode 0x1e = Meta_bracketright
-keycode 0x1f = o               
-keycode 0x20 = u               
-keycode 0x21 = bracketleft      braceleft       
-	control keycode 0x21 = Escape          
-	alt     keycode 0x21 = Meta_bracketleft
-keycode 0x22 = i               
-keycode 0x23 = p               
-keycode 0x24 = Return          
-	alt     keycode 0x24 = Meta_Control_m  
-keycode 0x25 = l               
-keycode 0x26 = j               
-keycode 0x27 = apostrophe       quotedbl        
-	control keycode 0x27 = Control_g       
-	alt     keycode 0x27 = Meta_apostrophe 
-keycode 0x28 = k               
-keycode 0x29 = semicolon        colon           
-	alt     keycode 0x29 = Meta_semicolon  
-keycode 0x2a = backslash        bar             
-	control keycode 0x2a = Control_backslash
-	alt     keycode 0x2a = Meta_backslash  
-keycode 0x2b = comma            less            
-	alt     keycode 0x2b = Meta_comma      
-keycode 0x2c = slash            question        
-	control keycode 0x2c = Delete          
-	alt     keycode 0x2c = Meta_slash      
-keycode 0x2d = n
-keycode 0x2e = m               
-keycode 0x2f = period           greater         
-	control keycode 0x2f = Compose         
-	alt     keycode 0x2f = Meta_period     
-keycode 0x30 = Tab              Tab             
-	alt     keycode 0x30 = Meta_Tab        
-keycode 0x31 = space            space           
-	control keycode 0x31 = nul             
-	alt     keycode 0x31 = Meta_space      
-keycode 0x32 = grave            asciitilde      
-	control keycode 0x32 = nul             
-	alt     keycode 0x32 = Meta_grave      
-keycode 0x33 = Delete           Delete          
-	control keycode 0x33 = BackSpace
-	alt     keycode 0x33 = Meta_Delete     
-keycode 0x34 =
-keycode 0x35 = Escape           Escape          
-	alt     keycode 0x35 = Meta_Escape     
-keycode 0x36 = Control         
-keycode 0x37 = Alt             
-keycode 0x38 = Shift
-keycode 0x39 = Caps_Lock       
-keycode 0x3a = AltGr           
-keycode 0x3b = Left            
-	alt     keycode 0x3b = Decr_Console
-keycode 0x3c = Right           
-	alt     keycode 0x3c = Incr_Console
-keycode 0x3d = Down            
-keycode 0x3e = Up              
-keycode 0x3f =
-keycode 0x40 =
-keycode 0x41 = KP_Period       
-keycode 0x42 =
-keycode 0x43 = KP_Multiply     
-keycode 0x44 =
-keycode 0x45 = KP_Add          
-keycode 0x46 =
-keycode 0x47 = Num_Lock
-#	shift   keycode 0x47 = Bare_Num_Lock
-keycode 0x48 =
-keycode 0x49 =
-keycode 0x4a =
-keycode 0x4b = KP_Divide       
-keycode 0x4c = KP_Enter        
-keycode 0x4d =
-keycode 0x4e = KP_Subtract     
-keycode 0x4f =
-keycode 0x50 =
-keycode 0x51 =
-#keycode 0x51 = KP_Equals
-keycode 0x52 = KP_0            
-	alt     keycode 0x52 = Ascii_0         
-	altgr   keycode 0x52 = Hex_0         
-keycode 0x53 = KP_1            
-	alt     keycode 0x53 = Ascii_1         
-	altgr   keycode 0x53 = Hex_1         
-keycode 0x54 = KP_2            
-	alt     keycode 0x54 = Ascii_2         
-	altgr   keycode 0x54 = Hex_2         
-keycode 0x55 = KP_3            
-	alt     keycode 0x55 = Ascii_3         
-	altgr   keycode 0x55 = Hex_3         
-keycode 0x56 = KP_4            
-	alt     keycode 0x56 = Ascii_4         
-	altgr   keycode 0x56 = Hex_4         
-keycode 0x57 = KP_5            
-	alt     keycode 0x57 = Ascii_5         
-	altgr   keycode 0x57 = Hex_5         
-keycode 0x58 = KP_6            
-	alt     keycode 0x58 = Ascii_6         
-	altgr   keycode 0x58 = Hex_6         
-keycode 0x59 = KP_7            
-	alt     keycode 0x59 = Ascii_7         
-	altgr   keycode 0x59 = Hex_7
-keycode 0x5b = KP_8            
-	alt     keycode 0x5b = Ascii_8         
-	altgr   keycode 0x5b = Hex_8         
-keycode 0x5c = KP_9            
-	alt     keycode 0x5c = Ascii_9         
-	altgr   keycode 0x5c = Hex_9         
-keycode 0x5d =
-keycode 0x5e =
-keycode 0x5f =
-keycode 0x60 = F5               F15              Console_17      
-	control keycode 0x60 = F5              
-	alt     keycode 0x60 = Console_5       
-	control alt     keycode 0x60 = Console_5       
-keycode 0x61 = F6               F16              Console_18      
-	control keycode 0x61 = F6              
-	alt     keycode 0x61 = Console_6       
-	control alt     keycode 0x61 = Console_6       
-keycode 0x62 = F7               F17              Console_19      
-	control keycode 0x62 = F7              
-	alt     keycode 0x62 = Console_7       
-	control alt     keycode 0x62 = Console_7       
-keycode 0x63 = F3               F13              Console_15      
-	control keycode 0x63 = F3              
-	alt     keycode 0x63 = Console_3       
-	control alt     keycode 0x63 = Console_3       
-keycode 0x64 = F8               F18              Console_20      
-	control keycode 0x64 = F8              
-	alt     keycode 0x64 = Console_8       
-	control alt     keycode 0x64 = Console_8       
-keycode 0x65 = F9               F19              Console_21      
-	control keycode 0x65 = F9              
-	alt     keycode 0x65 = Console_9       
-	control alt     keycode 0x65 = Console_9       
-keycode 0x66 =
-keycode 0x67 = F11              F11              Console_23      
-	control keycode 0x67 = F11             
-	alt     keycode 0x67 = Console_11      
-	control alt     keycode 0x67 = Console_11      
-keycode 0x68 =
-keycode 0x69 = F13             
-keycode 0x6a =
-keycode 0x6b = Scroll_Lock      Show_Memory      Show_Registers  
-	control keycode 0x6b = Show_State      
-	alt     keycode 0x6b = Scroll_Lock     
-keycode 0x6c =
-keycode 0x6d = F10              F20              Console_22      
-	control keycode 0x6d = F10             
-	alt     keycode 0x6d = Console_10      
-	control alt     keycode 0x6d = Console_10      
-keycode 0x6e =
-keycode 0x6f = F12              F12              Console_24      
-	control keycode 0x6f = F12             
-	alt     keycode 0x6f = Console_12      
-	control alt     keycode 0x6f = Console_12      
-keycode 0x70 =
-keycode 0x71 = Pause
-keycode 0x72 = Insert          
-keycode 0x73 = Home
-keycode 0x74 = Prior           
-	shift   keycode 0x74 = Scroll_Backward 
-keycode 0x75 = Remove          
-keycode 0x76 = F4               F14              Console_16      
-	control keycode 0x76 = F4              
-	alt     keycode 0x76 = Console_4       
-	control alt     keycode 0x76 = Console_4       
-keycode 0x77 = End
-keycode 0x78 = F2               F12              Console_14      
-	control keycode 0x78 = F2              
-	alt     keycode 0x78 = Console_2       
-	control alt     keycode 0x78 = Console_2       
-keycode 0x79 = Next            
-	shift   keycode 0x79 = Scroll_Forward  
-keycode 0x7a = F1               F11              Console_13      
-	control keycode 0x7a = F1              
-	alt     keycode 0x7a = Console_1       
-	control alt     keycode 0x7a = Console_1       
-keycode 0x7b = Shift
-keycode 0x7c = AltGr
-keycode 0x7d = Control
-keycode 0x7e =
-keycode 0x7f =
-#keycode 0x7f = Power
-	control shift   keycode 0x7f = Boot
-string F1 = "\033[[A"
-string F2 = "\033[[B"
-string F3 = "\033[[C"
-string F4 = "\033[[D"
-string F5 = "\033[[E"
-string F6 = "\033[17~"
-string F7 = "\033[18~"
-string F8 = "\033[19~"
-string F9 = "\033[20~"
-string F10 = "\033[21~"
-string F11 = "\033[23~"
-string F12 = "\033[24~"
-string F13 = "\033[25~"
-string F14 = "\033[26~"
-string F15 = "\033[28~"
-string F16 = "\033[29~"
-string F17 = "\033[31~"
-string F18 = "\033[32~"
-string F19 = "\033[33~"
-string F20 = "\033[34~"
-string Find = "\033[1~"
-string Insert = "\033[2~"
-string Remove = "\033[3~"
-string Select = "\033[4~"
-string Prior = "\033[5~"
-string Next = "\033[6~"
-string Macro = "\033[M"
-string Pause = "\033[P"
-compose '`' 'A' to 'À'
-compose '`' 'a' to 'à'
-compose '\'' 'A' to 'Á'
-compose '\'' 'a' to 'á'
-compose '^' 'A' to 'Â'
-compose '^' 'a' to 'â'
-compose '~' 'A' to 'Ã'
-compose '~' 'a' to 'ã'
-compose '"' 'A' to 'Ä'
-compose '"' 'a' to 'ä'
-compose 'O' 'A' to 'Å'
-compose 'o' 'a' to 'å'
-compose '0' 'A' to 'Å'
-compose '0' 'a' to 'å'
-compose 'A' 'A' to 'Å'
-compose 'a' 'a' to 'å'
-compose 'A' 'E' to 'Æ'
-compose 'a' 'e' to 'æ'
-compose ',' 'C' to 'Ç'
-compose ',' 'c' to 'ç'
-compose '`' 'E' to 'È'
-compose '`' 'e' to 'è'
-compose '\'' 'E' to 'É'
-compose '\'' 'e' to 'é'
-compose '^' 'E' to 'Ê'
-compose '^' 'e' to 'ê'
-compose '"' 'E' to 'Ë'
-compose '"' 'e' to 'ë'
-compose '`' 'I' to 'Ì'
-compose '`' 'i' to 'ì'
-compose '\'' 'I' to 'Í'
-compose '\'' 'i' to 'í'
-compose '^' 'I' to 'Î'
-compose '^' 'i' to 'î'
-compose '"' 'I' to 'Ï'
-compose '"' 'i' to 'ï'
-compose '-' 'D' to 'Ð'
-compose '-' 'd' to 'ð'
-compose '~' 'N' to 'Ñ'
-compose '~' 'n' to 'ñ'
-compose '`' 'O' to 'Ò'
-compose '`' 'o' to 'ò'
-compose '\'' 'O' to 'Ó'
-compose '\'' 'o' to 'ó'
-compose '^' 'O' to 'Ô'
-compose '^' 'o' to 'ô'
-compose '~' 'O' to 'Õ'
-compose '~' 'o' to 'õ'
-compose '"' 'O' to 'Ö'
-compose '"' 'o' to 'ö'
-compose '/' 'O' to 'Ø'
-compose '/' 'o' to 'ø'
-compose '`' 'U' to 'Ù'
-compose '`' 'u' to 'ù'
-compose '\'' 'U' to 'Ú'
-compose '\'' 'u' to 'ú'
-compose '^' 'U' to 'Û'
-compose '^' 'u' to 'û'
-compose '"' 'U' to 'Ü'
-compose '"' 'u' to 'ü'
-compose '\'' 'Y' to 'Ý'
-compose '\'' 'y' to 'ý'
-compose 'T' 'H' to 'Þ'
-compose 't' 'h' to 'þ'
-compose 's' 's' to 'ß'
-compose '"' 'y' to 'ÿ'
-compose 's' 'z' to 'ß'
-compose 'i' 'j' to 'ÿ'
diff -Nru a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
--- a/drivers/macintosh/macserial.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/macintosh/macserial.c	Sun Nov 10 19:28:39 2002
@@ -18,6 +18,7 @@
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/interrupt.h>
+#include <linux/workqueue.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
 #include <linux/major.h>
@@ -104,8 +105,6 @@
 #endif
 #define ZS_CLOCK         3686400 	/* Z8530 RTxC input clock rate */
 
-static DECLARE_TASK_QUEUE(tq_serial);
-
 static struct tty_driver serial_driver, callout_driver;
 static int serial_refcount;
 
@@ -372,8 +371,7 @@
 				  int event)
 {
 	info->event |= 1 << event;
-	queue_task(&info->tqueue, &tq_serial);
-	mark_bh(MACSERIAL_BH);
+	schedule_work(&info->tqueue);
 }
 
 /* Work out the flag value for a z8530 status value. */
@@ -712,20 +710,6 @@
 	restore_flags(flags);
 }
 
-/*
- * This routine is used to handle the "bottom half" processing for the
- * serial driver, known also the "software interrupt" processing.
- * This processing is done at the kernel interrupt level, after the
- * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
- * is where time-consuming activities which can not be done in the
- * interrupt driver proper are done; the interrupt driver schedules
- * them using rs_sched_event(), and they get done here.
- */
-static void do_serial_bh(void)
-{
-	run_task_queue(&tq_serial);
-}
-
 static void do_softint(void *private_)
 {
 	struct mac_serial	*info = (struct mac_serial *) private_;
@@ -876,7 +860,7 @@
 out:
 	spin_unlock_irqrestore(&info->rx_dma_lock, flags);
 	if (do_queue)
-		queue_task(&tty->flip.tqueue, &tq_timer);
+		tty_flip_buffer_push(tty);
 }
 
 static void poll_rxdma(unsigned long private_)
@@ -2572,9 +2556,6 @@
 	unsigned long flags;
 	struct mac_serial *info;
 
-	/* Setup base handler, and timer table. */
-	init_bh(MACSERIAL_BH, do_serial_bh);
-
 	/* Find out how many Z8530 SCCs we have */
 	if (zs_chain == 0)
 		probe_sccs();
@@ -2741,9 +2722,8 @@
 		info->event = 0;
 		info->count = 0;
 		info->blocked_open = 0;
-		info->tqueue.routine = do_softint;
-		info->tqueue.data = info;
-		info->callout_termios =callout_driver.init_termios;
+		INIT_WORK(&info->tqueue, do_softint, info);
+		info->callout_termios = callout_driver.init_termios;
 		info->normal_termios = serial_driver.init_termios;
 		init_waitqueue_head(&info->open_wait);
 		init_waitqueue_head(&info->close_wait);
@@ -2865,33 +2845,9 @@
 	/* Don't disable the transmitter. */
 }
 
-/*
- *	Receive character from the serial port
- */
-static int serial_console_wait_key(struct console *co)
-{
-	struct mac_serial *info = zs_soft + co->index;
-	int           val;
-
-	/* Turn of interrupts and enable the transmitter. */
-	write_zsreg(info->zs_channel, R1, info->curregs[1] & ~INT_ALL_Rx);
-	write_zsreg(info->zs_channel, R3, info->curregs[3] | RxENABLE);
-
-	/* Wait for something in the receive buffer. */
-	while((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0)
-		eieio();
-	val = read_zsdata(info->zs_channel);
-
-	/* Restore the values in the registers. */
-	write_zsreg(info->zs_channel, R1, info->curregs[1]);
-	write_zsreg(info->zs_channel, R3, info->curregs[3]);
-
-	return val;
-}
-
 static kdev_t serial_console_device(struct console *c)
 {
-	return MKDEV(TTY_MAJOR, 64 + c->index);
+	return mk_kdev(TTY_MAJOR, 64 + c->index);
 }
 
 /*
@@ -3079,7 +3035,6 @@
 	name:		"ttyS",
 	write:		serial_console_write,
 	device:		serial_console_device,
-	wait_key:	serial_console_wait_key,
 	setup:		serial_console_setup,
 	flags:		CON_PRINTBUFFER,
 	index:		-1,
diff -Nru a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h
--- a/drivers/macintosh/macserial.h	Sun Nov 10 19:28:39 2002
+++ b/drivers/macintosh/macserial.h	Sun Nov 10 19:28:39 2002
@@ -159,8 +159,7 @@
 	int			xmit_head;
 	int			xmit_tail;
 	int			xmit_cnt;
-	struct tq_struct	tqueue;
-	struct tq_struct	tqueue_hangup;
+	struct work_struct	tqueue;
 	struct termios		normal_termios;
 	struct termios		callout_termios;
 	wait_queue_head_t	open_wait;
diff -Nru a/drivers/macintosh/rtc.c b/drivers/macintosh/rtc.c
--- a/drivers/macintosh/rtc.c	Sun Nov 10 19:28:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,147 +0,0 @@
-/*
- * Linux/PowerPC Real Time Clock Driver
- *
- * heavily based on:
- * Linux/SPARC Real Time Clock Driver
- * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
- *
- * This is a little driver that lets a user-level program access
- * the PPC clocks chip. It is no use unless you
- * use the modified clock utility.
- *
- * Get the modified clock utility from:
- *   ftp://vger.rutgers.edu/pub/linux/Sparc/userland/clock.c
- */
-
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/miscdevice.h>
-#include <linux/slab.h>
-#include <linux/fcntl.h>
-#include <linux/poll.h>
-#include <linux/init.h>
-#include <linux/mc146818rtc.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/machdep.h>
-
-#include <asm/time.h>
-
-static int rtc_busy = 0;
-
-/* Retrieve the current date and time from the real time clock. */
-void get_rtc_time(struct rtc_time *t)
-{
-	unsigned long nowtime;
-
-	nowtime = (ppc_md.get_rtc_time)();
-
-	to_tm(nowtime, t);
-
-	t->tm_year -= 1900;
-	t->tm_mon -= 1; /* Make sure userland has a 0-based month */
-}
-
-/* Set the current date and time in the real time clock. */
-void set_rtc_time(struct rtc_time *t)
-{
-	unsigned long nowtime;
-
-	nowtime = mktime(t->tm_year+1900, t->tm_mon+1, t->tm_mday,
-			t->tm_hour, t->tm_min, t->tm_sec);
-
-	(ppc_md.set_rtc_time)(nowtime);
-}
-
-static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-	unsigned long arg)
-{
-	struct rtc_time rtc_tm;
-
-	switch (cmd)
-	{
-	case RTC_RD_TIME:
-		if (ppc_md.get_rtc_time)
-		{
-			get_rtc_time(&rtc_tm);
-
-			if (copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time)))
-				return -EFAULT;
-
-			return 0;
-		}
-		else
-			return -EINVAL;
-
-	case RTC_SET_TIME:
-		if (!capable(CAP_SYS_TIME))
-			return -EPERM;
-
-		if (ppc_md.set_rtc_time)
-		{
-			if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
-				return -EFAULT;
-
-			set_rtc_time(&rtc_tm);
-
-			return 0;
-		}
-		else
-			return -EINVAL;
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static int rtc_open(struct inode *inode, struct file *file)
-{
-	if (rtc_busy)
-		return -EBUSY;
-
-	rtc_busy = 1;
-
-	MOD_INC_USE_COUNT;
-
-	return 0;
-}
-
-static int rtc_release(struct inode *inode, struct file *file)
-{
-	MOD_DEC_USE_COUNT;
-	rtc_busy = 0;
-	return 0;
-}
-
-static struct file_operations rtc_fops = {
-	owner:		THIS_MODULE,
-	llseek:		no_llseek,
-	ioctl:		rtc_ioctl,
-	open:		rtc_open,
-	release:	rtc_release
-};
-
-static struct miscdevice rtc_dev = { RTC_MINOR, "rtc", &rtc_fops };
-
-static int __init rtc_init(void)
-{
-	int error;
-
-	error = misc_register(&rtc_dev);
-	if (error) {
-		printk(KERN_ERR "rtc: unable to get misc minor\n");
-		return error;
-	}
-
-	return 0;
-}
-
-static void __exit rtc_exit(void)
-{
-	misc_deregister(&rtc_dev);
-}
-
-module_init(rtc_init);
-module_exit(rtc_exit);
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c
--- a/drivers/macintosh/via-cuda.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/macintosh/via-cuda.c	Sun Nov 10 19:28:37 2002
@@ -17,6 +17,7 @@
 #include <linux/sched.h>
 #include <linux/adb.h>
 #include <linux/cuda.h>
+#include <linux/spinlock.h>
 #ifdef CONFIG_PPC
 #include <asm/prom.h>
 #include <asm/machdep.h>
@@ -31,6 +32,7 @@
 #include <linux/init.h>
 
 static volatile unsigned char *via;
+static spinlock_t cuda_lock = SPIN_LOCK_UNLOCKED;
 
 #ifdef CONFIG_MAC
 #define CUDA_IRQ IRQ_MAC_ADB
@@ -386,8 +388,8 @@
     req->sent = 0;
     req->complete = 0;
     req->reply_len = 0;
-    save_flags(flags); cli();
 
+    spin_lock_irqsave(&cuda_lock, flags);
     if (current_req != 0) {
 	last_req->next = req;
 	last_req = req;
@@ -397,15 +399,14 @@
 	if (cuda_state == idle)
 	    cuda_start();
     }
+    spin_unlock_irqrestore(&cuda_lock, flags);
 
-    restore_flags(flags);
     return 0;
 }
 
 static void
 cuda_start()
 {
-    unsigned long flags;
     struct adb_request *req;
 
     /* assert cuda_state == idle */
@@ -413,41 +414,46 @@
     req = current_req;
     if (req == 0)
 	return;
-    save_flags(flags); cli();
-    if ((via[B] & TREQ) == 0) {
-	restore_flags(flags);
+    if ((via[B] & TREQ) == 0)
 	return;			/* a byte is coming in from the CUDA */
-    }
 
     /* set the shift register to shift out and send a byte */
     via[ACR] |= SR_OUT; eieio();
     via[SR] = req->data[0]; eieio();
     via[B] &= ~TIP;
     cuda_state = sent_first_byte;
-    restore_flags(flags);
 }
 
 void
 cuda_poll()
 {
-    unsigned long flags;
+    if (via[IFR] & SR_INT) {
+	unsigned long flags;
 
-    save_flags(flags);
-    cli();
-    if (via[IFR] & SR_INT)
+	/* cuda_interrupt only takes a normal lock, we disable
+	 * interrupts here to avoid re-entering and thus deadlocking.
+	 * An option would be to disable only the IRQ source with
+	 * disable_irq(), would that work on m68k ? --BenH
+	 */
+	local_irq_save(flags);
 	cuda_interrupt(0, 0, 0);
-    restore_flags(flags);
+	local_irq_restore(flags);
+    }
 }
 
 static void
 cuda_interrupt(int irq, void *arg, struct pt_regs *regs)
 {
     int x, status;
-    struct adb_request *req;
-
+    struct adb_request *req = NULL;
+    unsigned char ibuf[16];
+    int ibuf_len = 0;
+    int complete = 0;
+    
     if ((via[IFR] & SR_INT) == 0)
 	return;
 
+    spin_lock(&cuda_lock);
     status = (~via[B] & (TIP|TREQ)) | (via[ACR] & SR_OUT); eieio();
     /* printk("cuda_interrupt: state=%d status=%x\n", cuda_state, status); */
     switch (cuda_state) {
@@ -502,8 +508,7 @@
 		cuda_state = awaiting_reply;
 	    } else {
 		current_req = req->next;
-		if (req->done)
-		    (*req->done)(req);
+		complete = 1;
 		/* not sure about this */
 		cuda_state = idle;
 		cuda_start();
@@ -544,12 +549,18 @@
 		    memmove(req->reply, req->reply + 2, req->reply_len);
 		}
 	    }
-	    req->complete = 1;
 	    current_req = req->next;
-	    if (req->done)
-		(*req->done)(req);
+	    complete = 1;
 	} else {
-	    cuda_input(cuda_rbuf, reply_ptr - cuda_rbuf, regs);
+	    /* This is tricky. We must break the spinlock to call
+	     * cuda_input. However, doing so means we might get
+	     * re-entered from another CPU getting an interrupt
+	     * or calling cuda_poll(). I ended up using the stack
+	     * (it's only for 16 bytes) and moving the actual
+	     * call to cuda_input to outside of the lock.
+	     */
+	    ibuf_len = reply_ptr - cuda_rbuf;
+	    memcpy(ibuf, cuda_rbuf, ibuf_len);
 	}
 	if (status == TREQ) {
 	    via[B] &= ~TIP; eieio();
@@ -565,6 +576,19 @@
     default:
 	printk("cuda_interrupt: unknown cuda_state %d?\n", cuda_state);
     }
+    spin_unlock(&cuda_lock);
+    if (complete && req) {
+    	void (*done)(struct adb_request *) = req->done;
+    	mb();
+    	req->complete = 1;
+    	/* Here, we assume that if the request has a done member, the
+    	 * struct request will survive to setting req->complete to 1
+    	 */
+    	if (done)
+		(*done)(req);
+    }
+    if (ibuf_len)
+	cuda_input(ibuf, ibuf_len, regs);
 }
 
 static void
diff -Nru a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
--- a/drivers/macintosh/via-pmu.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/macintosh/via-pmu.c	Sun Nov 10 19:28:41 2002
@@ -9,11 +9,7 @@
  * and the RTC (real time clock) chip.
  *
  * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
- * Copyright (C) 2001 Benjamin Herrenschmidt
- * 
- * todo: - Cleanup synchro between VIA interrupt and GPIO-based PMU
- *         interrupt.
- *
+ * Copyright (C) 2001-2002 Benjamin Herrenschmidt
  *
  */
 #include <stdarg.h>
@@ -111,14 +107,24 @@
 	reading_intr,
 } pmu_state;
 
+static volatile enum int_data_state {
+	int_data_empty,
+	int_data_fill,
+	int_data_ready,
+	int_data_flush
+} int_data_state[2] = { int_data_empty, int_data_empty };
+
 static struct adb_request *current_req;
 static struct adb_request *last_req;
 static struct adb_request *req_awaiting_reply;
-static unsigned char interrupt_data[256]; /* Made bigger: I've been told that might happen */
+static unsigned char interrupt_data[2][32];
+static int interrupt_data_len[2];
+static int int_data_last;
 static unsigned char *reply_ptr;
 static int data_index;
 static int data_len;
 static volatile int adb_int_pending;
+static volatile int disable_poll;
 static struct adb_request bright_req_1, bright_req_2, bright_req_3;
 static struct device_node *vias;
 static int pmu_kind = PMU_UNKNOWN;
@@ -174,12 +180,6 @@
 static int pmu_queue_request(struct adb_request *req);
 static void pmu_start(void);
 static void via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs);
-static void send_byte(int x);
-static void recv_byte(void);
-static void pmu_sr_intr(struct pt_regs *regs);
-static void pmu_done(struct adb_request *req);
-static void pmu_handle_data(unsigned char *data, int len,
-			    struct pt_regs *regs);
 static void gpio1_interrupt(int irq, void *arg, struct pt_regs *regs);
 static int proc_get_info(char *page, char **start, off_t off,
 			  int count, int *eof, void *data);
@@ -521,8 +521,8 @@
 
 	/* ack all pending interrupts */
 	timeout = 100000;
-	interrupt_data[0] = 1;
-	while (interrupt_data[0] || pmu_state != idle) {
+	interrupt_data[0][0] = 1;
+	while (interrupt_data[0][0] || pmu_state != idle) {
 		if (--timeout < 0) {
 			printk(KERN_ERR "init_pmu: timed out acking intrs\n");
 			return 0;
@@ -1176,7 +1176,7 @@
 	return 0;
 }
 
-static void __openfirmware
+static inline void
 wait_for_ack(void)
 {
 	/* Sightly increased the delay, I had one occurence of the message
@@ -1194,7 +1194,7 @@
 
 /* New PMU seems to be very sensitive to those timings, so we make sure
  * PCI is flushed immediately */
-static void __openfirmware
+static inline void
 send_byte(int x)
 {
 	volatile unsigned char *v = via;
@@ -1205,8 +1205,8 @@
 	(void)in_8(&v[B]);
 }
 
-static void __openfirmware
-recv_byte()
+static inline void
+recv_byte(void)
 {
 	volatile unsigned char *v = via;
 
@@ -1216,7 +1216,18 @@
 	(void)in_8(&v[B]);
 }
 
-static volatile int disable_poll;
+static inline void
+pmu_done(struct adb_request *req)
+{
+	void (*done)(struct adb_request *) = req->done;
+	mb();
+	req->complete = 1;
+    	/* Here, we assume that if the request has a done member, the
+    	 * struct request will survive to setting req->complete to 1
+    	 */
+	if (done)
+		(*done)(req);
+}
 
 static void __openfirmware
 pmu_start()
@@ -1281,9 +1292,9 @@
 	}
 
 	do {
-		spin_unlock(&pmu_lock);
+		spin_unlock_irqrestore(&pmu_lock, flags);
 		via_pmu_interrupt(0, 0, 0);
-		spin_lock(&pmu_lock);
+		spin_lock_irqsave(&pmu_lock, flags);
 		if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {
 #ifdef SUSPEND_USES_PMU
 			pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
@@ -1330,61 +1341,83 @@
 #endif /* SUSPEND_USES_PMU */
 }
 
+/* Interrupt data could be the result data from an ADB cmd */
 static void __openfirmware
-via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
+pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
 {
-	unsigned long flags;
-	int intr;
-	int nloop = 0;
-
-	/* This is a bit brutal, we can probably do better */
-	spin_lock_irqsave(&pmu_lock, flags);
-	++disable_poll;
-	
-	for (;;) {
-		intr = in_8(&via[IFR]) & (SR_INT | CB1_INT);
-		if (intr == 0)
-			break;
-		if (++nloop > 1000) {
-			printk(KERN_DEBUG "PMU: stuck in intr loop, "
-			       "intr=%x, ier=%x pmu_state=%d\n",
-			       intr, in_8(&via[IER]), pmu_state);
-			break;
-		}
-		out_8(&via[IFR], intr);
-		if (intr & SR_INT)
-			pmu_sr_intr(regs);
-		if (intr & CB1_INT)
-			adb_int_pending = 1;
+	asleep = 0;
+	if (drop_interrupts || len < 1) {
+		adb_int_pending = 0;
+		return;
 	}
-
-	if (pmu_state == idle) {
-		if (adb_int_pending) {
-			pmu_state = intack;
-			/* Sounds safer to make sure ACK is high before writing.
-			 * This helped kill a problem with ADB and some iBooks
+	/* Note: for some reason, we get an interrupt with len=1,
+	 * data[0]==0 after each normal ADB interrupt, at least
+	 * on the Pismo. Still investigating...  --BenH
+	 */
+	if (data[0] & PMU_INT_ADB) {
+		if ((data[0] & PMU_INT_ADB_AUTO) == 0) {
+			struct adb_request *req = req_awaiting_reply;
+			if (req == 0) {
+				printk(KERN_ERR "PMU: extra ADB reply\n");
+				return;
+			}
+			req_awaiting_reply = 0;
+			if (len <= 2)
+				req->reply_len = 0;
+			else {
+				memcpy(req->reply, data + 1, len - 1);
+				req->reply_len = len - 1;
+			}
+			pmu_done(req);
+		} else {
+#ifdef CONFIG_XMON
+			if (len == 4 && data[1] == 0x2c) {
+				extern int xmon_wants_key, xmon_adb_keycode;
+				if (xmon_wants_key) {
+					xmon_adb_keycode = data[2];
+					return;
+				}
+			}
+#endif /* CONFIG_XMON */
+#ifdef CONFIG_ADB
+			/*
+			 * XXX On the [23]400 the PMU gives us an up
+			 * event for keycodes 0x74 or 0x75 when the PC
+			 * card eject buttons are released, so we
+			 * ignore those events.
 			 */
-			wait_for_ack();
-			send_byte(PMU_INT_ACK);
-			adb_int_pending = 0;
-		} else if (current_req)
-			pmu_start();
-	}
-	
-	--disable_poll;
-	spin_unlock_irqrestore(&pmu_lock, flags);
-}
-
-static void __openfirmware
-gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
-{
-	if ((in_8(gpio_reg + 0x9) & 0x02) == 0) {
-		adb_int_pending = 1;
-		via_pmu_interrupt(0, 0, 0);
+			if (!(pmu_kind == PMU_OHARE_BASED && len == 4
+			      && data[1] == 0x2c && data[3] == 0xff
+			      && (data[2] & ~1) == 0xf4))
+				adb_input(data+1, len-1, regs, 1);
+#endif /* CONFIG_ADB */		
+		}
+	} else {
+		/* Sound/brightness button pressed */
+		if ((data[0] & PMU_INT_SNDBRT) && len == 3) {
+#ifdef CONFIG_PMAC_BACKLIGHT
+#ifdef CONFIG_INPUT_ADBHID
+			if (!disable_kernel_backlight)
+#endif /* CONFIG_INPUT_ADBHID */
+				set_backlight_level(data[1] >> 4);
+#endif /* CONFIG_PMAC_BACKLIGHT */
+		}
+#ifdef CONFIG_PMAC_PBOOK
+		/* Environement or tick interrupt, query batteries */
+		if (pmu_battery_count && (data[0] & PMU_INT_TICK)) {
+			if ((--query_batt_timer) == 0) {
+				query_battery_state();
+				query_batt_timer = BATTERY_POLLING_COUNT;
+			}
+		} else if (pmu_battery_count && (data[0] & PMU_INT_ENVIRONMENT))
+			query_battery_state();
+ 		if (data[0])
+			pmu_pass_intr(data, len);
+#endif /* CONFIG_PMAC_PBOOK */
 	}
 }
 
-static void __openfirmware
+static struct adb_request* __openfirmware
 pmu_sr_intr(struct pt_regs *regs)
 {
 	struct adb_request *req;
@@ -1393,7 +1426,7 @@
 	if (via[B] & TREQ) {
 		printk(KERN_ERR "PMU: spurious SR intr (%x)\n", via[B]);
 		out_8(&via[IFR], SR_INT);
-		return;
+		return NULL;
 	}
 	/* The ack may not yet be low when we get the interrupt */
 	while ((in_8(&via[B]) & TACK) != 0)
@@ -1426,11 +1459,8 @@
 			current_req = req->next;
 			if (req->reply_expected)
 				req_awaiting_reply = req;
-			else {
-				spin_unlock(&pmu_lock);
-				pmu_done(req);
-				spin_lock(&pmu_lock);
-			}
+			else
+				return req;
 		} else {
 			pmu_state = reading;
 			data_index = 0;
@@ -1443,7 +1473,7 @@
 		data_index = 0;
 		data_len = -1;
 		pmu_state = reading_intr;
-		reply_ptr = interrupt_data;
+		reply_ptr = interrupt_data[int_data_last];
 		recv_byte();
 		break;
 
@@ -1462,108 +1492,113 @@
 		}
 
 		if (pmu_state == reading_intr) {
-			spin_unlock(&pmu_lock);
-			pmu_handle_data(interrupt_data, data_index, regs);
-			spin_lock(&pmu_lock);
+			pmu_state = idle;
+			int_data_state[int_data_last] = int_data_ready;
+			interrupt_data_len[int_data_last] = data_len;
 		} else {
 			req = current_req;
 			current_req = req->next;
 			req->reply_len += data_index;
-			spin_unlock(&pmu_lock);
-			pmu_done(req);
-			spin_lock(&pmu_lock);
+			pmu_state = idle;
+			return req;
 		}
-		pmu_state = idle;
-
 		break;
 
 	default:
 		printk(KERN_ERR "via_pmu_interrupt: unknown state %d?\n",
 		       pmu_state);
 	}
+	return NULL;
 }
 
 static void __openfirmware
-pmu_done(struct adb_request *req)
+via_pmu_interrupt(int irq, void *arg, struct pt_regs *regs)
 {
-	req->complete = 1;
-	if (req->done)
-		(*req->done)(req);
+	unsigned long flags;
+	int intr;
+	int nloop = 0;
+	int int_data = -1;
+	struct adb_request *req = NULL;
+	
+	/* This is a bit brutal, we can probably do better */
+	spin_lock_irqsave(&pmu_lock, flags);
+	++disable_poll;
+	
+	for (;;) {
+		intr = in_8(&via[IFR]) & (SR_INT | CB1_INT);
+		if (intr == 0)
+			break;
+		if (++nloop > 1000) {
+			printk(KERN_DEBUG "PMU: stuck in intr loop, "
+			       "intr=%x, ier=%x pmu_state=%d\n",
+			       intr, in_8(&via[IER]), pmu_state);
+			break;
+		}
+		out_8(&via[IFR], intr);
+		if (intr & CB1_INT)
+			adb_int_pending = 1;
+		if (intr & SR_INT) {
+			req = pmu_sr_intr(regs);
+			if (req)
+				break;
+		}
+	}
+
+recheck:
+	if (pmu_state == idle) {
+		if (adb_int_pending) {
+			if (int_data_state[0] == int_data_empty)
+				int_data_last = 0;
+			else if (int_data_state[1] == int_data_empty)
+				int_data_last = 1;
+			else
+				goto no_free_slot;
+			pmu_state = intack;
+			int_data_state[int_data_last] = int_data_fill;
+			/* Sounds safer to make sure ACK is high before writing.
+			 * This helped kill a problem with ADB and some iBooks
+			 */
+			wait_for_ack();
+			send_byte(PMU_INT_ACK);
+			adb_int_pending = 0;
+no_free_slot:			
+		} else if (current_req)
+			pmu_start();
+	}
+	/* Mark the oldest buffer for flushing */
+	if (int_data_state[!int_data_last] == int_data_ready) {
+		int_data_state[!int_data_last] = int_data_flush;
+		int_data = !int_data_last;
+	} else if (int_data_state[int_data_last] == int_data_ready) {
+		int_data_state[int_data_last] = int_data_flush;
+		int_data = int_data_last;
+	}
+	--disable_poll;
+	spin_unlock_irqrestore(&pmu_lock, flags);
+
+	/* Deal with completed PMU requests outside of the lock */
+	if (req) {
+		pmu_done(req);
+		req = NULL;
+	}
+		
+	/* Deal with interrupt datas outside of the lock */
+	if (int_data >= 0) {
+		pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data], regs);
+		spin_lock_irqsave(&pmu_lock, flags);
+		++disable_poll;
+		int_data_state[int_data] = int_data_empty;
+		int_data = -1;
+		goto recheck;
+	}
 }
 
-/* Interrupt data could be the result data from an ADB cmd */
 static void __openfirmware
-pmu_handle_data(unsigned char *data, int len, struct pt_regs *regs)
+gpio1_interrupt(int irq, void *arg, struct pt_regs *regs)
 {
-	asleep = 0;
-	if (drop_interrupts || len < 1) {
-		adb_int_pending = 0;
-		return;
-	}
-	/* Note: for some reason, we get an interrupt with len=1,
-	 * data[0]==0 after each normal ADB interrupt, at least
-	 * on the Pismo. Still investigating...  --BenH
-	 */
-	if (data[0] & PMU_INT_ADB) {
-		if ((data[0] & PMU_INT_ADB_AUTO) == 0) {
-			struct adb_request *req = req_awaiting_reply;
-			if (req == 0) {
-				printk(KERN_ERR "PMU: extra ADB reply\n");
-				return;
-			}
-			req_awaiting_reply = 0;
-			if (len <= 2)
-				req->reply_len = 0;
-			else {
-				memcpy(req->reply, data + 1, len - 1);
-				req->reply_len = len - 1;
-			}
-			pmu_done(req);
-		} else {
-#ifdef CONFIG_XMON
-			if (len == 4 && data[1] == 0x2c) {
-				extern int xmon_wants_key, xmon_adb_keycode;
-				if (xmon_wants_key) {
-					xmon_adb_keycode = data[2];
-					return;
-				}
-			}
-#endif /* CONFIG_XMON */
-#ifdef CONFIG_ADB
-			/*
-			 * XXX On the [23]400 the PMU gives us an up
-			 * event for keycodes 0x74 or 0x75 when the PC
-			 * card eject buttons are released, so we
-			 * ignore those events.
-			 */
-			if (!(pmu_kind == PMU_OHARE_BASED && len == 4
-			      && data[1] == 0x2c && data[3] == 0xff
-			      && (data[2] & ~1) == 0xf4))
-				adb_input(data+1, len-1, regs, 1);
-#endif /* CONFIG_ADB */		
-		}
-	} else {
-		/* Sound/brightness button pressed */
-		if ((data[0] & PMU_INT_SNDBRT) && len == 3) {
-#ifdef CONFIG_PMAC_BACKLIGHT
-#ifdef CONFIG_INPUT_ADBHID
-			if (!disable_kernel_backlight)
-#endif /* CONFIG_INPUT_ADBHID */
-				set_backlight_level(data[1] >> 4);
-#endif /* CONFIG_PMAC_BACKLIGHT */
-		}
-#ifdef CONFIG_PMAC_PBOOK
-		/* Environement or tick interrupt, query batteries */
-		if (pmu_battery_count && (data[0] & PMU_INT_TICK)) {
-			if ((--query_batt_timer) == 0) {
-				query_battery_state();
-				query_batt_timer = BATTERY_POLLING_COUNT;
-			}
-		} else if (pmu_battery_count && (data[0] & PMU_INT_ENVIRONMENT))
-			query_battery_state();
- 		if (data[0])
-			pmu_pass_intr(data, len);
-#endif /* CONFIG_PMAC_PBOOK */
+	if ((in_8(gpio_reg + 0x9) & 0x02) == 0) {
+		adb_int_pending = 1;
+		via_pmu_interrupt(0, 0, 0);
 	}
 }
 
@@ -1635,7 +1670,7 @@
 {
 	struct adb_request req;
 
-	cli();
+	local_irq_disable();
 
 	drop_interrupts = 1;
 	
@@ -1658,7 +1693,7 @@
 {
 	struct adb_request req;
 
-	cli();
+	local_irq_disable();
 
 	drop_interrupts = 1;
 
@@ -1979,7 +2014,7 @@
 	unsigned long save_l2cr;
 	unsigned short pmcr1;
 	struct adb_request req;
-	int ret, timeout;
+	int ret;
 	struct pci_dev *grackle;
 
 	grackle = pci_find_slot(0, 0);
@@ -2036,17 +2071,16 @@
 	mb();
 	asm volatile("mtdec %0" : : "r" (0x7fffffff));
 	
-	/* Giveup the FPU */
-	if (current->thread.regs && (current->thread.regs->msr & MSR_FP) != 0)
-		giveup_fpu(current);
-
 	/* We can now disable MSR_EE */
-	cli();
+	local_irq_disable();
+
+	/* Giveup the FPU */
+	enable_kernel_fp();
 
 	/* For 750, save backside cache setting and disable it */
-	save_l2cr = _get_L2CR();	/* (returns 0 if not 750) */
-	if (save_l2cr)
-		_set_L2CR(0);
+	save_l2cr = _get_L2CR();	/* (returns -1 if not available) */
+	if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
+		_set_L2CR(save_l2cr & 0x7fffffff);
 
 	/* Ask the PMU to put us to sleep */
 	pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
@@ -2077,7 +2111,7 @@
 	restore_via_state();
 	
 	/* Restore L2 cache */
-	if (save_l2cr)
+	if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
  		_set_L2CR(save_l2cr);
 	
 	/* Restore userland MMU context */
@@ -2096,18 +2130,6 @@
 	while (!req.complete)
 		pmu_poll();
 
-	/* ack all pending interrupts */
-	timeout = 100000;
-	interrupt_data[0] = 1;
-	while (interrupt_data[0] || pmu_state != idle) {
-		if (--timeout < 0)
-			break;
-		if (pmu_state == idle)
-			adb_int_pending = 1;
-		via_pmu_interrupt(0, 0, 0);
-		udelay(10);
-	}
-
 	/* reenable interrupt controller */
 	pmac_sleep_restore_intrs();
 
@@ -2116,7 +2138,13 @@
 
 	/* Restart jiffies & scheduling */
 	wakeup_decrementer();
-	sti();
+
+	/* Force a poll of ADB interrupts */
+	adb_int_pending = 1;
+	via_pmu_interrupt(0, 0, 0);
+
+	/* Re-enable local CPU interrupts */
+	local_irq_enable();
 
 	/* Notify drivers */
 	broadcast_wake();
@@ -2127,8 +2155,9 @@
 int __openfirmware powerbook_sleep_Core99(void)
 {
 	unsigned long save_l2cr;
+	unsigned long save_l3cr;
 	struct adb_request req;
-	int ret, timeout;
+	int ret;
 	
 	if (!can_sleep) {
 		printk(KERN_ERR "Sleep mode not supported on this machine\n");
@@ -2187,6 +2216,9 @@
 	mb();
 	asm volatile("mtdec %0" : : "r" (0x7fffffff));
 
+	/* We can now disable MSR_EE */
+	local_irq_disable();
+
 	/* Giveup the FPU & vec */
 	enable_kernel_fp();
 
@@ -2195,12 +2227,12 @@
 		enable_kernel_altivec();
 #endif /* CONFIG_ALTIVEC */
 
-	/* We can now disable MSR_EE */
-	cli();
-
-	/* For 750, save backside cache setting and disable it */
-	save_l2cr = _get_L2CR();	/* (returns 0 if not 750) */
-	if (save_l2cr)
+	/* Save & disable L2 and L3 caches*/
+	save_l3cr = _get_L3CR();	/* (returns -1 if not available) */
+	save_l2cr = _get_L2CR();	/* (returns -1 if not available) */
+	if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
+		_set_L3CR(save_l3cr & 0x7fffffff);
+	if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
 		_set_L2CR(save_l2cr & 0x7fffffff);
 
 	/* Save the state of PCI config space for some slots */
@@ -2248,8 +2280,11 @@
 	pmu_blink(2);
 		
 	/* Restore L2 cache */
-	if (save_l2cr)
+	if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
  		_set_L2CR(save_l2cr);
+	/* Restore L3 cache */
+	if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
+ 		_set_L3CR(save_l3cr);
 	
 	/* Restore userland MMU context */
 	set_context(current->active_mm->context, current->active_mm->pgd);
@@ -2262,18 +2297,6 @@
 	while (!req.complete)
 		pmu_poll();
 		
-	/* ack all pending interrupts */
-	timeout = 100000;
-	interrupt_data[0] = 1;
-	while (interrupt_data[0] || pmu_state != idle) {
-		if (--timeout < 0)
-			break;
-		if (pmu_state == idle)
-			adb_int_pending = 1;
-		via_pmu_interrupt(0, 0, 0);
-		udelay(10);
-	}
-
 	/* reenable interrupt controller */
 	openpic_sleep_restore_intrs();
 
@@ -2282,7 +2305,13 @@
 
 	/* Restart jiffies & scheduling */
 	wakeup_decrementer();
-	sti();
+
+	/* Force a poll of ADB interrupts */
+	adb_int_pending = 1;
+	via_pmu_interrupt(0, 0, 0);
+
+	/* Re-enable local CPU interrupts */
+	local_irq_enable();
 
 	/* Notify drivers */
 	broadcast_wake();
@@ -2402,7 +2431,9 @@
 
 	/* Restart jiffies & scheduling */
 	wakeup_decrementer();
-	sti();
+
+	/* Re-enable local CPU interrupts */
+	local_irq_enable();
 
 	/* Notify drivers */
 	broadcast_wake();
@@ -2718,7 +2749,7 @@
 	if (l >= 0 && req->nbytes != l + 1)
 		return -EINVAL;
 
-	save_flags(flags); cli();
+	local_irq_save(flags);
 	while (pmu_state != idle)
 		pmu_poll();
 
@@ -2741,7 +2772,7 @@
 	if (req->done)
 		(*req->done)(req);
 
-	restore_flags(flags);
+	local_irq_restore(flags);
 	return 0;
 }
 #endif /* DEBUG_SLEEP */
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/md/md.c	Sun Nov 10 19:28:38 2002
@@ -34,7 +34,6 @@
 #include <linux/raid/md.h>
 #include <linux/sysctl.h>
 #include <linux/bio.h>
-#include <linux/raid/xor.h>
 #include <linux/devfs_fs_kernel.h>
 #include <linux/buffer_head.h> /* for invalidate_bdev */
 
@@ -995,8 +994,10 @@
 	mdk_rdev_t *rdev;
 	struct list_head *tmp;
 
-	ITERATE_RDEV(mddev,rdev,tmp)
+	ITERATE_RDEV(mddev,rdev,tmp) {
 		super_90_sync(mddev, rdev);
+		rdev->sb_loaded = 1;
+	}
 }
 
 static void md_update_sb(mddev_t * mddev)
@@ -1531,7 +1532,7 @@
 	int err = 0;
 	struct gendisk *disk = disks[mdidx(mddev)];
 
-	if (atomic_read(&mddev->active)>1) {
+	if (atomic_read(&mddev->active)>2) {
 		printk(STILL_IN_USE, mdidx(mddev));
 		err = -EBUSY;
 		goto out;
@@ -1561,6 +1562,7 @@
 					set_disk_ro(disk, 1);
 				goto out;
 			}
+			mddev->pers = NULL;
 			if (mddev->ro)
 				mddev->ro = 0;
 		}
@@ -1736,17 +1738,26 @@
 	start_rdev = md_import_device(startdev, 1);
 	if (IS_ERR(start_rdev)) {
 		printk(KERN_WARNING "md: could not import %s!\n", partition_name(startdev));
-		goto abort;
+		return err;
+	}
+
+	/* NOTE: this can only work for 0.90.0 superblocks */
+	sb = (mdp_super_t*)page_address(start_rdev->sb_page);
+	if (sb->major_version != 0 ||
+	    sb->minor_version != 90 ) {
+		printk(KERN_WARNING "md: can only autostart 0.90.0 arrays\n");
+		export_rdev(start_rdev);
+		return err;
 	}
 
 	if (start_rdev->faulty) {
 		printk(KERN_WARNING "md: can not autostart based on faulty %s!\n",
 						bdev_partition_name(start_rdev->bdev));
-		goto abort;
+		export_rdev(start_rdev);
+		return err;
 	}
 	list_add(&start_rdev->same_set, &pending_raid_disks);
 
-
 	for (i = 0; i < MD_SB_DISKS; i++) {
 		mdp_disk_t *desc;
 		dev_t dev;
@@ -1773,10 +1784,6 @@
 	autorun_devices();
 	return 0;
 
-abort:
-	if (start_rdev)
-		export_rdev(start_rdev);
-	return err;
 }
 
 #undef BAD_VERSION
@@ -2693,9 +2700,9 @@
 		sz += mddev->pers->status (page+sz, mddev);
 
 		sz += sprintf(page+sz, "\n      ");
-		if (mddev->curr_resync > 1)
+		if (mddev->curr_resync > 2)
 			sz += status_resync (page+sz, mddev);
-		else if (mddev->curr_resync == 1)
+		else if (mddev->curr_resync == 1 || mddev->curr_resync == 2)
 				sz += sprintf(page + sz, "	resync=DELAYED");
 
 		sz += sprintf(page + sz, "\n");
@@ -3050,7 +3057,6 @@
 	if ((code == SYS_DOWN) || (code == SYS_HALT) || (code == SYS_POWER_OFF)) {
 
 		printk(KERN_INFO "md: stopping all md devices.\n");
-		return NOTIFY_DONE;
 
 		ITERATE_MDDEV(mddev,tmp)
 			if (mddev_trylock(mddev)==0)
diff -Nru a/drivers/md/raid1.c b/drivers/md/raid1.c
--- a/drivers/md/raid1.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/md/raid1.c	Sun Nov 10 19:28:40 2002
@@ -173,12 +173,6 @@
 	struct bio *bio = r1_bio->master_bio;
 	unsigned long flags;
 
-	spin_lock_irqsave(&conf->resync_lock, flags);
-	if (!--conf->nr_pending) {
-		wake_up(&conf->wait_idle);
-		wake_up(&conf->wait_resume);
-	}
-	spin_unlock_irqrestore(&conf->resync_lock, flags);
 	/*
 	 * undo any possible partial request fixup magic:
 	 */
@@ -186,6 +180,19 @@
 		bio->bi_io_vec[bio->bi_vcnt-1].bv_len = PAGE_SIZE;
 	put_all_bios(conf, r1_bio);
 	mempool_free(r1_bio, conf->r1buf_pool);
+
+	spin_lock_irqsave(&conf->resync_lock, flags);
+	if (!conf->barrier)
+		BUG();
+	--conf->barrier;
+	wake_up(&conf->wait_resume);
+	wake_up(&conf->wait_idle);
+
+	if (!--conf->nr_pending) {
+		wake_up(&conf->wait_idle);
+		wake_up(&conf->wait_resume);
+	}
+	spin_unlock_irqrestore(&conf->resync_lock, flags);
 }
 
 static int map(mddev_t *mddev, mdk_rdev_t **rdevp)
@@ -442,17 +449,6 @@
 	spin_unlock_irq(&conf->resync_lock);
 }
 
-static void resume_device(conf_t *conf)
-{
-	spin_lock_irq(&conf->resync_lock);
-	if (!conf->barrier)
-		BUG();
-	--conf->barrier;
-	wake_up(&conf->wait_resume);
-	wake_up(&conf->wait_idle);
-	spin_unlock_irq(&conf->resync_lock);
-}
-
 static int make_request(request_queue_t *q, struct bio * bio)
 {
 	mddev_t *mddev = q->queuedata;
@@ -664,7 +660,6 @@
 
 	if (conf->barrier) BUG();
 	if (waitqueue_active(&conf->wait_idle)) BUG();
-	if (waitqueue_active(&conf->wait_resume)) BUG();
 
 	mempool_destroy(conf->r1buf_pool);
 	conf->r1buf_pool = NULL;
@@ -802,7 +797,6 @@
 
 	if (atomic_dec_and_test(&r1_bio->remaining)) {
 		md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, uptodate);
-		resume_device(conf);
 		put_buf(r1_bio);
 	}
 	atomic_dec(&conf->mirrors[mirror].rdev->nr_pending);
@@ -829,7 +823,6 @@
 		 */
 		printk(IO_ERROR, bdev_partition_name(bio->bi_bdev), (unsigned long long)r1_bio->sector);
 		md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0);
-		resume_device(conf);
 		put_buf(r1_bio);
 		return;
 	}
@@ -881,7 +874,6 @@
 		printk(KERN_ALERT "raid1: sync aborting as there is nowhere to write sector %llu\n", 
 			(unsigned long long)r1_bio->sector);
 		md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0);
-		resume_device(conf);
 		put_buf(r1_bio);
 		return;
 	}
@@ -1021,7 +1013,7 @@
 	atomic_inc(&conf->mirrors[disk].rdev->nr_pending);
 	spin_unlock_irq(&conf->device_lock);
 
-	mirror = conf->mirrors + conf->last_used;
+	mirror = conf->mirrors + disk;
 
 	r1_bio = mempool_alloc(conf->r1buf_pool, GFP_NOIO);
 
@@ -1032,6 +1024,7 @@
 	r1_bio->mddev = mddev;
 	r1_bio->sector = sector_nr;
 	r1_bio->cmd = SPECIAL;
+	r1_bio->read_disk = disk;
 
 	bio = r1_bio->master_bio;
 	nr_sectors = RESYNC_BLOCK_SIZE >> 9;
@@ -1155,6 +1148,8 @@
 	conf->raid_disks = mddev->raid_disks;
 	conf->mddev = mddev;
 	conf->device_lock = SPIN_LOCK_UNLOCKED;
+	if (conf->working_disks == 1)
+		mddev->state |= (1 << MD_SB_CLEAN);
 
 	conf->resync_lock = SPIN_LOCK_UNLOCKED;
 	init_waitqueue_head(&conf->wait_idle);
diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c
--- a/drivers/md/raid5.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/md/raid5.c	Sun Nov 10 19:28:37 2002
@@ -682,10 +682,9 @@
 	raid5_conf_t *conf = sh->raid_conf;
 	int i, pd_idx = sh->pd_idx, disks = conf->raid_disks, count;
 	void *ptr[MAX_XOR_BLOCKS];
-	struct bio *chosen[MD_SB_DISKS];
+	struct bio *chosen;
 
 	PRINTK("compute_parity, stripe %llu, method %d\n", (unsigned long long)sh->sector, method);
-	memset(chosen, 0, sizeof(chosen));
 
 	count = 1;
 	ptr[0] = page_address(sh->dev[pd_idx].page);
@@ -699,10 +698,10 @@
 			if (sh->dev[i].towrite &&
 			    test_bit(R5_UPTODATE, &sh->dev[i].flags)) {
 				ptr[count++] = page_address(sh->dev[i].page);
-				chosen[i] = sh->dev[i].towrite;
+				chosen = sh->dev[i].towrite;
 				sh->dev[i].towrite = NULL;
 				if (sh->dev[i].written) BUG();
-				sh->dev[i].written = chosen[i];
+				sh->dev[i].written = chosen;
 				check_xor();
 			}
 		}
@@ -711,10 +710,10 @@
 		memset(ptr[0], 0, STRIPE_SIZE);
 		for (i= disks; i-- ;)
 			if (i!=pd_idx && sh->dev[i].towrite) {
-				chosen[i] = sh->dev[i].towrite;
+				chosen = sh->dev[i].towrite;
 				sh->dev[i].towrite = NULL;
 				if (sh->dev[i].written) BUG();
-				sh->dev[i].written = chosen[i];
+				sh->dev[i].written = chosen;
 			}
 		break;
 	case CHECK_PARITY:
@@ -726,9 +725,9 @@
 	}
 	
 	for (i = disks; i--;)
-		if (chosen[i]) {
+		if (sh->dev[i].written) {
 			sector_t sector = sh->dev[i].sector;
-			copy_data(1, chosen[i], sh->dev[i].page, sector);
+			copy_data(1, sh->dev[i].written, sh->dev[i].page, sector);
 
 			set_bit(R5_LOCKED, &sh->dev[i].flags);
 			set_bit(R5_UPTODATE, &sh->dev[i].flags);
@@ -745,7 +744,7 @@
 		break;
 	case READ_MODIFY_WRITE:
 		for (i = disks; i--;)
-			if (chosen[i]) {
+			if (sh->dev[i].written) {
 				ptr[count++] = page_address(sh->dev[i].page);
 				check_xor();
 			}
@@ -836,6 +835,7 @@
 	int i;
 	int syncing;
 	int locked=0, uptodate=0, to_read=0, to_write=0, failed=0, written=0;
+	int non_overwrite = 0;
 	int failed_num=0;
 	struct r5dev *dev;
 
@@ -851,8 +851,6 @@
 	for (i=disks; i--; ) {
 		mdk_rdev_t *rdev;
 		dev = &sh->dev[i];
-		clear_bit(R5_Wantread, &dev->flags);
-		clear_bit(R5_Wantwrite, &dev->flags);
 		clear_bit(R5_Insync, &dev->flags);
 		clear_bit(R5_Syncio, &dev->flags);
 
@@ -885,7 +883,11 @@
 
 		
 		if (dev->toread) to_read++;
-		if (dev->towrite) to_write++;
+		if (dev->towrite) {
+			to_write++;
+			if (!test_bit(R5_OVERWRITE, &dev->flags))
+				non_overwrite++;
+		}
 		if (dev->written) written++;
 		rdev = conf->disks[i].rdev; /* FIXME, should I be looking rdev */
 		if (!rdev || !rdev->in_sync) {
@@ -977,12 +979,19 @@
 
 	/* Now we might consider reading some blocks, either to check/generate
 	 * parity, or to satisfy requests
+	 * or to load a block that is being partially written.
 	 */
-	if (to_read || (syncing && (uptodate+failed < disks))) {
+	if (to_read || non_overwrite || (syncing && (uptodate+failed < disks))) {
 		for (i=disks; i--;) {
 			dev = &sh->dev[i];
 			if (!test_bit(R5_LOCKED, &dev->flags) && !test_bit(R5_UPTODATE, &dev->flags) &&
-			    (dev->toread || syncing || (failed && sh->dev[failed_num].toread))) {
+			    (dev->toread ||
+			     (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
+			     syncing ||
+			     (failed && (sh->dev[failed_num].toread ||
+					 (sh->dev[failed_num].towrite && !test_bit(R5_OVERWRITE, &sh->dev[failed_num].flags))))
+				    )
+				) {
 				/* we would like to get this block, possibly
 				 * by computing it, but we might not be able to
 				 */
@@ -1160,48 +1169,56 @@
 		bi->bi_size = 0;
 		bi->bi_end_io(bi, bytes, 0);
 	}
-	for (i=disks; i-- ;) 
-		if (sh->dev[i].flags & ((1<<R5_Wantwrite)|(1<<R5_Wantread))) {
-			struct bio *bi = &sh->dev[i].req;
-			mdk_rdev_t *rdev ;
-
-			bi->bi_rw = 0;
-			if (test_bit(R5_Wantread, &sh->dev[i].flags))
-				bi->bi_end_io = raid5_end_read_request;
-			else {
-				bi->bi_end_io = raid5_end_write_request;
-				bi->bi_rw = 1;
-			}
-
-			spin_lock_irq(&conf->device_lock);
-			rdev = conf->disks[i].rdev;
-			if (rdev && rdev->faulty)
-				rdev = NULL;
-			if (rdev)
-				atomic_inc(&rdev->nr_pending);
-			spin_unlock_irq(&conf->device_lock);
-
-			if (rdev) {
-				if (test_bit(R5_Syncio, &sh->dev[i].flags))
-					md_sync_acct(rdev, STRIPE_SECTORS);
-
-				bi->bi_bdev = rdev->bdev;
-				PRINTK("for %llu schedule op %ld on disc %d\n", (unsigned long long)sh->sector, bi->bi_rw, i);
-				atomic_inc(&sh->count);
-				bi->bi_sector = sh->sector;
-				bi->bi_flags = 1 << BIO_UPTODATE;
-				bi->bi_vcnt = 1;	
-				bi->bi_idx = 0;
-				bi->bi_io_vec = &sh->dev[i].vec;
-				bi->bi_size = STRIPE_SIZE;
-				bi->bi_next = NULL;
-				generic_make_request(bi);
-			} else {
-				PRINTK("skip op %ld on disc %d for sector %llu\n", bi->bi_rw, i, (unsigned long long)sh->sector);
-				clear_bit(R5_LOCKED, &dev->flags);
-				set_bit(STRIPE_HANDLE, &sh->state);
-			}
+	for (i=disks; i-- ;) {
+		int rw;
+		struct bio *bi;
+		mdk_rdev_t *rdev;
+		if (test_and_clear_bit(R5_Wantwrite, &sh->dev[i].flags))
+			rw = 1;
+		else if (test_and_clear_bit(R5_Wantread, &sh->dev[i].flags))
+			rw = 0;
+		else
+			continue;
+ 
+		bi = &sh->dev[i].req;
+ 
+		bi->bi_rw = rw;
+		if (rw)
+			bi->bi_end_io = raid5_end_write_request;
+		else
+			bi->bi_end_io = raid5_end_read_request;
+ 
+		spin_lock_irq(&conf->device_lock);
+		rdev = conf->disks[i].rdev;
+		if (rdev && rdev->faulty)
+			rdev = NULL;
+		if (rdev)
+			atomic_inc(&rdev->nr_pending);
+		spin_unlock_irq(&conf->device_lock);
+ 
+		if (rdev) {
+			if (test_bit(R5_Syncio, &sh->dev[i].flags))
+				md_sync_acct(rdev, STRIPE_SECTORS);
+
+			bi->bi_bdev = rdev->bdev;
+			PRINTK("for %llu schedule op %ld on disc %d\n", (unsigned long long)sh->sector, bi->bi_rw, i);
+			atomic_inc(&sh->count);
+			bi->bi_sector = sh->sector;
+			bi->bi_flags = 1 << BIO_UPTODATE;
+			bi->bi_vcnt = 1;	
+			bi->bi_idx = 0;
+			bi->bi_io_vec = &sh->dev[i].vec;
+			bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
+			bi->bi_io_vec[0].bv_offset = 0;
+			bi->bi_size = STRIPE_SIZE;
+			bi->bi_next = NULL;
+			generic_make_request(bi);
+		} else {
+			PRINTK("skip op %ld on disc %d for sector %llu\n", bi->bi_rw, i, (unsigned long long)sh->sector);
+			clear_bit(R5_LOCKED, &dev->flags);
+			set_bit(STRIPE_HANDLE, &sh->state);
 		}
+	}
 }
 
 static inline void raid5_activate_delayed(raid5_conf_t *conf)
diff -Nru a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
--- a/drivers/media/video/msp3400.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/media/video/msp3400.c	Sun Nov 10 19:28:40 2002
@@ -1300,6 +1300,7 @@
 	}
 
 	/* timer for stereo checking */
+	init_timer(&msp->wake_stereo);
 	msp->wake_stereo.function = msp3400c_stereo_wake;
 	msp->wake_stereo.data     = (unsigned long)msp;
 
diff -Nru a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
--- a/drivers/media/video/tvaudio.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/media/video/tvaudio.c	Sun Nov 10 19:28:38 2002
@@ -1392,6 +1392,7 @@
 		/* start async thread */
 		DECLARE_MUTEX_LOCKED(sem);
 		chip->notify = &sem;
+		init_timer(&chip->wt);
 		chip->wt.function = chip_thread_wake;
 		chip->wt.data     = (unsigned long)chip;
 		init_waitqueue_head(&chip->wq);
diff -Nru a/drivers/mtd/cmdline.c b/drivers/mtd/cmdline.c
--- a/drivers/mtd/cmdline.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/mtd/cmdline.c	Sun Nov 10 19:28:40 2002
@@ -1,5 +1,5 @@
 /*
- * $Id: cmdline.c,v 1.4 2002/09/13 01:18:38 jamey Exp $
+ * $Id: cmdline.c,v 1.5 2002/11/06 22:40:04 rmk Exp $
  *
  * Read flash partition table from command line
  *
@@ -92,6 +92,11 @@
 	else
 	{
 		size = memparse(s, &s);
+		if (!size)
+		{
+			printk(KERN_ERR ERRP "couldn't parse number from input string\n");
+			return 0;
+		}
 		if (size < PAGE_SIZE)
 		{
 			printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
@@ -105,8 +110,13 @@
         /* check for offset */
         if (*s == '@') 
 	{
-           s++;
-           offset = memparse(s, &s);
+                s++;
+                offset = memparse(s, &s);
+		if (!offset)
+		{
+			printk(KERN_ERR ERRP "couldn't parse number from input string\n");
+			return 0;
+		}
         }
         /* now look for name */
 	if (*s == '(')
@@ -241,6 +251,17 @@
 				0,		/* first partition */
 				(unsigned char**)&this_mtd, /* out: extra mem */
 				mtd_id_len + 1 + sizeof(*this_mtd));
+		if(!parts)
+		{
+			/*
+			 * An error occurred. We're either:
+			 * a) out of memory, or
+			 * b) in the middle of the partition spec
+			 * Either way, this mtd is hosed and we're
+			 * unlikely to succeed in parsing any more
+			 */
+			 return 0;
+		 }
 
 		/* enter results */	    
 		this_mtd->parts = parts;
diff -Nru a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
--- a/drivers/mtd/ftl.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/mtd/ftl.c	Sun Nov 10 19:28:41 2002
@@ -26,7 +26,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
@@ -1302,5 +1302,5 @@
 module_exit(cleanup_ftl);
 
 MODULE_LICENSE("Dual MPL/GPL");
-MODULE_AUTHOR("David Hinds <dhinds@sonic.net>");
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
 MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices and M-Systems DiskOnChip 1000");
diff -Nru a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
--- a/drivers/mtd/mtdblock.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/mtd/mtdblock.c	Sun Nov 10 19:28:39 2002
@@ -394,8 +394,8 @@
 
 	while (!blk_queue_empty(&mtd_queue)) {
 		struct request *req = elv_next_request(&mtd_queue);
-		spin_unlock_irq(mtd_queue.queue_lock);
 		struct mtdblk_dev **p = req->rq_disk->private_data;
+		spin_unlock_irq(mtd_queue.queue_lock);
 		mtdblk = *p;
 		res = 0;
 
@@ -551,7 +551,7 @@
 		disk->major = MAJOR_NR;
 		disk->first_minor = mtd->index;
 		disk->fops = &mtd_fops;
-		sprintf(disk->disk_name, "mtd%d", mtd->index);
+		sprintf(disk->disk_name, "mtdblock%d", mtd->index);
 
 		mtddisk[mtd->index] = disk;
 		set_capacity(disk, mtd->size / 512);
diff -Nru a/drivers/net/3c505.c b/drivers/net/3c505.c
--- a/drivers/net/3c505.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/net/3c505.c	Sun Nov 10 19:28:41 2002
@@ -274,9 +274,12 @@
 
 static inline void set_hsf(struct net_device *dev, int hsf)
 {
-	cli();
+	elp_device *adapter = dev->priv;
+	unsigned long flags;
+
+	spin_lock_irqsave(&adapter->lock, flags);
 	outb_control((HCR_VAL(dev) & ~HSF_PCB_MASK) | hsf, dev);
-	sti();
+	spin_unlock_irqrestore(&adapter->lock, flags);
 }
 
 static int start_receive(struct net_device *, pcb_struct *);
@@ -325,8 +328,7 @@
 	if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) {
 		unsigned long flags, f;
 		printk("%s: DMA %s timed out, %d bytes left\n", dev->name, adapter->current_dma.direction ? "download" : "upload", get_dma_residue(dev->dma));
-		save_flags(flags);
-		cli();
+		spin_lock_irqsave(&adapter->lock, flags);
 		adapter->dmaing = 0;
 		adapter->busy = 0;
 		
@@ -337,7 +339,7 @@
 		if (adapter->rx_active)
 			adapter->rx_active--;
 		outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
-		restore_flags(flags);
+		spin_unlock_irqrestore(&adapter->lock, flags);
 	}
 }
 
@@ -405,6 +407,7 @@
 	int i;
 	int timeout;
 	elp_device *adapter = dev->priv;
+	unsigned long flags;
 
 	check_3c505_dma(dev);
 
@@ -428,7 +431,7 @@
 	if (send_pcb_slow(dev->base_addr, pcb->command))
 		goto abort;
 
-	cli();
+	spin_lock_irqsave(&adapter->lock, flags);
 
 	if (send_pcb_fast(dev->base_addr, pcb->length))
 		goto sti_abort;
@@ -442,7 +445,7 @@
 	outb_command(2 + pcb->length, dev->base_addr);
 
 	/* now wait for the acknowledgement */
-	sti();
+	spin_unlock_irqrestore(&adapter->lock, flags);
 
 	for (timeout = jiffies + 5*HZ/100; time_before(jiffies, timeout);) {
 		switch (GET_ASF(dev->base_addr)) {
@@ -463,7 +466,7 @@
 		printk("%s: timeout waiting for PCB acknowledge (status %02x)\n", dev->name, inb_status(dev->base_addr));
 
       sti_abort:
-	sti();
+	spin_unlock_irqrestore(&adapter->lock, flags);
       abort:
 	adapter->send_pcb_semaphore = 0;
 	return FALSE;
@@ -489,6 +492,7 @@
 	int total_length;
 	int stat;
 	int timeout;
+	unsigned long flags;
 
 	elp_device *adapter = dev->priv;
 
@@ -519,7 +523,7 @@
 		return FALSE;
 	}
 	/* read the data */
-	cli();
+	spin_lock_irqsave(&adapter->lock, flags);
 	i = 0;
 	do {
 		j = 0;
@@ -528,7 +532,7 @@
 		if (i > MAX_PCB_DATA)
 			INVALID_PCB_MSG(i);
 	} while ((stat & ASF_PCB_MASK) != ASF_PCB_END && j < 20000);
-	sti();
+	spin_unlock_irqrestore(&adapter->lock, flags);
 	if (j >= 20000) {
 		TIMEOUT_MSG(__LINE__);
 		return FALSE;
diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c
--- a/drivers/net/3c59x.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/net/3c59x.c	Sun Nov 10 19:28:36 2002
@@ -1804,10 +1804,10 @@
 		   inw(ioaddr + EL3_STATUS));
 	EL3WINDOW(4);
 	printk(KERN_ERR "  diagnostics: net %04x media %04x dma %08x fifo %04x\n",
-			(unsigned)inw(ioaddr + Wn4_NetDiag),
-			(unsigned)inw(ioaddr + Wn4_Media),
-			(unsigned)inl(ioaddr + PktStatus),
-			(unsigned)inw(ioaddr + Wn4_FIFODiag));
+			inw(ioaddr + Wn4_NetDiag),
+			inw(ioaddr + Wn4_Media),
+			inl(ioaddr + PktStatus),
+			inw(ioaddr + Wn4_FIFODiag));
 	/* Slight code bloat to be user friendly. */
 	if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
 		printk(KERN_ERR "%s: Transmitter encountered 16 collisions --"
@@ -2644,7 +2644,7 @@
 					vp->dirty_tx, vp->dirty_tx % TX_RING_SIZE,
 					vp->cur_tx, vp->cur_tx % TX_RING_SIZE);
 			printk(KERN_ERR "  Transmit list %8.8x vs. %p.\n",
-				   (unsigned)inl(ioaddr + DownListPtr),
+				   inl(ioaddr + DownListPtr),
 				   &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
 			issue_and_wait(dev, DownStall);
 			for (i = 0; i < TX_RING_SIZE; i++) {
diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig
--- a/drivers/net/Kconfig	Sun Nov 10 19:28:41 2002
+++ b/drivers/net/Kconfig	Sun Nov 10 19:28:41 2002
@@ -1066,6 +1066,20 @@
 	  <file:Documentation/networking/net-modules.txt>.  The module will be
 	  called apricot.o.
 
+config B44
+	tristate "Broadcom 4400 ethernet support (EXPERIMENTAL)"
+	depends on NET_PCI && PCI && EXPERIMENTAL
+	help
+	  If you have a network (Ethernet) controller of this type, say Y and
+	  read the Ethernet-HOWTO, available from
+	  <http://www.linuxdoc.org/docs.html#howto>.
+
+	  If you want to compile this as a module ( = code which can be
+	  inserted in and removed from the running kernel whenever you want),
+	  say M here and read <file:Documentation/modules.txt> as well as
+	  <file:Documentation/networking/net-modules.txt>.  The module will be
+	  called b44.o.
+
 config CS89x0
 	tristate "CS89x0 support"
 	depends on NET_PCI && ISA
diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile	Sun Nov 10 19:28:38 2002
+++ b/drivers/net/Makefile	Sun Nov 10 19:28:38 2002
@@ -101,6 +101,7 @@
 obj-$(CONFIG_LNE390) += lne390.o 8390.o
 obj-$(CONFIG_NE3210) += ne3210.o 8390.o
 obj-$(CONFIG_NET_SB1250_MAC) += sb1250-mac.o
+obj-$(CONFIG_B44) += b44.o
 
 obj-$(CONFIG_PPP) += ppp_generic.o slhc.o
 obj-$(CONFIG_PPP_ASYNC) += ppp_async.o
diff -Nru a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c
--- a/drivers/net/atari_bionet.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/net/atari_bionet.c	Sun Nov 10 19:28:40 2002
@@ -159,7 +159,7 @@
 static struct net_device_stats *net_get_stats(struct net_device *dev);
 static void bionet_tick(unsigned long);
 
-static struct timer_list bionet_timer = { function: bionet_tick };
+static struct timer_list bionet_timer = TIMER_INITIALIZER(bionet_tick, 0, 0);
 
 #define STRAM_ADDR(a)	(((a) & 0xff000000) == 0)
 
diff -Nru a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c
--- a/drivers/net/atari_pamsnet.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/net/atari_pamsnet.c	Sun Nov 10 19:28:38 2002
@@ -169,7 +169,7 @@
 
 static void pamsnet_intr(int irq, void *data, struct pt_regs *fp);
 
-static struct timer_list pamsnet_timer = { function: amsnet_tick };
+static struct timer_list pamsnet_timer = TIMER_INITIALIZER(amsnet_tick, 0, 0);
 
 #define STRAM_ADDR(a)	(((a) & 0xff000000) == 0)
 
diff -Nru a/drivers/net/b44.c b/drivers/net/b44.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/b44.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,1830 @@
+/* b44.c: Broadcom 4400 device driver.
+ *
+ * Copyright (C) 2002 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "b44.h"
+
+#define DRV_MODULE_NAME		"b44"
+#define PFX DRV_MODULE_NAME	": "
+#define DRV_MODULE_VERSION	"0.1"
+#define DRV_MODULE_RELDATE	"Nov 6, 2002"
+
+#define B44_DEF_MSG_ENABLE	  \
+	(NETIF_MSG_DRV		| \
+	 NETIF_MSG_PROBE	| \
+	 NETIF_MSG_LINK		| \
+	 NETIF_MSG_TIMER	| \
+	 NETIF_MSG_IFDOWN	| \
+	 NETIF_MSG_IFUP		| \
+	 NETIF_MSG_RX_ERR	| \
+	 NETIF_MSG_TX_ERR)
+
+/* length of time before we decide the hardware is borked,
+ * and dev->tx_timeout() should be called to fix the problem
+ */
+#define B44_TX_TIMEOUT			(5 * HZ)
+
+/* hardware minimum and maximum for a single frame's data payload */
+#define B44_MIN_MTU			60
+#define B44_MAX_MTU			1500
+
+#define B44_RX_RING_SIZE		512
+#define B44_DEF_RX_RING_PENDING		200
+#define B44_RX_RING_BYTES	(sizeof(struct dma_desc) * \
+				 B44_RX_RING_SIZE)
+#define B44_TX_RING_SIZE		512
+#define B44_DEF_TX_RING_PENDING		(B44_TX_RING_SIZE - 1)
+#define B44_TX_RING_BYTES	(sizeof(struct dma_desc) * \
+				 B44_TX_RING_SIZE)
+
+#define TX_RING_GAP(BP)	\
+	(B44_TX_RING_SIZE - (BP)->tx_pending)
+#define TX_BUFFS_AVAIL(BP)						\
+	(((BP)->tx_cons <= (BP)->tx_prod) ?				\
+	  (BP)->tx_cons + (BP)->tx_pending - (BP)->tx_prod :		\
+	  (BP)->tx_cons - (BP)->tx_prod - TX_RING_GAP(BP))
+#define NEXT_TX(N)		(((N) + 1) & (B44_TX_RING_SIZE - 1))
+
+/* XXX check this */
+#define RX_PKT_BUF_SZ		(1536 + bp->rx_offset + 64)
+
+/* minimum number of free TX descriptors required to wake up TX process */
+#define B44_TX_WAKEUP_THRESH		(B44_TX_RING_SIZE / 4)
+
+static char version[] __devinitdata =
+	DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
+
+MODULE_AUTHOR("David S. Miller (davem@redhat.com)");
+MODULE_DESCRIPTION("Broadcom 4400 ethernet driver");
+MODULE_LICENSE("GPL");
+MODULE_PARM(b44_debug, "i");
+MODULE_PARM_DESC(b44_debug, "B44 bitmapped debugging message enable value");
+
+static int b44_debug = -1;	/* -1 == use B44_DEF_MSG_ENABLE as value */
+
+/* XXX put this to pci_ids.h and pci.ids */
+#ifndef PCI_DEVICE_ID_BCM4401
+#define PCI_DEVICE_ID_BCM4401 0x4401
+#endif
+
+static struct pci_device_id b44_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_BCM4401,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ }	/* terminate list with empty entry */
+};
+
+MODULE_DEVICE_TABLE(pci, b44_pci_tbl);
+
+static void b44_halt(struct b44 *);
+static void b44_init_rings(struct b44 *);
+static int b44_init_hw(struct b44 *);
+
+static void b44_wait_bit(struct b44 *bp, unsigned long reg,
+			 u32 bit, unsigned long timeout, int clear)
+{
+	unsigned long i;
+
+	for (i = 0; i < timeout; i++) {
+		u32 val = br32(reg);
+
+		if (clear && !(val & bit))
+			break;
+		if (!clear && (val & bit))
+			break;
+		udelay(10);
+	}
+	if (i == timeout) {
+		printk(KERN_ERR PFX "%s: BUG!  Timeout waiting for bit %08x of register "
+		       "%lx to %s.\n",
+		       bp->dev->name,
+		       bit, reg,
+		       (clear ? "clear" : "set"));
+	}
+}
+
+/* Sonics SiliconBackplane support routines.  ROFL, you should see all the
+ * buzz words used on this company's website :-)
+ *
+ * All of these routines must be invoked with bp->lock held and
+ * interrupts disabled.
+ */
+
+#define SBID_SDRAM		0
+#define SBID_PCI_MEM		1
+#define SBID_PCI_CFG		2
+#define SBID_PCI_DMA		3
+#define	SBID_SDRAM_SWAPPED	4
+#define SBID_ENUM		5
+#define SBID_REG_SDRAM		6
+#define SBID_REG_ILINE20	7
+#define SBID_REG_EMAC		8
+#define SBID_REG_CODEC		9
+#define SBID_REG_USB		10
+#define SBID_REG_PCI		11
+#define SBID_REG_MIPS		12
+#define SBID_REG_EXTIF		13
+#define	SBID_EXTIF		14
+#define	SBID_EJTAG		15
+#define	SBID_MAX		16
+
+static u32 ssb_get_addr(struct b44 *bp, u32 id, u32 instance)
+{
+	switch (id) {
+	case SBID_PCI_DMA:
+		return 0x40000000;
+	case SBID_ENUM:
+		return 0x18000000;
+	case SBID_REG_EMAC:
+		return 0x18000000;
+	case SBID_REG_CODEC:
+		return 0x18001000;
+	case SBID_REG_PCI:
+		return 0x18002000;
+	default:
+		return 0;
+	};
+}
+
+static u32 ssb_get_core_rev(struct b44 *bp)
+{
+	return (br32(B44_SBIDHIGH) & SBIDHIGH_RC_MASK);
+}
+
+static u32 ssb_pci_setup(struct b44 *bp, u32 cores)
+{
+	u32 bar_orig, pci_rev, val;
+
+	pci_read_config_dword(bp->pdev, SSB_BAR0_WIN, &bar_orig);
+	pci_write_config_dword(bp->pdev, SSB_BAR0_WIN,
+			       ssb_get_addr(bp, SBID_REG_PCI, 0));
+	pci_rev = ssb_get_core_rev(bp);
+
+	val = br32(B44_SBINTVEC);
+	val |= cores;
+	bw32(B44_SBINTVEC, val);
+
+	val = br32(SSB_PCI_TRANS_2);
+	val |= SSB_PCI_PREF | SSB_PCI_BURST;
+	bw32(SSB_PCI_TRANS_2, val);
+
+	pci_write_config_dword(bp->pdev, SSB_BAR0_WIN, bar_orig);
+
+	return pci_rev;
+}
+
+static void ssb_core_disable(struct b44 *bp)
+{
+	if (br32(B44_SBTMSLOW) & SBTMSLOW_RESET)
+		return;
+
+	bw32(B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_CLOCK));
+	b44_wait_bit(bp, B44_SBTMSLOW, SBTMSLOW_REJECT, 100000, 0);
+	b44_wait_bit(bp, B44_SBTMSHIGH, SBTMSHIGH_BUSY, 100000, 1);
+	bw32(B44_SBTMSLOW, (SBTMSLOW_FGC | SBTMSLOW_CLOCK |
+			    SBTMSLOW_REJECT | SBTMSLOW_RESET));
+	br32(B44_SBTMSLOW);
+	udelay(1);
+	bw32(B44_SBTMSLOW, (SBTMSLOW_REJECT | SBTMSLOW_RESET));
+	br32(B44_SBTMSLOW);
+	udelay(1);
+}
+
+static void ssb_core_reset(struct b44 *bp)
+{
+	u32 val;
+
+	ssb_core_disable(bp);
+	bw32(B44_SBTMSLOW, (SBTMSLOW_RESET | SBTMSLOW_CLOCK | SBTMSLOW_FGC));
+	br32(B44_SBTMSLOW);
+	udelay(1);
+
+	/* Clear SERR if set, this is a hw bug workaround.  */
+	if (br32(B44_SBTMSHIGH) & SBTMSHIGH_SERR)
+		bw32(B44_SBTMSHIGH, 0);
+
+	val = br32(B44_SBIMSTATE);
+	if (val & (SBIMSTATE_IBE | SBIMSTATE_TO))
+		bw32(B44_SBIMSTATE, val & ~(SBIMSTATE_IBE | SBIMSTATE_TO));
+
+	bw32(B44_SBTMSLOW, (SBTMSLOW_CLOCK | SBTMSLOW_FGC));
+	br32(B44_SBTMSLOW);
+	udelay(1);
+
+	bw32(B44_SBTMSLOW, (SBTMSLOW_CLOCK));
+	br32(B44_SBTMSLOW);
+	udelay(1);
+}
+
+static int ssb_core_unit(struct b44 *bp)
+{
+#if 0
+	u32 val = br32(B44_SBADMATCH0);
+	u32 base;
+
+	type = val & SBADMATCH0_TYPE_MASK;
+	switch (type) {
+	case 0:
+		base = val & SBADMATCH0_BS0_MASK;
+		break;
+
+	case 1:
+		base = val & SBADMATCH0_BS1_MASK;
+		break;
+
+	case 2:
+	default:
+		base = val & SBADMATCH0_BS2_MASK;
+		break;
+	};
+#endif
+	return 0;
+}
+
+static int ssb_is_core_up(struct b44 *bp)
+{
+	return ((br32(B44_SBTMSLOW) & (SBTMSLOW_RESET | SBTMSLOW_REJECT | SBTMSLOW_CLOCK))
+		== SBTMSLOW_CLOCK);
+}
+
+static void __b44_cam_write(struct b44 *bp, char *data, int index)
+{
+	u32 val;
+
+	val  = ((u32) data[2]) << 24;
+	val |= ((u32) data[3]) << 16;
+	val |= ((u32) data[4]) <<  8;
+	val |= ((u32) data[5]) <<  0;
+	bw32(B44_CAM_DATA_LO, val);
+	val = (CAM_DATA_HI_VALID | 
+	       (((u32) data[0]) << 8) |
+	       (((u32) data[1]) << 0));
+	bw32(B44_CAM_DATA_HI, val);
+	bw32(B44_CAM_CTRL, (CAM_CTRL_WRITE |
+			    (index << CAM_CTRL_INDEX_SHIFT)));
+	b44_wait_bit(bp, B44_CAM_CTRL, CAM_CTRL_BUSY, 100, 1);	
+}
+
+static inline void __b44_disable_ints(struct b44 *bp)
+{
+	bw32(B44_IMASK, 0);
+}
+
+static void b44_disable_ints(struct b44 *bp)
+{
+	__b44_disable_ints(bp);
+
+	/* Flush posted writes. */
+	br32(B44_IMASK);
+}
+
+static void b44_enable_ints(struct b44 *bp)
+{
+	bw32(B44_IMASK, bp->imask);
+}
+
+static int b44_readphy(struct b44 *bp, int reg, u32 *val)
+{
+	bw32(B44_EMAC_ISTAT, EMAC_INT_MII);
+	bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START |
+			     (MDIO_OP_READ << MDIO_DATA_OP_SHIFT) |
+			     (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
+			     (reg << MDIO_DATA_RA_SHIFT) |
+			     (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT)));
+	b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+	*val = br32(B44_MDIO_DATA) & MDIO_DATA_DATA;
+	return 0;
+}
+
+static int b44_writephy(struct b44 *bp, int reg, u32 val)
+{
+	bw32(B44_EMAC_ISTAT, EMAC_INT_MII);
+	bw32(B44_MDIO_DATA, (MDIO_DATA_SB_START |
+			     (MDIO_OP_WRITE << MDIO_DATA_OP_SHIFT) |
+			     (bp->phy_addr << MDIO_DATA_PMD_SHIFT) |
+			     (reg << MDIO_DATA_RA_SHIFT) |
+			     (MDIO_TA_VALID << MDIO_DATA_TA_SHIFT) |
+			     (val & MDIO_DATA_DATA)));
+	b44_wait_bit(bp, B44_EMAC_ISTAT, EMAC_INT_MII, 100, 0);
+	return 0;
+}
+
+static int b44_phy_reset(struct b44 *bp)
+{
+	u32 val;
+	int err;
+
+	err = b44_writephy(bp, MII_BMCR, BMCR_RESET);
+	if (err)
+		return err;
+	udelay(100);
+	err = b44_readphy(bp, MII_BMCR, &val);
+	if (!err) {
+		if (val & BMCR_RESET) {
+			printk(KERN_ERR PFX "%s: PHY Reset would not complete.\n",
+			       bp->dev->name);
+			err = -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+#if 0
+static int b44_set_power_state(struct b44 *bp, int state)
+{
+}
+#endif
+
+static void __b44_set_flow_ctrl(struct b44 *bp, u32 pause_flags)
+{
+	u32 val;
+
+	bp->flags &= ~(B44_FLAG_TX_PAUSE | B44_FLAG_RX_PAUSE);
+	bp->flags |= pause_flags;
+
+	val = br32(B44_RXCONFIG);
+	if (pause_flags & B44_FLAG_RX_PAUSE)
+		val |= RXCONFIG_FLOW;
+	else
+		val &= ~RXCONFIG_FLOW;
+	bw32(B44_RXCONFIG, val);
+
+	val = br32(B44_MAC_FLOW);
+	if (pause_flags & B44_FLAG_TX_PAUSE)
+		val |= (MAC_FLOW_PAUSE_ENAB |
+			(0xc0 & MAC_FLOW_RX_HI_WATER));
+	else
+		val &= ~MAC_FLOW_PAUSE_ENAB;
+	bw32(B44_MAC_FLOW, val);
+}
+
+static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote)
+{
+	u32 pause_enab = bp->flags & (B44_FLAG_TX_PAUSE |
+				      B44_FLAG_RX_PAUSE);
+
+	if (local & ADVERTISE_PAUSE_CAP) {
+		if (local & ADVERTISE_PAUSE_ASYM) {
+			if (remote & LPA_PAUSE_CAP)
+				pause_enab |= (B44_FLAG_TX_PAUSE |
+					       B44_FLAG_RX_PAUSE);
+			else if (remote & LPA_PAUSE_ASYM)
+				pause_enab |= B44_FLAG_RX_PAUSE;
+		} else {
+			if (remote & LPA_PAUSE_CAP)
+				pause_enab |= (B44_FLAG_TX_PAUSE |
+					       B44_FLAG_RX_PAUSE);
+		}
+	} else if (local & ADVERTISE_PAUSE_ASYM) {
+		if ((remote & LPA_PAUSE_CAP) &&
+		    (remote & LPA_PAUSE_ASYM))
+			pause_enab |= B44_FLAG_TX_PAUSE;
+	}
+
+	__b44_set_flow_ctrl(bp, pause_enab);
+}
+
+static int b44_setup_phy(struct b44 *bp)
+{
+	u32 val;
+	int err;
+
+	if ((err = b44_readphy(bp, B44_MII_ALEDCTRL, &val)) != 0)
+		goto out;
+	if ((err = b44_writephy(bp, B44_MII_ALEDCTRL,
+				val & MII_ALEDCTRL_ALLMSK)) != 0)
+		goto out;
+	if ((err = b44_readphy(bp, B44_MII_TLEDCTRL, &val)) != 0)
+		goto out;
+	if ((err = b44_writephy(bp, B44_MII_TLEDCTRL,
+				val | MII_TLEDCTRL_ENABLE)) != 0)
+		goto out;
+
+	if (!(bp->flags & B44_FLAG_FORCE_LINK)) {
+		u32 adv = ADVERTISE_CSMA;
+
+		if (bp->flags & B44_FLAG_ADV_10HALF)
+			adv |= ADVERTISE_10HALF;
+		if (bp->flags & B44_FLAG_ADV_10FULL)
+			adv |= ADVERTISE_10FULL;
+		if (bp->flags & B44_FLAG_ADV_100HALF)
+			adv |= ADVERTISE_100HALF;
+		if (bp->flags & B44_FLAG_ADV_100FULL)
+			adv |= ADVERTISE_100FULL;
+
+		if (bp->flags & B44_FLAG_PAUSE_AUTO)
+			adv |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+
+		if ((err = b44_writephy(bp, MII_ADVERTISE, adv)) != 0)
+			goto out;
+		if ((err = b44_writephy(bp, MII_BMCR, (BMCR_ANENABLE |
+						       BMCR_ANRESTART))) != 0)
+			goto out;
+	} else {
+		u32 bmcr;
+
+		if ((err = b44_readphy(bp, MII_BMCR, &bmcr)) != 0)
+			goto out;
+		bmcr &= ~(BMCR_FULLDPLX | BMCR_ANENABLE | BMCR_SPEED100);
+		if (bp->flags & B44_FLAG_100_BASE_T)
+			bmcr |= BMCR_SPEED100;
+		if (bp->flags & B44_FLAG_FULL_DUPLEX)
+			bmcr |= BMCR_FULLDPLX;
+		if ((err = b44_writephy(bp, MII_BMCR, bmcr)) != 0)
+			goto out;
+
+		/* Since we will not be negotiating there is no safe way
+		 * to determine if the link partner supports flow control
+		 * or not.  So just disable it completely in this case.
+		 */
+		b44_set_flow_ctrl(bp, 0, 0);
+	}
+
+out:
+	return err;
+}
+
+static void b44_stats_update(struct b44 *bp)
+{
+	unsigned long reg;
+	u32 *val;
+
+	val = &bp->hw_stats.tx_good_octets;
+	for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL) {
+		*val++ += br32(reg);
+	}
+	val = &bp->hw_stats.rx_good_octets;
+	for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL) {
+		*val++ += br32(reg);
+	}
+}
+
+static void b44_link_report(struct b44 *bp)
+{
+	if (!netif_carrier_ok(bp->dev)) {
+		printk(KERN_INFO PFX "%s: Link is down.\n", bp->dev->name);
+	} else {
+		printk(KERN_INFO PFX "%s: Link is up at %d Mbps, %s duplex.\n",
+		       bp->dev->name,
+		       (bp->flags & B44_FLAG_100_BASE_T) ? 100 : 10,
+		       (bp->flags & B44_FLAG_FULL_DUPLEX) ? "full" : "half");
+
+		printk(KERN_INFO PFX "%s: Flow control is %s for TX and "
+		       "%s for RX.\n",
+		       bp->dev->name,
+		       (bp->flags & B44_FLAG_TX_PAUSE) ? "on" : "off",
+		       (bp->flags & B44_FLAG_RX_PAUSE) ? "on" : "off");
+	}
+}
+
+static void b44_check_phy(struct b44 *bp)
+{
+	u32 bmsr, aux;
+
+	if (!b44_readphy(bp, MII_BMSR, &bmsr) &&
+	    !b44_readphy(bp, B44_MII_AUXCTRL, &aux) &&
+	    (bmsr != 0xffff)) {
+		if (aux & MII_AUXCTRL_SPEED)
+			bp->flags |= B44_FLAG_100_BASE_T;
+		else
+			bp->flags &= ~B44_FLAG_100_BASE_T;
+		if (aux & MII_AUXCTRL_DUPLEX)
+			bp->flags |= B44_FLAG_FULL_DUPLEX;
+		else
+			bp->flags &= ~B44_FLAG_FULL_DUPLEX;
+
+		if (!netif_carrier_ok(bp->dev) &&
+		    (bmsr & BMSR_LSTATUS)) {
+			u32 val = br32(B44_TX_CTRL);
+			u32 local_adv, remote_adv;
+
+			if (bp->flags & B44_FLAG_FULL_DUPLEX)
+				val |= TX_CTRL_DUPLEX;
+			else
+				val &= ~TX_CTRL_DUPLEX;
+			bw32(B44_TX_CTRL, val);
+
+			if (!(bp->flags & B44_FLAG_FORCE_LINK) &&
+			    !b44_readphy(bp, MII_ADVERTISE, &local_adv) &&
+			    !b44_readphy(bp, MII_LPA, &remote_adv))
+				b44_set_flow_ctrl(bp, local_adv, remote_adv);
+
+			/* Link now up */
+			netif_carrier_on(bp->dev);
+			b44_link_report(bp);
+		} else if (netif_carrier_ok(bp->dev)) {
+			/* Link now down */
+			netif_carrier_off(bp->dev);
+			b44_link_report(bp);
+		}
+
+		if (bmsr & BMSR_RFAULT)
+			printk(KERN_WARNING PFX "%s: Remote fault detected in PHY\n",
+			       bp->dev->name);
+		if (bmsr & BMSR_JCD)
+			printk(KERN_WARNING PFX "%s: Jabber detected in PHY\n",
+			       bp->dev->name);
+	}
+}
+
+static void b44_timer(unsigned long __opaque)
+{
+	struct b44 *bp = (struct b44 *) __opaque;
+
+	spin_lock_irq(&bp->lock);
+
+	b44_check_phy(bp);
+
+	b44_stats_update(bp);
+
+	spin_unlock_irq(&bp->lock);
+
+	bp->timer.expires = jiffies + HZ;
+	add_timer(&bp->timer);
+}
+
+static void b44_tx(struct b44 *bp)
+{
+	u32 cur, cons;
+
+	cur  = br32(B44_DMATX_STAT) & DMATX_STAT_CDMASK;
+	cur /= sizeof(struct dma_desc);
+
+	/* XXX needs updating when NETIF_F_SG is supported */
+	for (cons = bp->tx_cons; cons != cur; cons = NEXT_TX(cons)) {
+		struct ring_info *rp = &bp->tx_buffers[cons];
+		struct sk_buff *skb = rp->skb;
+
+		if (unlikely(skb == NULL))
+			BUG();
+
+
+		pci_unmap_single(bp->pdev,
+				 pci_unmap_addr(rp, mapping),
+				 skb->len,
+				 PCI_DMA_TODEVICE);
+		rp->skb = NULL;
+		dev_kfree_skb_irq(skb);
+	}
+
+	bp->tx_cons = cons;
+	if (netif_queue_stopped(bp->dev) &&
+	    TX_BUFFS_AVAIL(bp) > B44_TX_WAKEUP_THRESH)
+		netif_wake_queue(bp->dev);
+
+	bw32(B44_GPTIMER, 0);
+}
+
+static int b44_alloc_rx_skb(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
+{
+	struct dma_desc *dp;
+	struct ring_info *src_map, *map;
+	struct sk_buff *skb;
+	dma_addr_t mapping;
+	int dest_idx;
+	u32 ctrl;
+
+	src_map = NULL;
+	if (src_idx >= 0)
+		src_map = &bp->rx_buffers[src_idx];
+	dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1);
+	map = &bp->rx_buffers[dest_idx];
+	skb = dev_alloc_skb(RX_PKT_BUF_SZ);
+	if (skb == NULL)
+		return -ENOMEM;
+
+	skb->dev = bp->dev;
+	mapping = pci_map_single(bp->pdev, skb->data,
+				 RX_PKT_BUF_SZ,
+				 PCI_DMA_FROMDEVICE);
+	skb_reserve(skb, bp->rx_offset);
+
+	map->skb = skb;
+	pci_unmap_addr_set(map, mapping, mapping);
+
+	if (src_map != NULL)
+		src_map->skb = NULL;
+
+	ctrl  = (DESC_CTRL_LEN & (RX_PKT_BUF_SZ - bp->rx_offset));
+	if (dest_idx == (B44_RX_RING_SIZE - 1))
+		ctrl |= DESC_CTRL_EOT;
+
+	dp = &bp->rx_ring[dest_idx];
+	dp->ctrl = cpu_to_le32(ctrl);
+	dp->addr = cpu_to_le32((u32) mapping + bp->rx_offset + bp->dma_offset);
+
+	return RX_PKT_BUF_SZ;
+}
+
+static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
+{
+	struct dma_desc *src_desc, *dest_desc;
+	struct ring_info *src_map, *dest_map;
+	int dest_idx;
+	u32 ctrl;
+
+	dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1);
+	dest_desc = &bp->rx_ring[dest_idx];
+	dest_map = &bp->rx_buffers[dest_idx];
+	src_desc = &bp->rx_ring[src_idx];
+	src_map = &bp->rx_buffers[src_idx];
+
+	dest_map->skb = src_map->skb;
+	pci_unmap_addr_set(dest_map, mapping,
+			   pci_unmap_addr(src_map, mapping));
+
+	ctrl = src_desc->ctrl;
+	if (dest_idx == (B44_RX_RING_SIZE - 1))
+		ctrl |= cpu_to_le32(DESC_CTRL_EOT);
+
+	dest_desc->ctrl = ctrl;
+	dest_desc->addr = src_desc->addr;
+}
+
+static int b44_rx(struct b44 *bp, int budget)
+{
+	int received;
+	u32 cons, prod;
+
+	received = 0;
+	prod  = br32(B44_DMARX_STAT) & DMARX_STAT_CDMASK;
+	prod /= sizeof(struct dma_desc);
+	cons = bp->rx_cons;
+
+	while (cons != prod && budget > 0) {
+		struct ring_info *rp = &bp->rx_buffers[cons];
+		struct sk_buff *skb = rp->skb;
+		dma_addr_t map = pci_unmap_addr(rp, mapping);
+		struct rx_header *rh;
+		u16 len;
+
+		pci_dma_sync_single(bp->pdev, map,
+				    RX_PKT_BUF_SZ,
+				    PCI_DMA_FROMDEVICE);
+		rh = (struct rx_header *) (skb->data - bp->rx_offset);
+		len = cpu_to_le16(rh->len);
+		if (rh->flags & cpu_to_le16(RX_FLAG_ERRORS)) {
+		drop_it:
+			b44_recycle_rx(bp, cons, bp->rx_prod);
+		drop_it_no_recycle:
+			bp->stats.rx_dropped++;
+			goto next_pkt;
+		}
+
+		if (len > RX_COPY_THRESHOLD) {
+			int skb_size;
+			skb_size = b44_alloc_rx_skb(bp, cons, bp->rx_prod);
+			if (skb_size < 0)
+				goto drop_it;
+			pci_unmap_single(bp->pdev, map,
+					 skb_size, PCI_DMA_FROMDEVICE);
+			skb_put(skb, len);
+		} else {
+			struct sk_buff *copy_skb;
+
+			b44_recycle_rx(bp, cons, bp->rx_prod);
+			copy_skb = dev_alloc_skb(len + 2);
+			if (copy_skb == NULL)
+				goto drop_it_no_recycle;
+
+			copy_skb->dev = bp->dev;
+			skb_reserve(copy_skb, 2);
+			skb_put(copy_skb, len);
+			/* DMA sync done above */
+			memcpy(copy_skb->data, skb->data, len);
+
+			skb = copy_skb;
+		}
+		skb->ip_summed = CHECKSUM_NONE;
+		skb->protocol = eth_type_trans(skb, bp->dev);
+		netif_receive_skb(skb);
+		bp->dev->last_rx = jiffies;
+		received++;
+		budget--;
+	next_pkt:
+		bp->rx_prod = (bp->rx_prod + 1) &
+			(B44_RX_RING_SIZE - 1);
+		cons = (cons + 1) & (B44_RX_RING_SIZE - 1);
+	}
+
+	bp->rx_cons = cons;
+
+	return received;
+}
+
+static int b44_poll(struct net_device *netdev, int *budget)
+{
+	struct b44 *bp = netdev->priv;
+	int done;
+
+	spin_lock_irq(&bp->lock);
+
+	if (bp->istat & (ISTAT_TX | ISTAT_TO)) {
+		/* spin_lock(&bp->tx_lock); */
+		b44_tx(bp);
+		/* spin_unlock(&bp->tx_lock); */
+	}
+
+	done = 1;
+	if (bp->istat & ISTAT_RX) {
+		int orig_budget = *budget;
+		int work_done;
+
+		if (orig_budget > netdev->quota)
+			orig_budget = netdev->quota;
+
+		work_done = b44_rx(bp, orig_budget);
+
+		*budget -= work_done;
+		netdev->quota -= work_done;
+
+		if (work_done >= orig_budget)
+			done = 0;
+	}
+
+	if (bp->istat & ISTAT_ERRORS) {
+		b44_halt(bp);
+		b44_init_rings(bp);
+		b44_init_hw(bp);
+		netif_wake_queue(bp->dev);
+		done = 1;
+	}
+
+	if (done) {
+		netif_rx_complete(netdev);
+		b44_enable_ints(bp);
+	}
+	spin_unlock_irq(&bp->lock);
+
+	return (done ? 0 : 1);
+}
+
+static void b44_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct b44 *bp = dev->priv;
+	unsigned long flags;
+	u32 istat, imask;
+
+	spin_lock_irqsave(&bp->lock, flags);
+
+	istat = br32(B44_ISTAT);
+	imask = br32(B44_IMASK);
+
+	/* ??? What the fuck is the purpose of the interrupt mask
+	 * ??? register if we have to mask it out by hand anyways?
+	 */
+	istat &= imask;
+	if (istat) {
+		if (netif_rx_schedule_prep(dev)) {
+			/* NOTE: These writes are posted by the readback of
+			 *       the ISTAT register below.
+			 */
+			bp->istat = istat;
+			__b44_disable_ints(bp);
+			__netif_rx_schedule(dev);
+		} else {
+			printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
+			       dev->name);
+		}
+
+		bw32(B44_ISTAT, istat);
+		br32(B44_ISTAT);
+	}
+	spin_unlock_irqrestore(&bp->lock, flags);
+}
+
+static void b44_tx_timeout(struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+
+	printk(KERN_ERR PFX "%s: transmit timed out, resetting\n",
+	       dev->name);
+
+	spin_lock_irq(&bp->lock);
+
+	b44_halt(bp);
+	b44_init_rings(bp);
+	b44_init_hw(bp);
+
+	spin_unlock_irq(&bp->lock);
+
+	netif_wake_queue(dev);
+}
+
+static int b44_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+	dma_addr_t mapping;
+	u32 len, entry, ctrl;
+
+	len = skb->len;
+	spin_lock_irq(&bp->lock);
+
+	/* This is a hard error, log it. */
+	if (unlikely(TX_BUFFS_AVAIL(bp) < 1)) {
+		netif_stop_queue(dev);
+		spin_unlock_irq(&bp->lock);
+		printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
+		       dev->name);
+		return 1;
+	}
+
+	entry = bp->tx_prod;
+	mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
+
+	bp->tx_buffers[entry].skb = skb;
+	pci_unmap_addr_set(&bp->tx_buffers[entry], mapping, mapping);
+
+	ctrl  = (len & DESC_CTRL_LEN);
+	ctrl |= DESC_CTRL_IOC | DESC_CTRL_SOF | DESC_CTRL_EOF;
+	if (entry == (B44_TX_RING_SIZE - 1))
+		ctrl |= DESC_CTRL_EOT;
+
+	bp->tx_ring[entry].ctrl = cpu_to_le32(ctrl);
+	bp->tx_ring[entry].addr = cpu_to_le32((u32) mapping);
+
+	entry = NEXT_TX(entry);
+
+	bp->tx_prod = entry;
+
+	wmb();
+
+	bw32(B44_DMATX_PTR, entry * sizeof(struct dma_desc));
+	if (bp->flags & B44_FLAG_BUGGY_TXPTR)
+		bw32(B44_DMATX_PTR, entry * sizeof(struct dma_desc));
+	if (bp->flags & B44_FLAG_REORDER_BUG)
+		br32(B44_DMATX_PTR);
+
+	if (TX_BUFFS_AVAIL(bp) < 1)
+		netif_stop_queue(dev);
+
+	spin_unlock_irq(&bp->lock);
+
+	dev->trans_start = jiffies;
+
+	return 0;
+}
+
+static int b44_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct b44 *bp = dev->priv;
+
+	if (new_mtu < B44_MIN_MTU || new_mtu > B44_MAX_MTU)
+		return -EINVAL;
+
+	if (!netif_running(dev)) {
+		/* We'll just catch it later when the
+		 * device is up'd.
+		 */
+		dev->mtu = new_mtu;
+		return 0;
+	}
+
+	spin_lock_irq(&bp->lock);
+	b44_halt(bp);
+	dev->mtu = new_mtu;
+	b44_init_rings(bp);
+	b44_init_hw(bp);
+	spin_unlock_irq(&bp->lock);
+
+	return 0;
+}
+
+/* Free up pending packets in all rx/tx rings.
+ *
+ * The chip has been shut down and the driver detached from
+ * the networking, so no interrupts or new tx packets will
+ * end up in the driver.  bp->lock is not held and we are not
+ * in an interrupt context and thus may sleep.
+ */
+static void b44_free_rings(struct b44 *bp)
+{
+	struct ring_info *rp;
+	int i;
+
+	for (i = 0; i < B44_RX_RING_SIZE; i++) {
+		rp = &bp->rx_buffers[i];
+
+		if (rp->skb == NULL)
+			continue;
+		pci_unmap_single(bp->pdev,
+				 pci_unmap_addr(rp, mapping),
+				 RX_PKT_BUF_SZ - bp->rx_offset,
+				 PCI_DMA_FROMDEVICE);
+		dev_kfree_skb_any(rp->skb);
+		rp->skb = NULL;
+	}
+
+	/* XXX needs changes once NETIF_F_SG is set... */
+	for (i = 0; i < B44_TX_RING_SIZE; i++) {
+		rp = &bp->tx_buffers[i];
+
+		if (rp->skb == NULL)
+			continue;
+		pci_unmap_single(bp->pdev,
+				 pci_unmap_addr(rp, mapping),
+				 rp->skb->len,
+				 PCI_DMA_TODEVICE);
+		dev_kfree_skb_any(rp->skb);
+		rp->skb = NULL;
+	}
+}
+
+/* Initialize tx/rx rings for packet processing.
+ *
+ * The chip has been shut down and the driver detached from
+ * the networking, so no interrupts or new tx packets will
+ * end up in the driver.  bp->lock is not held and we are not
+ * in an interrupt context and thus may sleep.
+ */
+static void b44_init_rings(struct b44 *bp)
+{
+	int i;
+
+	b44_free_rings(bp);
+
+	memset(bp->rx_ring, 0, B44_RX_RING_BYTES);
+	memset(bp->tx_ring, 0, B44_TX_RING_BYTES);
+
+	for (i = 0; i < bp->rx_pending; i++) {
+		if (b44_alloc_rx_skb(bp, -1, i) < 0)
+			break;
+	}
+}
+
+/*
+ * Must not be invoked with interrupt sources disabled and
+ * the hardware shutdown down.
+ */
+static void b44_free_consistent(struct b44 *bp)
+{
+	if (bp->rx_buffers) {
+		kfree(bp->rx_buffers);
+		bp->rx_buffers = NULL;
+	}
+	if (bp->tx_buffers) {
+		kfree(bp->tx_buffers);
+		bp->tx_buffers = NULL;
+	}
+	if (bp->rx_ring) {
+		pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+				    bp->rx_ring, bp->rx_ring_dma);
+		bp->rx_ring = NULL;
+	}
+	if (bp->tx_ring) {
+		pci_free_consistent(bp->pdev, DMA_TABLE_BYTES,
+				    bp->tx_ring, bp->tx_ring_dma);
+		bp->tx_ring = NULL;
+	}
+}
+
+/*
+ * Must not be invoked with interrupt sources disabled and
+ * the hardware shutdown down.  Can sleep.
+ */
+static int b44_alloc_consistent(struct b44 *bp)
+{
+	int size;
+
+	size  = B44_RX_RING_SIZE * sizeof(struct ring_info);
+	bp->rx_buffers = kmalloc(size, GFP_KERNEL);
+	if (!bp->rx_buffers)
+		goto out_err;
+	memset(bp->rx_buffers, 0, size);
+
+	size = B44_TX_RING_SIZE * sizeof(struct ring_info);
+	bp->tx_buffers = kmalloc(size, GFP_KERNEL);
+	if (!bp->tx_buffers)
+		goto out_err;
+	memset(bp->tx_buffers, 0, size);
+
+	size = DMA_TABLE_BYTES;
+	bp->rx_ring = pci_alloc_consistent(bp->pdev, size, &bp->rx_ring_dma);
+	if (!bp->rx_ring)
+		goto out_err;
+
+	bp->tx_ring = pci_alloc_consistent(bp->pdev, size, &bp->tx_ring_dma);
+	if (!bp->tx_ring)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	b44_free_consistent(bp);
+	return -ENOMEM;
+}
+
+/* bp->lock is held. */
+static void b44_clear_stats(struct b44 *bp)
+{
+	unsigned long reg;
+
+	bw32(B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
+	for (reg = B44_TX_GOOD_O; reg <= B44_TX_PAUSE; reg += 4UL)
+		br32(reg);
+	for (reg = B44_RX_GOOD_O; reg <= B44_RX_NPAUSE; reg += 4UL)
+		br32(reg);
+}
+
+/* bp->lock is held. */
+static void b44_chip_reset(struct b44 *bp)
+{
+	if (ssb_is_core_up(bp)) {
+		bw32(B44_RCV_LAZY, 0);
+		bw32(B44_ENET_CTRL, ENET_CTRL_DISABLE);
+		b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 100, 1);
+		bw32(B44_DMATX_CTRL, 0);
+		bp->tx_prod = bp->tx_cons = 0;
+		b44_wait_bit(bp, B44_DMARX_STAT, DMARX_STAT_SIDLE, 100, 0);
+		bw32(B44_DMARX_CTRL, 0);
+		bp->rx_prod = bp->rx_cons = 0;
+	} else {
+		ssb_pci_setup(bp, (bp->core_unit == 0 ?
+				   SBINTVEC_ENET0 :
+				   SBINTVEC_ENET1));
+	}
+
+	ssb_core_reset(bp);
+
+	b44_clear_stats(bp);
+
+	/* Make PHY accessible. */
+	bw32(B44_MDIO_CTRL, (MDIO_CTRL_PREAMBLE |
+			     (0x0d & MDIO_CTRL_MAXF_MASK)));
+	br32(B44_MDIO_CTRL);
+
+	if (!(br32(B44_DEVCTRL) & DEVCTRL_IPP)) {
+		bw32(B44_ENET_CTRL, ENET_CTRL_EPSEL);
+		br32(B44_ENET_CTRL);
+		bp->flags &= ~B44_FLAG_INTERNAL_PHY;
+	} else {
+		u32 val = br32(B44_DEVCTRL);
+
+		if (val & DEVCTRL_EPR) {
+			bw32(B44_DEVCTRL, (val & ~DEVCTRL_EPR));
+			br32(B44_DEVCTRL);
+			udelay(100);
+		}
+		bp->flags |= B44_FLAG_INTERNAL_PHY;
+	}
+}
+
+/* bp->lock is held. */
+static void b44_halt(struct b44 *bp)
+{
+	b44_disable_ints(bp);
+	b44_chip_reset(bp);
+}
+
+/* bp->lock is held. */
+static void __b44_set_mac_addr(struct b44 *bp)
+{
+	bw32(B44_CAM_CTRL, 0);
+	if (!(bp->dev->flags & IFF_PROMISC)) {
+		u32 val;
+
+		__b44_cam_write(bp, bp->dev->dev_addr, 0);
+		val = br32(B44_CAM_CTRL);
+		bw32(B44_CAM_CTRL, val | CAM_CTRL_ENABLE);
+	}
+}
+
+static int b44_set_mac_addr(struct net_device *dev, void *p)
+{
+	struct b44 *bp = dev->priv;
+	struct sockaddr *addr = p;
+
+	if (netif_running(dev))
+		return -EBUSY;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+	spin_lock_irq(&bp->lock);
+	__b44_set_mac_addr(bp);
+	spin_unlock_irq(&bp->lock);
+
+	return 0;
+}
+
+/* Called at device open time to get the chip ready for
+ * packet processing.  Invoked with bp->lock held.
+ */
+static void __b44_set_rx_mode(struct net_device *);
+static int b44_init_hw(struct b44 *bp)
+{
+	u32 val;
+
+	b44_disable_ints(bp);
+	b44_chip_reset(bp);
+	b44_phy_reset(bp);
+	b44_setup_phy(bp);
+	val = br32(B44_MAC_CTRL);
+	bw32(B44_MAC_CTRL, val | MAC_CTRL_CRC32_ENAB);
+	bw32(B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT));
+
+	/* This sets the MAC address too.  */
+	__b44_set_rx_mode(bp->dev);
+
+	/* MTU + eth header + possible VLAN tag + struct rx_header */
+	bw32(B44_RXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + 24);
+	bw32(B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + 24);
+
+	bw32(B44_TX_WMARK, 56); /* XXX magic */
+	bw32(B44_DMATX_CTRL, DMATX_CTRL_ENABLE);
+	bw32(B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset);
+	bw32(B44_DMARX_CTRL, (DMARX_CTRL_ENABLE |
+			      (bp->rx_offset << DMARX_CTRL_ROSHIFT)));
+	bw32(B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset);
+
+	bw32(B44_DMARX_PTR, bp->rx_pending);
+
+	bw32(B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ);
+
+	val = br32(B44_ENET_CTRL);
+	bw32(B44_ENET_CTRL, (val | ENET_CTRL_ENABLE));
+
+	return 0;
+}
+
+static int b44_open(struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+	int err;
+
+	err = b44_alloc_consistent(bp);
+	if (err)
+		return err;
+
+	err = request_irq(dev->irq, b44_interrupt,
+			  SA_SHIRQ, dev->name, dev);
+	if (err) {
+		b44_free_consistent(bp);
+		return err;
+	}
+
+	spin_lock_irq(&bp->lock);
+
+	b44_init_rings(bp);
+	err = b44_init_hw(bp);
+	if (err) {
+		b44_halt(bp);
+		b44_free_rings(bp);
+	} else {
+		bp->flags |= B44_FLAG_INIT_COMPLETE;
+	}
+
+	spin_unlock_irq(&bp->lock);
+
+	if (err) {
+		free_irq(dev->irq, dev);
+		b44_free_consistent(bp);
+		return err;
+	} else {
+		init_timer(&bp->timer);
+		bp->timer.expires = jiffies + HZ;
+		bp->timer.data = (unsigned long) bp;
+		bp->timer.function = b44_timer;
+		add_timer(&bp->timer);
+	}
+
+	spin_lock_irq(&bp->lock);
+
+	b44_enable_ints(bp);
+
+	spin_unlock_irq(&bp->lock);
+
+	return 0;
+}
+
+#if 0
+/*static*/ void b44_dump_state(struct b44 *bp)
+{
+	u32 val32, val32_2, val32_3, val32_4, val32_5;
+	u16 val16;
+
+	pci_read_config_word(bp->pdev, PCI_STATUS, &val16);
+	printk("DEBUG: PCI status [%04x] \n", val16);
+
+}
+#endif
+
+static int b44_close(struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+
+	netif_stop_queue(dev);
+
+	spin_lock_irq(&bp->lock);
+	spin_unlock_irq(&bp->lock);
+
+	free_irq(dev->irq, dev);
+
+	b44_free_consistent(bp);
+
+	return 0;
+}
+
+static struct net_device_stats *b44_get_stats(struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+	struct net_device_stats *nstat = &bp->stats;
+	struct b44_hw_stats *hwstat = &bp->hw_stats;
+
+	/* Convert HW stats into netdevice stats. */
+	nstat->rx_packets = hwstat->rx_pkts;
+	nstat->tx_packets = hwstat->tx_pkts;
+	nstat->rx_bytes   = hwstat->rx_octets;
+	nstat->tx_bytes   = hwstat->tx_octets;
+	nstat->tx_errors  = (hwstat->tx_jabber_pkts +
+			     hwstat->tx_oversize_pkts +
+			     hwstat->tx_underruns +
+			     hwstat->tx_excessive_cols +
+			     hwstat->tx_late_cols);
+	nstat->multicast  = hwstat->tx_multicast_pkts;
+	nstat->collisions = hwstat->tx_total_cols;
+
+	nstat->rx_length_errors = (hwstat->rx_oversize_pkts +
+				   hwstat->rx_undersize);
+	nstat->rx_over_errors   = hwstat->rx_missed_pkts;
+	nstat->rx_frame_errors  = hwstat->rx_align_errs;
+	nstat->rx_crc_errors    = hwstat->rx_crc_errs;
+	nstat->rx_errors        = (hwstat->rx_jabber_pkts +
+				   hwstat->rx_oversize_pkts +
+				   hwstat->rx_missed_pkts +
+				   hwstat->rx_crc_align_errs +
+				   hwstat->rx_undersize +
+				   hwstat->rx_crc_errs +
+				   hwstat->rx_align_errs +
+				   hwstat->rx_symbol_errs);
+
+	nstat->tx_aborted_errors = hwstat->tx_underruns;
+	nstat->tx_carrier_errors = hwstat->tx_carrier_lost;
+
+	return nstat;
+}
+
+static void __b44_load_mcast(struct b44 *bp, struct net_device *dev)
+{
+	struct dev_mc_list *mclist;
+	int i, num_ents;
+
+	num_ents = min_t(int, dev->mc_count, B44_MCAST_TABLE_SIZE);
+	mclist = dev->mc_list;
+	for (i = 0; mclist && i < num_ents; i++, mclist = mclist->next) {
+		__b44_cam_write(bp, mclist->dmi_addr, i + 1);
+	}
+}
+
+static void __b44_set_rx_mode(struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+	u32 val;
+
+	val = br32(B44_RXCONFIG);
+	val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI);
+	if (dev->flags & IFF_PROMISC) {
+		val |= RXCONFIG_PROMISC;
+		bw32(B44_RXCONFIG, val);
+	} else {
+		__b44_set_mac_addr(bp);
+
+		if (dev->flags & IFF_ALLMULTI)
+			val |= RXCONFIG_ALLMULTI;
+		else
+			__b44_load_mcast(bp, dev);
+
+		bw32(B44_RXCONFIG, val);
+	}
+}
+
+static void b44_set_rx_mode(struct net_device *dev)
+{
+	struct b44 *bp = dev->priv;
+
+	spin_lock_irq(&bp->lock);
+	__b44_set_rx_mode(dev);
+	spin_unlock_irq(&bp->lock);
+}
+
+static int b44_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	struct b44 *bp = dev->priv;
+	struct pci_dev *pci_dev = bp->pdev;
+	u32 ethcmd;
+
+	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO:{
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_MODULE_NAME);
+		strcpy (info.version, DRV_MODULE_VERSION);
+		memset(&info.fw_version, 0, sizeof(info.fw_version));
+		strcpy (info.bus_info, pci_dev->slot_name);
+		info.eedump_len = 0;
+		info.regdump_len = 0;
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+	case ETHTOOL_GSET: {
+		struct ethtool_cmd cmd = { ETHTOOL_GSET };
+
+		if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
+			return -EAGAIN;
+		cmd.supported = (SUPPORTED_Autoneg);
+		cmd.supported |= (SUPPORTED_100baseT_Half |
+				  SUPPORTED_100baseT_Full |
+				  SUPPORTED_10baseT_Half |
+				  SUPPORTED_10baseT_Full |
+				  SUPPORTED_MII);
+
+		cmd.advertising = 0;
+		if (bp->flags & B44_FLAG_ADV_10HALF)
+			cmd.advertising |= ADVERTISE_10HALF;
+		if (bp->flags & B44_FLAG_ADV_10FULL)
+			cmd.advertising |= ADVERTISE_10FULL;
+		if (bp->flags & B44_FLAG_ADV_100HALF)
+			cmd.advertising |= ADVERTISE_100HALF;
+		if (bp->flags & B44_FLAG_ADV_100FULL)
+			cmd.advertising |= ADVERTISE_100FULL;
+		cmd.advertising |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+		cmd.speed = (bp->flags & B44_FLAG_100_BASE_T) ?
+			SPEED_100 : SPEED_10;
+		cmd.duplex = (bp->flags & B44_FLAG_FULL_DUPLEX) ?
+			DUPLEX_FULL : DUPLEX_HALF;
+		cmd.port = 0;
+		cmd.phy_address = bp->phy_addr;
+		cmd.transceiver = (bp->flags & B44_FLAG_INTERNAL_PHY) ?
+			XCVR_INTERNAL : XCVR_EXTERNAL;
+		cmd.autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ?
+			AUTONEG_DISABLE : AUTONEG_ENABLE;
+		cmd.maxtxpkt = 0;
+		cmd.maxrxpkt = 0;
+		if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SSET: {
+		struct ethtool_cmd cmd;
+
+		if (!(bp->flags & B44_FLAG_INIT_COMPLETE))
+			return -EAGAIN;
+
+		if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+			return -EFAULT;
+
+		/* We do not support gigabit. */
+		if (cmd.autoneg == AUTONEG_ENABLE) {
+			if (cmd.advertising &
+			    (ADVERTISED_1000baseT_Half |
+			     ADVERTISED_1000baseT_Full))
+				return -EINVAL;
+		} else if ((cmd.speed != SPEED_100 &&
+			    cmd.speed != SPEED_10) ||
+			   (cmd.duplex != DUPLEX_HALF &&
+			    cmd.duplex != DUPLEX_FULL)) {
+				return -EINVAL;
+		}
+
+		spin_lock_irq(&bp->lock);
+
+		if (cmd.autoneg == AUTONEG_ENABLE) {
+			bp->flags &= ~B44_FLAG_FORCE_LINK;
+			bp->flags &= ~(B44_FLAG_ADV_10HALF |
+				       B44_FLAG_ADV_10FULL |
+				       B44_FLAG_ADV_100HALF |
+				       B44_FLAG_ADV_100FULL);
+			if (cmd.advertising & ADVERTISE_10HALF)
+				bp->flags |= B44_FLAG_ADV_10HALF;
+			if (cmd.advertising & ADVERTISE_10FULL)
+				bp->flags |= B44_FLAG_ADV_10FULL;
+			if (cmd.advertising & ADVERTISE_100HALF)
+				bp->flags |= B44_FLAG_ADV_100HALF;
+			if (cmd.advertising & ADVERTISE_100FULL)
+				bp->flags |= B44_FLAG_ADV_100FULL;
+		} else {
+			bp->flags |= B44_FLAG_FORCE_LINK;
+			if (cmd.speed == SPEED_100)
+				bp->flags |= B44_FLAG_100_BASE_T;
+			if (cmd.duplex == DUPLEX_FULL)
+				bp->flags |= B44_FLAG_FULL_DUPLEX;
+		}
+
+		b44_setup_phy(bp);
+
+		spin_unlock_irq(&bp->lock);
+
+		return 0;
+	}
+
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = { ETHTOOL_GMSGLVL };
+		edata.data = bp->msg_enable;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		bp->msg_enable = edata.data;
+		return 0;
+	}
+	case ETHTOOL_NWAY_RST: {
+		u32 bmcr;
+		int r;
+
+		spin_lock_irq(&bp->lock);
+		b44_readphy(bp, MII_BMCR, &bmcr);
+		b44_readphy(bp, MII_BMCR, &bmcr);
+		r = -EINVAL;
+		if (bmcr & BMCR_ANENABLE) {
+			b44_writephy(bp, MII_BMCR,
+				     bmcr | BMCR_ANRESTART);
+			r = 0;
+		}
+		spin_unlock_irq(&bp->lock);
+
+		return r;
+	}
+	case ETHTOOL_GLINK: {
+		struct ethtool_value edata = { ETHTOOL_GLINK };
+		edata.data = netif_carrier_ok(bp->dev) ? 1 : 0;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_GRINGPARAM: {
+		struct ethtool_ringparam ering = { ETHTOOL_GRINGPARAM };
+
+		ering.rx_max_pending = B44_RX_RING_SIZE - 1;
+		ering.rx_pending = bp->rx_pending;
+
+		/* XXX ethtool lacks a tx_max_pending, oops... */
+
+		if (copy_to_user(useraddr, &ering, sizeof(ering)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SRINGPARAM: {
+		struct ethtool_ringparam ering;
+
+		if (copy_from_user(&ering, useraddr, sizeof(ering)))
+			return -EFAULT;
+
+		if ((ering.rx_pending > B44_RX_RING_SIZE - 1) ||
+		    (ering.rx_mini_pending != 0) ||
+		    (ering.rx_jumbo_pending != 0) ||
+		    (ering.tx_pending > B44_TX_RING_SIZE - 1))
+			return -EINVAL;
+
+		spin_lock_irq(&bp->lock);
+
+		bp->rx_pending = ering.rx_pending;
+		bp->tx_pending = ering.tx_pending;
+
+		b44_halt(bp);
+		b44_init_rings(bp);
+		b44_init_hw(bp);
+		netif_wake_queue(bp->dev);
+		spin_unlock_irq(&bp->lock);
+
+		return 0;
+	}
+	case ETHTOOL_GPAUSEPARAM: {
+		struct ethtool_pauseparam epause = { ETHTOOL_GPAUSEPARAM };
+
+		epause.autoneg =
+			(bp->flags & B44_FLAG_PAUSE_AUTO) != 0;
+		epause.rx_pause =
+			(bp->flags & B44_FLAG_RX_PAUSE) != 0;
+		epause.tx_pause =
+			(bp->flags & B44_FLAG_TX_PAUSE) != 0;
+		if (copy_to_user(useraddr, &epause, sizeof(epause)))
+			return -EFAULT;
+		return 0;
+	}
+	case ETHTOOL_SPAUSEPARAM: {
+		struct ethtool_pauseparam epause;
+
+		if (copy_from_user(&epause, useraddr, sizeof(epause)))
+			return -EFAULT;
+
+		spin_lock_irq(&bp->lock);
+		if (epause.autoneg)
+			bp->flags |= B44_FLAG_PAUSE_AUTO;
+		else
+			bp->flags &= ~B44_FLAG_PAUSE_AUTO;
+		if (epause.rx_pause)
+			bp->flags |= B44_FLAG_RX_PAUSE;
+		else
+			bp->flags &= ~B44_FLAG_RX_PAUSE;
+		if (epause.tx_pause)
+			bp->flags |= B44_FLAG_TX_PAUSE;
+		else
+			bp->flags &= ~B44_FLAG_TX_PAUSE;
+		if (bp->flags & B44_FLAG_PAUSE_AUTO) {
+			b44_halt(bp);
+			b44_init_rings(bp);
+			b44_init_hw(bp);
+		} else {
+			__b44_set_flow_ctrl(bp, bp->flags);
+		}
+		spin_unlock_irq(&bp->lock);
+
+		return 0;
+	}
+	};
+
+	return -EOPNOTSUPP;
+}
+
+static int b44_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+	struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data;
+	struct b44 *bp = dev->priv;
+	int err;
+
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return b44_ethtool_ioctl(dev, (void *) ifr->ifr_data);
+
+	case SIOCGMIIPHY:
+		data->phy_id = bp->phy_addr;
+
+		/* fallthru */
+	case SIOCGMIIREG: {
+		u32 mii_regval;
+
+		spin_lock_irq(&bp->lock);
+		err = b44_readphy(bp, data->reg_num & 0x1f, &mii_regval);
+		spin_unlock_irq(&bp->lock);
+
+		data->val_out = mii_regval;
+
+		return err;
+	}
+
+	case SIOCSMIIREG:
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+
+		spin_lock_irq(&bp->lock);
+		err = b44_writephy(bp, data->reg_num & 0x1f, data->val_in);
+		spin_unlock_irq(&bp->lock);
+
+		return err;
+
+	default:
+		/* do nothing */
+		break;
+	};
+	return -EOPNOTSUPP;
+}
+
+/* Read 128-bytes of EEPROM. */
+static int b44_read_eeprom(struct b44 *bp, u8 *data)
+{
+	long i;
+	u16 *ptr = (u16 *) data;
+
+	for (i = 0; i < 128; i += 2)
+		ptr[i / 2] = readw(bp->regs + 4096 + i);
+
+	return 0;
+}
+
+static int __devinit b44_get_invariants(struct b44 *bp)
+{
+	u8 eeprom[128];
+	int err;
+
+	err = b44_read_eeprom(bp, &eeprom[0]);
+	if (err)
+		goto out;
+
+	bp->dev->dev_addr[0] = eeprom[79];
+	bp->dev->dev_addr[1] = eeprom[78];
+	bp->dev->dev_addr[2] = eeprom[81];
+	bp->dev->dev_addr[3] = eeprom[80];
+	bp->dev->dev_addr[4] = eeprom[83];
+	bp->dev->dev_addr[5] = eeprom[82];
+
+	bp->phy_addr = eeprom[90] & 0x1f;
+	bp->mdc_port = (eeprom[90] >> 14) & 0x1;
+
+	/* With this, plus the rx_header prepended to the data by the
+	 * hardware, we'll land the ethernet header on a 2-byte boundary.
+	 */
+	bp->rx_offset = 30;
+
+	bp->imask = IMASK_DEF;
+
+	bp->core_unit = ssb_core_unit(bp);
+	bp->dma_offset = ssb_get_addr(bp, SBID_PCI_DMA, 0);
+
+	bp->flags |= B44_FLAG_BUGGY_TXPTR;
+
+out:
+	return err;
+}
+
+static int __devinit b44_init_one(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
+{
+	static int b44_version_printed = 0;
+	unsigned long b44reg_base, b44reg_len;
+	struct net_device *dev;
+	struct b44 *bp;
+	int err, i;
+
+	if (b44_version_printed++ == 0)
+		printk(KERN_INFO "%s", version);
+
+	err = pci_enable_device(pdev);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot enable PCI device, "
+		       "aborting.\n");
+		return err;
+	}
+
+	if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+		printk(KERN_ERR PFX "Cannot find proper PCI device "
+		       "base address, aborting.\n");
+		err = -ENODEV;
+		goto err_out_disable_pdev;
+	}
+
+	err = pci_request_regions(pdev, DRV_MODULE_NAME);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot obtain PCI resources, "
+		       "aborting.\n");
+		goto err_out_disable_pdev;
+	}
+
+	pci_set_master(pdev);
+
+	err = pci_set_dma_mask(pdev, (u64) 0xffffffff);
+	if (err) {
+		printk(KERN_ERR PFX "No usable DMA configuration, "
+		       "aborting.\n");
+		goto err_out_free_res;
+	}
+
+	b44reg_base = pci_resource_start(pdev, 0);
+	b44reg_len = pci_resource_len(pdev, 0);
+
+	dev = alloc_etherdev(sizeof(*bp));
+	if (!dev) {
+		printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
+		err = -ENOMEM;
+		goto err_out_free_res;
+	}
+
+	SET_MODULE_OWNER(dev);
+
+	/* No interesting netdevice features in this card... */
+	dev->features |= 0;
+
+	bp = dev->priv;
+	bp->pdev = pdev;
+	bp->dev = dev;
+	if (b44_debug > 0)
+		bp->msg_enable = b44_debug;
+	else
+		bp->msg_enable = B44_DEF_MSG_ENABLE;
+
+	spin_lock_init(&bp->lock);
+
+	bp->regs = (unsigned long) ioremap(b44reg_base, b44reg_len);
+	if (bp->regs == 0UL) {
+		printk(KERN_ERR PFX "Cannot map device registers, "
+		       "aborting.\n");
+		err = -ENOMEM;
+		goto err_out_free_dev;
+	}
+
+	bp->rx_pending = B44_DEF_RX_RING_PENDING;
+	bp->tx_pending = B44_DEF_TX_RING_PENDING;
+
+	dev->open = b44_open;
+	dev->stop = b44_close;
+	dev->hard_start_xmit = b44_start_xmit;
+	dev->get_stats = b44_get_stats;
+	dev->set_multicast_list = b44_set_rx_mode;
+	dev->set_mac_address = b44_set_mac_addr;
+	dev->do_ioctl = b44_ioctl;
+	dev->tx_timeout = b44_tx_timeout;
+	dev->poll = b44_poll;
+	dev->weight = 64;
+	dev->watchdog_timeo = B44_TX_TIMEOUT;
+	dev->change_mtu = b44_change_mtu;
+	dev->irq = pdev->irq;
+
+	err = b44_get_invariants(bp);
+	if (err) {
+		printk(KERN_ERR PFX "Problem fetching invariants of chip, "
+		       "aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	/* By default, advertise all speed/duplex settings. */
+	bp->flags |= (B44_FLAG_ADV_10HALF | B44_FLAG_ADV_10FULL |
+		      B44_FLAG_ADV_100HALF | B44_FLAG_ADV_100FULL);
+
+	/* By default, auto-negotiate PAUSE. */
+	bp->flags |= B44_FLAG_PAUSE_AUTO;
+
+	err = register_netdev(dev);
+	if (err) {
+		printk(KERN_ERR PFX "Cannot register net device, "
+		       "aborting.\n");
+		goto err_out_iounmap;
+	}
+
+	pci_set_drvdata(pdev, dev);
+
+	pci_save_state(bp->pdev, bp->pci_cfg_state);
+
+	printk(KERN_INFO "%s: Broadcom 4400 10/100BaseT Ethernet ", dev->name);
+	for (i = 0; i < 6; i++)
+		printk("%2.2x%c", dev->dev_addr[i],
+		       i == 5 ? '\n' : ':');
+
+	return 0;
+
+err_out_iounmap:
+	iounmap((void *) bp->regs);
+
+err_out_free_dev:
+	kfree(dev);
+
+err_out_free_res:
+	pci_release_regions(pdev);
+
+err_out_disable_pdev:
+	pci_disable_device(pdev);
+	pci_set_drvdata(pdev, NULL);
+	return err;
+}
+
+static void __devexit b44_remove_one(struct pci_dev *pdev)
+{
+	struct net_device *dev = pci_get_drvdata(pdev);
+
+	if (dev) {
+		unregister_netdev(dev);
+		iounmap((void *) ((struct b44 *)(dev->priv))->regs);
+		kfree(dev);
+		pci_release_regions(pdev);
+		pci_disable_device(pdev);
+		pci_set_drvdata(pdev, NULL);
+	}
+}
+
+static struct pci_driver b44_driver = {
+	.name		= DRV_MODULE_NAME,
+	.id_table	= b44_pci_tbl,
+	.probe		= b44_init_one,
+	.remove		= __devexit_p(b44_remove_one),
+#if 0
+	.suspend	= b44_suspend,
+	.resume		= b44_resume
+#endif
+};
+
+static int __init b44_init(void)
+{
+	return pci_module_init(&b44_driver);
+}
+
+static void __exit b44_cleanup(void)
+{
+	pci_unregister_driver(&b44_driver);
+}
+
+module_init(b44_init);
+module_exit(b44_cleanup);
diff -Nru a/drivers/net/b44.h b/drivers/net/b44.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/b44.h	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,543 @@
+#ifndef _B44_H
+#define _B44_H
+
+/* Register layout. */
+#define	B44_DEVCTRL	0x0000UL /* Device Control */
+#define  DEVCTRL_PFE		0x00000080 /* Pattern Filtering Enable */
+#define  DEVCTRL_IPP		0x00000400 /* Internal EPHY Present */
+#define  DEVCTRL_EPR		0x00008000 /* EPHY Reset */
+#define  DEVCTRL_PME		0x00001000 /* PHY Mode Enable */
+#define  DEVCTRL_PMCE		0x00002000 /* PHY Mode Clocks Enable */
+#define  DEVCTRL_PADDR		0x0007c000 /* PHY Address */
+#define  DEVCTRL_PADDR_SHIFT	18
+#define B44_BIST_STAT	0x000CUL /* Built-In Self-Test Status */
+#define B44_WKUP_LEN	0x0010UL /* Wakeup Length */
+#define  WKUP_LEN_P0_MASK	0x0000007f /* Pattern 0 */
+#define  WKUP_LEN_D0		0x00000080
+#define  WKUP_LEN_P1_MASK	0x00007f00 /* Pattern 1 */
+#define  WKUP_LEN_P1_SHIFT	8
+#define  WKUP_LEN_D1		0x00008000
+#define  WKUP_LEN_P2_MASK	0x007f0000 /* Pattern 2 */
+#define  WKUP_LEN_P2_SHIFT	16
+#define  WKUP_LEN_D2		0x00000000
+#define  WKUP_LEN_P3_MASK	0x7f000000 /* Pattern 3 */
+#define  WKUP_LEN_P3_SHIFT	24
+#define  WKUP_LEN_D3		0x80000000
+#define B44_ISTAT	0x0020UL /* Interrupt Status */
+#define  ISTAT_PME		0x00000040 /* Power Management Event */
+#define  ISTAT_TO		0x00000080 /* General Purpose Timeout */
+#define  ISTAT_DSCE		0x00000400 /* Descriptor Error */
+#define  ISTAT_DATAE		0x00000800 /* Data Error */
+#define  ISTAT_DPE		0x00001000 /* Descr. Protocol Error */
+#define  ISTAT_RDU		0x00002000 /* Receive Descr. Underflow */
+#define  ISTAT_RFO		0x00004000 /* Receive FIFO Overflow */
+#define  ISTAT_TFU		0x00008000 /* Transmit FIFO Underflow */
+#define  ISTAT_RX		0x00010000 /* RX Interrupt */
+#define  ISTAT_TX		0x01000000 /* TX Interrupt */
+#define  ISTAT_EMAC		0x04000000 /* EMAC Interrupt */
+#define  ISTAT_MII_WRITE	0x08000000 /* MII Write Interrupt */
+#define  ISTAT_MII_READ		0x10000000 /* MII Read Interrupt */
+#define  ISTAT_ERRORS (ISTAT_DSCE|ISTAT_DATAE|ISTAT_DPE|ISTAT_RDU|ISTAT_RFO|ISTAT_TFU)
+#define B44_IMASK	0x0024UL /* Interrupt Mask */
+#define  IMASK_DEF		(ISTAT_ERRORS | ISTAT_TO | ISTAT_RX | ISTAT_TX)
+#define B44_GPTIMER	0x0028UL /* General Purpose Timer */
+#define B44_FILT_ADDR	0x0090UL /* ENET Filter Address */
+#define B44_FILT_DATA	0x0094UL /* ENET Filter Data */
+#define B44_TXBURST	0x00A0UL /* TX Max Burst Length */
+#define B44_RXBURST	0x00A4UL /* RX Max Burst Length */
+#define B44_MAC_CTRL	0x00A8UL /* MAC Control */
+#define  MAC_CTRL_CRC32_ENAB	0x00000001 /* CRC32 Generation Enable */
+#define  MAC_CTRL_PHY_PDOWN	0x00000004 /* Onchip EPHY Powerdown */
+#define  MAC_CTRL_PHY_EDET	0x00000008 /* Onchip EPHY Energy Detected */
+#define  MAC_CTRL_PHY_LEDCTRL	0x000000e0 /* Onchip EPHY LED Control */
+#define  MAC_CTRL_PHY_LEDCTRL_SHIFT 5
+#define B44_MAC_FLOW	0x00ACUL /* MAC Flow Control */
+#define  MAC_FLOW_RX_HI_WATER	0x000000ff /* Receive FIFO HI Water Mark */
+#define  MAC_FLOW_PAUSE_ENAB	0x00008000 /* Enable Pause Frame Generation */
+#define B44_RCV_LAZY	0x0100UL /* Lazy Interrupt Control */
+#define  RCV_LAZY_TO_MASK	0x00ffffff /* Timeout */
+#define  RCV_LAZY_FC_MASK	0xff000000 /* Frame Count */
+#define  RCV_LAZY_FC_SHIFT	24
+#define B44_DMATX_CTRL	0x0200UL /* DMA TX Control */
+#define  DMATX_CTRL_ENABLE	0x00000001 /* Enable */
+#define  DMATX_CTRL_SUSPEND	0x00000002 /* Suepend Request */
+#define  DMATX_CTRL_LPBACK	0x00000004 /* Loopback Enable */
+#define  DMATX_CTRL_FAIRPRIOR	0x00000008 /* Fair Priority */
+#define  DMATX_CTRL_FLUSH	0x00000010 /* Flush Request */
+#define B44_DMATX_ADDR	0x0204UL /* DMA TX Descriptor Ring Address */
+#define B44_DMATX_PTR	0x0208UL /* DMA TX Last Posted Descriptor */
+#define B44_DMATX_STAT	0x020CUL /* DMA TX Current Active Desc. + Status */
+#define  DMATX_STAT_CDMASK	0x00000fff /* Current Descriptor Mask */
+#define  DMATX_STAT_SMASK	0x0000f000 /* State Mask */
+#define  DMATX_STAT_SDISABLED	0x00000000 /* State Disabled */
+#define  DMATX_STAT_SACTIVE	0x00001000 /* State Active */
+#define  DMATX_STAT_SIDLE	0x00002000 /* State Idle Wait */
+#define  DMATX_STAT_SSTOPPED	0x00003000 /* State Stopped */
+#define  DMATX_STAT_SSUSP	0x00004000 /* State Suspend Pending */
+#define  DMATX_STAT_EMASK	0x000f0000 /* Error Mask */
+#define  DMATX_STAT_ENONE	0x00000000 /* Error None */
+#define  DMATX_STAT_EDPE	0x00010000 /* Error Desc. Protocol Error */
+#define  DMATX_STAT_EDFU	0x00020000 /* Error Data FIFO Underrun */
+#define  DMATX_STAT_EBEBR	0x00030000 /* Error Bus Error on Buffer Read */
+#define  DMATX_STAT_EBEDA	0x00040000 /* Error Bus Error on Desc. Access */
+#define  DMATX_STAT_FLUSHED	0x00100000 /* Flushed */
+#define B44_DMARX_CTRL	0x0210UL /* DMA RX Control */
+#define  DMARX_CTRL_ENABLE	0x00000001 /* Enable */
+#define  DMARX_CTRL_ROMASK	0x000000fe /* Receive Offset Mask */
+#define  DMARX_CTRL_ROSHIFT	1 	   /* Receive Offset Shift */
+#define B44_DMARX_ADDR	0x0214UL /* DMA RX Descriptor Ring Address */
+#define B44_DMARX_PTR	0x0218UL /* DMA RX Last Posted Descriptor */
+#define B44_DMARX_STAT	0x021CUL /* DMA RX Current Active Desc. + Status */
+#define  DMARX_STAT_CDMASK	0x00000fff /* Current Descriptor Mask */
+#define  DMARX_STAT_SMASK	0x0000f000 /* State Mask */
+#define  DMARX_STAT_SDISABLED	0x00000000 /* State Disbaled */
+#define  DMARX_STAT_SACTIVE	0x00001000 /* State Active */
+#define  DMARX_STAT_SIDLE	0x00002000 /* State Idle Wait */
+#define  DMARX_STAT_SSTOPPED	0x00003000 /* State Stopped */
+#define  DMARX_STAT_EMASK	0x000f0000 /* Error Mask */
+#define  DMARX_STAT_ENONE	0x00000000 /* Error None */
+#define  DMARX_STAT_EDPE	0x00010000 /* Error Desc. Protocol Error */
+#define  DMARX_STAT_EDFO	0x00020000 /* Error Data FIFO Overflow */
+#define  DMARX_STAT_EBEBW	0x00030000 /* Error Bus Error on Buffer Write */
+#define  DMARX_STAT_EBEDA	0x00040000 /* Error Bus Error on Desc. Access */
+#define B44_DMAFIFO_AD	0x0220UL /* DMA FIFO Diag Address */
+#define  DMAFIFO_AD_OMASK	0x0000ffff /* Offset Mask */
+#define  DMAFIFO_AD_SMASK	0x000f0000 /* Select Mask */
+#define  DMAFIFO_AD_SXDD	0x00000000 /* Select Transmit DMA Data */
+#define  DMAFIFO_AD_SXDP	0x00010000 /* Select Transmit DMA Pointers */
+#define  DMAFIFO_AD_SRDD	0x00040000 /* Select Receive DMA Data */
+#define  DMAFIFO_AD_SRDP	0x00050000 /* Select Receive DMA Pointers */
+#define  DMAFIFO_AD_SXFD	0x00080000 /* Select Transmit FIFO Data */
+#define  DMAFIFO_AD_SXFP	0x00090000 /* Select Transmit FIFO Pointers */
+#define  DMAFIFO_AD_SRFD	0x000c0000 /* Select Receive FIFO Data */
+#define  DMAFIFO_AD_SRFP	0x000c0000 /* Select Receive FIFO Pointers */
+#define B44_DMAFIFO_LO	0x0224UL /* DMA FIFO Diag Low Data */
+#define B44_DMAFIFO_HI	0x0228UL /* DMA FIFO Diag High Data */
+#define B44_RXCONFIG	0x0400UL /* EMAC RX Config */
+#define  RXCONFIG_DBCAST	0x00000001 /* Disable Broadcast */
+#define  RXCONFIG_ALLMULTI	0x00000002 /* Accept All Multicast */
+#define  RXCONFIG_NORX_WHILE_TX	0x00000004 /* Receive Disable While Transmitting */
+#define  RXCONFIG_PROMISC	0x00000008 /* Promiscuous Enable */
+#define  RXCONFIG_LPBACK	0x00000010 /* Loopback Enable */
+#define  RXCONFIG_FLOW		0x00000020 /* Flow Control Enable */
+#define  RXCONFIG_FLOW_ACCEPT	0x00000040 /* Accept Unicast Flow Control Frame */
+#define  RXCONFIG_RFILT		0x00000080 /* Reject Filter */
+#define B44_RXMAXLEN	0x0404UL /* EMAC RX Max Packet Length */
+#define B44_TXMAXLEN	0x0408UL /* EMAC TX Max Packet Length */
+#define B44_MDIO_CTRL	0x0410UL /* EMAC MDIO Control */
+#define  MDIO_CTRL_MAXF_MASK	0x0000007f /* MDC Frequency */
+#define  MDIO_CTRL_PREAMBLE	0x00000080 /* MII Preamble Enable */
+#define B44_MDIO_DATA	0x0414UL /* EMAC MDIO Data */
+#define  MDIO_DATA_DATA		0x0000ffff /* R/W Data */
+#define  MDIO_DATA_TA_MASK	0x00030000 /* Turnaround Value */
+#define  MDIO_DATA_TA_SHIFT	16
+#define  MDIO_TA_VALID		2
+#define  MDIO_DATA_RA_MASK	0x007c0000 /* Register Address */
+#define  MDIO_DATA_RA_SHIFT	18
+#define  MDIO_DATA_PMD_MASK	0x0f800000 /* Physical Media Device */
+#define  MDIO_DATA_PMD_SHIFT	23
+#define  MDIO_DATA_OP_MASK	0x30000000 /* Opcode */
+#define  MDIO_DATA_OP_SHIFT	28
+#define  MDIO_OP_WRITE		1
+#define  MDIO_OP_READ		2
+#define  MDIO_DATA_SB_MASK	0xc0000000 /* Start Bits */
+#define  MDIO_DATA_SB_SHIFT	30
+#define  MDIO_DATA_SB_START	0x10000000 /* Start Of Frame */
+#define B44_EMAC_IMASK	0x0418UL /* EMAC Interrupt Mask */
+#define B44_EMAC_ISTAT	0x041CUL /* EMAC Interrupt Status */
+#define  EMAC_INT_MII		0x00000001 /* MII MDIO Interrupt */
+#define  EMAC_INT_MIB		0x00000002 /* MIB Interrupt */
+#define  EMAC_INT_FLOW		0x00000003 /* Flow Control Interrupt */
+#define B44_CAM_DATA_LO	0x0420UL /* EMAC CAM Data Low */
+#define B44_CAM_DATA_HI	0x0424UL /* EMAC CAM Data High */
+#define  CAM_DATA_HI_VALID	0x00010000 /* Valid Bit */
+#define B44_CAM_CTRL	0x0428UL /* EMAC CAM Control */
+#define  CAM_CTRL_ENABLE	0x00000001 /* CAM Enable */
+#define  CAM_CTRL_MSEL		0x00000002 /* Mask Select */
+#define  CAM_CTRL_READ		0x00000004 /* Read */
+#define  CAM_CTRL_WRITE		0x00000008 /* Read */
+#define  CAM_CTRL_INDEX_MASK	0x003f0000 /* Index Mask */
+#define  CAM_CTRL_INDEX_SHIFT	16
+#define  CAM_CTRL_BUSY		0x80000000 /* CAM Busy */
+#define B44_ENET_CTRL	0x042CUL /* EMAC ENET Control */
+#define  ENET_CTRL_ENABLE	0x00000001 /* EMAC Enable */
+#define  ENET_CTRL_DISABLE	0x00000002 /* EMAC Disable */
+#define  ENET_CTRL_SRST		0x00000004 /* EMAC Soft Reset */
+#define  ENET_CTRL_EPSEL	0x00000008 /* External PHY Select */
+#define B44_TX_CTRL	0x0430UL /* EMAC TX Control */
+#define  TX_CTRL_DUPLEX		0x00000001 /* Full Duplex */
+#define  TX_CTRL_FMODE		0x00000002 /* Flow Mode */
+#define  TX_CTRL_SBENAB		0x00000004 /* Single Backoff Enable */
+#define  TX_CTRL_SMALL_SLOT	0x00000008 /* Small Slottime */
+#define B44_TX_WMARK	0x0434UL /* EMAC TX Watermark */
+#define B44_MIB_CTRL	0x0438UL /* EMAC MIB Control */
+#define  MIB_CTRL_CLR_ON_READ	0x00000001 /* Autoclear on Read */
+#define B44_TX_GOOD_O	0x0500UL /* MIB TX Good Octets */
+#define B44_TX_GOOD_P	0x0504UL /* MIB TX Good Packets */
+#define B44_TX_O	0x0508UL /* MIB TX Octets */
+#define B44_TX_P	0x050CUL /* MIB TX Packets */
+#define B44_TX_BCAST	0x0510UL /* MIB TX Broadcast Packets */
+#define B44_TX_MCAST	0x0514UL /* MIB TX Multicast Packets */
+#define B44_TX_64	0x0518UL /* MIB TX <= 64 byte Packets */
+#define B44_TX_65_127	0x051CUL /* MIB TX 65 to 127 byte Packets */
+#define B44_TX_128_255	0x0520UL /* MIB TX 128 to 255 byte Packets */
+#define B44_TX_256_511	0x0524UL /* MIB TX 256 to 511 byte Packets */
+#define B44_TX_512_1023	0x0528UL /* MIB TX 512 to 1023 byte Packets */
+#define B44_TX_1024_MAX	0x052CUL /* MIB TX 1024 to max byte Packets */
+#define B44_TX_JABBER	0x0530UL /* MIB TX Jabber Packets */
+#define B44_TX_OSIZE	0x0534UL /* MIB TX Oversize Packets */
+#define B44_TX_FRAG	0x0538UL /* MIB TX Fragment Packets */
+#define B44_TX_URUNS	0x053CUL /* MIB TX Underruns */
+#define B44_TX_TCOLS	0x0540UL /* MIB TX Total Collisions */
+#define B44_TX_SCOLS	0x0544UL /* MIB TX Single Collisions */
+#define B44_TX_MCOLS	0x0548UL /* MIB TX Multiple Collisions */
+#define B44_TX_ECOLS	0x054CUL /* MIB TX Excessive Collisions */
+#define B44_TX_LCOLS	0x0550UL /* MIB TX Late Collisions */
+#define B44_TX_DEFERED	0x0554UL /* MIB TX Defered Packets */
+#define B44_TX_CLOST	0x0558UL /* MIB TX Carrier Lost */
+#define B44_TX_PAUSE	0x055CUL /* MIB TX Pause Packets */
+#define B44_RX_GOOD_O	0x0580UL /* MIB RX Good Octets */
+#define B44_RX_GOOD_P	0x0584UL /* MIB RX Good Packets */
+#define B44_RX_O	0x0588UL /* MIB RX Octets */
+#define B44_RX_P	0x058CUL /* MIB RX Packets */
+#define B44_RX_BCAST	0x0590UL /* MIB RX Broadcast Packets */
+#define B44_RX_MCAST	0x0594UL /* MIB RX Multicast Packets */
+#define B44_RX_64	0x0598UL /* MIB RX <= 64 byte Packets */
+#define B44_RX_65_127	0x059CUL /* MIB RX 65 to 127 byte Packets */
+#define B44_RX_128_255	0x05A0UL /* MIB RX 128 to 255 byte Packets */
+#define B44_RX_256_511	0x05A4UL /* MIB RX 256 to 511 byte Packets */
+#define B44_RX_512_1023	0x05A8UL /* MIB RX 512 to 1023 byte Packets */
+#define B44_RX_1024_MAX	0x05ACUL /* MIB RX 1024 to max byte Packets */
+#define B44_RX_JABBER	0x05B0UL /* MIB RX Jabber Packets */
+#define B44_RX_OSIZE	0x05B4UL /* MIB RX Oversize Packets */
+#define B44_RX_FRAG	0x05B8UL /* MIB RX Fragment Packets */
+#define B44_RX_MISS	0x05BCUL /* MIB RX Missed Packets */
+#define B44_RX_CRCA	0x05C0UL /* MIB RX CRC Align Errors */
+#define B44_RX_USIZE	0x05C4UL /* MIB RX Undersize Packets */
+#define B44_RX_CRC	0x05C8UL /* MIB RX CRC Errors */
+#define B44_RX_ALIGN	0x05CCUL /* MIB RX Align Errors */
+#define B44_RX_SYM	0x05D0UL /* MIB RX Symbol Errors */
+#define B44_RX_PAUSE	0x05D4UL /* MIB RX Pause Packets */
+#define B44_RX_NPAUSE	0x05D8UL /* MIB RX Non-Pause Packets */
+#define B44_SBIPSFLAG	0x0F08UL /* SB Initiator Port OCP Slave Flag */
+#define  SBIPSFLAG_IMASK1	0x0000003f /* Which sbflags --> mips interrupt 1 */
+#define  SBIPSFLAG_ISHIFT1	0
+#define  SBIPSFLAG_IMASK2	0x00003f00 /* Which sbflags --> mips interrupt 2 */
+#define  SBIPSFLAG_ISHIFT2	8
+#define  SBIPSFLAG_IMASK3	0x003f0000 /* Which sbflags --> mips interrupt 3 */
+#define  SBIPSFLAG_ISHIFT3	16
+#define  SBIPSFLAG_IMASK4	0x3f000000 /* Which sbflags --> mips interrupt 4 */
+#define  SBIPSFLAG_ISHIFT4	24
+#define B44_SBTPSFLAG	0x0F18UL /* SB Target Port OCP Slave Flag */
+#define  SBTPS_NUM0_MASK	0x0000003f
+#define  SBTPS_F0EN0		0x00000040
+#define B44_SBADMATCH3	0x0F60UL /* SB Address Match 3 */
+#define B44_SBADMATCH2	0x0F68UL /* SB Address Match 2 */
+#define B44_SBADMATCH1	0x0F70UL /* SB Address Match 1 */
+#define B44_SBIMSTATE	0x0F90UL /* SB Initiator Agent State */
+#define  SBIMSTATE_PC		0x0000000f /* Pipe Count */
+#define  SBIMSTATE_AP_MASK	0x00000030 /* Arbitration Priority */
+#define  SBIMSTATE_AP_BOTH	0x00000000 /* Use both timeslices and token */
+#define  SBIMSTATE_AP_TS	0x00000010 /* Use timeslices only */
+#define  SBIMSTATE_AP_TK	0x00000020 /* Use token only */
+#define  SBIMSTATE_AP_RSV	0x00000030 /* Reserved */
+#define  SBIMSTATE_IBE		0x00020000 /* In Band Error */
+#define  SBIMSTATE_TO		0x00040000 /* Timeout */
+#define B44_SBINTVEC	0x0F94UL /* SB Interrupt Mask */
+#define  SBINTVEC_PCI		0x00000001 /* Enable interrupts for PCI */
+#define  SBINTVEC_ENET0		0x00000002 /* Enable interrupts for enet 0 */
+#define  SBINTVEC_ILINE20	0x00000004 /* Enable interrupts for iline20 */
+#define  SBINTVEC_CODEC		0x00000008 /* Enable interrupts for v90 codec */
+#define  SBINTVEC_USB		0x00000010 /* Enable interrupts for usb */
+#define  SBINTVEC_EXTIF		0x00000020 /* Enable interrupts for external i/f */
+#define  SBINTVEC_ENET1		0x00000040 /* Enable interrupts for enet 1 */
+#define B44_SBTMSLOW	0x0F98UL /* SB Target State Low */
+#define  SBTMSLOW_RESET		0x00000001 /* Reset */
+#define  SBTMSLOW_REJECT	0x00000002 /* Reject */
+#define  SBTMSLOW_CLOCK		0x00010000 /* Clock Enable */
+#define  SBTMSLOW_FGC		0x00020000 /* Force Gated Clocks On */
+#define  SBTMSLOW_PE		0x40000000 /* Power Management Enable */
+#define  SBTMSLOW_BE		0x80000000 /* BIST Enable */
+#define B44_SBTMSHIGH	0x0F9CUL /* SB Target State High */
+#define  SBTMSHIGH_SERR		0x00000001 /* S-error */
+#define  SBTMSHIGH_INT		0x00000002 /* Interrupt */
+#define  SBTMSHIGH_BUSY		0x00000004 /* Busy */
+#define  SBTMSHIGH_GCR		0x20000000 /* Gated Clock Request */
+#define  SBTMSHIGH_BISTF	0x40000000 /* BIST Failed */
+#define  SBTMSHIGH_BISTD	0x80000000 /* BIST Done */
+#define B44_SBBWA0	0x0FA0UL /* SB Bandwidth Allocation Table 0 */
+#define  SBBWA0_TAB0_MASK	0x0000ffff /* Lookup Table 0 */
+#define  SBBWA0_TAB0_SHIFT	0
+#define  SBBWA0_TAB1_MASK	0xffff0000 /* Lookup Table 0 */
+#define  SBBWA0_TAB1_SHIFT	16
+#define B44_SBIMCFGLOW	0x0FA8UL /* SB Initiator Configuration Low */
+#define  SBIMCFGLOW_STO_MASK	0x00000003 /* Service Timeout */
+#define  SBIMCFGLOW_RTO_MASK	0x00000030 /* Request Timeout */
+#define  SBIMCFGLOW_RTO_SHIFT	4
+#define  SBIMCFGLOW_CID_MASK	0x00ff0000 /* Connection ID */
+#define  SBIMCFGLOW_CID_SHIFT	16
+#define B44_SBIMCFGHIGH	0x0FACUL /* SB Initiator Configuration High */
+#define  SBIMCFGHIGH_IEM_MASK	0x0000000c /* Inband Error Mode */
+#define  SBIMCFGHIGH_TEM_MASK	0x00000030 /* Timeout Error Mode */
+#define  SBIMCFGHIGH_TEM_SHIFT	4
+#define  SBIMCFGHIGH_BEM_MASK	0x000000c0 /* Bus Error Mode */
+#define  SBIMCFGHIGH_BEM_SHIFT	6
+#define B44_SBADMATCH0	0x0FB0UL /* SB Address Match 0 */
+#define  SBADMATCH0_TYPE_MASK	0x00000003 /* Address Type */
+#define  SBADMATCH0_AD64	0x00000004 /* Reserved */
+#define  SBADMATCH0_AI0_MASK	0x000000f8 /* Type0 Size */
+#define  SBADMATCH0_AI0_SHIFT	3
+#define  SBADMATCH0_AI1_MASK	0x000001f8 /* Type1 Size */
+#define  SBADMATCH0_AI1_SHIFT	3
+#define  SBADMATCH0_AI2_MASK	0x000001f8 /* Type2 Size */
+#define  SBADMATCH0_AI2_SHIFT	3
+#define  SBADMATCH0_ADEN	0x00000400 /* Enable */
+#define  SBADMATCH0_ADNEG	0x00000800 /* Negative Decode */
+#define  SBADMATCH0_BS0_MASK	0xffffff00 /* Type0 Base Address */
+#define  SBADMATCH0_BS0_SHIFT	8
+#define  SBADMATCH0_BS1_MASK	0xfffff000 /* Type1 Base Address */
+#define  SBADMATCH0_BS1_SHIFT	12
+#define  SBADMATCH0_BS2_MASK	0xffff0000 /* Type2 Base Address */
+#define  SBADMATCH0_BS2_SHIFT	16
+#define B44_SBTMCFGLOW	0x0FB8UL /* SB Target Configuration Low */
+#define  SBTMCFGLOW_CD_MASK	0x000000ff /* Clock Divide Mask */
+#define  SBTMCFGLOW_CO_MASK	0x0000f800 /* Clock Offset Mask */
+#define  SBTMCFGLOW_CO_SHIFT	11
+#define  SBTMCFGLOW_IF_MASK	0x00fc0000 /* Interrupt Flags Mask */
+#define  SBTMCFGLOW_IF_SHIFT	18
+#define  SBTMCFGLOW_IM_MASK	0x03000000 /* Interrupt Mode Mask */
+#define  SBTMCFGLOW_IM_SHIFT	24
+#define B44_SBTMCFGHIGH	0x0FBCUL /* SB Target Configuration High */
+#define  SBTMCFGHIGH_BM_MASK	0x00000003 /* Busy Mode */
+#define  SBTMCFGHIGH_RM_MASK	0x0000000C /* Retry Mode */
+#define  SBTMCFGHIGH_RM_SHIFT	2
+#define  SBTMCFGHIGH_SM_MASK	0x00000030 /* Stop Mode */
+#define  SBTMCFGHIGH_SM_SHIFT	4
+#define  SBTMCFGHIGH_EM_MASK	0x00000300 /* Error Mode */
+#define  SBTMCFGHIGH_EM_SHIFT	8
+#define  SBTMCFGHIGH_IM_MASK	0x00000c00 /* Interrupt Mode */
+#define  SBTMCFGHIGH_IM_SHIFT	10
+#define B44_SBBCFG	0x0FC0UL /* SB Broadcast Configuration */
+#define  SBBCFG_LAT_MASK	0x00000003 /* SB Latency */
+#define  SBBCFG_MAX0_MASK	0x000f0000 /* MAX Counter 0 */
+#define  SBBCFG_MAX0_SHIFT	16
+#define  SBBCFG_MAX1_MASK	0x00f00000 /* MAX Counter 1 */
+#define  SBBCFG_MAX1_SHIFT	20
+#define B44_SBBSTATE	0x0FC8UL /* SB Broadcast State */
+#define  SBBSTATE_SRD		0x00000001 /* ST Reg Disable */
+#define  SBBSTATE_HRD		0x00000002 /* Hold Reg Disable */
+#define B44_SBACTCNFG	0x0FD8UL /* SB Activate Configuration */
+#define B44_SBFLAGST	0x0FE8UL /* SB Current SBFLAGS */
+#define B44_SBIDLOW	0x0FF8UL /* SB Identification Low */
+#define  SBIDLOW_CS_MASK	0x00000003 /* Config Space Mask */
+#define  SBIDLOW_AR_MASK	0x00000038 /* Num Address Ranges Supported */
+#define  SBIDLOW_AR_SHIFT	3
+#define  SBIDLOW_SYNCH		0x00000040 /* Sync */
+#define  SBIDLOW_INIT		0x00000080 /* Initiator */
+#define  SBIDLOW_MINLAT_MASK	0x00000f00 /* Minimum Backplane Latency */
+#define  SBIDLOW_MINLAT_SHIFT	8
+#define  SBIDLOW_MAXLAT_MASK	0x0000f000 /* Maximum Backplane Latency */
+#define  SBIDLOW_MAXLAT_SHIFT	12
+#define  SBIDLOW_FIRST		0x00010000 /* This Initiator is First */
+#define  SBIDLOW_CW_MASK	0x000c0000 /* Cycle Counter Width */
+#define  SBIDLOW_CW_SHIFT	18
+#define  SBIDLOW_TP_MASK	0x00f00000 /* Target Ports */
+#define  SBIDLOW_TP_SHIFT	20
+#define  SBIDLOW_IP_MASK	0x0f000000 /* Initiator Ports */
+#define  SBIDLOW_IP_SHIFT	24
+#define B44_SBIDHIGH	0x0FFCUL /* SB Identification High */
+#define  SBIDHIGH_RC_MASK	0x0000000f /* Revision Code */
+#define  SBIDHIGH_CC_MASK	0x0000fff0 /* Core Code */
+#define  SBIDHIGH_CC_SHIFT	4
+#define  SBIDHIGH_VC_MASK	0xffff0000 /* Vendor Code */
+#define  SBIDHIGH_VC_SHIFT	16
+
+#define  CORE_CODE_ILINE20	0x801
+#define  CORE_CODE_SDRAM	0x803
+#define  CORE_CODE_PCI		0x804
+#define  CORE_CODE_MIPS		0x805
+#define  CORE_CODE_ENET		0x806
+#define  CORE_CODE_CODEC	0x807
+#define  CORE_CODE_USB		0x808
+#define  CORE_CODE_ILINE100	0x80a
+#define  CORE_CODE_EXTIF	0x811
+
+/* SSB PCI config space registers.  */
+#define	SSB_BAR0_WIN		0x80
+#define	SSB_BAR1_WIN		0x84
+#define	SSB_SPROM_CONTROL	0x88
+#define	SSB_BAR1_CONTROL	0x8c
+
+/* SSB core and hsot control registers.  */
+#define SSB_CONTROL		0x0000UL
+#define SSB_ARBCONTROL		0x0010UL
+#define SSB_ISTAT		0x0020UL
+#define SSB_IMASK		0x0024UL
+#define SSB_MBOX		0x0028UL
+#define SSB_BCAST_ADDR		0x0050UL
+#define SSB_BCAST_DATA		0x0054UL
+#define SSB_PCI_TRANS_0		0x0100UL
+#define SSB_PCI_TRANS_1		0x0104UL
+#define SSB_PCI_TRANS_2		0x0108UL
+#define SSB_SPROM		0x0800UL
+
+#define SSB_PCI_MEM		0x00000000
+#define SSB_PCI_IO		0x00000001
+#define SSB_PCI_CFG0		0x00000002
+#define SSB_PCI_CFG1		0x00000003
+#define SSB_PCI_PREF		0x00000004
+#define SSB_PCI_BURST		0x00000008
+#define SSB_PCI_MASK0		0xfc000000
+#define SSB_PCI_MASK1		0xfc000000
+#define SSB_PCI_MASK2		0xc0000000
+
+#define br32(REG)	readl(bp->regs + (REG))
+#define bw32(REG,VAL)	writel((VAL), bp->regs + (REG))
+
+/* 4400 PHY registers */
+#define B44_MII_AUXCTRL		24	/* Auxiliary Control */
+#define  MII_AUXCTRL_DUPLEX	0x0001  /* Full Duplex */
+#define  MII_AUXCTRL_SPEED	0x0002  /* 1=100Mbps, 0=10Mbps */
+#define  MII_AUXCTRL_FORCED	0x0004	/* Forced 10/100 */
+#define B44_MII_ALEDCTRL	26	/* Activity LED */
+#define  MII_ALEDCTRL_ALLMSK	0x7fff
+#define B44_MII_TLEDCTRL	27	/* Traffic Meter LED */
+#define  MII_TLEDCTRL_ENABLE	0x0040
+
+/* XXX Add this to mii.h */
+#ifndef ADVERTISE_PAUSE
+#define ADVERTISE_PAUSE_CAP		0x0400
+#endif
+#ifndef ADVERTISE_PAUSE_ASYM
+#define ADVERTISE_PAUSE_ASYM		0x0800
+#endif
+#ifndef LPA_PAUSE
+#define LPA_PAUSE_CAP			0x0400
+#endif
+#ifndef LPA_PAUSE_ASYM
+#define LPA_PAUSE_ASYM			0x0800
+#endif
+
+struct dma_desc {
+	u32	ctrl;
+	u32	addr;
+};
+
+/* There are only 12 bits in the DMA engine for descriptor offsetting
+ * so the table must be aligned on a boundry of this.
+ */
+#define DMA_TABLE_BYTES		4096
+
+#define DESC_CTRL_LEN	0x00001fff
+#define DESC_CTRL_CMASK	0x0ff00000 /* Core specific bits */
+#define DESC_CTRL_EOT	0x10000000 /* End of Table */
+#define DESC_CTRL_IOC	0x20000000 /* Interrupt On Completion */
+#define DESC_CTRL_EOF	0x40000000 /* End of Frame */
+#define DESC_CTRL_SOF	0x80000000 /* Start of Frame */
+
+#define RX_COPY_THRESHOLD  	256
+
+struct rx_header {
+	u16	len;
+	u16	flags;
+	u16	pad[12];
+};
+#define RX_HEADER_LEN	28
+
+#define RX_FLAG_OFIFO	0x00000001 /* FIFO Overflow */
+#define RX_FLAG_CRCERR	0x00000002 /* CRC Error */
+#define RX_FLAG_SERR	0x00000004 /* Receive Symbol Error */
+#define RX_FLAG_ODD	0x00000008 /* Frame has odd number of nibbles */
+#define RX_FLAG_LARGE	0x00000010 /* Frame is > RX MAX Length */
+#define RX_FLAG_MCAST	0x00000020 /* Dest is Multicast Address */
+#define RX_FLAG_BCAST	0x00000040 /* Dest is Broadcast Address */
+#define RX_FLAG_MISS	0x00000080 /* Received due to promisc mode */
+#define RX_FLAG_LAST	0x00000800 /* Last buffer in frame */
+#define RX_FLAG_ERRORS	(RX_FLAG_ODD | RX_FLAG_SERR | RX_FLAG_CRCERR | RX_FLAG_OFIFO)
+
+struct ring_info {
+	struct sk_buff		*skb;
+	DECLARE_PCI_UNMAP_ADDR(mapping);
+};
+
+#define B44_MCAST_TABLE_SIZE	32
+
+/* SW copy of device statistics, kept up to date by periodic timer
+ * which probes HW values.  Must have same relative layout as HW
+ * register above, because b44_stats_update depends upon this.
+ */
+struct b44_hw_stats {
+	u32 tx_good_octets, tx_good_pkts, tx_octets;
+	u32 tx_pkts, tx_broadcast_pkts, tx_multicast_pkts;
+	u32 tx_len_64, tx_len_65_to_127, tx_len_128_to_255;
+	u32 tx_len_256_to_511, tx_len_512_to_1023, tx_len_1024_to_max;
+	u32 tx_jabber_pkts, tx_oversize_pkts, tx_fragment_pkts;
+	u32 tx_underruns, tx_total_cols, tx_single_cols;
+	u32 tx_multiple_cols, tx_excessive_cols, tx_late_cols;
+	u32 tx_defered, tx_carrier_lost, tx_pause_pkts;
+	u32 __pad1[8];
+
+	u32 rx_good_octets, rx_good_pkts, rx_octets;
+	u32 rx_pkts, rx_broadcast_pkts, rx_multicast_pkts;
+	u32 rx_len_64, rx_len_65_to_127, rx_len_128_to_255;
+	u32 rx_len_256_to_511, rx_len_512_to_1023, rx_len_1024_to_max;
+	u32 rx_jabber_pkts, rx_oversize_pkts, rx_fragment_pkts;
+	u32 rx_missed_pkts, rx_crc_align_errs, rx_undersize;
+	u32 rx_crc_errs, rx_align_errs, rx_symbol_errs;
+	u32 rx_pause_pkts, rx_nonpause_pkts;
+};
+
+struct b44 {
+	spinlock_t		lock;
+
+	u32			imask, istat;
+
+	struct dma_desc		*rx_ring, *tx_ring;
+
+	u32			tx_prod, tx_cons;
+	u32			rx_prod, rx_cons;
+
+	struct ring_info	*rx_buffers;
+	struct ring_info	*tx_buffers;
+
+	u32			dma_offset;
+	u32			flags;
+#define B44_FLAG_INIT_COMPLETE	0x00000001
+#define B44_FLAG_BUGGY_TXPTR	0x00000002
+#define B44_FLAG_REORDER_BUG	0x00000004
+#define B44_FLAG_PAUSE_AUTO	0x00008000
+#define B44_FLAG_FULL_DUPLEX	0x00010000
+#define B44_FLAG_100_BASE_T	0x00020000
+#define B44_FLAG_TX_PAUSE	0x00040000
+#define B44_FLAG_RX_PAUSE	0x00080000
+#define B44_FLAG_FORCE_LINK	0x00100000
+#define B44_FLAG_ADV_10HALF	0x01000000
+#define B44_FLAG_ADV_10FULL	0x02000000
+#define B44_FLAG_ADV_100HALF	0x04000000
+#define B44_FLAG_ADV_100FULL	0x08000000
+#define B44_FLAG_INTERNAL_PHY	0x10000000
+
+	u32			rx_offset;
+
+	u32			msg_enable;
+
+	struct timer_list	timer;
+
+	struct net_device_stats	stats;
+	struct b44_hw_stats	hw_stats;
+
+	unsigned long		regs;
+	struct pci_dev		*pdev;
+	struct net_device	*dev;
+
+	dma_addr_t		rx_ring_dma, tx_ring_dma;
+
+	u32			rx_pending;
+	u32			tx_pending;
+	u32			pci_cfg_state[64 / sizeof(u32)];
+	u8			phy_addr;
+	u8			mdc_port;
+	u8			core_unit;
+};
+
+#endif /* _B44_H */
diff -Nru a/drivers/net/bmac.c b/drivers/net/bmac.c
--- a/drivers/net/bmac.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/net/bmac.c	Sun Nov 10 19:28:36 2002
@@ -25,10 +25,10 @@
 #include <asm/pgtable.h>
 #include <asm/machdep.h>
 #include <asm/pmac_feature.h>
+#include <asm/irq.h>
 #ifdef CONFIG_PMAC_PBOOK
 #include <linux/adb.h>
 #include <linux/pmu.h>
-#include <asm/irq.h>
 #endif
 #include "bmac.h"
 
@@ -1053,7 +1053,7 @@
 {
 	struct dev_mc_list *dmi = dev->mc_list;
 	char *addrs;
-	int i, j, bit, byte;
+	int i;
 	unsigned short rx_cfg;
 	u32 crc;
 
@@ -1403,7 +1403,7 @@
 
 	memset((char *) bp->tx_cmds, 0,
 	       (N_TX_RING + N_RX_RING + 2) * sizeof(struct dbdma_cmd));
-	/*     init_timer(&bp->tx_timeout); */
+	init_timer(&bp->tx_timeout);
 	/*     bp->timeout_active = 0; */
 
 	ret = request_irq(dev->irq, bmac_misc_intr, 0, "BMAC-misc", dev);
diff -Nru a/drivers/net/dl2k.c b/drivers/net/dl2k.c
--- a/drivers/net/dl2k.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/net/dl2k.c	Sun Nov 10 19:28:39 2002
@@ -30,17 +30,32 @@
     1.09	2002/03/07	Move rx-poll-now to re-fill loop.	
     				Added rio_timer() to watch rx buffers. 
     1.10	2002/04/16	Fixed miscount of carrier error.
-    1.11	2002/05/23	Added ISR schedule scheme.
+    1.11	2002/05/23	Added ISR schedule scheme
     				Fixed miscount of rx frame error for DGE-550SX.
     				Fixed VLAN bug.
     1.12	2002/06/13	Lock tx_coalesce=1 on 10/100Mbps mode.
- */
-
+    1.13	2002/08/13	1. Fix disconnection (many tx:carrier/rx:frame
+    				   errs) with some mainboards.
+    				2. Use definition "DRV_NAME" "DRV_VERSION" 
+				   "DRV_RELDATE" for flexibility.	
+    1.14	2002/08/14	Support ethtool.	
+    1.15	2002/08/27	Changed the default media to Auto-Negotiation
+				for the fiber devices.    
+    1.16	2002/09/04      More power down time for fiber devices auto-
+    				negotiation.
+				Fix disconnect bug after ifup and ifdown.
+    1.17	2002/10/03	Fix RMON statistics overflow. 
+			     	Always use I/O mapping to access eeprom, 
+				avoid system freezing with some chipsets.
+
+*/
+#define DRV_NAME	"D-Link DL2000-based linux driver"
+#define DRV_VERSION	"v1.17"
+#define DRV_RELDATE	"2002/10/04"
 #include "dl2k.h"
 
 static char version[] __devinitdata =
-    KERN_INFO "D-Link DL2000-based linux driver v1.12 2002/06/13\n";
-
+      KERN_INFO DRV_NAME " " DRV_VERSION " " DRV_RELDATE "\n";	
 #define MAX_UNITS 8
 static int mtu[MAX_UNITS];
 static int vlan[MAX_UNITS];
@@ -92,6 +107,7 @@
 static void set_multicast (struct net_device *dev);
 static struct net_device_stats *get_stats (struct net_device *dev);
 static int clear_stats (struct net_device *dev);
+static int rio_ethtool_ioctl (struct net_device *dev, void *useraddr);
 static int rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 static int rio_close (struct net_device *dev);
 static int find_miiphy (struct net_device *dev);
@@ -257,12 +273,8 @@
 	np->link_status = 0;
 	/* Set media and reset PHY */
 	if (np->phy_media) {
-		/* default 1000mbps_fd for fiber deivices */
-		if (np->an_enable == 1) {
-			np->an_enable = 0;
-			np->speed = 1000;
-			np->full_duplex = 1;
-		} else if (np->an_enable == 2) {
+		/* default Auto-Negotiation for fiber deivices */
+	 	if (np->an_enable == 2) {
 			np->an_enable = 1;
 		}
 		mii_set_media_pcs (dev);
@@ -275,10 +287,6 @@
 	}
 	pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id);
 
-	/* Reset all logic functions */
-	writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
-		ioaddr + ASICCtrl + 2);
-
 	err = register_netdev (dev);
 	if (err)
 		goto err_out_unmap_rx;
@@ -357,11 +365,16 @@
 
 	int cid, next;
 
+#ifdef	MEM_MAPPING
+	ioaddr = pci_resource_start (np->pdev, 0);
+#endif
 	/* Read eeprom */
 	for (i = 0; i < 128; i++) {
 		((u16 *) sromdata)[i] = le16_to_cpu (read_eeprom (ioaddr, i));
 	}
-
+#ifdef	MEM_MAPPING
+	ioaddr = dev->base_addr;
+#endif	
 	/* Check CRC */
 	crc = ~ether_crc_le (256 - 4, sromdata);
 	if (psrom->crc != crc) {
@@ -421,10 +434,17 @@
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	int i;
-
+	u16 macctrl;
+	
 	i = request_irq (dev->irq, &rio_interrupt, SA_SHIRQ, dev->name, dev);
 	if (i)
 		return i;
+	
+	/* Reset all logic functions */
+	writew (GlobalReset | DMAReset | FIFOReset | NetworkReset | HostReset,
+		ioaddr + ASICCtrl + 2);
+	mdelay(10);
+	
 	/* DebugCtrl bit 4, 5, 9 must set */
 	writel (readl (ioaddr + DebugCtrl) | 0x0230, ioaddr + DebugCtrl);
 
@@ -448,7 +468,7 @@
 	writeb (0xff, ioaddr + TxDMAPollPeriod);
 	writeb (0x30, ioaddr + RxDMABurstThresh);
 	writeb (0x30, ioaddr + RxDMAUrgentThresh);
-
+	writel (0x0007ffff, ioaddr + RmonStatMask);
 	/* clear statistics */
 	clear_stats (dev);
 
@@ -467,9 +487,6 @@
 			ioaddr + MACCtrl);
 	}
 
-	/* Enable default interrupts */
-	EnableInt ();
-
 	init_timer (&np->timer);
 	np->timer.expires = jiffies + 1*HZ;
 	np->timer.data = (unsigned long) dev;
@@ -479,8 +496,18 @@
 	/* Start Tx/Rx */
 	writel (readl (ioaddr + MACCtrl) | StatsEnable | RxEnable | TxEnable, 
 			ioaddr + MACCtrl);
+	
+	macctrl = 0;
+	macctrl |= (np->vlan) ? AutoVLANuntagging : 0;
+	macctrl |= (np->full_duplex) ? DuplexSelect : 0;
+	macctrl |= (np->tx_flow) ? TxFlowControlEnable : 0;
+	macctrl |= (np->rx_flow) ? RxFlowControlEnable : 0;
+	writew(macctrl,	ioaddr + MACCtrl);
 
 	netif_start_queue (dev);
+	
+	/* Enable default interrupts */
+	EnableInt ();
 	return 0;
 }
 
@@ -626,7 +653,7 @@
 	}
 #endif
 	if (np->vlan) {
-		txdesc->status |=
+		tfc_vlan_tag =
 		    cpu_to_le64 (VLANTagInsert) |
 		    (cpu_to_le64 (np->vlan) << 32) |
 		    (cpu_to_le64 (skb->priority) << 45);
@@ -720,9 +747,10 @@
 	long flag = 0;
 	
 	if (irq)
-		spin_lock_irqsave(&np->tx_lock, flag);
-	else
 		spin_lock(&np->tx_lock);
+	else
+		spin_lock_irqsave(&np->tx_lock, flag);
+			
 	/* Free used tx skbuffs */
 	while (entry != np->cur_tx) {
 		struct sk_buff *skb;
@@ -743,9 +771,9 @@
 		tx_use++;
 	}
 	if (irq)
-		spin_unlock_irqrestore(&np->tx_lock, flag);
-	else
 		spin_unlock(&np->tx_lock);
+	else
+		spin_unlock_irqrestore(&np->tx_lock, flag);
 	np->old_tx = entry;
 
 	/* If the ring is no longer full, clear tx_full and 
@@ -809,8 +837,13 @@
 		/* Let TxStartThresh stay default value */
 	}
 	/* Maximum Collisions */
+#ifdef ETHER_STATS	
+	if (tx_status & 0x08) 
+		np->stats.collisions16++;
+#else
 	if (tx_status & 0x08) 
 		np->stats.collisions++;
+#endif
 	/* Restart the Tx */
 	writel (readw (dev->base_addr + MACCtrl) | TxEnable, ioaddr + MACCtrl);
 }
@@ -1103,6 +1136,7 @@
 	u16 rx_mode = 0;
 	int i;
 	int bit;
+	int index, crc;
 	struct dev_mc_list *mclist;
 	struct netdev_private *np = dev->priv;
 	
@@ -1122,17 +1156,16 @@
 		rx_mode =
 		    ReceiveBroadcast | ReceiveMulticastHash | ReceiveUnicast;
 		for (i=0, mclist = dev->mc_list; mclist && i < dev->mc_count; 
-			i++, mclist=mclist->next) {
-
-			int index = 0;
-			int crc = ether_crc_le (ETH_ALEN, mclist->dmi_addr);
-
+				i++, mclist=mclist->next) 
+		{
+			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 (bit = 0; bit < 6; bit++)
-				if (crc & (1 << (31 - bit)))
-					index |= (1 << bit);
-
+			for (index=0, bit=0; bit < 6; bit++) {
+				if (test_bit(31-bit, &crc)) {
+					 set_bit(bit, &index);
+				}
+			}
 			hash_table[index / 32] |= (1 << (index % 32));
 		}
 	} else {
@@ -1149,6 +1182,132 @@
 }
 
 static int
+rio_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	struct netdev_private *np = dev->priv;
+       	u32 ethcmd;
+	
+	if (copy_from_user (&ethcmd, useraddr, sizeof (ethcmd)))
+		return -EFAULT;
+	switch (ethcmd) {
+		case ETHTOOL_GDRVINFO: {
+			struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+			strcpy(info.driver, "DL2K");
+			strcpy(info.version, DRV_VERSION);
+			strcpy(info.bus_info, np->pdev->slot_name);
+			memset(&info.fw_version, 0, sizeof(info.fw_version));
+			if (copy_to_user(useraddr, &info, sizeof(info)))
+				return -EFAULT;
+			return 0;
+		}	
+ 	
+		case ETHTOOL_GSET: {
+			struct ethtool_cmd cmd = { ETHTOOL_GSET };
+			if (np->phy_media) {
+				/* fiber device */
+				cmd.supported = SUPPORTED_Autoneg | 
+							SUPPORTED_FIBRE;
+				cmd.advertising= ADVERTISED_Autoneg |
+							ADVERTISED_FIBRE;
+				cmd.port = PORT_FIBRE;
+				cmd.transceiver = XCVR_INTERNAL;	
+			} else {
+				/* copper device */
+				cmd.supported = SUPPORTED_10baseT_Half | 
+					SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half
+					| SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Full |
+					SUPPORTED_Autoneg | SUPPORTED_MII;
+				cmd.advertising = ADVERTISED_10baseT_Half |
+					ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Half |
+					ADVERTISED_100baseT_Full | ADVERTISED_1000baseT_Full|
+					ADVERTISED_Autoneg | ADVERTISED_MII;
+				cmd.port = PORT_MII;
+				cmd.transceiver = XCVR_INTERNAL;
+			}
+			if ( np->link_status ) { 
+				cmd.speed = np->speed;
+				cmd.duplex = np->full_duplex ? 
+						    DUPLEX_FULL : DUPLEX_HALF;
+			} else {
+				cmd.speed = -1;
+				cmd.duplex = -1;
+			}
+			if ( np->an_enable)
+				cmd.autoneg = AUTONEG_ENABLE;
+			else
+				cmd.autoneg = AUTONEG_DISABLE;
+			
+			cmd.phy_address = np->phy_addr;
+
+			if (copy_to_user(useraddr, &cmd,
+					sizeof(cmd)))
+				return -EFAULT;
+			return 0;				   
+		}
+		case ETHTOOL_SSET: {
+			struct ethtool_cmd cmd;
+			if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+				return -EFAULT;
+			netif_carrier_off(dev);
+			if (cmd.autoneg == AUTONEG_ENABLE) {
+				if (np->an_enable)
+					return 0;
+				else {
+					np->an_enable = 1;
+					mii_set_media(dev);
+					return 0;	
+				}	
+			} else {
+				np->an_enable = 0;
+				if (np->speed == 1000){
+					cmd.speed = SPEED_100;			
+					cmd.duplex = DUPLEX_FULL;
+					printk("Warning!! Can't disable Auto negotiation in 1000Mbps, change to Manul 100Mbps, Full duplex.\n");
+					}
+				switch(cmd.speed + cmd.duplex){
+				
+				case SPEED_10 + DUPLEX_HALF:
+					np->speed = 10;
+					np->full_duplex = 0;
+					break;
+				
+				case SPEED_10 + DUPLEX_FULL:
+					np->speed = 10;
+					np->full_duplex = 1;
+					break;
+				case SPEED_100 + DUPLEX_HALF:
+					np->speed = 100;
+					np->full_duplex = 0;
+					break;
+				case SPEED_100 + DUPLEX_FULL:
+					np->speed = 100;
+					np->full_duplex = 1;
+					break;
+				case SPEED_1000 + DUPLEX_HALF:/* not supported */
+				case SPEED_1000 + DUPLEX_FULL:/* not supported */
+				default:
+					return -EINVAL;	
+				}
+				mii_set_media(dev);
+			}
+		return 0;		   
+		}
+#ifdef ETHTOOL_GLINK		
+		case ETHTOOL_GLINK:{
+		struct ethtool_value link = { ETHTOOL_GLINK };
+		link.data = np->link_status;
+		if (copy_to_user(useraddr, &link, sizeof(link)))
+			return -EFAULT;
+		return 0;
+		}			   
+#endif
+		default:
+		return -EOPNOTSUPP;
+	}	
+}
+
+
+static int
 rio_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	int phy_addr;
@@ -1160,6 +1319,8 @@
 
 	phy_addr = np->phy_addr;
 	switch (cmd) {
+	case SIOCETHTOOL:
+		return rio_ethtool_ioctl (dev, (void *) rq->ifr_data);		
 	case SIOCDEVPRIVATE:
 		break;
 	
@@ -1210,14 +1371,15 @@
 #define EEP_READ 0x0200
 #define EEP_BUSY 0x8000
 /* Read the EEPROM word */
+/* We use I/O instruction to read/write eeprom to avoid fail on some machines */
 int
 read_eeprom (long ioaddr, int eep_addr)
 {
 	int i = 1000;
-	writew (EEP_READ | (eep_addr & 0xff), ioaddr + EepromCtrl);
+	outw (EEP_READ | (eep_addr & 0xff), ioaddr + EepromCtrl);
 	while (i-- > 0) {
-		if (!(readw (ioaddr + EepromCtrl) & EEP_BUSY)) {
-			return readw (ioaddr + EepromData);
+		if (!(inw (ioaddr + EepromCtrl) & EEP_BUSY)) {
+			return inw (ioaddr + EepromData);
 		}
 	}
 	return 0;
@@ -1464,7 +1626,7 @@
 		/* 3) Power Down */
 		bmcr.image = 0x1940;	/* must be 0x1940 */
 		mii_write (dev, phy_addr, MII_BMCR, bmcr.image);
-		mdelay (10);	/* wait a certain time */
+		mdelay (100);	/* wait a certain time */
 
 		/* 4) Advertise nothing */
 		mii_write (dev, phy_addr, MII_ANAR, 0);
diff -Nru a/drivers/net/dl2k.h b/drivers/net/dl2k.h
--- a/drivers/net/dl2k.h	Sun Nov 10 19:28:41 2002
+++ b/drivers/net/dl2k.h	Sun Nov 10 19:28:41 2002
@@ -27,9 +27,11 @@
 #include <linux/skbuff.h>
 #include <linux/init.h>
 #include <linux/crc32.h>
+#include <linux/ethtool.h>
 #include <asm/processor.h>	/* Processor type for cache alignment. */
 #include <asm/bitops.h>
 #include <asm/io.h>
+#include <asm/uaccess.h>
 #include <linux/delay.h>
 #include <linux/spinlock.h>
 #include <linux/time.h>
diff -Nru a/drivers/net/e100/e100.h b/drivers/net/e100/e100.h
--- a/drivers/net/e100/e100.h	Sun Nov 10 19:28:38 2002
+++ b/drivers/net/e100/e100.h	Sun Nov 10 19:28:38 2002
@@ -927,8 +927,6 @@
 
 	struct proc_dir_entry *proc_parent;
 
-	rwlock_t isolate_lock;
-	int driver_isolated;
 	char *id_string;
 	char *cable_status;
 	char *mdix_status;
@@ -977,8 +975,7 @@
 extern unsigned char e100_get_link_state(struct e100_private *bdp);
 extern unsigned char e100_wait_scb(struct e100_private *bdp);
 
-extern void e100_deisolate_driver(struct e100_private *bdp,
-				  u8 recover, u8 full_reset);
+extern void e100_deisolate_driver(struct e100_private *bdp, u8 full_reset);
 extern unsigned char e100_hw_reset_recover(struct e100_private *bdp,
 					   u32 reset_cmd);
 
diff -Nru a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c
--- a/drivers/net/e100/e100_main.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/net/e100/e100_main.c	Sun Nov 10 19:28:39 2002
@@ -135,7 +135,7 @@
 
 /* Global Data structures and variables */
 char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";
-char e100_driver_version[]="2.1.24-k1";
+char e100_driver_version[]="2.1.24-k2";
 const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";
 char e100_short_driver_name[] = "e100";
 static int e100nics = 0;
@@ -935,13 +935,6 @@
 
 	bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-
-	if (bdp->driver_isolated) {
-		rc = -EBUSY;
-		goto exit;
-	}
-
 	/* setup the tcb pool */
 	if (!e100_alloc_tcb_pool(bdp)) {
 		rc = -ENOMEM;
@@ -990,7 +983,6 @@
 err_exit:
 	e100_clear_pools(bdp);
 exit:
-	read_unlock(&(bdp->isolate_lock));
 	return rc;
 }
 
@@ -1008,9 +1000,6 @@
 	free_irq(dev->irq, dev);
 	e100_clear_pools(bdp);
 
-	/* set the isolate flag to false, so e100_open can be called */
-	bdp->driver_isolated = false;
-
 	return 0;
 }
 
@@ -1031,13 +1020,6 @@
 	int notify_stop = false;
 	struct e100_private *bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-
-	if (bdp->driver_isolated) {
-		rc = -EBUSY;
-		goto exit2;
-	}
-
 	if (!spin_trylock(&bdp->bd_non_tx_lock)) {
 		notify_stop = true;
 		rc = 1;
@@ -1060,7 +1042,6 @@
 exit1:
 	spin_unlock(&bdp->bd_non_tx_lock);
 exit2:
-	read_unlock(&(bdp->isolate_lock));
 	if (notify_stop) {
 		netif_stop_queue(dev);
 	}
@@ -1115,18 +1096,11 @@
 
 	bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
 	if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) {
 		memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN);
 		rc = 0;
 	}
 
-exit:
-	read_unlock(&(bdp->isolate_lock));
 	return rc;
 }
 
@@ -1180,10 +1154,6 @@
 	unsigned char promisc_enbl;
 	unsigned char mulcast_enbl;
 
-	read_lock(&(bdp->isolate_lock));
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
 	promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC);
 	mulcast_enbl = ((dev->flags & IFF_ALLMULTI) ||
 			(dev->mc_count > MAX_MULTICAST_ADDRS));
@@ -1195,14 +1165,11 @@
 	e100_config(bdp);
 
 	if (promisc_enbl || mulcast_enbl) {
-		goto exit;	/* no need for Multicast Cmd */
+		return;	/* no need for Multicast Cmd */
 	}
 
 	/* get the multicast CB */
 	e100_set_multi_exec(dev);
-
-exit:
-	read_unlock(&(bdp->isolate_lock));
 }
 
 static int
@@ -1308,8 +1275,6 @@
 	spin_lock_init(&(bdp->bd_non_tx_lock));
 	spin_lock_init(&(bdp->config_lock));
 	spin_lock_init(&(bdp->mdi_access_lock));
-	bdp->isolate_lock = RW_LOCK_UNLOCKED;
-	bdp->driver_isolated = false;
 
 	return 1;
 }
@@ -1625,12 +1590,8 @@
 {
 	struct e100_private *bdp = dev->priv;
 
-	read_lock(&(bdp->isolate_lock));
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
 	if (!netif_running(dev)) {
-		goto exit;
+		return;
 	}
 	e100_get_mdix_status(bdp);
 
@@ -1721,9 +1682,6 @@
 
 	if (list_empty(&bdp->active_rx_list))
 		e100_trigger_SWI(bdp);
-
-exit:
-	read_unlock(&(bdp->isolate_lock));
 }
 
 /**
@@ -1828,11 +1786,6 @@
 		return;
 	}
 
-	read_lock(&(bdp->isolate_lock));
-	if (bdp->driver_isolated) {
-		goto exit;
-	}
-
 	/* SWI intr (triggered by watchdog) is signal to allocate new skb buffers */
 	if (intr_status & SCB_STATUS_ACK_SWI) {
 		e100_alloc_skbs(bdp);
@@ -1849,9 +1802,7 @@
 		e100_tx_srv(bdp);
 	}
 
-exit:
 	e100_set_intr_mask(bdp);
-	read_unlock(&(bdp->isolate_lock));
 }
 
 /**
@@ -2656,7 +2607,7 @@
 	if (in_interrupt())
 		return e100_delayed_exec_non_cu_cmd(bdp, command);
 
-	if (netif_running(bdp->device) && (!bdp->driver_isolated))
+	if (netif_running(bdp->device) && netif_carrier_ok(bdp->device))
 		return e100_delayed_exec_non_cu_cmd(bdp, command);
 
 	spin_lock_bh(&(bdp->bd_non_tx_lock));
@@ -3054,33 +3005,32 @@
 void
 e100_isolate_driver(struct e100_private *bdp)
 {
-	write_lock_irq(&(bdp->isolate_lock));
-	bdp->driver_isolated = true;
-	write_unlock_irq(&(bdp->isolate_lock));
-
-	del_timer_sync(&bdp->watchdog_timer);
-
-	del_timer_sync(&bdp->hwi_timer);
-	/* If in middle of cable diag, */
-	if (bdp->hwi_started) {
-		bdp->hwi_started = 0;
-		e100_hwi_restore(bdp);
-	}
-
-	if (netif_running(bdp->device))
-		netif_stop_queue(bdp->device);
-
-	bdp->last_tcb = NULL;
-
+	if (netif_running(bdp->device)) {
+		e100_dis_intr(bdp);
+		del_timer_sync(&bdp->watchdog_timer);
+		del_timer_sync(&bdp->hwi_timer);
+		/* If in middle of cable diag, */
+		if (bdp->hwi_started) {
+			bdp->hwi_started = 0;
+			e100_hwi_restore(bdp);
+		}
+		netif_carrier_off(bdp->device);
+		netif_stop_queue(bdp->device); 
+		bdp->last_tcb = NULL;
+	} 
 	e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
 }
 
 void
 e100_set_speed_duplex(struct e100_private *bdp)
 {
+	if (netif_carrier_ok(bdp->device))
+		e100_isolate_driver(bdp);
 	e100_phy_set_speed_duplex(bdp, true);
 	e100_config_fc(bdp);	/* re-config flow-control if necessary */
 	e100_config(bdp);	
+	if (netif_carrier_ok(bdp->device))
+		e100_deisolate_driver(bdp, false);
 }
 
 static void
@@ -3160,29 +3110,21 @@
 }
 
 void
-e100_deisolate_driver(struct e100_private *bdp, u8 recover, u8 full_init)
+e100_deisolate_driver(struct e100_private *bdp, u8 full_reset)
 {
-	if (full_init) {
-		e100_sw_reset(bdp, PORT_SOFTWARE_RESET);
-		if (!e100_hw_reset_recover(bdp, PORT_SOFTWARE_RESET))
-			printk(KERN_ERR "e100: e100_deisolate_driver:"
-			       " HW SOFTWARE reset recover failed\n");
-	}
+	u32 cmd = full_reset ? PORT_SOFTWARE_RESET : PORT_SELECTIVE_RESET;
+	e100_sw_reset(bdp, cmd);
+	if (cmd == PORT_SOFTWARE_RESET) {
+		if (!e100_hw_reset_recover(bdp, cmd))
+			printk(KERN_ERR "e100: e100_deisolate_driver:" 
+		       		" device configuration failed\n");
+	} 
 
-	if (recover) {
+	if (netif_running(bdp->device)) {
 
 		bdp->next_cu_cmd = START_WAIT;
 		bdp->last_tcb = NULL;
 
-		/* lets reset the chip */
-		if (!full_init) {
-			e100_sw_reset(bdp, PORT_SELECTIVE_RESET);
-
-			if (!e100_hw_reset_recover(bdp, PORT_SELECTIVE_RESET)) {
-				printk(KERN_ERR "e100: e100_deisolate_driver:"
-				       " HW reset recover failed\n");
-			}
-		}
 		e100_start_ru(bdp);
 
 		/* relaunch watchdog timer in 2 sec */
@@ -3192,14 +3134,9 @@
 		// or have unsent frames on the tcb chain
 		e100_tcb_add_C_bit(bdp);
 		e100_tx_srv(bdp);
-
+		netif_wake_queue(bdp->device);
 		e100_set_intr_mask(bdp);
-
-		if (netif_running(bdp->device))
-			netif_wake_queue(bdp->device);
 	}
-
-	bdp->driver_isolated = false;
 }
 
 static int
@@ -4165,22 +4102,17 @@
 {
 	struct net_device *netdev = pci_get_drvdata(pcid);
 	struct e100_private *bdp = netdev->priv;
-	u8 recover = false;
-	u8 full_init = false;
+	u8 full_reset = false;
 
 	pci_set_power_state(pcid, 0);
 	pci_enable_wake(pcid, 0, 0);	/* Clear PME status and disable PME */
 	pci_restore_state(pcid, bdp->pci_state);
 
-	if (netif_running(netdev)) {
-		recover = true;
-	}
-
 	if (bdp->wolopts & (WAKE_UCAST | WAKE_ARP)) {
-		full_init = true;
+		full_reset = true;
 	}
 
-	e100_deisolate_driver(bdp, recover, full_init);
+	e100_deisolate_driver(bdp, full_reset);
 
 	return 0;
 }
diff -Nru a/drivers/net/e100/e100_test.c b/drivers/net/e100/e100_test.c
--- a/drivers/net/e100/e100_test.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/net/e100/e100_test.c	Sun Nov 10 19:28:39 2002
@@ -95,12 +95,8 @@
 		test_info [E100_EEPROM_TEST_FAIL] = true;
 	}
 
-	/* fully recover only if the device is open*/
-	if (netif_running(dev))  {
-		e100_deisolate_driver(bdp, true, false);
-	} else {
-    		e100_deisolate_driver(bdp, false, false);
-	}
+	e100_deisolate_driver(bdp, false);
+
 	/*Let card recover from the test*/
 	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule_timeout(HZ * 2);
diff -Nru a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
--- a/drivers/net/hamradio/yam.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/net/hamradio/yam.c	Sun Nov 10 19:28:40 2002
@@ -170,7 +170,7 @@
 static char ax25_test[7] =
 {'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
 
-static struct timer_list yam_timer;
+static struct timer_list yam_timer = TIMER_INITIALIZER(NULL, 0, 0);
 
 /* --------------------------------------------------------------------- */
 
diff -Nru a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig
--- a/drivers/net/irda/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/drivers/net/irda/Kconfig	Sun Nov 10 19:28:40 2002
@@ -9,7 +9,7 @@
 	depends on IRDA
 	help
 	  Say Y here if you want to build support for the IrTTY line
-	  discipline.  If you want to compile it as a module (irtty.o), say M
+	  discipline.  If you want to compile it as a module (irtty-sir.o), say M
 	  here and read <file:Documentation/modules.txt>.  IrTTY makes it
 	  possible to use Linux's own serial driver for all IrDA ports that
 	  are 16550 compatible.  Most IrDA chips are 16550 compatible so you
@@ -18,6 +18,69 @@
 
 	  If unsure, say Y.
 
+comment "Dongle support"
+
+config DONGLE
+	bool "Serial dongle support"
+	help
+	  Say Y here if you have an infrared device that connects to your
+	  computer's serial port. These devices are called dongles. Then say Y
+	  or M to the driver for your particular dongle below.
+
+	  Note that the answer to this question won't directly affect the
+	  kernel: saying N will just cause the configurator to skip all
+	  the questions about serial dongles.
+
+config ESI_DONGLE
+	tristate "ESI JetEye PC dongle"
+	depends on DONGLE && IRDA
+	help
+	  Say Y here if you want to build support for the Extended Systems
+	  JetEye PC dongle.  If you want to compile it as a module, say M here
+	  and read <file:Documentation/modules.txt>.  The ESI dongle attaches
+	  to the normal 9-pin serial port connector, and can currently only be
+	  used by IrTTY.  To activate support for ESI dongles you will have to
+	  start irattach like this: "irattach -d esi".
+
+config ACTISYS_DONGLE
+	tristate "ACTiSYS IR-220L and IR220L+ dongle"
+	depends on DONGLE && IRDA
+	help
+	  Say Y here if you want to build support for the ACTiSYS IR-220L and
+	  IR220L+ dongles.  If you want to compile it as a module, say M here
+	  and read <file:Documentation/modules.txt>.  The ACTiSYS dongles
+	  attaches to the normal 9-pin serial port connector, and can
+	  currently only be used by IrTTY.  To activate support for ACTiSYS
+	  dongles you will have to start irattach like this:
+	  "irattach -d actisys" or "irattach -d actisys+".
+
+config TEKRAM_DONGLE
+	tristate "Tekram IrMate 210B dongle"
+	depends on DONGLE && IRDA
+	help
+	  Say Y here if you want to build support for the Tekram IrMate 210B
+	  dongle.  If you want to compile it as a module, say M here and read
+	  <file:Documentation/modules.txt>.  The Tekram dongle attaches to the
+	  normal 9-pin serial port connector, and can currently only be used
+	  by IrTTY.  To activate support for Tekram dongles you will have to
+	  start irattach like this: "irattach -d tekram".
+
+comment "Old SIR device drivers"
+
+config IRTTY_OLD
+	tristate "Old IrTTY (broken)"
+	depends on IRDA
+	help
+	  Say Y here if you want to build support for the IrTTY line
+	  discipline.  If you want to compile it as a module (irtty.o), say M
+	  here and read <file:Documentation/modules.txt>.  IrTTY makes it
+	  possible to use Linux's own serial driver for all IrDA ports that
+	  are 16550 compatible.  Most IrDA chips are 16550 compatible so you
+	  should probably say Y to this option.  Using IrTTY will however
+	  limit the speed of the connection to 115200 bps (IrDA SIR mode).
+
+	  If unsure, say N.
+
 config IRPORT_SIR
 	tristate "IrPORT (IrDA serial driver)"
 	depends on IRDA
@@ -35,10 +98,10 @@
 
 	  If unsure, say Y.
 
-comment "Dongle support"
+comment "Old Serial dongle support"
 
-config DONGLE
-	bool "Serial dongle support"
+config DONGLE_OLD
+	bool "Old Serial dongle support"
 	help
 	  Say Y here if you have an infrared device that connects to your
 	  computer's serial port. These devices are called dongles. Then say Y
@@ -48,9 +111,9 @@
 	  kernel: saying N will just cause the configurator to skip all
 	  the questions about serial dongles.
 
-config ESI_DONGLE
+config ESI_DONGLE_OLD
 	tristate "ESI JetEye PC dongle"
-	depends on DONGLE && IRDA
+	depends on DONGLE_OLD && IRDA
 	help
 	  Say Y here if you want to build support for the Extended Systems
 	  JetEye PC dongle.  If you want to compile it as a module, say M here
@@ -59,9 +122,9 @@
 	  used by IrTTY.  To activate support for ESI dongles you will have to
 	  start irattach like this: "irattach -d esi".
 
-config ACTISYS_DONGLE
+config ACTISYS_DONGLE_OLD
 	tristate "ACTiSYS IR-220L and IR220L+ dongle"
-	depends on DONGLE && IRDA
+	depends on DONGLE_OLD && IRDA
 	help
 	  Say Y here if you want to build support for the ACTiSYS IR-220L and
 	  IR220L+ dongles.  If you want to compile it as a module, say M here
@@ -71,9 +134,9 @@
 	  dongles you will have to start irattach like this:
 	  "irattach -d actisys" or "irattach -d actisys+".
 
-config TEKRAM_DONGLE
+config TEKRAM_DONGLE_OLD
 	tristate "Tekram IrMate 210B dongle"
-	depends on DONGLE && IRDA
+	depends on DONGLE_OLD && IRDA
 	help
 	  Say Y here if you want to build support for the Tekram IrMate 210B
 	  dongle.  If you want to compile it as a module, say M here and read
@@ -84,7 +147,7 @@
 
 config GIRBIL_DONGLE
 	tristate "Greenwich GIrBIL dongle"
-	depends on DONGLE && IRDA
+	depends on DONGLE_OLD && IRDA
 	help
 	  Say Y here if you want to build support for the Greenwich GIrBIL
 	  dongle.  If you want to compile it as a module, say M here and read
@@ -95,7 +158,7 @@
 
 config LITELINK_DONGLE
 	tristate "Parallax LiteLink dongle"
-	depends on DONGLE && IRDA
+	depends on DONGLE_OLD && IRDA
 	help
 	  Say Y here if you want to build support for the Parallax Litelink
 	  dongle.  If you want to compile it as a module, say M here and read
@@ -106,7 +169,7 @@
 
 config MCP2120_DONGLE
 	tristate "Microchip MCP2120"
-	depends on DONGLE && IRDA
+	depends on DONGLE_OLD && IRDA
 	help
 	  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
@@ -120,7 +183,7 @@
 
 config OLD_BELKIN_DONGLE
 	tristate "Old Belkin dongle"
-	depends on DONGLE && IRDA
+	depends on DONGLE_OLD && IRDA
 	help
 	  Say Y here if you want to build support for the Adaptec Airport 1000
 	  and 2000 dongles.  If you want to compile it as a module, say M here
@@ -130,11 +193,11 @@
 
 config EP7211_IR
 	tristate "EP7211 I/R support"
-	depends on DONGLE && ARCH_EP7211 && IRDA
+	depends on DONGLE_OLD && ARCH_EP7211 && IRDA
 
 config ACT200L_DONGLE
 	tristate "ACTiSYS IR-200L dongle (EXPERIMENTAL)"
-	depends on DONGLE && EXPERIMENTAL && IRDA
+	depends on DONGLE_OLD && EXPERIMENTAL && IRDA
 	help
 	  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
@@ -145,7 +208,7 @@
 
 config MA600_DONGLE
 	tristate "Mobile Action MA600 dongle (EXPERIMENTAL)"
-	depends on DONGLE && EXPERIMENTAL && IRDA
+	depends on DONGLE_OLD && EXPERIMENTAL && IRDA
 	---help---
 	  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
diff -Nru a/drivers/net/irda/Makefile b/drivers/net/irda/Makefile
--- a/drivers/net/irda/Makefile	Sun Nov 10 19:28:39 2002
+++ b/drivers/net/irda/Makefile	Sun Nov 10 19:28:39 2002
@@ -5,10 +5,12 @@
 # Rewritten to use lists instead of if-statements.
 #
 
-export-objs	= irport.o
+export-objs	= irport.o sir_core.o
 
-obj-$(CONFIG_IRTTY_SIR)		+= irtty.o
+# Old SIR drivers (irtty is broken)
+obj-$(CONFIG_IRTTY_OLD)		+= irtty.o
 obj-$(CONFIG_IRPORT_SIR)	+= 		irport.o
+# FIR drivers
 obj-$(CONFIG_USB_IRDA)		+= irda-usb.o
 obj-$(CONFIG_NSC_FIR)		+= nsc-ircc.o
 obj-$(CONFIG_WINBOND_FIR)	+= w83977af_ir.o
@@ -18,9 +20,10 @@
 obj-$(CONFIG_SMC_IRCC_FIR)	+= smc-ircc.o	irport.o
 obj-$(CONFIG_ALI_FIR)		+= ali-ircc.o
 obj-$(CONFIG_VLSI_FIR)		+= vlsi_ir.o
-obj-$(CONFIG_ESI_DONGLE)	+= esi.o
-obj-$(CONFIG_TEKRAM_DONGLE)	+= tekram.o
-obj-$(CONFIG_ACTISYS_DONGLE)	+= actisys.o
+# Old dongle drivers for old SIR drivers
+obj-$(CONFIG_ESI_OLD)		+= esi.o
+obj-$(CONFIG_TEKRAM_OLD)	+= tekram.o
+obj-$(CONFIG_ACTISYS_OLD)	+= actisys.o
 obj-$(CONFIG_GIRBIL_DONGLE)	+= girbil.o
 obj-$(CONFIG_LITELINK_DONGLE)	+= litelink.o
 obj-$(CONFIG_OLD_BELKIN_DONGLE)	+= old_belkin.o
@@ -28,5 +31,14 @@
 obj-$(CONFIG_MCP2120_DONGLE)	+= mcp2120.o
 obj-$(CONFIG_ACT200L_DONGLE)	+= act200l.o
 obj-$(CONFIG_MA600_DONGLE)	+= ma600.o
+# New SIR drivers
+obj-$(CONFIG_IRTTY_SIR)		+= irtty-sir.o	sir-dev.o
+# New dongles drivers for new SIR drivers
+obj-$(CONFIG_ESI_DONGLE)	+= esi-sir.o
+obj-$(CONFIG_TEKRAM_DONGLE)	+= tekram-sir.o
+obj-$(CONFIG_ACTISYS_DONGLE)	+= actisys-sir.o
+
+# The SIR helper module
+sir-dev-objs := sir_core.o sir_dev.o sir_dongle.o sir_kthread.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/net/irda/actisys-sir.c b/drivers/net/irda/actisys-sir.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/irda/actisys-sir.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,240 @@
+/*********************************************************************
+ *                
+ * Filename:      actisys.c
+ * Version:       1.1
+ * Description:   Implementation for the ACTiSYS IR-220L and IR-220L+ 
+ *                dongles
+ * Status:        Beta.
+ * Authors:       Dag Brattli <dagb@cs.uit.no> (initially)
+ *		  Jean Tourrilhes <jt@hpl.hp.com> (new version)
+ *		  Martin Diehl <mad@mdiehl.de> (new version for sir_dev)
+ * Created at:    Wed Oct 21 20:02:35 1998
+ * Modified at:   Sun Oct 27 22:02:13 2002
+ * Modified by:   Martin Diehl <mad@mdiehl.de>
+ * 
+ *     Copyright (c) 1998-1999 Dag Brattli, All Rights Reserved.
+ *     Copyright (c) 1999 Jean Tourrilhes
+ *     Copyright (c) 2002 Martin Diehl
+ *      
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version.
+ *  
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ *     
+ ********************************************************************/
+
+/*
+ * Changelog
+ *
+ * 0.8 -> 0.9999 - Jean
+ *	o New initialisation procedure : much safer and correct
+ *	o New procedure the change speed : much faster and simpler
+ *	o Other cleanups & comments
+ *	Thanks to Lichen Wang @ Actisys for his excellent help...
+ *
+ * 1.0 -> 1.1 - Martin Diehl
+ *	modified for new sir infrastructure
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+
+#include "sir-dev.h"
+
+/* 
+ * Define the timing of the pulses we send to the dongle (to reset it, and
+ * to toggle speeds). Basically, the limit here is the propagation speed of
+ * the signals through the serial port, the dongle being much faster.  Any
+ * serial port support 115 kb/s, so we are sure that pulses 8.5 us wide can
+ * go through cleanly . If you are on the wild side, you can try to lower
+ * this value (Actisys recommended me 2 us, and 0 us work for me on a P233!)
+ */
+#define MIN_DELAY 10	/* 10 us to be on the conservative side */
+
+static int actisys_open(struct sir_dev *);
+static int actisys_close(struct sir_dev *);
+static int actisys_change_speed(struct sir_dev *, unsigned);
+static int actisys_reset(struct sir_dev *);
+
+/* These are the baudrates supported, in the order available */
+/* Note : the 220L doesn't support 38400, but we will fix that below */
+static __u32 baud_rates[] = { 9600, 19200, 57600, 115200, 38400 };
+
+#define MAX_SPEEDS (sizeof(baud_rates)/sizeof(baud_rates[0]))
+
+static struct dongle_driver act220l = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "Actisys ACT-220L",
+	.type		= IRDA_ACTISYS_DONGLE,
+	.open		= actisys_open,
+	.close		= actisys_close,
+	.reset		= actisys_reset,
+	.set_speed	= actisys_change_speed,
+};
+
+static struct dongle_driver act220l_plus = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "Actisys ACT-220L+",
+	.type		= IRDA_ACTISYS_PLUS_DONGLE,
+	.open		= actisys_open,
+	.close		= actisys_close,
+	.reset		= actisys_reset,
+	.set_speed	= actisys_change_speed,
+};
+
+int __init actisys_sir_init(void)
+{
+	int ret;
+
+	/* First, register an Actisys 220L dongle */
+	ret = irda_register_dongle(&act220l);
+	if (ret < 0)
+		return ret;
+
+	/* Now, register an Actisys 220L+ dongle */
+	ret = irda_register_dongle(&act220l_plus);
+	if (ret < 0) {
+		irda_unregister_dongle(&act220l);
+		return ret;
+	}
+	return 0;
+}
+
+void __exit actisys_sir_cleanup(void)
+{
+	/* We have to remove both dongles */
+	irda_unregister_dongle(&act220l_plus);
+	irda_unregister_dongle(&act220l);
+}
+
+static int actisys_open(struct sir_dev *dev)
+{
+	struct qos_info *qos = &dev->qos;
+
+	dev->set_dtr_rts(dev, TRUE, TRUE);
+
+	/* Set the speeds we can accept */
+	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+
+	/* Remove support for 38400 if this is not a 220L+ dongle */
+	if (dev->dongle_drv->type == IRDA_ACTISYS_DONGLE)
+		qos->baud_rate.bits &= ~IR_38400;
+
+	qos->min_turn_time.bits = 0x7f; /* Needs 0.01 ms */
+	irda_qos_bits_to_value(qos);
+
+	return 0;
+}
+
+static int actisys_close(struct sir_dev *dev)
+{
+	/* Power off the dongle */
+	dev->set_dtr_rts(dev, FALSE, FALSE);
+
+	return 0;
+}
+
+/*
+ * Function actisys_change_speed (task)
+ *
+ *    Change speed of the ACTiSYS IR-220L and IR-220L+ type IrDA dongles.
+ *    To cycle through the available baud rates, pulse RTS low for a few us.
+ *
+ *	First, we reset the dongle to always start from a known state.
+ *	Then, we cycle through the speeds by pulsing RTS low and then up.
+ *	The dongle allow us to pulse quite fast, se we can set speed in one go,
+ * which is must faster ( < 100 us) and less complex than what is found
+ * in some other dongle drivers...
+ *	Note that even if the new speed is the same as the current speed,
+ * we reassert the speed. This make sure that things are all right,
+ * and it's fast anyway...
+ *	By the way, this function will work for both type of dongles,
+ * because the additional speed is at the end of the sequence...
+ */
+static int actisys_change_speed(struct sir_dev *dev, unsigned speed)
+{
+	int ret = 0;
+	int i = 0;
+
+        IRDA_DEBUG(4, "%s(), speed=%d (was %d)\n", __FUNCTION__,
+        	speed, dev->speed);
+
+	/* dongle was already resetted from irda_request state machine,
+	 * we are in known state (dongle default)
+	 */
+
+	/* 
+	 * Now, we can set the speed requested. Send RTS pulses until we
+         * reach the target speed 
+	 */
+	for (i=0; i<MAX_SPEEDS; i++) {
+		if (speed == baud_rates[i]) {
+			dev->speed = baud_rates[i];
+			break;
+		}
+		/* Set RTS low for 10 us */
+		dev->set_dtr_rts(dev, TRUE, FALSE);
+		udelay(MIN_DELAY);
+
+		/* Set RTS high for 10 us */
+		dev->set_dtr_rts(dev, TRUE, TRUE);
+		udelay(MIN_DELAY);
+	}
+
+	/* Check if life is sweet... */
+	if (i >= MAX_SPEEDS)
+		ret = -1;  /* This should not happen */
+
+	/* Basta lavoro, on se casse d'ici... */
+	return ret;
+}
+
+/*
+ * Function actisys_reset (task)
+ *
+ *      Reset the Actisys type dongle. Warning, this function must only be
+ *      called with a process context!
+ *
+ * We need to do two things in this function :
+ *	o first make sure that the dongle is in a state where it can operate
+ *	o second put the dongle in a know state
+ *
+ *	The dongle is powered of the RTS and DTR lines. In the dongle, there
+ * is a big capacitor to accomodate the current spikes. This capacitor
+ * takes a least 50 ms to be charged. In theory, the Bios set those lines
+ * up, so by the time we arrive here we should be set. It doesn't hurt
+ * to be on the conservative side, so we will wait...
+ * <Martin : move above comment to irda_config_fsm>
+ *	Then, we set the speed to 9600 b/s to get in a known state (see in
+ * change_speed for details). It is needed because the IrDA stack
+ * has tried to set the speed immediately after our first return,
+ * so before we can be sure the dongle is up and running.
+ */
+
+static int actisys_reset(struct sir_dev *dev)
+{
+	/* Reset the dongle : set DTR low for 10 us */
+	dev->set_dtr_rts(dev, FALSE, TRUE);
+	udelay(MIN_DELAY);
+
+	/* Go back to normal mode */
+	dev->set_dtr_rts(dev, TRUE, TRUE);
+	
+	dev->speed = 9600;	/* That's the default */
+
+	return 0;
+}
+
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no> - Jean Tourrilhes <jt@hpl.hp.com>");
+MODULE_DESCRIPTION("ACTiSYS IR-220L and IR-220L+ dongle driver");	
+MODULE_LICENSE("GPL");
+
+module_init(actisys_sir_init);
+module_exit(actisys_sir_cleanup);
diff -Nru a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c
--- a/drivers/net/irda/donauboe.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/net/irda/donauboe.c	Sun Nov 10 19:28:39 2002
@@ -1825,26 +1825,26 @@
   return 0;
 }
 
-static struct pci_driver toshoboe_pci_driver = {
-  name		: "toshoboe",
-  id_table	: toshoboe_pci_tbl,
-  probe		: toshoboe_open,
-  remove	: toshoboe_close,
-  suspend	: toshoboe_gotosleep,
-  resume	: toshoboe_wakeup 
+static struct pci_driver donauboe_pci_driver = {
+	.name		= "donauboe",
+	.id_table	= toshoboe_pci_tbl,
+	.probe		= toshoboe_open,
+	.remove		= toshoboe_close,
+	.suspend	= toshoboe_gotosleep,
+	.resume		= toshoboe_wakeup 
 };
 
-int __init
-toshoboe_init (void)
+static int __init
+donauboe_init (void)
 {
-  return pci_module_init(&toshoboe_pci_driver);
+  return pci_module_init(&donauboe_pci_driver);
 }
 
-STATIC void __exit
-toshoboe_cleanup (void)
+static void __exit
+donauboe_cleanup (void)
 {
-  pci_unregister_driver(&toshoboe_pci_driver);
+  pci_unregister_driver(&donauboe_pci_driver);
 }
 
-module_init(toshoboe_init);
-module_exit(toshoboe_cleanup);
+module_init(donauboe_init);
+module_exit(donauboe_cleanup);
diff -Nru a/drivers/net/irda/esi-sir.c b/drivers/net/irda/esi-sir.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/irda/esi-sir.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,145 @@
+/*********************************************************************
+ *                
+ * Filename:      esi.c
+ * Version:       1.6
+ * Description:   Driver for the Extended Systems JetEye PC dongle
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Sat Feb 21 18:54:38 1998
+ * Modified at:   Sun Oct 27 22:01:04 2002
+ * Modified by:   Martin Diehl <mad@mdiehl.de>
+ * 
+ *     Copyright (c) 1999 Dag Brattli, <dagb@cs.uit.no>,
+ *     Copyright (c) 1998 Thomas Davis, <ratbert@radiks.net>,
+ *     Copyright (c) 2002 Martin Diehl, <mad@mdiehl.de>,
+ *     All Rights Reserved.
+ *     
+ *     This program is free software; you can redistribute it and/or 
+ *     modify it under the terms of the GNU General Public License as 
+ *     published by the Free Software Foundation; either version 2 of 
+ *     the License, or (at your option) any later version.
+ * 
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *     GNU General Public License for more details.
+ * 
+ *     You should have received a copy of the GNU General Public License 
+ *     along with this program; if not, write to the Free Software 
+ *     Foundation, Inc., 59 Temple Place, Suite 330, Boston, 
+ *     MA 02111-1307 USA
+ *     
+ ********************************************************************/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+
+#include "sir-dev.h"
+
+static int esi_open(struct sir_dev *);
+static int esi_close(struct sir_dev *);
+static int esi_change_speed(struct sir_dev *, unsigned);
+static int esi_reset(struct sir_dev *);
+
+static struct dongle_driver esi = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "JetEye PC ESI-9680 PC",
+	.type		= IRDA_ESI_DONGLE,
+	.open		= esi_open,
+	.close		= esi_close,
+	.reset		= esi_reset,
+	.set_speed	= esi_change_speed,
+};
+
+static int __init esi_sir_init(void)
+{
+	return irda_register_dongle(&esi);
+}
+
+static void __exit esi_sir_cleanup(void)
+{
+	irda_unregister_dongle(&esi);
+}
+
+static int esi_open(struct sir_dev *dev)
+{
+	struct qos_info *qos = &dev->qos;
+
+	qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200;
+	qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */
+	irda_qos_bits_to_value(qos);
+
+	/* shouldn't we do set_dtr_rts(FALSE, TRUE) here (power up at 9600)? */
+
+	return 0;
+}
+
+static int esi_close(struct sir_dev *dev)
+{
+	/* Power off dongle */
+	dev->set_dtr_rts(dev, FALSE, FALSE);
+
+	return 0;
+}
+
+/*
+ * Function esi_change_speed (task)
+ *
+ *    Set the speed for the Extended Systems JetEye PC ESI-9680 type dongle
+ *
+ */
+static int esi_change_speed(struct sir_dev *dev, unsigned speed)
+{
+	int dtr, rts;
+	
+	switch (speed) {
+	case 19200:
+		dtr = TRUE;
+		rts = FALSE;
+		break;
+	case 115200:
+		dtr = rts = TRUE;
+		break;
+	default:
+		speed = 9600;
+		/* fall through */
+	case 9600:
+		dtr = FALSE;
+		rts = TRUE;
+		break;
+	}
+
+	/* Change speed of dongle */
+	dev->set_dtr_rts(dev, dtr, rts);
+	dev->speed = speed;
+
+	/* do we need some delay for power stabilization? */
+
+	return 0;
+}
+
+/*
+ * Function esi_reset (task)
+ *
+ *    Reset dongle;
+ *
+ */
+static int esi_reset(struct sir_dev *dev)
+{
+	dev->set_dtr_rts(dev, FALSE, FALSE);
+
+	/* Hm, probably repower to 9600 and some delays? */
+
+	return 0;
+}
+
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("Extended Systems JetEye PC dongle driver");
+MODULE_LICENSE("GPL");
+
+module_init(esi_sir_init);
+module_exit(esi_sir_cleanup);
+
diff -Nru a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
--- a/drivers/net/irda/irda-usb.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/net/irda/irda-usb.c	Sun Nov 10 19:28:39 2002
@@ -1487,7 +1487,7 @@
 	 * specify an alternate, but very few driver do like this.
 	 * Jean II */
 	ret = usb_set_interface(dev, intf->altsetting->desc.bInterfaceNumber, 0);
-	IRDA_DEBUG(1, "usb-irda: set interface %d result %d\n", intf->altsetting->bInterfaceNumber, ret);
+	IRDA_DEBUG(1, "usb-irda: set interface %d result %d\n", intf->altsetting->desc.bInterfaceNumber, ret);
 	switch (ret) {
 		case 0:
 			break;
diff -Nru a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/irda/irtty-sir.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,684 @@
+/*********************************************************************
+ *                
+ * Filename:      irtty-sir.c
+ * Version:       2.0
+ * Description:   IrDA line discipline implementation
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Tue Dec  9 21:18:38 1997
+ * Modified at:   Sun Oct 27 22:13:30 2002
+ * Modified by:   Martin Diehl <mad@mdiehl.de>
+ * Sources:       slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
+ *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ * 
+ *     Copyright (c) 1998-2000 Dag Brattli,
+ *     Copyright (c) 2002 Martin Diehl,
+ *     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.
+ *  
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ *     
+ ********************************************************************/    
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/tty.h>
+#include <linux/init.h>
+#include <asm/uaccess.h>
+#include <linux/smp_lock.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>
+
+#include "sir-dev.h"
+#include "irtty-sir.h"
+
+MODULE_PARM(qos_mtt_bits, "i");
+MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
+
+static int qos_mtt_bits = 0x03;      /* 5 ms or more */
+
+/* ------------------------------------------------------- */
+
+/* device configuration callbacks always invoked with irda-thread context */
+
+/* find out, how many chars we have in buffers below us
+ * this is allowed to lie, i.e. return less chars than we
+ * actually have. The returned value is used to determine
+ * how long the irdathread should wait before doing the
+ * real blocking wait_until_sent()
+ */
+
+static int irtty_chars_in_buffer(struct sir_dev *dev)
+{
+	struct sirtty_cb *priv = dev->priv;
+
+	ASSERT(priv != NULL, return -1;);
+	ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
+
+	return priv->tty->driver.chars_in_buffer(priv->tty);
+}
+
+/* Wait (sleep) until underlaying hardware finished transmission
+ * i.e. hardware buffers are drained
+ * this must block and not return before all characters are really sent
+ *
+ * If the tty sits on top of a 16550A-like uart, there are typically
+ * up to 16 bytes in the fifo - f.e. 9600 bps 8N1 needs 16.7 msec
+ *
+ * With usbserial the uart-fifo is basically replaced by the converter's
+ * outgoing endpoint buffer, which can usually hold 64 bytes (at least).
+ * With pl2303 it appears we are safe with 60msec here.
+ *
+ * I really wish all serial drivers would provide
+ * correct implementation of wait_until_sent()
+ */
+
+#define USBSERIAL_TX_DONE_DELAY	60
+
+static void irtty_wait_until_sent(struct sir_dev *dev)
+{
+	struct sirtty_cb *priv = dev->priv;
+	struct tty_struct *tty;
+
+	ASSERT(priv != NULL, return;);
+	ASSERT(priv->magic == IRTTY_MAGIC, return;);
+
+	tty = priv->tty;
+	if (tty->driver.wait_until_sent) {
+		lock_kernel();
+		tty->driver.wait_until_sent(tty, MSECS_TO_JIFFIES(100));
+		unlock_kernel();
+	}
+	else {
+		set_task_state(current, TASK_UNINTERRUPTIBLE);
+		schedule_timeout(MSECS_TO_JIFFIES(USBSERIAL_TX_DONE_DELAY));
+	}
+}
+
+/* 
+ *  Function irtty_change_speed (dev, speed)
+ *
+ *    Change the speed of the serial port.
+ *
+ * This may sleep in set_termios (usbserial driver f.e.) and must
+ * not be called from interrupt/timer/tasklet therefore.
+ * All such invocations are deferred to kIrDAd now so we can sleep there.
+ */
+
+static int irtty_change_speed(struct sir_dev *dev, unsigned speed)
+{
+	struct sirtty_cb *priv = dev->priv;
+	struct tty_struct *tty;
+        struct termios old_termios;
+	int cflag;
+
+	ASSERT(priv != NULL, return -1;);
+	ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
+
+	tty = priv->tty;
+
+	lock_kernel();
+	old_termios = *(tty->termios);
+	cflag = tty->termios->c_cflag;
+
+	cflag &= ~CBAUD;
+
+	IRDA_DEBUG(2, "%s(), Setting speed to %d\n", __FUNCTION__, speed);
+
+	switch (speed) {
+	case 1200:
+		cflag |= B1200;
+		break;
+	case 2400:
+		cflag |= B2400;
+		break;
+	case 4800:
+		cflag |= B4800;
+		break;
+	case 19200:
+		cflag |= B19200;
+		break;
+	case 38400:
+		cflag |= B38400;
+		break;
+	case 57600:
+		cflag |= B57600;
+		break;
+	case 115200:
+		cflag |= B115200;
+		break;
+	case 9600:
+	default:
+		cflag |= B9600;
+		break;
+	}	
+
+	tty->termios->c_cflag = cflag;
+	if (tty->driver.set_termios)
+		tty->driver.set_termios(tty, &old_termios);
+	unlock_kernel();
+
+	priv->io.speed = speed;
+
+	return 0;
+}
+
+/*
+ * Function irtty_set_dtr_rts (dev, dtr, rts)
+ *
+ *    This function can be used by dongles etc. to set or reset the status
+ *    of the dtr and rts lines
+ */
+
+static int irtty_set_dtr_rts(struct sir_dev *dev, int dtr, int rts)
+{
+	struct sirtty_cb *priv = dev->priv;
+	int arg = 0;
+
+	ASSERT(priv != NULL, return -1;);
+	ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
+
+#ifdef TIOCM_OUT2 /* Not defined for ARM */
+	arg = TIOCM_OUT2;
+#endif
+	if (rts)
+		arg |= TIOCM_RTS;
+	if (dtr)
+		arg |= TIOCM_DTR;
+
+	/*
+	 * The ioctl() function, or actually set_modem_info() in serial.c
+	 * expects a pointer to the argument in user space. This is working
+	 * here because we are always called from the kIrDAd thread which
+	 * has set_fs(KERNEL_DS) permanently set. Therefore copy_from_user()
+	 * is happy with our arg-parameter being local here in kernel space.
+	 */
+
+	lock_kernel();
+	if (priv->tty->driver.ioctl(priv->tty, NULL, TIOCMSET, (unsigned long) &arg)) { 
+		IRDA_DEBUG(2, "%s(), error doing ioctl!\n", __FUNCTION__);
+	}
+	unlock_kernel();
+
+	return 0;
+}
+
+/* ------------------------------------------------------- */
+
+/* called from sir_dev when there is more data to send
+ * context is either netdev->hard_xmit or some transmit-completion bh
+ * i.e. we are under spinlock here and must not sleep.
+ *
+ * Note: as of 2.5.44 the usb-serial driver calls down() on a semaphore
+ * hence we are hitting the might_sleep bugcatcher. IMHO the whole tty-api
+ * would be pretty pointless if write_room/write would be allowed to sleep.
+ * Furthermore other tty ldiscs (like ppp) do also require the driver not
+ * to sleep there. Hence this is considered a current limitation of
+ * usb-serial.
+ */
+
+static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t len)
+{
+	struct sirtty_cb *priv = dev->priv;
+	struct tty_struct *tty;
+	int writelen;
+
+	ASSERT(priv != NULL, return -1;);
+	ASSERT(priv->magic == IRTTY_MAGIC, return -1;);
+
+	tty = priv->tty;
+	if (!tty->driver.write)
+		return 0;
+	tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
+	if (tty->driver.write_room) {
+		writelen = tty->driver.write_room(tty);
+		if (writelen > len)
+			writelen = len;
+	}
+	else
+		writelen = len;
+	return tty->driver.write(tty, 0, ptr, writelen);
+}
+
+/* ------------------------------------------------------- */
+
+/* irda line discipline callbacks */
+
+/* 
+ *  Function irtty_receive_buf( tty, cp, count)
+ *
+ *    Handle the 'receiver data ready' interrupt.  This function is called
+ *    by the 'tty_io' module in the kernel when a block of IrDA data has
+ *    been received, which can now be decapsulated and delivered for
+ *    further processing 
+ *
+ * calling context depends on underlying driver and tty->low_latency!
+ * for example (low_latency: 1 / 0):
+ * serial.c:	uart-interrupt / softint
+ * usbserial:	urb-complete-interrupt / softint
+ */
+
+static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+			      char *fp, int count) 
+{
+	struct sir_dev *dev;
+	struct sirtty_cb *priv = tty->disc_data;
+	int	i;
+
+	if (unlikely(!priv || priv->magic!=IRTTY_MAGIC))
+		return;
+	/* Please use ASSERT - Fix ASSERT as needed - Jean II */
+
+	if (unlikely(count==0))		/* yes, this happens */
+		return;
+
+	dev = priv->dev;
+	if (!dev) {
+		printk(KERN_ERR "%s(), not ready yet!\n", __FUNCTION__);
+		return;
+	}
+
+	for (i = 0; i < count; i++) {
+		/* 
+		 *  Characters received with a parity error, etc?
+		 */
+ 		if (fp && *fp++) { 
+			IRDA_DEBUG(0, "Framing or parity error!\n");
+			sirdev_receive(dev, NULL, 0);	/* notify sir_dev (updating stats) */
+			return;
+ 		}
+	}
+
+	sirdev_receive(dev, cp, count);
+}
+
+/*
+ * Function irtty_receive_room (tty)
+ *
+ *    Used by the TTY to find out how much data we can receive at a time
+ * 
+*/
+static int irtty_receive_room(struct tty_struct *tty) 
+{
+	struct sirtty_cb *priv = tty->disc_data;
+
+	if (unlikely(!priv || priv->magic!=IRTTY_MAGIC))
+		return 0;
+
+	return 65536;  /* We can handle an infinite amount of data. :-) */
+}
+
+/*
+ * Function irtty_write_wakeup (tty)
+ *
+ *    Called by the driver when there's room for more data.  If we have
+ *    more packets to send, we send them here.
+ *
+ */
+static void irtty_write_wakeup(struct tty_struct *tty) 
+{
+	struct sirtty_cb *priv = tty->disc_data;
+
+	if (unlikely(!priv || priv->magic!=IRTTY_MAGIC))
+		return;
+
+	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+
+	if (priv->dev)
+		sirdev_write_complete(priv->dev);
+}
+
+/* ------------------------------------------------------- */
+
+/*
+ * Function irtty_stop_receiver (tty, stop)
+ *
+ */
+
+static inline void irtty_stop_receiver(struct tty_struct *tty, int stop)
+{
+	struct termios old_termios;
+	int cflag;
+
+	lock_kernel();
+	old_termios = *(tty->termios);
+	cflag = tty->termios->c_cflag;
+	
+	if (stop)
+		cflag &= ~CREAD;
+	else
+		cflag |= CREAD;
+
+	tty->termios->c_cflag = cflag;
+	if (tty->driver.set_termios)
+		tty->driver.set_termios(tty, &old_termios);
+	unlock_kernel();
+}
+
+/*****************************************************************/
+
+DECLARE_MUTEX(irtty_sem);		/* serialize ldisc open/close with sir_dev */
+
+/* notifier from sir_dev when irda% device gets opened (ifup) */
+
+static int irtty_start_dev(struct sir_dev *dev)
+{
+	struct sirtty_cb *priv;
+	struct tty_struct *tty;
+
+	/* serialize with ldisc open/close */
+	down(&irtty_sem);
+
+	priv = dev->priv;
+	if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
+		up(&irtty_sem);
+		return -ESTALE;
+	}
+
+	tty = priv->tty;
+
+	if (tty->driver.start)
+		tty->driver.start(tty);
+	/* Make sure we can receive more data */
+	irtty_stop_receiver(tty, FALSE);
+
+	up(&irtty_sem);
+	return 0;
+}
+
+/* notifier from sir_dev when irda% device gets closed (ifdown) */
+
+static int irtty_stop_dev(struct sir_dev *dev)
+{
+	struct sirtty_cb *priv;
+	struct tty_struct *tty;
+
+	/* serialize with ldisc open/close */
+	down(&irtty_sem);
+
+	priv = dev->priv;
+	if (unlikely(!priv || priv->magic!=IRTTY_MAGIC)) {
+		up(&irtty_sem);
+		return -ESTALE;
+	}
+
+	tty = priv->tty;
+
+	/* Make sure we don't receive more data */
+	irtty_stop_receiver(tty, TRUE);
+	if (tty->driver.stop)
+		tty->driver.stop(tty);
+
+	up(&irtty_sem);
+
+	return 0;
+}
+
+/* ------------------------------------------------------- */
+
+struct sir_driver sir_tty_drv = {
+	.owner			= THIS_MODULE,
+	.driver_name		= "sir_tty",
+	.start_dev		= irtty_start_dev,
+	.stop_dev		= irtty_stop_dev,
+	.do_write		= irtty_do_write,
+	.chars_in_buffer	= irtty_chars_in_buffer,
+	.wait_until_sent	= irtty_wait_until_sent,
+	.set_speed		= irtty_change_speed,
+	.set_dtr_rts		= irtty_set_dtr_rts,
+};
+
+/* ------------------------------------------------------- */
+
+/*
+ * Function irtty_ioctl (tty, file, cmd, arg)
+ *
+ *     The Swiss army knife of system calls :-)
+ *
+ */
+static int irtty_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct irtty_info { char name[6]; } info;
+	struct sir_dev *dev;
+	struct sirtty_cb *priv = tty->disc_data;
+	int size = _IOC_SIZE(cmd);
+	int err = 0;
+
+	ASSERT(priv != NULL, return -ENODEV;);
+	ASSERT(priv->magic == IRTTY_MAGIC, return -EBADR;);
+
+	IRDA_DEBUG(3, "%s(cmd=0x%X)\n", __FUNCTION__, cmd);
+
+	dev = priv->dev;
+	ASSERT(dev != NULL, return -1;);
+
+	if (_IOC_DIR(cmd) & _IOC_READ)
+		err = verify_area(VERIFY_WRITE, (void *) arg, size);
+	else if (_IOC_DIR(cmd) & _IOC_WRITE)
+		err = verify_area(VERIFY_READ, (void *) arg, size);
+	if (err)
+		return err;
+	
+	switch (cmd) {
+	case TCGETS:
+	case TCGETA:
+		err = n_tty_ioctl(tty, file, cmd, arg);
+		break;
+
+	case IRTTY_IOCTDONGLE:
+		/* this call blocks for completion */
+		err = sirdev_set_dongle(dev, (IRDA_DONGLE) arg);
+		break;
+
+	case IRTTY_IOCGET:
+		ASSERT(dev->netdev != NULL, return -1;);
+
+		memset(&info, 0, sizeof(info)); 
+		strncpy(info.name, dev->netdev->name, sizeof(info.name)-1);
+
+		if (copy_to_user((void *)arg, &info, sizeof(info)))
+			err = -EFAULT;
+		break;
+	default:
+		err = -ENOIOCTLCMD;
+		break;
+	}
+	return err;
+}
+
+
+/* 
+ *  Function irtty_open(tty)
+ *
+ *    This function is called by the TTY module when the IrDA line
+ *    discipline is called for.  Because we are sure the tty line exists,
+ *    we only have to link it to a free IrDA channel.  
+ */
+static int irtty_open(struct tty_struct *tty) 
+{
+	struct sir_dev *dev;
+	struct sirtty_cb *priv;
+	char hwname[16];
+	int ret = 0;
+
+	/* unfortunately, there's no tty_ldisc->owner field
+	 * so there is some window for SMP race with rmmod
+	 */
+	MOD_INC_USE_COUNT;
+
+	/* First make sure we're not already connected. */
+	if (tty->disc_data != NULL) {
+		priv = tty->disc_data;
+		if (priv && priv->magic == IRTTY_MAGIC) {
+			ret = -EEXIST;
+			goto out;
+		}
+		tty->disc_data = NULL;		/* ### */
+	}
+
+	/* stop the underlying  driver */
+	irtty_stop_receiver(tty, TRUE);
+	if (tty->driver.stop)
+		tty->driver.stop(tty);
+
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	
+/* from old irtty - but what is it good for?
+ * we _are_ the ldisc and we _dont_ implement flush_buffer!
+ *
+ *	if (tty->ldisc.flush_buffer)
+ *		tty->ldisc.flush_buffer(tty);
+ */
+
+
+	/* create device name - could we use tty_name() here? */
+
+	if (strchr(tty->driver.name, '%')) {
+		sprintf(hwname, tty->driver.name,
+			minor(tty->device) - tty->driver.minor_start +
+			tty->driver.name_base);
+	}
+	else {
+		sprintf(hwname, "%s%d", tty->driver.name,
+			minor(tty->device) - tty->driver.minor_start +
+			tty->driver.name_base);
+	}
+
+	/* apply mtt override */
+	sir_tty_drv.qos_mtt_bits = qos_mtt_bits;
+
+	/* get a sir device instance for this driver */
+	dev = sirdev_get_instance(&sir_tty_drv, hwname);
+	if (!dev) {
+		ret = -ENODEV;
+		goto out;
+	}
+
+	/* allocate private device info block */
+	priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		goto out_put;
+	memset(priv, 0, sizeof(*priv));
+
+	priv->magic = IRTTY_MAGIC;
+	priv->tty = tty;
+	priv->dev = dev;
+
+	/* serialize with start_dev - in case we were racing with ifup */
+	down(&irtty_sem);
+
+	dev->priv = priv;
+	tty->disc_data = priv;
+
+	up(&irtty_sem);
+
+	printk(KERN_INFO "%s - done\n", __FUNCTION__);
+
+	return 0;
+
+out_put:
+	sirdev_put_instance(dev);
+out:
+	MOD_DEC_USE_COUNT;
+	return ret;
+}
+
+/* 
+ *  Function irtty_close (tty)
+ *
+ *    Close down a IrDA channel. This means flushing out any pending queues,
+ *    and then restoring the TTY line discipline to what it was before it got
+ *    hooked to IrDA (which usually is TTY again).  
+ */
+static void irtty_close(struct tty_struct *tty) 
+{
+	struct sirtty_cb *priv = tty->disc_data;
+
+	if (!priv  ||  priv->magic != IRTTY_MAGIC)
+		return;
+
+	/* Hm, with a dongle attached the dongle driver wants
+	 * to close the dongle - which requires the use of
+	 * some tty write and/or termios or ioctl operations.
+	 * Are we allowed to call those when already requested
+	 * to shutdown the ldisc?
+	 * If not, we should somehow mark the dev being staled.
+	 * Question remains, how to close the dongle in this case...
+	 * For now let's assume we are granted to issue tty driver calls
+	 * until we return here from the ldisc close. I'm just wondering
+	 * how this behaves with hotpluggable serial hardware like
+	 * rs232-pcmcia card or usb-serial...
+	 *
+	 * priv->tty = NULL?;
+	 */
+
+	/* we are dead now */
+	tty->disc_data = 0;
+
+	sirdev_put_instance(priv->dev);
+
+	/* Stop tty */
+	irtty_stop_receiver(tty, TRUE);
+	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
+	if (tty->driver.stop)
+		tty->driver.stop(tty);
+
+	kfree(priv);
+
+	MOD_DEC_USE_COUNT;
+}
+
+/* ------------------------------------------------------- */
+
+static struct tty_ldisc irda_ldisc = {
+	.magic		= TTY_LDISC_MAGIC,
+ 	.name		= "irda",
+	.flags		= 0,
+	.open		= irtty_open,
+	.close		= irtty_close,
+	.read		= NULL,
+	.write		= NULL,
+	.ioctl		= irtty_ioctl,
+ 	.poll		= NULL,
+	.receive_buf	= irtty_receive_buf,
+	.receive_room	= irtty_receive_room,
+	.write_wakeup	= irtty_write_wakeup,
+};
+
+/* ------------------------------------------------------- */
+
+static int __init irtty_sir_init(void)
+{
+	int err;
+
+	if ((err = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0)
+		ERROR("IrDA: can't register line discipline (err = %d)\n",
+			err);
+	return err;
+}
+
+static void __exit irtty_sir_cleanup(void) 
+{
+	int err;
+
+	if ((err = tty_register_ldisc(N_IRDA, NULL))) {
+		ERROR("%s(), can't unregister line discipline (err = %d)\n",
+		      __FUNCTION__, err);
+	}
+}
+
+module_init(irtty_sir_init);
+module_exit(irtty_sir_cleanup);
+
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("IrDA TTY device driver");
+MODULE_LICENSE("GPL");
+
diff -Nru a/drivers/net/irda/irtty-sir.h b/drivers/net/irda/irtty-sir.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/irda/irtty-sir.h	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,34 @@
+/*********************************************************************
+ *
+ *	sir_tty.h:	definitions for the irtty_sir client driver (former irtty)
+ *
+ *	Copyright (c) 2002 Martin Diehl
+ *
+ *	This program is free software; you can redistribute it and/or 
+ *	modify it under the terms of the 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 IRTTYSIR_H
+#define IRTTYSIR_H
+
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>		// chipio_t
+
+#define IRTTY_IOC_MAGIC 'e'
+#define IRTTY_IOCTDONGLE  _IO(IRTTY_IOC_MAGIC, 1)
+#define IRTTY_IOCGET     _IOR(IRTTY_IOC_MAGIC, 2, struct irtty_info)
+#define IRTTY_IOC_MAXNR   2
+
+struct sirtty_cb {
+	magic_t magic;
+
+	struct sir_dev *dev;
+	struct tty_struct  *tty;
+
+	chipio_t io;               /* IrDA controller information */
+};
+
+#endif
diff -Nru a/drivers/net/irda/sir-dev.h b/drivers/net/irda/sir-dev.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/irda/sir-dev.h	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,203 @@
+/*********************************************************************
+ *
+ *	sir.h:	include file for irda-sir device abstraction layer
+ *
+ *	Copyright (c) 2002 Martin Diehl
+ *
+ *	This program is free software; you can redistribute it and/or 
+ *	modify it under the terms of the 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 IRDA_SIR_H
+#define IRDA_SIR_H
+
+#include <linux/netdevice.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/irda_device.h>		// iobuff_t
+
+/* FIXME: unify irda_request with sir_fsm! */
+
+struct irda_request {
+	struct list_head lh_request;
+	unsigned long pending;
+	void (*func)(void *);
+	void *data;
+	struct timer_list timer;
+};
+
+struct sir_fsm {
+	struct semaphore	sem;
+	struct irda_request	rq;
+	unsigned		state, substate;
+	int			param;
+	int			result;
+};
+
+#define SIRDEV_STATE_WAIT_TX_COMPLETE	0x0100
+
+/* substates for wait_tx_complete */
+#define SIRDEV_STATE_WAIT_XMIT		0x0101
+#define SIRDEV_STATE_WAIT_UNTIL_SENT	0x0102
+#define SIRDEV_STATE_TX_DONE		0x0103
+
+#define SIRDEV_STATE_DONGLE_OPEN		0x0300
+
+/* 0x0301-0x03ff reserved for individual dongle substates */
+
+#define SIRDEV_STATE_DONGLE_CLOSE	0x0400
+
+/* 0x0401-0x04ff reserved for individual dongle substates */
+
+#define SIRDEV_STATE_SET_DTR_RTS		0x0500
+
+#define SIRDEV_STATE_SET_SPEED		0x0700
+#define SIRDEV_STATE_DONGLE_CHECK	0x0800
+#define SIRDEV_STATE_DONGLE_RESET	0x0900
+
+/* 0x0901-0x09ff reserved for individual dongle substates */
+
+#define SIRDEV_STATE_DONGLE_SPEED	0x0a00
+/* 0x0a01-0x0aff reserved for individual dongle substates */
+
+#define SIRDEV_STATE_PORT_SPEED		0x0b00
+#define SIRDEV_STATE_DONE		0x0c00
+#define SIRDEV_STATE_ERROR		0x0d00
+#define SIRDEV_STATE_COMPLETE		0x0e00
+
+#define SIRDEV_STATE_DEAD		0xffff
+
+
+struct sir_dev;
+
+struct dongle_driver {
+
+	struct module *owner;
+
+	const char *driver_name;
+
+	IRDA_DONGLE type;
+
+	int	(*open)(struct sir_dev *dev);
+	int	(*close)(struct sir_dev *dev);
+	int	(*reset)(struct sir_dev *dev);
+	int	(*set_speed)(struct sir_dev *dev, unsigned speed);
+
+	struct list_head dongle_list;
+};
+
+struct sir_driver {
+
+	struct module *owner;
+
+	const char *driver_name;
+
+	int qos_mtt_bits;
+
+	int (*chars_in_buffer)(struct sir_dev *dev);
+	void (*wait_until_sent)(struct sir_dev *dev);
+	int (*set_speed)(struct sir_dev *dev, unsigned speed);
+	int (*set_dtr_rts)(struct sir_dev *dev, int dtr, int rts);
+
+	int (*do_write)(struct sir_dev *dev, const unsigned char *ptr, size_t len);
+
+	int (*start_dev)(struct sir_dev *dev);
+	int (*stop_dev)(struct sir_dev *dev);
+};
+
+
+/* exported */
+
+extern int irda_register_dongle(struct dongle_driver *new);
+extern int irda_unregister_dongle(struct dongle_driver *drv);
+
+extern struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *name);
+extern int sirdev_put_instance(struct sir_dev *self);
+
+extern int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type);
+extern void sirdev_write_complete(struct sir_dev *dev);
+extern int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count);
+
+/* not exported */
+
+extern int sirdev_get_dongle(struct sir_dev *self, IRDA_DONGLE type);
+extern int sirdev_put_dongle(struct sir_dev *self);
+
+extern int sirdev_raw_write(struct sir_dev *dev, const char *buf, int len);
+extern int sirdev_raw_read(struct sir_dev *dev, char *buf, int len);
+extern void sirdev_enable_rx(struct sir_dev *dev);
+
+extern int sirdev_schedule_request(struct sir_dev *dev, int state, unsigned param);
+extern int __init irda_thread_create(void);
+extern void __exit irda_thread_join(void);
+
+/* inline helpers */
+
+static inline int sirdev_schedule_speed(struct sir_dev *dev, unsigned speed)
+{
+	return sirdev_schedule_request(dev, SIRDEV_STATE_SET_SPEED, speed);
+}
+
+static inline int sirdev_schedule_dongle_open(struct sir_dev *dev, int dongle_id)
+{
+	return sirdev_schedule_request(dev, SIRDEV_STATE_DONGLE_OPEN, dongle_id);
+}
+
+static inline int sirdev_schedule_dongle_close(struct sir_dev *dev)
+{
+	return sirdev_schedule_request(dev, SIRDEV_STATE_DONGLE_CLOSE, 0);
+}
+
+static inline int sirdev_schedule_dtr_rts(struct sir_dev *dev, int dtr, int rts)
+{
+	int	dtrrts;
+
+	dtrrts = ((dtr) ? 0x02 : 0x00) | ((rts) ? 0x01 : 0x00);
+	return sirdev_schedule_request(dev, SIRDEV_STATE_SET_DTR_RTS, dtrrts);
+}
+
+#if 0
+static inline int sirdev_schedule_mode(struct sir_dev *dev, int mode)
+{
+	return sirdev_schedule_request(dev, SIRDEV_STATE_SET_MODE, mode);
+}
+#endif
+
+
+struct sir_dev {
+	struct net_device *netdev;
+	struct net_device_stats stats;
+
+	struct irlap_cb    *irlap;
+
+	struct qos_info qos;
+
+	char hwname[32];
+
+	struct sir_fsm fsm;
+	atomic_t enable_rx;
+	spinlock_t tx_lock;
+
+	u32 new_speed;
+ 	u32 flags;
+
+	unsigned	speed;
+
+	iobuff_t tx_buff;          /* Transmit buffer */
+	iobuff_t rx_buff;          /* Receive buffer */
+	struct sk_buff *tx_skb;
+
+	const struct dongle_driver * dongle_drv;
+	const struct sir_driver * drv;
+	void *priv;
+
+	/* dongle callbacks to the SIR device */
+	int (*read)(struct sir_dev *, char *buf, int len);
+	int (*write)(struct sir_dev *, const char *buf, int len);
+	int (*set_dtr_rts)(struct sir_dev *, int dtr, int rts);
+};
+
+#endif	/* IRDA_SIR_H */
diff -Nru a/drivers/net/irda/sir_core.c b/drivers/net/irda/sir_core.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/irda/sir_core.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,52 @@
+/*********************************************************************
+ *
+ *	sir_core.c:	module core for irda-sir abstraction layer
+ *
+ *	Copyright (c) 2002 Martin Diehl
+ * 
+ *	This program is free software; you can redistribute it and/or 
+ *	modify it under the terms of the 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/kernel.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+
+#include "sir-dev.h"
+
+/***************************************************************************/
+
+MODULE_AUTHOR("Martin Diehl <info@mdiehl.de>");
+MODULE_DESCRIPTION("IrDA SIR core");
+MODULE_LICENSE("GPL");
+
+/***************************************************************************/
+
+EXPORT_SYMBOL(irda_register_dongle);
+EXPORT_SYMBOL(irda_unregister_dongle);
+
+EXPORT_SYMBOL(sirdev_get_instance);
+EXPORT_SYMBOL(sirdev_put_instance);
+
+EXPORT_SYMBOL(sirdev_set_dongle);
+EXPORT_SYMBOL(sirdev_write_complete);
+EXPORT_SYMBOL(sirdev_receive);
+
+static int __init sir_core_init(void)
+{
+	return irda_thread_create();
+}
+
+static void __exit sir_core_exit(void)
+{
+	irda_thread_join();
+}
+
+module_init(sir_core_init);
+module_exit(sir_core_exit);
+
diff -Nru a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/irda/sir_dev.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,673 @@
+/*********************************************************************
+ *
+ *	sir_dev.c:	irda sir network device
+ * 
+ *	Copyright (c) 2002 Martin Diehl
+ * 
+ *	This program is free software; you can redistribute it and/or 
+ *	modify it under the terms of the 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/kernel.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+
+#include <net/irda/irda.h>
+#include <net/irda/wrapper.h>
+#include <net/irda/irda_device.h>
+
+#include "sir-dev.h"
+
+/***************************************************************************/
+
+void sirdev_enable_rx(struct sir_dev *dev)
+{
+	if (unlikely(atomic_read(&dev->enable_rx)))
+		return;
+
+	/* flush rx-buffer - should also help in case of problems with echo cancelation */
+	dev->rx_buff.data = dev->rx_buff.head;
+	dev->tx_buff.len = 0;
+	atomic_set(&dev->enable_rx, 1);
+}
+
+static int sirdev_is_receiving(struct sir_dev *dev)
+{
+	if (!atomic_read(&dev->enable_rx))
+		return 0;
+
+	return (dev->rx_buff.state != OUTSIDE_FRAME);
+}
+
+int sirdev_set_dongle(struct sir_dev *dev, IRDA_DONGLE type)
+{
+	int err;
+
+	IRDA_DEBUG(3, "%s : requesting dongle %d.\n", __FUNCTION__, type);
+
+	err = sirdev_schedule_dongle_open(dev, type);
+	if (unlikely(err))
+		return err;
+	down(&dev->fsm.sem);		/* block until config change completed */
+	err = dev->fsm.result;
+	up(&dev->fsm.sem);
+	return err;
+}
+
+/* used by dongle drivers for dongle programming */
+
+int sirdev_raw_write(struct sir_dev *dev, const char *buf, int len)
+{
+	int ret;
+
+	if (unlikely(len > dev->tx_buff.truesize))
+		return -ENOSPC;
+
+	spin_lock_bh(&dev->tx_lock);		/* serialize with other tx operations */
+	while (dev->tx_buff.len > 0) {		/* wait until tx idle */
+		spin_unlock_bh(&dev->tx_lock);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(MSECS_TO_JIFFIES(10));
+		spin_lock_bh(&dev->tx_lock);
+	}
+
+	dev->tx_buff.data = dev->tx_buff.head;
+	memcpy(dev->tx_buff.data, buf, len);	
+
+	ret = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len);
+	spin_unlock_bh(&dev->tx_lock);
+	return ret;
+}
+
+/* seems some dongle drivers may need this */
+
+int sirdev_raw_read(struct sir_dev *dev, char *buf, int len)
+{
+	int count;
+
+	if (atomic_read(&dev->enable_rx))
+		return -EIO;		/* fail if we expect irda-frames */
+
+	count = (len < dev->rx_buff.len) ? len : dev->rx_buff.len;
+
+	if (count > 0)
+		memcpy(buf, dev->rx_buff.head, count);
+
+	/* forget trailing stuff */
+	dev->rx_buff.data = dev->rx_buff.head;
+	dev->rx_buff.len = 0;
+	dev->rx_buff.state = OUTSIDE_FRAME;
+
+	return count;
+}
+
+/**********************************************************************/
+
+/* called from client driver - likely with bh-context - to indicate
+ * it made some progress with transmission. Hence we send the next
+ * chunk, if any, or complete the skb otherwise
+ */
+
+void sirdev_write_complete(struct sir_dev *dev)
+{
+	struct sk_buff *skb;
+	int actual = 0;
+	int err;
+	
+	spin_lock_bh(&dev->tx_lock);
+
+	IRDA_DEBUG(3, "%s() - dev->tx_buff.len = %d\n",
+		   __FUNCTION__, dev->tx_buff.len);
+
+	if (likely(dev->tx_buff.len > 0))  {
+		/* Write data left in transmit buffer */
+		actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len);
+
+		if (likely(actual>0)) {
+			dev->tx_buff.data += actual;
+			dev->tx_buff.len  -= actual;
+		}
+		else if (unlikely(actual<0)) {
+			/* could be dropped later when we have tx_timeout to recover */
+			ERROR("%s: drv->do_write failed (%d)\n", __FUNCTION__, actual);
+			if ((skb=dev->tx_skb) != NULL) {
+				dev->tx_skb = NULL;
+				dev_kfree_skb_any(skb);
+				dev->stats.tx_errors++;		      
+				dev->stats.tx_dropped++;		      
+			}
+			dev->tx_buff.len = 0;
+		}
+		if (dev->tx_buff.len > 0) {
+			spin_unlock_bh(&dev->tx_lock);
+			return;
+		}
+	}
+
+	/* we have finished now sending this skb.
+	 * update statistics and free the skb.
+	 * finally we check and trigger a pending speed change, if any.
+	 * if not we switch to rx mode and wake the queue for further
+	 * packets.
+	 * note the scheduled speed request blocks until the lower
+	 * client driver and the corresponding hardware has really
+	 * finished sending all data (xmit fifo drained f.e.)
+	 * before the speed change gets finally done and the queue
+	 * re-activated.
+	 */
+
+	IRDA_DEBUG(5, "%s(), finished with frame!\n", __FUNCTION__);
+		
+	if ((skb=dev->tx_skb) != NULL) {
+		dev->tx_skb = NULL;
+		dev->stats.tx_packets++;		      
+		dev->stats.tx_bytes += skb->len;
+		dev_kfree_skb_any(skb);
+	}
+
+	if (unlikely(dev->new_speed > 0)) {
+		IRDA_DEBUG(5, "%s(), Changing speed!\n", __FUNCTION__);
+		err = sirdev_schedule_speed(dev, dev->new_speed);
+		if (unlikely(err)) {
+			/* should never happen
+			 * forget the speed change and hope the stack recovers
+			 */
+			ERROR("%s - schedule speed change failed: %d\n", __FUNCTION__, err);
+			netif_wake_queue(dev->netdev);
+		}
+		/* else: success
+		 *	speed change in progress now
+		 *	on completion dev->new_speed gets cleared,
+		 *	rx-reenabled and the queue restarted
+		 */
+	}
+	else {
+		sirdev_enable_rx(dev);
+		netif_wake_queue(dev->netdev);
+	}
+
+	spin_unlock_bh(&dev->tx_lock);
+}
+
+/* called from client driver - likely with bh-context - to give us
+ * some more received bytes. We put them into the rx-buffer,
+ * normally unwrapping and building LAP-skb's (unless rx disabled)
+ */
+
+int sirdev_receive(struct sir_dev *dev, const unsigned char *cp, size_t count) 
+{
+	if (!dev || !dev->netdev) {
+		IRDA_DEBUG(0, "%s(), not ready yet!\n", __FUNCTION__);
+		/* Use WARNING instead of IRDA_DEBUG */
+		return -1;
+	}
+
+	if (!dev->irlap) {
+		IRDA_DEBUG(0, "%s - too early: %p / %d!\n", __FUNCTION__, cp, count);
+		/* Use WARNING instead of IRDA_DEBUG */
+		return -1;
+	}
+
+	if (cp==NULL) {
+		/* error already at lower level receive
+		 * just update stats and set media busy
+		 */
+		irda_device_set_media_busy(dev->netdev, TRUE);
+		dev->stats.rx_dropped++;
+		printk(KERN_INFO "%s; rx-drop: %d\n", __FUNCTION__, count);
+		return 0;
+	}
+
+	/* Read the characters into the buffer */
+ 	while (count--) {
+		if (likely(atomic_read(&dev->enable_rx))) {
+			/* Unwrap and destuff one byte */
+			async_unwrap_char(dev->netdev, &dev->stats, 
+				  &dev->rx_buff, *cp++);
+		}
+		else {
+			/* rx not enabled: save the raw bytes and never
+			 * trigger any netif_rx. The received bytes are flushed
+			 * later when we re-enable rx but might be read meanwhile
+			 * by the dongle driver.
+			 */
+			dev->rx_buff.data[dev->rx_buff.len++] = *cp++;
+		}
+
+		/* What should we do when the buffer is full? */
+		if (unlikely(dev->rx_buff.len == dev->rx_buff.truesize))
+			dev->rx_buff.len = 0;
+			
+	}
+
+	return 0;
+}
+
+/**********************************************************************/
+
+/* callbacks from network layer */
+
+static struct net_device_stats *sirdev_get_stats(struct net_device *ndev)
+{
+	struct sir_dev *dev = ndev->priv;
+
+	return (dev) ? &dev->stats : NULL;
+}
+
+static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+	struct sir_dev *dev = ndev->priv;
+	int actual = 0;
+	int err;
+	s32 speed;
+
+	ASSERT(dev != NULL, return 0;);
+
+	netif_stop_queue(ndev);
+
+	IRDA_DEBUG(3, "%s(), skb->len = %d\n", __FUNCTION__, skb->len);
+
+	speed = irda_get_next_speed(skb);
+	if ((speed != dev->speed) && (speed != -1)) {
+		if (!skb->len) {
+			err = sirdev_schedule_speed(dev, speed);
+			if (unlikely(err == -EWOULDBLOCK)) {
+				/* Failed to initiate the speed change, likely the fsm
+				 * is still busy (pretty unlikely, but...)
+				 * We refuse to accept the skb and return with the queue
+				 * stopped so the network layer will retry after the
+				 * fsm completes and wakes the queue.
+				 */
+				 return 1;
+			}
+			else if (unlikely(err)) {
+				/* other fatal error - forget the speed change and
+				 * hope the stack will recover somehow
+				 */
+				 netif_start_queue(ndev);
+			}
+			/* else: success
+			 *	speed change in progress now
+			 *	on completion the queue gets restarted
+			 */
+
+			dev_kfree_skb_any(skb);
+			return 0;
+		} else
+			dev->new_speed = speed;
+	}
+
+	/* Init tx buffer*/
+	dev->tx_buff.data = dev->tx_buff.head;
+
+	/* Check problems */
+	if(spin_is_locked(&dev->tx_lock)) {
+		IRDA_DEBUG(3, "%s(), write not completed\n", __FUNCTION__);
+	}
+
+	/* serialize with write completion */
+	spin_lock_bh(&dev->tx_lock);
+
+        /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
+	dev->tx_buff.len = async_wrap_skb(skb, dev->tx_buff.data, dev->tx_buff.truesize); 
+
+	/* transmission will start now - disable receive.
+	 * if we are just in the middle of an incoming frame,
+	 * treat it as collision. probably it's a good idea to
+	 * reset the rx_buf OUTSIDE_FRAME in this case too?
+	 */
+	atomic_set(&dev->enable_rx, 0);
+	if (unlikely(sirdev_is_receiving(dev)))
+		dev->stats.collisions++;
+
+	actual = dev->drv->do_write(dev, dev->tx_buff.data, dev->tx_buff.len);
+
+	if (likely(actual > 0)) {
+		dev->tx_skb = skb;
+		ndev->trans_start = jiffies;
+		dev->tx_buff.data += actual;
+		dev->tx_buff.len -= actual;
+	}
+	else if (unlikely(actual < 0)) {
+		/* could be dropped later when we have tx_timeout to recover */
+		ERROR("%s: drv->do_write failed (%d)\n", __FUNCTION__, actual);
+		dev_kfree_skb_any(skb);
+		dev->stats.tx_errors++;		      
+		dev->stats.tx_dropped++;		      
+		netif_wake_queue(ndev);
+	}
+	spin_unlock_bh(&dev->tx_lock);
+
+	return 0;
+}
+
+/* called from network layer with rtnl hold */
+
+static int sirdev_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *) rq;
+	struct sir_dev *dev = ndev->priv;
+	int ret = 0;
+
+	ASSERT(dev != NULL, return -1;);
+
+	IRDA_DEBUG(3, "%s(), %s, (cmd=0x%X)\n", __FUNCTION__, ndev->name, cmd);
+	
+	switch (cmd) {
+	case SIOCSBANDWIDTH: /* Set bandwidth */
+		if (!capable(CAP_NET_ADMIN))
+			ret = -EPERM;
+		else
+			ret = sirdev_schedule_speed(dev, irq->ifr_baudrate);
+		/* cannot sleep here for completion
+		 * we are called from network layer with rtnl hold
+		 */
+		break;
+
+	case SIOCSDONGLE: /* Set dongle */
+		if (!capable(CAP_NET_ADMIN))
+			ret = -EPERM;
+		else
+			ret = sirdev_schedule_dongle_open(dev, irq->ifr_dongle);
+		/* cannot sleep here for completion
+		 * we are called from network layer with rtnl hold
+		 */
+		break;
+
+	case SIOCSMEDIABUSY: /* Set media busy */
+		if (!capable(CAP_NET_ADMIN))
+			ret = -EPERM;
+		else
+			irda_device_set_media_busy(dev->netdev, TRUE);
+		break;
+
+	case SIOCGRECEIVING: /* Check if we are receiving right now */
+		irq->ifr_receiving = sirdev_is_receiving(dev);
+		break;
+
+	case SIOCSDTRRTS:
+		if (!capable(CAP_NET_ADMIN))
+			ret = -EPERM;
+		else
+			ret = sirdev_schedule_dtr_rts(dev, irq->ifr_dtr, irq->ifr_rts);
+		/* cannot sleep here for completion
+		 * we are called from network layer with rtnl hold
+		 */
+		break;
+
+	case SIOCSMODE:
+#if 0
+		if (!capable(CAP_NET_ADMIN))
+			ret = -EPERM;
+		else
+			ret = sirdev_schedule_mode(dev, irq->ifr_mode);
+		/* cannot sleep here for completion
+		 * we are called from network layer with rtnl hold
+		 */
+		break;
+#endif
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	
+	return ret;
+}
+
+/* ----------------------------------------------------------------------------- */
+
+#define SIRBUF_ALLOCSIZE 4269	/* worst case size of a wrapped IrLAP frame */
+
+static int sirdev_alloc_buffers(struct sir_dev *dev)
+{
+	dev->rx_buff.truesize = SIRBUF_ALLOCSIZE; 
+	dev->tx_buff.truesize = SIRBUF_ALLOCSIZE;
+
+	dev->rx_buff.head = kmalloc(dev->rx_buff.truesize, GFP_KERNEL);
+	if (dev->rx_buff.head == NULL)
+		return -ENOMEM;
+	memset(dev->rx_buff.head, 0, dev->rx_buff.truesize);
+
+	dev->tx_buff.head = kmalloc(dev->tx_buff.truesize, GFP_KERNEL);
+	if (dev->tx_buff.head == NULL) {
+		kfree(dev->rx_buff.head);
+		dev->rx_buff.head = NULL;
+		return -ENOMEM;
+		memset(dev->tx_buff.head, 0, dev->tx_buff.truesize);
+	}
+
+	dev->tx_buff.data = dev->tx_buff.head;
+	dev->rx_buff.data = dev->rx_buff.head;
+	dev->tx_buff.len = 0;
+	dev->rx_buff.len = 0;
+
+	dev->rx_buff.in_frame = FALSE;
+	dev->rx_buff.state = OUTSIDE_FRAME;
+	return 0;
+};
+
+static void sirdev_free_buffers(struct sir_dev *dev)
+{
+	if (dev->rx_buff.head)
+		kfree(dev->rx_buff.head);
+	if (dev->tx_buff.head)
+		kfree(dev->tx_buff.head);
+	dev->rx_buff.head = dev->tx_buff.head = NULL;
+}
+
+static int sirdev_open(struct net_device *ndev)
+{
+	struct sir_dev *dev = ndev->priv;
+	const struct sir_driver *drv = dev->drv;
+
+	if (!drv)
+		return -ENODEV;
+
+	lock_kernel();		/* serialize with rmmod */
+	/* increase the reference count of the driver module before doing serious stuff */
+	if (drv->owner  &&  !try_inc_mod_count(drv->owner)) {
+		unlock_kernel();
+		return -ESTALE;
+	}
+	unlock_kernel();
+
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+
+	if (sirdev_alloc_buffers(dev))
+		goto errout_dec;
+
+	if (!dev->drv->start_dev  ||  dev->drv->start_dev(dev))
+		goto errout_free;
+
+	sirdev_enable_rx(dev);
+
+	netif_start_queue(ndev);
+	dev->irlap = irlap_open(ndev, &dev->qos, dev->hwname);
+	if (!dev->irlap)
+		goto errout_stop;
+
+	netif_wake_queue(ndev);
+
+	printk(KERN_INFO "%s - done, speed = %d\n", __FUNCTION__, dev->speed);
+
+	return 0;
+
+errout_stop:
+	atomic_set(&dev->enable_rx, 0);
+	if (dev->drv->stop_dev)
+		dev->drv->stop_dev(dev);
+errout_free:
+	sirdev_free_buffers(dev);
+errout_dec:
+	if (drv->owner)
+		__MOD_DEC_USE_COUNT(drv->owner);
+	return -EAGAIN;
+}
+
+static int sirdev_close(struct net_device *ndev)
+{
+	struct sir_dev *dev = ndev->priv;
+	const struct sir_driver *drv;
+
+	printk(KERN_INFO "%s\n", __FUNCTION__);
+
+	netif_stop_queue(ndev);
+
+	down(&dev->fsm.sem);		/* block on pending config completion */
+
+	atomic_set(&dev->enable_rx, 0);
+
+	if (unlikely(!dev->irlap))
+		goto out;
+	irlap_close(dev->irlap);
+	dev->irlap = NULL;
+
+	drv = dev->drv;
+	if (unlikely(!drv  ||  !dev->priv))
+		goto out;
+
+	if (drv->stop_dev)
+		drv->stop_dev(dev);
+
+	sirdev_free_buffers(dev);
+
+	lock_kernel();
+	if (drv->owner)
+		__MOD_DEC_USE_COUNT(drv->owner);
+	unlock_kernel();
+
+out:
+	dev->speed = 0;
+	up(&dev->fsm.sem);
+	return 0;
+}
+
+/* ----------------------------------------------------------------------------- */
+
+static int sirdev_init(struct net_device *ndev)
+{
+	struct sir_dev *dev = ndev->priv;
+
+	SET_MODULE_OWNER(ndev);
+
+	/* Set up to be a normal IrDA network device driver */
+	irda_device_setup(ndev);
+
+	dev->flags = IFF_SIR | IFF_PIO;
+
+	/* Override the network functions we need to use */
+	ndev->hard_start_xmit = sirdev_hard_xmit;
+	ndev->open = sirdev_open;
+	ndev->stop = sirdev_close;
+	ndev->get_stats = sirdev_get_stats;
+	ndev->do_ioctl = sirdev_ioctl;
+
+	return 0;
+}
+
+
+struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *name)
+{
+	struct net_device *ndev;
+	struct sir_dev *dev;
+
+	printk(KERN_INFO "%s - %s\n", __FUNCTION__, name);
+
+	/* instead of adding tests to protect against drv->do_write==NULL
+	 * at several places we refuse to create a sir_dev instance for
+	 * drivers which dont implement do_write.
+	 */
+	if (!drv ||  !drv->do_write)
+		return NULL;
+
+	/*
+	 *  Allocate new instance of the device
+	 */
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (dev == NULL) {
+		printk(KERN_ERR "IrDA: Can't allocate memory for "
+		       "IrDA control block!\n");
+		goto out;
+	}
+	memset(dev, 0, sizeof(*dev));
+
+	irda_init_max_qos_capabilies(&dev->qos);
+	dev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+	dev->qos.min_turn_time.bits = drv->qos_mtt_bits;
+	irda_qos_bits_to_value(&dev->qos);
+
+	strncpy(dev->hwname, name, sizeof(dev->hwname)-1);
+
+	ndev = kmalloc(sizeof(*ndev), GFP_KERNEL);
+	if (ndev == NULL)
+		goto out_freedev;
+	memset(ndev, 0, sizeof(*ndev));
+
+	atomic_set(&dev->enable_rx, 0);
+	dev->tx_skb = NULL;
+
+	spin_lock_init(&dev->tx_lock);
+	init_MUTEX(&dev->fsm.sem);
+
+	INIT_LIST_HEAD(&dev->fsm.rq.lh_request);
+	dev->fsm.rq.pending = 0;
+	init_timer(&dev->fsm.rq.timer);
+
+	dev->drv = drv;
+	dev->netdev = ndev;
+
+	ndev->priv = (void *) dev;
+	ndev->init = sirdev_init;
+
+	strcpy(ndev->name, "irda%d");
+	if (register_netdev(ndev)) {
+		ERROR("%s(), register_netdev() failed!\n", __FUNCTION__);
+		goto out_freenetdev;
+	}
+
+	return dev;
+
+out_freenetdev:
+	kfree(ndev);
+out_freedev:
+	kfree(dev);
+out:
+	return NULL;
+}
+
+int sirdev_put_instance(struct sir_dev *dev)
+{
+	int err = 0;
+
+	printk(KERN_INFO "%s\n", __FUNCTION__);
+
+	atomic_set(&dev->enable_rx, 0);
+
+	netif_carrier_off(dev->netdev);
+	netif_device_detach(dev->netdev);
+
+	if (dev->dongle_drv)
+		err = sirdev_schedule_dongle_close(dev);
+	if (err)
+		ERROR("%s - error %d\n", __FUNCTION__, err);
+
+	sirdev_close(dev->netdev);
+
+	down(&dev->fsm.sem);
+	dev->fsm.state = SIRDEV_STATE_DEAD;	/* mark staled */
+	dev->dongle_drv = NULL;
+	dev->priv = NULL;
+	up(&dev->fsm.sem);
+
+	/* Remove netdevice */
+	if (dev->netdev)
+		unregister_netdev(dev->netdev);
+
+	kfree(dev);
+
+	return 0;
+}
+
diff -Nru a/drivers/net/irda/sir_dongle.c b/drivers/net/irda/sir_dongle.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/irda/sir_dongle.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,146 @@
+/*********************************************************************
+ *
+ *	sir_dongle.c:	manager for serial dongle protocol drivers
+ *
+ *	Copyright (c) 2002 Martin Diehl
+ *
+ *	This program is free software; you can redistribute it and/or 
+ *	modify it under the terms of the 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/kernel.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/kmod.h>
+
+#include <net/irda/irda.h>
+
+#include "sir-dev.h"
+
+/**************************************************************************
+ *
+ * dongle registration and attachment
+ *
+ */
+
+static LIST_HEAD(dongle_list);			/* list of registered dongle drivers */
+static DECLARE_MUTEX(dongle_list_lock);		/* protects the list */
+
+int irda_register_dongle(struct dongle_driver *new)
+{
+	struct list_head *entry;
+	struct dongle_driver *drv;
+
+	IRDA_DEBUG(0, "%s : registering dongle \"%s\" (%d).\n",
+		   __FUNCTION__, new->driver_name, new->type);
+
+	down(&dongle_list_lock);
+	list_for_each(entry, &dongle_list) {
+		drv = list_entry(entry, struct dongle_driver, dongle_list);
+		if (new->type == drv->type) {
+			up(&dongle_list_lock);
+			return -EEXIST;
+		}
+	}
+	list_add(&new->dongle_list, &dongle_list);
+	up(&dongle_list_lock);
+	return 0;
+}
+
+int irda_unregister_dongle(struct dongle_driver *drv)
+{
+	down(&dongle_list_lock);
+	list_del(&drv->dongle_list);
+	up(&dongle_list_lock);
+	return 0;
+}
+
+int sirdev_get_dongle(struct sir_dev *dev, IRDA_DONGLE type)
+{
+	struct list_head *entry;
+	const struct dongle_driver *drv = NULL;
+	int err = -EINVAL;
+
+#ifdef CONFIG_KMOD
+	char modname[30];
+
+	sprintf(modname, "irda-dongle-%d", type);
+	request_module(modname);
+#endif
+
+	if (dev->dongle_drv != NULL)
+		return -EBUSY;
+	
+	/* serialize access to the list of registered dongles */
+	down(&dongle_list_lock);
+
+	list_for_each(entry, &dongle_list) {
+		drv = list_entry(entry, struct dongle_driver, dongle_list);
+		if (drv->type == type)
+			break;
+		else
+			drv = NULL;
+	}
+
+	if (!drv) {
+		err = -ENODEV;
+		goto out_unlock;	/* no such dongle */
+	}
+
+	/* handling of SMP races with dongle module removal - three cases:
+	 * 1) dongle driver was already unregistered - then we haven't found the
+	 *	requested dongle above and are already out here
+	 * 2) the module is already marked deleted but the driver is still
+	 *	registered - then the try_inc_mod_count() below will fail
+	 * 3) the try_inc_mod_count() below succeeds before the module is marked
+	 *	deleted - then sys_delete_module() fails and prevents the removal
+	 *	because the module is in use.
+	 */
+
+	if (drv->owner && !try_inc_mod_count(drv->owner)) {
+		err = -ESTALE;
+		goto out_unlock;	/* rmmod already pending */
+	}
+
+	/* Initialize dongle driver callbacks */
+	dev->read        = sirdev_raw_read;
+	dev->write       = sirdev_raw_write;
+	dev->set_dtr_rts = dev->drv->set_dtr_rts;
+
+	dev->dongle_drv = drv;
+
+	if (!drv->open  ||  (err=drv->open(dev))!=0)
+		goto out_reject;		/* failed to open driver */
+
+	up(&dongle_list_lock);
+	return 0;
+
+out_reject:
+	dev->dongle_drv = NULL;
+	if (drv->owner)
+		__MOD_DEC_USE_COUNT(drv->owner);
+out_unlock:
+	up(&dongle_list_lock);
+	return err;
+}
+
+int sirdev_put_dongle(struct sir_dev *dev)
+{
+	const struct dongle_driver *drv = dev->dongle_drv;
+
+	if (drv) {
+		if (drv->close)
+			drv->close(dev);		/* close this dongle instance */
+
+		dev->dongle_drv = NULL;			/* unlink the dongle driver */
+
+		if (drv->owner)
+			__MOD_DEC_USE_COUNT(drv->owner);/* decrement driver's module refcount */
+	}
+
+	return 0;
+}
diff -Nru a/drivers/net/irda/sir_kthread.c b/drivers/net/irda/sir_kthread.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/irda/sir_kthread.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,543 @@
+/*********************************************************************
+ *
+ *	sir_kthread.c:		dedicated thread to process scheduled
+ *				sir device setup requests
+ *
+ *	Copyright (c) 2002 Martin Diehl
+ *
+ *	This program is free software; you can redistribute it and/or 
+ *	modify it under the terms of the 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/kernel.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include <net/irda/irda.h>
+
+#include "sir-dev.h"
+
+/**************************************************************************
+ *
+ * kIrDAd kernel thread and config state machine
+ *
+ */
+
+struct irda_request_queue {
+	struct list_head request_list;
+	spinlock_t lock;
+	task_t *thread;
+	struct completion exit;
+	wait_queue_head_t kick, done;
+	atomic_t num_pending;
+};
+
+static struct irda_request_queue irda_rq_queue;
+
+static int irda_queue_request(struct irda_request *rq)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	if (!test_and_set_bit(0, &rq->pending)) {
+		spin_lock_irqsave(&irda_rq_queue.lock, flags);
+		list_add_tail(&rq->lh_request, &irda_rq_queue.request_list);
+		wake_up(&irda_rq_queue.kick);
+		atomic_inc(&irda_rq_queue.num_pending);
+		spin_unlock_irqrestore(&irda_rq_queue.lock, flags);
+		ret = 1;
+	}
+	return ret;
+}
+
+static void irda_request_timer(unsigned long data)
+{
+	struct irda_request *rq = (struct irda_request *)data;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&irda_rq_queue.lock, flags);
+	list_add_tail(&rq->lh_request, &irda_rq_queue.request_list);
+	wake_up(&irda_rq_queue.kick);
+	spin_unlock_irqrestore(&irda_rq_queue.lock, flags);
+}
+
+static int irda_queue_delayed_request(struct irda_request *rq, unsigned long delay)
+{
+	int ret = 0;
+	struct timer_list *timer = &rq->timer;
+
+	if (!test_and_set_bit(0, &rq->pending)) {
+		timer->expires = jiffies + delay;
+		timer->function = irda_request_timer;
+		timer->data = (unsigned long)rq;
+		atomic_inc(&irda_rq_queue.num_pending);
+		add_timer(timer);
+		ret = 1;
+	}
+	return ret;
+}
+
+static void run_irda_queue(void)
+{
+	unsigned long flags;
+	struct list_head *entry, *tmp;
+	struct irda_request *rq;
+
+	spin_lock_irqsave(&irda_rq_queue.lock, flags);
+	list_for_each_safe(entry, tmp, &irda_rq_queue.request_list) {
+		rq = list_entry(entry, struct irda_request, lh_request);
+		list_del_init(entry);
+		spin_unlock_irqrestore(&irda_rq_queue.lock, flags);
+
+		clear_bit(0, &rq->pending);
+		rq->func(rq->data);
+
+		if (atomic_dec_and_test(&irda_rq_queue.num_pending))
+			wake_up(&irda_rq_queue.done);
+
+		spin_lock_irqsave(&irda_rq_queue.lock, flags);
+	}
+	spin_unlock_irqrestore(&irda_rq_queue.lock, flags);
+}		
+
+static int irda_rt_prio = 0;		/* MODULE_PARM? */
+
+static int irda_thread(void *startup)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	daemonize();
+	strcpy(current->comm, "kIrDAd");
+
+	spin_lock_irq(&current->sig->siglock);
+	sigfillset(&current->blocked);
+	recalc_sigpending();
+	spin_unlock_irq(&current->sig->siglock);
+
+	set_fs(KERNEL_DS);
+
+	if (irda_rt_prio > 0) {
+#if 0		/* works but requires EXPORT_SYMBOL(setscheduler) */
+		struct sched_param param;
+
+		param.sched_priority = irda_rt_prio;
+		setscheduler(0, SCHED_FIFO, &param);
+#endif
+
+#if 0		/* doesn't work - has some tendency to trigger instant reboot!
+		 * looks like we would have to deactivate current on the
+		 * runqueue - which is only possible inside of kernel/sched.h
+		 */
+
+		/* runqueues are per-cpu and we are current on this cpu. Hence
+		 * The tasklist_lock with irq-off protects our runqueue too
+		 * and we don't have to lock it (which would be impossible,
+		 * because it is private in kernel/sched.c)
+		 */
+
+		read_lock_irq(&tasklist_lock);
+		current->rt_priority = (irda_rt_prio<MAX_RT_PRIO)
+					? irda_rt_prio : MAX_RT_PRIO-1;
+		current->policy = SCHED_FIFO;
+		current->prio = MAX_USER_RT_PRIO-1 - irda_rt_prio;
+		read_unlock_irq(&tasklist_lock);
+#endif
+	}
+
+	irda_rq_queue.thread = current;
+
+	complete((struct completion *)startup);
+
+	while (irda_rq_queue.thread != NULL) {
+
+		set_task_state(current, TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&irda_rq_queue.kick, &wait);
+		if (list_empty(&irda_rq_queue.request_list))
+			schedule();
+		else
+			set_task_state(current, TASK_RUNNING);
+		remove_wait_queue(&irda_rq_queue.kick, &wait);
+
+		run_irda_queue();
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,35)
+	reparent_to_init();
+#endif
+	complete_and_exit(&irda_rq_queue.exit, 0);
+	/* never reached */
+	return 0;
+}
+
+
+static void flush_irda_queue(void)
+{
+	if (atomic_read(&irda_rq_queue.num_pending)) {
+
+		DECLARE_WAITQUEUE(wait, current);
+
+		if (!list_empty(&irda_rq_queue.request_list))
+			run_irda_queue();
+
+		set_task_state(current, TASK_UNINTERRUPTIBLE);
+		add_wait_queue(&irda_rq_queue.done, &wait);
+		if (atomic_read(&irda_rq_queue.num_pending))
+			schedule();
+		else
+			set_task_state(current, TASK_RUNNING);
+		remove_wait_queue(&irda_rq_queue.done, &wait);
+	}
+}
+
+/* substate handler of the config-fsm to handle the cases where we want
+ * to wait for transmit completion before changing the port configuration
+ */
+
+static int irda_tx_complete_fsm(struct sir_dev *dev)
+{
+	struct sir_fsm *fsm = &dev->fsm;
+	unsigned next_state, delay;
+	unsigned bytes_left;
+
+	do {
+		next_state = fsm->substate;	/* default: stay in current substate */
+		delay = 0;
+
+		switch(fsm->substate) {
+
+		case SIRDEV_STATE_WAIT_XMIT:
+			if (dev->drv->chars_in_buffer)
+				bytes_left = dev->drv->chars_in_buffer(dev);
+			else
+				bytes_left = 0;
+			if (!bytes_left) {
+				next_state = SIRDEV_STATE_WAIT_UNTIL_SENT;
+				break;
+			}
+
+			if (dev->speed > 115200)
+				delay = (bytes_left*8*10000) / (dev->speed/100);
+			else if (dev->speed > 0)
+				delay = (bytes_left*10*10000) / (dev->speed/100);
+			else
+				delay = 0;
+			/* expected delay (usec) until remaining bytes are sent */
+			if (delay < 100) {
+				udelay(delay);
+				delay = 0;
+				break;
+			}
+			/* sleep some longer delay (msec) */
+			delay = (delay+999) / 1000;
+			break;
+
+		case SIRDEV_STATE_WAIT_UNTIL_SENT:
+			/* block until underlaying hardware buffer are empty */
+			if (dev->drv->wait_until_sent)
+				dev->drv->wait_until_sent(dev);
+			next_state = SIRDEV_STATE_TX_DONE;
+			break;
+
+		case SIRDEV_STATE_TX_DONE:
+			return 0;
+
+		default:
+			ERROR("%s - undefined state\n", __FUNCTION__);
+			return -EINVAL;
+		}
+		fsm->substate = next_state;
+	} while (delay == 0);
+	return delay;
+}
+
+/*
+ * Function irda_config_fsm
+ *
+ * State machine to handle the configuration of the device (and attached dongle, if any).
+ * This handler is scheduled for execution in kIrDAd context, so we can sleep.
+ * however, kIrDAd is shared by all sir_dev devices so we better don't sleep there too
+ * long. Instead, for longer delays we start a timer to reschedule us later.
+ * On entry, fsm->sem is always locked and the netdev xmit queue stopped.
+ * Both must be unlocked/restarted on completion - but only on final exit.
+ */
+
+static void irda_config_fsm(void *data)
+{
+	struct sir_dev *dev = data;
+	struct sir_fsm *fsm = &dev->fsm;
+	int next_state;
+	int ret = -1;
+	unsigned delay;
+
+	IRDA_DEBUG(2, "%s(), <%ld>\n", __FUNCTION__, jiffies); 
+
+	do {
+		IRDA_DEBUG(3, "%s - state=0x%04x / substate=0x%04x\n",
+			__FUNCTION__, fsm->state, fsm->substate);
+
+		next_state = fsm->state;
+		delay = 0;
+
+		switch(fsm->state) {
+
+		case SIRDEV_STATE_DONGLE_OPEN:
+			if (dev->dongle_drv != NULL) {
+				ret = sirdev_put_dongle(dev);
+				if (ret) {
+					fsm->result = -EINVAL;
+					next_state = SIRDEV_STATE_ERROR;
+					break;
+				}
+			}
+
+			/* Initialize dongle */
+			ret = sirdev_get_dongle(dev, fsm->param);
+			if (ret) {
+				fsm->result = ret;
+				next_state = SIRDEV_STATE_ERROR;
+				break;
+			}
+
+			/* Dongles are powered through the modem control lines which
+			 * were just set during open. Before resetting, let's wait for
+			 * the power to stabilize. This is what some dongle drivers did
+			 * in open before, while others didn't - should be safe anyway.
+			 */
+
+			delay = 50;
+			fsm->substate = SIRDEV_STATE_DONGLE_RESET;
+			next_state = SIRDEV_STATE_DONGLE_RESET;
+
+			fsm->param = 9600;
+
+			break;
+
+		case SIRDEV_STATE_DONGLE_CLOSE:
+			/* shouldn't we just treat this as success=? */
+			if (dev->dongle_drv == NULL) {
+				fsm->result = -EINVAL;
+				next_state = SIRDEV_STATE_ERROR;
+				break;
+			}
+
+			ret = sirdev_put_dongle(dev);
+			if (ret) {
+				fsm->result = ret;
+				next_state = SIRDEV_STATE_ERROR;
+				break;
+			}
+			next_state = SIRDEV_STATE_DONE;
+			break;
+
+		case SIRDEV_STATE_SET_DTR_RTS:
+			if (dev->drv->set_dtr_rts) {
+				int	dtr, rts;
+
+				dtr = (fsm->param&0x02) ? TRUE : FALSE;
+				rts = (fsm->param&0x01) ? TRUE : FALSE;
+				ret = dev->drv->set_dtr_rts(dev,dtr,rts);
+			}
+			else
+				ret = -EINVAL;
+			next_state = SIRDEV_STATE_DONE;
+			break;
+
+		case SIRDEV_STATE_SET_SPEED:
+			fsm->substate = SIRDEV_STATE_WAIT_XMIT;
+			next_state = SIRDEV_STATE_DONGLE_CHECK;
+			break;
+
+		case SIRDEV_STATE_DONGLE_CHECK:
+			ret = irda_tx_complete_fsm(dev);
+			if (ret < 0) {
+				fsm->result = ret;
+				next_state = SIRDEV_STATE_ERROR;
+				break;
+			}
+			if ((delay=ret) != 0)
+				break;
+
+			if (dev->dongle_drv) {
+				fsm->substate = SIRDEV_STATE_DONGLE_RESET;
+				next_state = SIRDEV_STATE_DONGLE_RESET;
+			}
+			else {
+				dev->speed = fsm->param;
+				next_state = SIRDEV_STATE_PORT_SPEED;
+			}
+			break;
+
+		case SIRDEV_STATE_DONGLE_RESET:
+			if (dev->dongle_drv->reset) {
+				ret = dev->dongle_drv->reset(dev);	
+				if (ret < 0) {
+					fsm->result = ret;
+					next_state = SIRDEV_STATE_ERROR;
+					break;
+				}
+			}
+			else
+				ret = 0;
+			if ((delay=ret) == 0) {
+				/* set serial port according to dongle default speed */
+				if (dev->drv->set_speed)
+					dev->drv->set_speed(dev, dev->speed);
+				fsm->substate = SIRDEV_STATE_DONGLE_SPEED;
+				next_state = SIRDEV_STATE_DONGLE_SPEED;
+			}
+			break;
+
+		case SIRDEV_STATE_DONGLE_SPEED:				
+			if (dev->dongle_drv->reset) {
+				ret = dev->dongle_drv->set_speed(dev, fsm->param);
+				if (ret < 0) {
+					fsm->result = ret;
+					next_state = SIRDEV_STATE_ERROR;
+					break;
+				}
+			}
+			else
+				ret = 0;
+			if ((delay=ret) == 0)
+				next_state = SIRDEV_STATE_PORT_SPEED;
+			break;
+
+		case SIRDEV_STATE_PORT_SPEED:
+			/* Finally we are ready to change the serial port speed */
+			if (dev->drv->set_speed)
+				dev->drv->set_speed(dev, dev->speed);
+			dev->new_speed = 0;
+			next_state = SIRDEV_STATE_DONE;
+			break;
+
+		case SIRDEV_STATE_DONE:
+			/* Signal network layer so it can send more frames */
+			netif_wake_queue(dev->netdev);
+			next_state = SIRDEV_STATE_COMPLETE;
+			break;
+
+		default:
+			ERROR("%s - undefined state\n", __FUNCTION__);
+			fsm->result = -EINVAL;
+			/* fall thru */
+
+		case SIRDEV_STATE_ERROR:
+			ERROR("%s - error: %d\n", __FUNCTION__, fsm->result);
+
+#if 0	/* don't enable this before we have netdev->tx_timeout to recover */
+			netif_stop_queue(dev->netdev);
+#else
+			netif_wake_queue(dev->netdev);
+#endif
+			/* fall thru */
+
+		case SIRDEV_STATE_COMPLETE:
+			/* config change finished, so we are not busy any longer */
+			sirdev_enable_rx(dev);
+			printk(KERN_INFO "%s - up\n", __FUNCTION__);
+			up(&fsm->sem);
+			return;
+		}
+		fsm->state = next_state;
+	} while(!delay);
+
+	irda_queue_delayed_request(&fsm->rq, MSECS_TO_JIFFIES(delay));
+}
+
+/* schedule some device configuration task for execution by kIrDAd
+ * on behalf of the above state machine.
+ * can be called from process or interrupt/tasklet context.
+ */
+
+int sirdev_schedule_request(struct sir_dev *dev, int initial_state, unsigned param)
+{
+	struct sir_fsm *fsm = &dev->fsm;
+	int xmit_was_down;
+
+//	IRDA_DEBUG(2, "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param);
+
+	printk(KERN_INFO "%s - state=0x%04x / param=%u\n", __FUNCTION__, initial_state, param);
+
+	if (in_interrupt()) {
+		if (down_trylock(&fsm->sem)) {
+			IRDA_DEBUG(1, "%s(), state machine busy!\n", __FUNCTION__);
+			return -EWOULDBLOCK;
+		}
+	}
+	else
+		down(&fsm->sem);
+	printk(KERN_INFO "%s - down\n", __FUNCTION__);
+
+	if (fsm->state == SIRDEV_STATE_DEAD) {
+		/* race with sirdev_close should never happen */
+		ERROR("%s(), instance staled!\n", __FUNCTION__);
+		printk(KERN_INFO "%s - up\n", __FUNCTION__);
+		up(&fsm->sem);
+		return -ESTALE;		/* or better EPIPE? */
+	}
+
+	xmit_was_down = netif_queue_stopped(dev->netdev);
+	netif_stop_queue(dev->netdev);
+	atomic_set(&dev->enable_rx, 0);
+
+	fsm->state = initial_state;
+	fsm->param = param;
+	fsm->result = 0;
+
+	INIT_LIST_HEAD(&fsm->rq.lh_request);
+	fsm->rq.pending = 0;
+	fsm->rq.func = irda_config_fsm;
+	fsm->rq.data = dev;
+
+	if (!irda_queue_request(&fsm->rq)) {	/* returns 0 on error! */
+		atomic_set(&dev->enable_rx, 1);
+		if (!xmit_was_down)
+			netif_wake_queue(dev->netdev);		
+		printk(KERN_INFO "%s - up\n", __FUNCTION__);
+		up(&fsm->sem);
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+int __init irda_thread_create(void)
+{
+	struct completion startup;
+	int pid;
+
+	spin_lock_init(&irda_rq_queue.lock);
+	irda_rq_queue.thread = NULL;
+	INIT_LIST_HEAD(&irda_rq_queue.request_list);
+	init_waitqueue_head(&irda_rq_queue.kick);
+	init_waitqueue_head(&irda_rq_queue.done);
+	atomic_set(&irda_rq_queue.num_pending, 0);
+
+	init_completion(&startup);
+	pid = kernel_thread(irda_thread, &startup, CLONE_FS|CLONE_FILES);
+	if (pid <= 0)
+		return -EAGAIN;
+	else
+		wait_for_completion(&startup);
+
+	return 0;
+}
+
+void __exit irda_thread_join(void) 
+{
+	if (irda_rq_queue.thread) {
+		flush_irda_queue();
+		init_completion(&irda_rq_queue.exit);
+		irda_rq_queue.thread = NULL;
+		wake_up(&irda_rq_queue.kick);		
+		wait_for_completion(&irda_rq_queue.exit);
+	}
+}
+
diff -Nru a/drivers/net/irda/tekram-sir.c b/drivers/net/irda/tekram-sir.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/irda/tekram-sir.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,265 @@
+/*********************************************************************
+ *                
+ * Filename:      tekram.c
+ * Version:       1.3
+ * Description:   Implementation of the Tekram IrMate IR-210B dongle
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Wed Oct 21 20:02:35 1998
+ * Modified at:   Sun Oct 27 22:02:38 2002
+ * Modified by:   Martin Diehl <mad@mdiehl.de>
+ * 
+ *     Copyright (c) 1998-1999 Dag Brattli,
+ *     Copyright (c) 2002 Martin Diehl,
+ *     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.
+ *  
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ *     
+ ********************************************************************/
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+
+#include <net/irda/irda.h>
+
+#include "sir-dev.h"
+
+MODULE_PARM(tekram_delay, "i");
+MODULE_PARM_DESC(tekram_delay, "tekram dongle write complete delay");
+static int tekram_delay = 50;		/* default is 50 ms */
+
+static int tekram_open(struct sir_dev *);
+static int tekram_close(struct sir_dev *);
+static int tekram_change_speed(struct sir_dev *, unsigned);
+static int tekram_reset(struct sir_dev *);
+
+#define TEKRAM_115200 0x00
+#define TEKRAM_57600  0x01
+#define TEKRAM_38400  0x02
+#define TEKRAM_19200  0x03
+#define TEKRAM_9600   0x04
+
+#define TEKRAM_PW     0x10 /* Pulse select bit */
+
+static struct dongle_driver tekram = {
+	.owner		= THIS_MODULE,
+	.driver_name	= "Tekram IR-210B",
+	.type		= IRDA_TEKRAM_DONGLE,
+	.open		= tekram_open,
+	.close		= tekram_close,
+	.reset		= tekram_reset,
+	.set_speed	= tekram_change_speed,
+};
+
+int __init tekram_sir_init(void)
+{
+	if (tekram_delay < 1  ||  tekram_delay>500)
+		tekram_delay = 200;
+	return irda_register_dongle(&tekram);
+}
+
+void __exit tekram_sir_cleanup(void)
+{
+	irda_unregister_dongle(&tekram);
+}
+
+#define TEKRAM_STATE_POWERED	(SIRDEV_STATE_DONGLE_OPEN + 1)
+
+static int tekram_open(struct sir_dev *dev)
+{
+	unsigned delay = 0;
+	unsigned next_state = dev->fsm.substate;
+	struct qos_info *qos = &dev->qos;
+
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+
+	switch(dev->fsm.substate) {
+
+	case SIRDEV_STATE_DONGLE_OPEN:
+		dev->set_dtr_rts(dev, TRUE, TRUE);
+		next_state = TEKRAM_STATE_POWERED;
+		delay = 50;
+		break;
+
+	case TEKRAM_STATE_POWERED:
+		qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
+		qos->min_turn_time.bits = 0x01; /* Needs at least 10 ms */	
+		irda_qos_bits_to_value(qos);
+		return 0;
+
+	default:
+		ERROR("%s - undefined state\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	dev->fsm.substate = next_state;
+
+	return delay;
+}
+
+static int tekram_close(struct sir_dev *dev)
+{
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+
+	/* Power off dongle */
+	dev->set_dtr_rts(dev, FALSE, FALSE);
+
+	return 0;
+}
+
+/*
+ * Function tekram_change_speed (dev, state, speed)
+ *
+ *    Set the speed for the Tekram IRMate 210 type dongle. Warning, this 
+ *    function must be called with a process context!
+ *
+ *    Algorithm
+ *    1. clear DTR 
+ *    2. set RTS, and wait at least 7 us
+ *    3. send Control Byte to the IR-210 through TXD to set new baud rate
+ *       wait until the stop bit of Control Byte is sent (for 9600 baud rate, 
+ *       it takes about 100 msec)
+ *
+ *	[oops, why 100 msec? sending 1 byte (10 bits) takes 1.05 msec
+ *	 - is this probably to compensate for delays in tty layer?]
+ *
+ *    5. clear RTS (return to NORMAL Operation)
+ *    6. wait at least 50 us, new setting (baud rate, etc) takes effect here 
+ *       after
+ */
+
+#define TEKRAM_STATE_WAIT_SPEED	(SIRDEV_STATE_DONGLE_SPEED + 1)
+
+static int tekram_change_speed(struct sir_dev *dev, unsigned speed)
+{
+	unsigned delay = 0;
+	unsigned next_state = dev->fsm.substate;
+	u8 byte;
+	
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+
+	switch(dev->fsm.substate) {
+
+	case SIRDEV_STATE_DONGLE_SPEED:
+
+		switch (speed) {
+		default:
+			speed = 9600;
+			/* fall thru */
+		case 9600:
+			byte = TEKRAM_PW|TEKRAM_9600;
+			break;
+		case 19200:
+			byte = TEKRAM_PW|TEKRAM_19200;
+			break;
+		case 38400:
+			byte = TEKRAM_PW|TEKRAM_38400;
+			break;
+		case 57600:
+			byte = TEKRAM_PW|TEKRAM_57600;
+			break;
+		case 115200:
+			byte = TEKRAM_115200;
+			break;
+		}
+
+		/* Set DTR, Clear RTS */
+		dev->set_dtr_rts(dev, TRUE, FALSE);
+	
+		/* Wait at least 7us */
+		udelay(14);
+
+		/* Write control byte */
+		dev->write(dev, &byte, 1);
+		
+		dev->speed = speed;
+
+		next_state = TEKRAM_STATE_WAIT_SPEED;
+		delay = tekram_delay;		/* default: 50 ms */
+		break;
+
+	case TEKRAM_STATE_WAIT_SPEED:
+		/* Set DTR, Set RTS */
+		dev->set_dtr_rts(dev, TRUE, TRUE);
+
+		udelay(50);
+
+		return 0;
+
+	default:
+		ERROR("%s - undefined state\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	dev->fsm.substate = next_state;
+
+	return delay;
+}
+
+/*
+ * Function tekram_reset (driver)
+ *
+ *      This function resets the tekram dongle. Warning, this function 
+ *      must be called with a process context!! 
+ *
+ *      Algorithm:
+ *    	  0. Clear RTS and DTR, and wait 50 ms (power off the IR-210 )
+ *        1. clear RTS 
+ *        2. set DTR, and wait at least 1 ms 
+ *        3. clear DTR to SPACE state, wait at least 50 us for further 
+ *         operation
+ */
+
+
+#define TEKRAM_STATE_WAIT_RESET	(SIRDEV_STATE_DONGLE_RESET + 1)
+
+static int tekram_reset(struct sir_dev *dev)
+{
+	unsigned delay = 0;
+	unsigned next_state = dev->fsm.substate;
+
+	IRDA_DEBUG(2, "%s()\n", __FUNCTION__);
+
+	switch(dev->fsm.substate) {
+
+	case SIRDEV_STATE_DONGLE_RESET:
+		/* Clear DTR, Set RTS */
+		dev->set_dtr_rts(dev, FALSE, TRUE); 
+
+		next_state = TEKRAM_STATE_WAIT_RESET;
+		delay = 1;		/* Should sleep 1 ms */
+		break;
+
+	case TEKRAM_STATE_WAIT_RESET:
+		/* Set DTR, Set RTS */
+		dev->set_dtr_rts(dev, TRUE, TRUE);
+	
+		/* Wait at least 50 us */
+		udelay(75);
+
+		return 0;
+
+	default:
+		ERROR("%s - undefined state\n", __FUNCTION__);
+		return -EINVAL;
+	}
+
+	dev->fsm.substate = next_state;
+
+	return delay;
+}
+
+MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
+MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver");
+MODULE_LICENSE("GPL");
+		
+module_init(tekram_sir_init);
+module_exit(tekram_sir_cleanup);
diff -Nru a/drivers/net/mace.c b/drivers/net/mace.c
--- a/drivers/net/mace.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/net/mace.c	Sun Nov 10 19:28:38 2002
@@ -362,6 +362,24 @@
     return 0;
 }
 
+static inline void mace_clean_rings(struct mace_data *mp)
+{
+    int i;
+
+    /* free some skb's */
+    for (i = 0; i < N_RX_RING; ++i) {
+	if (mp->rx_bufs[i] != 0) {
+	    dev_kfree_skb(mp->rx_bufs[i]);
+	    mp->rx_bufs[i] = 0;
+	}
+    }
+    for (i = mp->tx_empty; i != mp->tx_fill; ) {
+	dev_kfree_skb(mp->tx_bufs[i]);
+	if (++i >= N_TX_RING)
+	    i = 0;
+    }
+}
+
 static int mace_open(struct net_device *dev)
 {
     struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -430,24 +448,6 @@
     out_8(&mb->imr, RCVINT);
 
     return 0;
-}
-
-static inline void mace_clean_rings(struct mace_data *mp)
-{
-    int i;
-
-    /* free some skb's */
-    for (i = 0; i < N_RX_RING; ++i) {
-	if (mp->rx_bufs[i] != 0) {
-	    dev_kfree_skb(mp->rx_bufs[i]);
-	    mp->rx_bufs[i] = 0;
-	}
-    }
-    for (i = mp->tx_empty; i != mp->tx_fill; ) {
-	dev_kfree_skb(mp->tx_bufs[i]);
-	if (++i >= N_TX_RING)
-	    i = 0;
-    }
 }
 
 static int mace_close(struct net_device *dev)
diff -Nru a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
--- a/drivers/net/pcmcia/3c574_cs.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/net/pcmcia/3c574_cs.c	Sun Nov 10 19:28:38 2002
@@ -515,6 +515,8 @@
 		lp->autoselect = config.u.autoselect;
 	}
 
+	init_timer(&lp->media);
+
 	{
 		int phy;
 		
diff -Nru a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
--- a/drivers/net/pcmcia/3c589_cs.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/net/pcmcia/3c589_cs.c	Sun Nov 10 19:28:41 2002
@@ -745,6 +745,7 @@
     netif_start_queue(dev);
     
     tc589_reset(dev);
+    init_timer(&lp->media);
     lp->media.function = &media_check;
     lp->media.data = (unsigned long)lp;
     lp->media.expires = jiffies + HZ;
diff -Nru a/drivers/net/pcmcia/ax8390.h b/drivers/net/pcmcia/ax8390.h
--- a/drivers/net/pcmcia/ax8390.h	Sun Nov 10 19:28:39 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,187 +0,0 @@
-/* Generic NS8390 register definitions. */
-/* This file is part of Donald Becker's 8390 drivers, and is distributed
-   under the same license. Auto-loading of 8390.o only in v2.2 - Paul G.
-   Some of these names and comments originated from the Crynwr
-   packet drivers, which are distributed under the GPL. */
-
-#ifndef _8390_h
-#define _8390_h
-
-#include <linux/config.h>
-#include <linux/if_ether.h>
-#include <linux/ioport.h>
-#include <linux/skbuff.h>
-
-#define TX_2X_PAGES 12
-#define TX_1X_PAGES 6
-
-/* Should always use two Tx slots to get back-to-back transmits. */
-#define EI_PINGPONG
-
-#ifdef EI_PINGPONG
-#define TX_PAGES TX_2X_PAGES
-#else
-#define TX_PAGES TX_1X_PAGES
-#endif
-
-#define ETHER_ADDR_LEN 6
-
-/* The 8390 specific per-packet-header format. */
-struct e8390_pkt_hdr {
-  unsigned char status; /* status */
-  unsigned char next;   /* pointer to next packet. */
-  unsigned short count; /* header + packet length in bytes */
-};
-
-#ifdef notdef
-extern int ei_debug;
-#else
-#define ei_debug 1
-#endif
-
-static int ethdev_init(struct net_device *dev);
-static void NS8390_init(struct net_device *dev, int startp);
-static int ei_open(struct net_device *dev);
-static int ei_close(struct net_device *dev);
-static void ei_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-
-/* Most of these entries should be in 'struct net_device' (or most of the
-   things in there should be here!) */
-/* You have one of these per-board */
-struct ei_device {
-	const char *name;
-	void (*reset_8390)(struct net_device *);
-	void (*get_8390_hdr)(struct net_device *, struct e8390_pkt_hdr *, int);
-	void (*block_output)(struct net_device *, int, const unsigned char *, int);
-	void (*block_input)(struct net_device *, int, struct sk_buff *, int);
-	unsigned char mcfilter[8];
-	unsigned open:1;
-	unsigned word16:1;  		/* We have the 16-bit (vs 8-bit) version of the card. */
-	unsigned txing:1;		/* Transmit Active */
-	unsigned irqlock:1;		/* 8390's intrs disabled when '1'. */
-	unsigned dmaing:1;		/* Remote DMA Active */
-	unsigned char tx_start_page, rx_start_page, stop_page;
-	unsigned char current_page;	/* Read pointer in buffer  */
-	unsigned char interface_num;	/* Net port (AUI, 10bT.) to use. */
-	unsigned char txqueue;		/* Tx Packet buffer queue length. */
-	short tx1, tx2;			/* Packet lengths for ping-pong tx. */
-	short lasttx;			/* Alpha version consistency check. */
-	unsigned char reg0;		/* Register '0' in a WD8013 */
-	unsigned char reg5;		/* Register '5' in a WD8013 */
-	unsigned char saved_irq;	/* Original dev->irq value. */
-	struct net_device_stats stat;	/* The new statistics table. */
-	u32 *reg_offset;		/* Register mapping table */
-	spinlock_t page_lock;		/* Page register locks */
-	unsigned long priv;		/* Private field to store bus IDs etc. */
-};
-
-/* The maximum number of 8390 interrupt service routines called per IRQ. */
-#define MAX_SERVICE 12
-
-/* The maximum time waited (in jiffies) before assuming a Tx failed. (20ms) */
-#define TX_TIMEOUT (20*HZ/100)
-
-#define ei_status (*(struct ei_device *)(dev->priv))
-
-/* Some generic ethernet register configurations. */
-#define E8390_TX_IRQ_MASK	0xa	/* For register EN0_ISR */
-#define E8390_RX_IRQ_MASK	0x5
-#define E8390_RXCONFIG		0x44	/* EN0_RXCR: broadcasts, no multicast,errors */
-#define E8390_RXOFF		0x20	/* EN0_RXCR: Accept no packets */
-#define E8390_TXCONFIG		0x00	/* EN0_TXCR: Normal transmit mode */
-#define E8390_TXOFF		0x02	/* EN0_TXCR: Transmitter off */
-
-/*  Register accessed at EN_CMD, the 8390 base addr.  */
-#define E8390_STOP	0x01	/* Stop and reset the chip */
-#define E8390_START	0x02	/* Start the chip, clear reset */
-#define E8390_TRANS	0x04	/* Transmit a frame */
-#define E8390_RREAD	0x08	/* Remote read */
-#define E8390_RWRITE	0x10	/* Remote write  */
-#define E8390_NODMA	0x20	/* Remote DMA */
-#define E8390_PAGE0	0x00	/* Select page chip registers */
-#define E8390_PAGE1	0x40	/* using the two high-order bits */
-#define E8390_PAGE2	0x80	/* Page 3 is invalid. */
-
-/*
- *	Only generate indirect loads given a machine that needs them.
- */
- 
-#if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \
-    defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE) || \
-    defined(CONFIG_HYDRA) || defined(CONFIG_HYDRA_MODULE)
-#define EI_SHIFT(x)	(ei_local->reg_offset[x])
-#else
-#define EI_SHIFT(x)	(x)
-#endif
-
-#define E8390_CMD	EI_SHIFT(0x00)  /* The command register (for all pages) */
-/* Page 0 register offsets. */
-#define EN0_CLDALO	EI_SHIFT(0x01)	/* Low byte of current local dma addr  RD */
-#define EN0_STARTPG	EI_SHIFT(0x01)	/* Starting page of ring bfr WR */
-#define EN0_CLDAHI	EI_SHIFT(0x02)	/* High byte of current local dma addr  RD */
-#define EN0_STOPPG	EI_SHIFT(0x02)	/* Ending page +1 of ring bfr WR */
-#define EN0_BOUNDARY	EI_SHIFT(0x03)	/* Boundary page of ring bfr RD WR */
-#define EN0_TSR		EI_SHIFT(0x04)	/* Transmit status reg RD */
-#define EN0_TPSR	EI_SHIFT(0x04)	/* Transmit starting page WR */
-#define EN0_NCR		EI_SHIFT(0x05)	/* Number of collision reg RD */
-#define EN0_TCNTLO	EI_SHIFT(0x05)	/* Low  byte of tx byte count WR */
-#define EN0_FIFO	EI_SHIFT(0x06)	/* FIFO RD */
-#define EN0_TCNTHI	EI_SHIFT(0x06)	/* High byte of tx byte count WR */
-#define EN0_ISR		EI_SHIFT(0x07)	/* Interrupt status reg RD WR */
-#define EN0_CRDALO	EI_SHIFT(0x08)	/* low byte of current remote dma address RD */
-#define EN0_RSARLO	EI_SHIFT(0x08)	/* Remote start address reg 0 */
-#define EN0_CRDAHI	EI_SHIFT(0x09)	/* high byte, current remote dma address RD */
-#define EN0_RSARHI	EI_SHIFT(0x09)	/* Remote start address reg 1 */
-#define EN0_RCNTLO	EI_SHIFT(0x0a)	/* Remote byte count reg WR */
-#define EN0_RCNTHI	EI_SHIFT(0x0b)	/* Remote byte count reg WR */
-#define EN0_RSR		EI_SHIFT(0x0c)	/* rx status reg RD */
-#define EN0_RXCR	EI_SHIFT(0x0c)	/* RX configuration reg WR */
-#define EN0_TXCR	EI_SHIFT(0x0d)	/* TX configuration reg WR */
-#define EN0_COUNTER0	EI_SHIFT(0x0d)	/* Rcv alignment error counter RD */
-#define EN0_DCFG	EI_SHIFT(0x0e)	/* Data configuration reg WR */
-#define EN0_COUNTER1	EI_SHIFT(0x0e)	/* Rcv CRC error counter RD */
-#define EN0_IMR		EI_SHIFT(0x0f)	/* Interrupt mask reg WR */
-#define EN0_COUNTER2	EI_SHIFT(0x0f)	/* Rcv missed frame error counter RD */
-
-/* Bits in EN0_ISR - Interrupt status register */
-#define ENISR_RX	0x01	/* Receiver, no error */
-#define ENISR_TX	0x02	/* Transmitter, no error */
-#define ENISR_RX_ERR	0x04	/* Receiver, with error */
-#define ENISR_TX_ERR	0x08	/* Transmitter, with error */
-#define ENISR_OVER	0x10	/* Receiver overwrote the ring */
-#define ENISR_COUNTERS	0x20	/* Counters need emptying */
-#define ENISR_RDC	0x40	/* remote dma complete */
-#define ENISR_RESET	0x80	/* Reset completed */
-#define ENISR_ALL	0x3f	/* Interrupts we will enable */
-
-/* Bits in EN0_DCFG - Data config register */
-#define ENDCFG_WTS	0x01	/* word transfer mode selection */
-
-/* Page 1 register offsets. */
-#define EN1_PHYS   EI_SHIFT(0x01)	/* This board's physical enet addr RD WR */
-#define EN1_PHYS_SHIFT(i)  EI_SHIFT(i+1) /* Get and set mac address */
-#define EN1_CURPAG EI_SHIFT(0x07)	/* Current memory page RD WR */
-#define EN1_MULT   EI_SHIFT(0x08)	/* Multicast filter mask array (8 bytes) RD WR */
-#define EN1_MULT_SHIFT(i)  EI_SHIFT(8+i) /* Get and set multicast filter */
-
-/* Bits in received packet status byte and EN0_RSR*/
-#define ENRSR_RXOK	0x01	/* Received a good packet */
-#define ENRSR_CRC	0x02	/* CRC error */
-#define ENRSR_FAE	0x04	/* frame alignment error */
-#define ENRSR_FO	0x08	/* FIFO overrun */
-#define ENRSR_MPA	0x10	/* missed pkt */
-#define ENRSR_PHY	0x20	/* physical/multicast address */
-#define ENRSR_DIS	0x40	/* receiver disable. set in monitor mode */
-#define ENRSR_DEF	0x80	/* deferring */
-
-/* Transmitted packet status, EN0_TSR. */
-#define ENTSR_PTX 0x01	/* Packet transmitted without error */
-#define ENTSR_ND  0x02	/* The transmit wasn't deferred. */
-#define ENTSR_COL 0x04	/* The transmit collided at least once. */
-#define ENTSR_ABT 0x08  /* The transmit collided 16 times, and was deferred. */
-#define ENTSR_CRS 0x10	/* The carrier sense was lost. */
-#define ENTSR_FU  0x20  /* A "FIFO underrun" occurred during transmit. */
-#define ENTSR_CDH 0x40	/* The collision detect "heartbeat" signal was lost. */
-#define ENTSR_OWC 0x80  /* There was an out-of-window collision. */
-
-#endif /* _8390_h */
diff -Nru a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
--- a/drivers/net/pcmcia/axnet_cs.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/net/pcmcia/axnet_cs.c	Sun Nov 10 19:28:40 2002
@@ -11,8 +11,8 @@
 
     Copyright (C) 2001 David A. Hinds -- dahinds@users.sourceforge.net
 
-    axnet_cs.c 1.11 2001/06/12 12:42:40
-    
+    axnet_cs.c 1.28 2002/06/29 06:27:37
+
     The network driver code is based on Donald Becker's NE2000 code:
 
     Written 1992,1993 by Donald Becker.
@@ -20,7 +20,7 @@
     Director, National Security Agency.  This software may be used and
     distributed according to the terms of the GNU General Public License,
     incorporated herein by reference.
-    Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov
+    Donald Becker may be reached at becker@scyld.com
 
 ======================================================================*/
 
@@ -33,14 +33,15 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/delay.h>
+#include <linux/spinlock.h>
 #include <linux/ethtool.h>
-#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
+#include <asm/uaccess.h>
 
 #include <linux/netdevice.h>
-#include "ax8390.h"
+#include "../8390.h"
 
 #include <pcmcia/version.h>
 #include <pcmcia/cs_types.h>
@@ -53,34 +54,25 @@
 #define AXNET_CMD	0x00
 #define AXNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
 #define AXNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
-#define AXNET_MISC	0x18	/* For IBM CCAE and Socket EA cards */
 #define AXNET_MII_EEP	0x14	/* Offset of MII access port */
+#define AXNET_TEST	0x15	/* Offset of TEST Register port */
+#define AXNET_GPIO	0x17	/* Offset of General Purpose Register Port */
 
 #define AXNET_START_PG	0x40	/* First page of TX buffer */
 #define AXNET_STOP_PG	0x80	/* Last page +1 of RX ring */
 
 #define AXNET_RDC_TIMEOUT 0x02	/* Max wait in jiffies for Tx RDC */
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"axnet_cs.c 1.11 2001/06/12 12:42:40 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
-
-#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb);
-#define skb_tx_check(dev, skb)
-#define add_rx_bytes(stats, n) (stats)->rx_bytes += n;
-#define add_tx_bytes(stats, n) (stats)->tx_bytes += n;
-#define netif_mark_up(dev)	do { } while (0)
-#define netif_mark_down(dev)	do { } while (0)
+#define IS_AX88190	0x0001
+#define IS_AX88790	0x0002
 
 /*====================================================================*/
 
-/* Parameters that can be set with 'insmod' */
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("Asix AX88190 PCMCIA ethernet driver");
+MODULE_LICENSE("GPL");
 
 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
@@ -89,9 +81,14 @@
 static int irq_list[4] = { -1 };
 MODULE_PARM(irq_list, "1-4i");
 
-/* Ugh!  Let the user hardwire the hardware address for queer cards */
-static int hw_addr[6] = { 0, /* ... */ };
-MODULE_PARM(hw_addr, "6i");
+#ifdef PCMCIA_DEBUG
+INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"axnet_cs.c 1.28 2002/06/29 06:27:37 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
 
 /*====================================================================*/
 
@@ -122,6 +119,12 @@
 static dev_info_t dev_info = "axnet_cs";
 static dev_link_t *dev_list;
 
+static int axdev_init(struct net_device *dev);
+static void AX88190_init(struct net_device *dev, int startp);
+static int ax_open(struct net_device *dev);
+static int ax_close(struct net_device *dev);
+static void ax_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
 /*====================================================================*/
 
 typedef struct axnet_dev_t {
@@ -134,6 +137,7 @@
     u_short		link_status;
     u_char		duplex_flag;
     int			phy_id;
+    int			flags;
 } axnet_dev_t;
 
 /*======================================================================
@@ -212,7 +216,7 @@
     link->conf.Attributes = CONF_ENABLE_IRQ;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    ethdev_init(dev);
+    axdev_init(dev);
     dev->init = &axnet_init;
     dev->open = &axnet_open;
     dev->stop = &axnet_close;
@@ -304,7 +308,7 @@
 	{0x00,	EN0_RCNTHI},
 	{0x00,	EN0_IMR},	/* Mask completion irq. */
 	{0xFF,	EN0_ISR},
-	{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
+	{E8390_RXOFF|0x40, EN0_RXCR},	/* 0x60  Set to monitor */
 	{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
 	{0x10,	EN0_RCNTLO},
 	{0x00,	EN0_RCNTHI},
@@ -333,30 +337,6 @@
 
 /*======================================================================
 
-    This should be totally unnecessary... but when we can't figure
-    out the hardware address any other way, we'll let the user hard
-    wire it when the module is initialized.
-
-======================================================================*/
-
-static int get_hwired(dev_link_t *link)
-{
-    struct net_device *dev = link->priv;
-    int i;
-
-    for (i = 0; i < 6; i++)
-	if (hw_addr[i] != 0) break;
-    if (i == 6)
-	return 0;
-
-    for (i = 0; i < 6; i++)
-	dev->dev_addr[i] = hw_addr[i];
-
-    return 1;
-} /* get_hwired */
-
-/*======================================================================
-
     axnet_config() is scheduled to run after a CARD_INSERTION event
     is received, to configure the PCMCIA socket, and to make the
     ethernet device available to the system.
@@ -421,7 +401,8 @@
     CS_CHECK(GetTupleData, handle, &tuple);
     CS_CHECK(ParseTuple, handle, &tuple, &parse);
     link->conf.ConfigBase = parse.config.base;
-    link->conf.Present = parse.config.rmask[0];
+    /* don't trust the CIS on this; Linksys got it wrong */
+    link->conf.Present = 0x63;
 
     /* Configure card */
     link->state |= DEV_CONFIG;
@@ -442,7 +423,7 @@
 	if ((cfg->index == 0) || (cfg->io.nwin == 0))
 	    goto next_entry;
 	
-	link->conf.ConfigIndex = cfg->index;
+	link->conf.ConfigIndex = 0x05;
 	/* For multifunction cards, by convention, we configure the
 	   network function with window 0, and serial with window 1 */
 	if (io->nwin > 1) {
@@ -482,9 +463,9 @@
 	goto failed;
     }
 
-    if (!get_prom(link) && !get_hwired(link)) {
-	printk(KERN_NOTICE "axnet_cs: unable to read hardware net"
-	       " address for io base %#3lx\n", dev->base_addr);
+    if (!get_prom(link)) {
+	printk(KERN_NOTICE "axnet_cs: this is not an AX88190 card!\n");
+	printk(KERN_NOTICE "axnet_cs: use pcnet_cs instead.\n");
 	unregister_netdev(dev);
 	goto failed;
     }
@@ -501,17 +482,37 @@
 
     strcpy(info->node.dev_name, dev->name);
     link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
 
-    printk(KERN_INFO "%s: Asix AX88190: io %#3lx, irq %d, hw_addr ",
-	   dev->name, dev->base_addr, dev->irq);
+    if (inb(dev->base_addr + AXNET_TEST) != 0)
+	info->flags |= IS_AX88790;
+    else
+	info->flags |= IS_AX88190;
+
+    printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, hw_addr ",
+	   dev->name, ((info->flags & IS_AX88790) ? 7 : 1),
+	   dev->base_addr, dev->irq);
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
 
+    if (info->flags & IS_AX88790)
+	outb(0x10, dev->base_addr + AXNET_GPIO);  /* select Internal PHY */
+
     for (i = 0; i < 32; i++) {
 	j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
 	if ((j != 0) && (j != 0xffff)) break;
     }
+
+    /* Maybe PHY is in power down mode. (PPD_SET = 1) 
+       Bit 2 of CCSR is active low. */ 
+    if (i == 32) {
+	conf_reg_t reg = { 0, CS_WRITE, CISREG_CCSR, 0x04 };
+ 	CardServices(AccessConfigurationRegister, link->handle, &reg);
+	for (i = 0; i < 32; i++) {
+	    j = mdio_read(dev->base_addr + AXNET_MII_EEP, i, 1);
+	    if ((j != 0) && (j != 0xffff)) break;
+	}
+    }
+
     info->phy_id = (i < 32) ? i : -1;
     if (i < 32) {
 	DEBUG(0, "  MII transceiver at index %d, status %x.\n", i, j);
@@ -519,12 +520,14 @@
 	printk(KERN_NOTICE "  No MII transceivers found!\n");
     }
 
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
 
 cs_failed:
     cs_error(link->handle, last_fn, last_ret);
 failed:
     axnet_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
 } /* axnet_config */
 
@@ -544,7 +547,7 @@
 
     if (link->open) {
 	DEBUG(1, "axnet_cs: release postponed, '%s' still open\n",
-	      info->node.dev_name);
+	      ((axnet_dev_t *)(link->priv))->node.dev_name);
 	link->state |= DEV_STALE_CONFIG;
 	return;
     }
@@ -583,7 +586,7 @@
 	}
 	break;
     case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT;
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
 	axnet_config(link);
 	break;
     case CS_EVENT_PM_SUSPEND:
@@ -604,7 +607,7 @@
 	    CardServices(RequestConfiguration, link->handle, &link->conf);
 	    if (link->open) {
 		axnet_reset_8390(&info->dev);
-		NS8390_init(&info->dev, 1);
+		AX88190_init(&info->dev, 1);
 		netif_device_attach(&info->dev);
 	    }
 	}
@@ -689,12 +692,13 @@
     request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev);
 
     info->link_status = 0x00;
+    init_timer(&info->watchdog);
     info->watchdog.function = &ei_watchdog;
     info->watchdog.data = (u_long)info;
     info->watchdog.expires = jiffies + HZ;
     add_timer(&info->watchdog);
 
-    return ei_open(dev);
+    return ax_open(dev);
 } /* axnet_open */
 
 /*====================================================================*/
@@ -706,11 +710,11 @@
 
     DEBUG(2, "axnet_close('%s')\n", dev->name);
 
+    ax_close(dev);
     free_irq(dev->irq, dev);
     
     link->open--;
     netif_stop_queue(dev);
-    netif_mark_down(dev);
     del_timer(&info->watchdog);
     if (link->state & DEV_STALE_CONFIG)
 	mod_timer(&link->release, jiffies + HZ/20);
@@ -757,7 +761,7 @@
 {
     axnet_dev_t *info = dev_id;
     info->stale = 0;
-    ei_interrupt(irq, dev_id, regs);
+    ax_interrupt(irq, dev_id, regs);
 }
 
 static void ei_watchdog(u_long arg)
@@ -809,7 +813,7 @@
 	    else
 		printk(KERN_INFO "%s: link partner did not autonegotiate\n",
 		       dev->name);
-	    NS8390_init(dev, 1);
+	    AX88190_init(dev, 1);
 	}
 	info->link_status = link;
     }
@@ -821,23 +825,22 @@
 
 static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
 {
-    u32 ethcmd;
-
-    if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
-	return -EFAULT;
-
-    switch (ethcmd) {
-    case ETHTOOL_GDRVINFO: {
-	struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
-
-	strncpy(info.driver, "axnet_cs", sizeof(info.driver)-1);
-	if (copy_to_user(useraddr, &info, sizeof(info)))
-	    return -EFAULT;
-	return 0;
-    }
-    }
-
-    return -EOPNOTSUPP;
+	u32 ethcmd;
+		
+	if (copy_from_user(&ethcmd, useraddr, sizeof(ethcmd)))
+		return -EFAULT;
+	
+	switch (ethcmd) {
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = {ETHTOOL_GDRVINFO};
+		strncpy(info.driver, "axnet_cs", sizeof(info.driver)-1);
+		if (copy_to_user(useraddr, &info, sizeof(info)))
+			return -EFAULT;
+		return 0;
+	}
+	}
+	
+	return -EOPNOTSUPP;
 }
 
 /*====================================================================*/
@@ -849,7 +852,7 @@
     ioaddr_t mii_addr = dev->base_addr + AXNET_MII_EEP;
     switch (cmd) {
     case SIOCETHTOOL:
-	return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+        return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
     case SIOCDEVPRIVATE:
 	data[0] = info->phy_id;
     case SIOCDEVPRIVATE+1:
@@ -940,7 +943,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "axnet_cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &axnet_attach, &axnet_detach);
     return 0;
@@ -969,10 +972,11 @@
 	This software may be used and distributed according to the terms
 	of the GNU General Public License, incorporated herein by reference.
 
-	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
-	Center of Excellence in Space Data and Information Sciences
-	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
-  
+	The author may be reached as becker@scyld.com, or C/O
+	Scyld Computing Corporation
+	410 Severn Ave., Suite 210
+	Annapolis MD 21403
+
   This is the chip-specific code for many 8390-based ethernet adaptors.
   This is not a complete driver, it must be combined with board-specific
   code such as ne.c, wd.c, 3c503.c, etc.
@@ -982,7 +986,6 @@
   a simple innocent change. Please contact me or Donald if you think
   you have found something that needs changing. -- PG
 
-
   Changelog:
 
   Paul Gortmaker	: remove set_bit lock, other cleanups.
@@ -1006,8 +1009,8 @@
 
   */
 
-static const char *version =
-    "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n";
+static const char *version_8390 =
+    "8390.c:v1.10cvs 9/23/94 Donald Becker (becker@scyld.com)\n";
 
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
@@ -1087,25 +1090,23 @@
  *	them.
  */
  
-
-
 /**
- * ei_open - Open/initialize the board.
+ * ax_open - Open/initialize the board.
  * @dev: network device to initialize
  *
  * This routine goes all-out, setting everything
  * up anew at each open, even though many of these registers should only
  * need to be set once at boot.
  */
-static int ei_open(struct net_device *dev)
+static int ax_open(struct net_device *dev)
 {
 	unsigned long flags;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 
-	/* This can't happen unless somebody forgot to call ethdev_init(). */
+	/* This can't happen unless somebody forgot to call axdev_init(). */
 	if (ei_local == NULL) 
 	{
-		printk(KERN_EMERG "%s: ei_open passed a non-existent device!\n", dev->name);
+		printk(KERN_EMERG "%s: ax_open passed a non-existent device!\n", dev->name);
 		return -ENXIO;
 	}
 
@@ -1124,16 +1125,38 @@
 	 */
       
       	spin_lock_irqsave(&ei_local->page_lock, flags);
-	NS8390_init(dev, 1);
+	AX88190_init(dev, 1);
 	/* Set the flag before we drop the lock, That way the IRQ arrives
 	   after its set and we get no silly warnings */
-	netif_mark_up(dev);
 	netif_start_queue(dev);
       	spin_unlock_irqrestore(&ei_local->page_lock, flags);
 	ei_local->irqlock = 0;
 	return 0;
 }
 
+#define dev_lock(dev) (((struct ei_device *)(dev)->priv)->page_lock)
+
+/**
+ * ax_close - shut down network device
+ * @dev: network device to close
+ *
+ * Opposite of ax_open(). Only used when "ifconfig <devname> down" is done.
+ */
+int ax_close(struct net_device *dev)
+{
+	unsigned long flags;
+
+	/*
+	 *      Hold the page lock during close
+	 */
+
+	spin_lock_irqsave(&dev_lock(dev), flags);
+	AX88190_init(dev, 0);
+	spin_unlock_irqrestore(&dev_lock(dev), flags);
+	netif_stop_queue(dev);
+	return 0;
+}
+
 /**
  * ei_tx_timeout - handle transmit time out condition
  * @dev: network device which has apparently fallen asleep
@@ -1173,7 +1196,7 @@
 		
 	/* Try to restart the card.  Perhaps the user has fixed something. */
 	ei_reset_8390(dev);
-	NS8390_init(dev, 1);
+	AX88190_init(dev, 1);
 		
 	spin_unlock(&ei_local->page_lock);
 	enable_irq(dev->irq);
@@ -1196,7 +1219,6 @@
 	unsigned long flags;
 
 	netif_stop_queue(dev);
-	skb_tx_check(dev, skb);
 
 	length = skb->len;
 
@@ -1209,7 +1231,6 @@
 	outb_p(0x00, e8390_base + EN0_IMR);
 	spin_unlock_irqrestore(&ei_local->page_lock, flags);
 	
-	
 	/*
 	 *	Slow phase with lock held.
 	 */
@@ -1222,8 +1243,6 @@
 
 	send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
     
-#ifdef EI_PINGPONG
-
 	/*
 	 * We have two Tx slots available for use. Find the first free
 	 * slot, and then perform some sanity checks. With two Tx bufs,
@@ -1292,22 +1311,6 @@
 	else
 		netif_start_queue(dev);
 
-#else	/* EI_PINGPONG */
-
-	/*
-	 * Only one Tx buffer in use. You need two Tx bufs to come close to
-	 * back-to-back transmits. Expect a 20 -> 25% performance hit on
-	 * reasonable hardware if you only use one Tx buffer.
-	 */
-
-	ei_block_output(dev, length, skb->data, ei_local->tx_start_page);
-	ei_local->txing = 1;
-	NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
-	dev->trans_start = jiffies;
-	netif_stop_queue(dev);
-
-#endif	/* EI_PINGPONG */
-
 	/* Turn 8390 interrupts back on. */
 	ei_local->irqlock = 0;
 	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
@@ -1315,14 +1318,14 @@
 	spin_unlock(&ei_local->page_lock);
 	enable_irq(dev->irq);
 
-	DEV_KFREE_SKB (skb);
-	add_tx_bytes(&ei_local->stat, send_length);
+	dev_kfree_skb (skb);
+	ei_local->stat.tx_bytes += send_length;
     
 	return 0;
 }
-
+
 /**
- * ei_interrupt - handle the interrupts from an 8390
+ * ax_interrupt - handle the interrupts from an 8390
  * @irq: interrupt number
  * @dev_id: a pointer to the net_device
  * @regs: unused
@@ -1334,7 +1337,7 @@
  * needed.
  */
 
-static void ei_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static void ax_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct net_device *dev = dev_id;
 	long e8390_base;
@@ -1501,8 +1504,6 @@
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	int status = inb(e8390_base + EN0_TSR);
     
-#ifdef EI_PINGPONG
-
 	/*
 	 * There are two Tx buffers, see which one finished, and trigger
 	 * the send of another one if it exists.
@@ -1545,13 +1546,6 @@
 //	else printk(KERN_WARNING "%s: unexpected TX-done interrupt, lasttx=%d.\n",
 //			dev->name, ei_local->lasttx);
 
-#else	/* EI_PINGPONG */
-	/*
-	 *  Single Tx buffer: mark it free so another packet can be loaded.
-	 */
-	ei_local->txing = 0;
-#endif
-
 	/* Minimize Tx latency: update the statistics after we restart TXing. */
 	if (status & ENTSR_COL)
 		ei_local->stat.collisions++;
@@ -1659,7 +1653,7 @@
 				netif_rx(skb);
 				dev->last_rx = jiffies;
 				ei_local->stat.rx_packets++;
-				add_rx_bytes(&ei_local->stat, pkt_len);
+				ei_local->stat.rx_bytes += pkt_len;
 				if (pkt_stat & ENRSR_PHY)
 					ei_local->stat.multicast++;
 			}
@@ -1805,11 +1799,11 @@
 	long e8390_base = dev->base_addr;
 
   	if(dev->flags&IFF_PROMISC)
-  		outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
+  		outb_p(E8390_RXCONFIG | 0x58, e8390_base + EN0_RXCR);
 	else if(dev->flags&IFF_ALLMULTI || dev->mc_list)
-  		outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
+  		outb_p(E8390_RXCONFIG | 0x48, e8390_base + EN0_RXCR);
   	else
-  		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
+  		outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR);
 }
 
 /*
@@ -1817,28 +1811,28 @@
  *	be parallel to just about everything else. Its also fairly quick and
  *	not called too often. Must protect against both bh and irq users
  */
- 
+
 static void set_multicast_list(struct net_device *dev)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&((struct ei_device *)dev->priv)->page_lock, flags);
+	spin_lock_irqsave(&dev_lock(dev), flags);
 	do_set_multicast_list(dev);
-	spin_unlock_irqrestore(&((struct ei_device *)dev->priv)->page_lock, flags);
+	spin_unlock_irqrestore(&dev_lock(dev), flags);
 }	
 
 /**
- * ethdev_init - init rest of 8390 device struct
+ * axdev_init - init rest of 8390 device struct
  * @dev: network device structure to init
  *
  * Initialize the rest of the 8390 device structure.  Do NOT __init
  * this, as it is used by 8390 based modular drivers too.
  */
 
-static int ethdev_init(struct net_device *dev)
+static int axdev_init(struct net_device *dev)
 {
 	if (ei_debug > 1)
-		printk(version);
+		printk(version_8390);
     
 	if (dev->priv == NULL) 
 	{
@@ -1860,21 +1854,19 @@
         
 	return 0;
 }
-
-
 
 /* This page of functions should be 8390 generic */
 /* Follow National Semi's recommendations for initializing the "NIC". */
 
 /**
- * NS8390_init - initialize 8390 hardware
+ * AX88190_init - initialize 8390 hardware
  * @dev: network device to initialize
  * @startp: boolean.  non-zero value to initiate chip processing
  *
  *	Must be called with lock held.
  */
 
-static void NS8390_init(struct net_device *dev, int startp)
+static void AX88190_init(struct net_device *dev, int startp)
 {
 	axnet_dev_t *info = (axnet_dev_t *)dev;
 	long e8390_base = dev->base_addr;
@@ -1891,7 +1883,7 @@
 	outb_p(0x00,  e8390_base + EN0_RCNTLO);
 	outb_p(0x00,  e8390_base + EN0_RCNTHI);
 	/* Set to monitor and loopback mode -- this is vital!. */
-	outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
+	outb_p(E8390_RXOFF|0x40, e8390_base + EN0_RXCR); /* 0x60 */
 	outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
 	/* Set the transmit page and receive ring. */
 	outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
@@ -1935,7 +1927,7 @@
 		outb_p(E8390_TXCONFIG | info->duplex_flag,
 		       e8390_base + EN0_TXCR); /* xmit on. */
 		/* 3c503 TechMan says rxconfig only after the NIC is started. */
-		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on,  */
+		outb_p(E8390_RXCONFIG | 0x40, e8390_base + EN0_RXCR); /* rx on, */
 		do_set_multicast_list(dev);	/* (re)load the mcast table */
 	}
 }
diff -Nru a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
--- a/drivers/net/pcmcia/fmvj18x_cs.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/net/pcmcia/fmvj18x_cs.c	Sun Nov 10 19:28:40 2002
@@ -1,5 +1,5 @@
 /*======================================================================
-    fmvj18x_cs.c 2.6 2001/09/17
+    fmvj18x_cs.c 2.8 2002/03/23
 
     A fmvj18x (and its compatibles) PCMCIA client driver
 
@@ -29,7 +29,7 @@
 ======================================================================*/
 
 #define DRV_NAME	"fmvj18x_cs"
-#define DRV_VERSION	"2.6"
+#define DRV_VERSION	"2.8"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -65,6 +65,10 @@
 /*====================================================================*/
 
 /* Module parameters */
+
+MODULE_DESCRIPTION("fmvj18x and compatible PCMCIA ethernet driver");
+MODULE_LICENSE("GPL");
+
 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 /* Bit map of interrupts to choose from */
@@ -80,7 +84,7 @@
 #ifdef PCMCIA_DEBUG
 INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version = DRV_NAME ".c " DRV_VERSION " 2001/09/17";
+static char *version = DRV_NAME ".c " DRV_VERSION " 2002/03/23";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -91,6 +95,7 @@
  */
 static void fmvj18x_config(dev_link_t *link);
 static int fmvj18x_get_hwinfo(dev_link_t *link, u_char *node_id);
+static int fmvj18x_setup_mfc(dev_link_t *link);
 static void fmvj18x_release(u_long arg);
 static int fmvj18x_event(event_t event, int priority,
 			  event_callback_args_t *args);
@@ -122,8 +127,6 @@
 	       XXX10304
 } cardtype_t;
 
-#define MANFID_UNGERMANN 0x02c0
-
 /*
     driver specific data structure
 */
@@ -388,6 +391,45 @@
 #define CS_CHECK(fn, args...) \
 while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
 
+static int mfc_try_io_port(dev_link_t *link)
+{
+    int i, ret;
+    static ioaddr_t serial_base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+
+    for (i = 0; i < 5; i++) {
+	link->io.BasePort2 = serial_base[i];
+	link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+	if (link->io.BasePort2 == 0) {
+	    link->io.NumPorts2 = 0;
+	    printk(KERN_NOTICE "fmvj18x_cs: out of resource for serial\n");
+	}
+	ret = CardServices(RequestIO, link->handle, &link->io);
+	if (ret == CS_SUCCESS) return ret;
+    }
+    return ret;
+}
+
+static int ungermann_try_io_port(dev_link_t *link)
+{
+    int ret;
+    ioaddr_t ioaddr;
+    /*
+	Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360
+	0x380,0x3c0 only for ioport.
+    */
+    for (ioaddr = 0x300; ioaddr < 0x3e0; ioaddr += 0x20) {
+	link->io.BasePort1 = ioaddr;
+	ret = CardServices(RequestIO, link->handle, &link->io);
+	if (ret == CS_SUCCESS) {
+	    /* calculate ConfigIndex value */
+	    link->conf.ConfigIndex = 
+		((link->io.BasePort1 & 0x0f0) >> 3) | 0x22;
+	    return ret;
+	}
+    }
+    return ret;	/* RequestIO failed */
+}
+
 static void fmvj18x_config(dev_link_t *link)
 {
     client_handle_t handle = link->handle;
@@ -401,7 +443,7 @@
     cardtype_t cardtype;
     char *card_name = "unknown";
     u_char *node_id;
-    
+
     DEBUG(0, "fmvj18x_config(0x%p)\n", link);
 
     /*
@@ -444,6 +486,11 @@
 		CardServices(GetStatus, handle, &status);
 		if (status.CardState & CS_EVENT_3VCARD)
 		    link->conf.Vcc = 33; /* inserted in 3.3V slot */
+	    } else if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410) {
+		/* MultiFunction Card */
+		link->conf.ConfigBase = 0x800;
+		link->conf.ConfigIndex = 0x47;
+		link->io.NumPorts2 = 8;
 	    }
 	    break;
 	case MANFID_CONTEC:
@@ -481,31 +528,22 @@
 	    break;
 	case MANFID_UNGERMANN:
 	    cardtype = UNGERMANN;
-	    /*
-	       Ungermann-Bass Access/CARD accepts 0x300,0x320,0x340,0x360
-	       0x380,0x3c0 only for ioport.
-	    */
-	    for (link->io.BasePort1 = 0x300; link->io.BasePort1 < 0x3e0;
-		link->io.BasePort1 += 0x20) {
-		ret = CardServices(RequestIO, link->handle, &link->io);
-		if (ret == CS_SUCCESS) {
-		/* calculate ConfigIndex value */
-		link->conf.ConfigIndex = 
-		    ((link->io.BasePort1 & 0x0f0) >> 3) | 0x22;
-		goto req_irq;
-		}
-	    }
-	    /* if ioport allocation is failed, goto failed */
-	    printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
-	    goto failed;
+	    break;
 	default:
 	    cardtype = MBH10302;
 	    link->conf.ConfigIndex = 1;
 	}
     }
 
-    CS_CHECK(RequestIO, link->handle, &link->io);
-req_irq:
+    if (link->io.NumPorts2 != 0) {
+	ret = mfc_try_io_port(link);
+	if (ret != CS_SUCCESS) goto cs_failed;
+    } else if (cardtype == UNGERMANN) {
+	ret = ungermann_try_io_port(link);
+	if (ret != CS_SUCCESS) goto cs_failed;
+    } else { 
+	CS_CHECK(RequestIO, link->handle, &link->io);
+    }
     CS_CHECK(RequestIRQ, link->handle, &link->irq);
     CS_CHECK(RequestConfiguration, link->handle, &link->conf);
     dev->irq = link->irq.AssignedIRQ;
@@ -515,19 +553,22 @@
 	goto failed;
     }
 
+    if (link->io.BasePort2 != 0)
+	fmvj18x_setup_mfc(link);
+
     ioaddr = dev->base_addr;
 
     /* Reset controller */
-    if( sram_config == 0 ) 
+    if (sram_config == 0) 
 	outb(CONFIG0_RST, ioaddr + CONFIG_0);
     else
 	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
 
     /* Power On chip and select bank 0 */
-    if(cardtype == UNGERMANN)
-	outb(BANK_0U, ioaddr + CONFIG_1);
-    else
+    if (cardtype == MBH10302)
 	outb(BANK_0, ioaddr + CONFIG_1);
+    else
+	outb(BANK_0U, ioaddr + CONFIG_1);
     
     /* Set hardware address */
     switch (cardtype) {
@@ -591,7 +632,6 @@
 
     strcpy(lp->node.dev_name, dev->name);
     link->dev = &lp->node;
-    link->state &= ~DEV_CONFIG_PENDING;
 
     lp->cardtype = cardtype;
     /* print current configuration */
@@ -601,6 +641,7 @@
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
 
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
     
 cs_failed:
@@ -608,6 +649,7 @@
     cs_error(link->handle, last_fn, last_ret);
 failed:
     fmvj18x_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
 
 } /* fmvj18x_config */
 /*====================================================================*/
@@ -666,6 +708,51 @@
 } /* fmvj18x_get_hwinfo */
 /*====================================================================*/
 
+static int fmvj18x_setup_mfc(dev_link_t *link)
+{
+    win_req_t req;
+    memreq_t mem;
+    u_char *base;
+    int i, j;
+    local_info_t *lp = link->priv;
+    struct net_device *dev = &lp->dev;
+    ioaddr_t ioaddr;
+
+    /* Allocate a small memory window */
+    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+    req.Base = 0; req.Size = 0;
+    req.AccessSpeed = 0;
+    link->win = (window_handle_t)link->handle;
+    i = CardServices(RequestWindow, &link->win, &req);
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestWindow, i);
+	return -1;
+    }
+
+    base = ioremap(req.Base, req.Size);
+    mem.Page = 0;
+    mem.CardOffset = 0;
+    CardServices(MapMemPage, link->win, &mem);
+
+    ioaddr = dev->base_addr;
+    writeb(0x47, base+0x800);	/* Config Option Register of LAN */
+    writeb(0x0, base+0x802);	/* Config and Status Register */
+
+    writeb(ioaddr & 0xff, base+0x80a);		/* I/O Base(Low) of LAN */
+    writeb((ioaddr >> 8) & 0xff, base+0x80c);	/* I/O Base(High) of LAN */
+   
+    writeb(0x45, base+0x820);	/* Config Option Register of Modem */
+    writeb(0x8, base+0x822);	/* Config and Status Register */
+
+    iounmap(base);
+    j = CardServices(ReleaseWindow, link->win);
+    if (j != CS_SUCCESS)
+	cs_error(link->handle, ReleaseWindow, j);
+    return 0;
+
+}
+/*====================================================================*/
+
 static void fmvj18x_release(u_long arg)
 {
     dev_link_t *link = (dev_link_t *)arg;
@@ -752,7 +839,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "fmvj18x: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &fmvj18x_attach, &fmvj18x_detach);
     return 0;
@@ -942,10 +1029,10 @@
 	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
 
     /* Power On chip and select bank 0 */
-    if( lp->cardtype == UNGERMANN)
-	outb(BANK_0U, ioaddr + CONFIG_1);
-    else
+    if (lp->cardtype == MBH10302)
 	outb(BANK_0, ioaddr + CONFIG_1);
+    else
+	outb(BANK_0U, ioaddr + CONFIG_1);
 
     /* Set Tx modes */
     outb(D_TX_MODE, ioaddr + TX_MODE);
@@ -957,20 +1044,20 @@
         outb(dev->dev_addr[i], ioaddr + NODE_ID + i);
 
     /* Switch to bank 1 */
-    if ( lp->cardtype == UNGERMANN )
-	outb(BANK_1U, ioaddr + CONFIG_1);
-    else
+    if (lp->cardtype == MBH10302)
 	outb(BANK_1, ioaddr + CONFIG_1);
+    else
+	outb(BANK_1U, ioaddr + CONFIG_1);
 
     /* set the multicast table to accept none. */
     for (i = 0; i < 6; i++) 
         outb(0x00, ioaddr + MAR_ADR + i);
 
     /* Switch to bank 2 (runtime mode) */
-    if ( lp->cardtype == UNGERMANN )
-	outb(BANK_2U, ioaddr + CONFIG_1);
-    else
+    if (lp->cardtype == MBH10302)
 	outb(BANK_2, ioaddr + CONFIG_1);
+    else
+	outb(BANK_2U, ioaddr + CONFIG_1);
 
     /* set 16col ctrl bits */
     if( lp->cardtype == TDK || lp->cardtype == CONTEC) 
@@ -999,16 +1086,16 @@
     outb(0xff, ioaddr + TX_STATUS);
     outb(0xff, ioaddr + RX_STATUS);
 
-    if( lp->cardtype != TDK ) 
-    		outb(INTR_OFF, ioaddr + LAN_CTRL);
+    if (lp->cardtype == MBH10302)
+	outb(INTR_OFF, ioaddr + LAN_CTRL);
 
     /* Turn on Rx interrupts */
     outb(D_TX_INTR, ioaddr + TX_INTR);
     outb(D_RX_INTR, ioaddr + RX_INTR);
 
     /* Turn on interrupts from LAN card controller */
-    if( lp->cardtype != TDK ) 
-		outb(INTR_ON, ioaddr + LAN_CTRL);
+    if (lp->cardtype == MBH10302)
+	outb(INTR_ON, ioaddr + LAN_CTRL);
 } /* fjn_reset */
 
 /*====================================================================*/
@@ -1063,7 +1150,7 @@
 
 	    skb_reserve(skb, 2);
 	    insw(ioaddr + DATAPORT, skb_put(skb, pkt_len),
-		    (pkt_len + 1) >> 1);
+		 (pkt_len + 1) >> 1);
 	    skb->protocol = eth_type_trans(skb, dev);
 
 #ifdef PCMCIA_DEBUG
@@ -1090,7 +1177,7 @@
 	   has done a netif_wake_queue() for us and will work on them
 	   when we get to the bottom-half routine. */
 /*
-    if( lp->cardtype != TDK ) {
+    if (lp->cardtype != TDK) {
 	int i;
 	for (i = 0; i < 20; i++) {
 	    if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == F_BUF_EMP)
@@ -1223,7 +1310,7 @@
     outb(CHIP_OFF ,ioaddr + CONFIG_1);
 
     /* Set the ethernet adaptor disable IRQ */
-    if( lp->cardtype != TDK ) 
+    if (lp->cardtype == MBH10302)
 	outb(INTR_OFF, ioaddr + LAN_CTRL);
 
     link->open--;
@@ -1252,8 +1339,8 @@
 {
     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 */
-    unsigned long flags;
+    u_char mc_filter[8];		 /* Multicast hash filter */
+    u_long flags;
     int i;
     
     if (dev->flags & IFF_PROMISC) {
@@ -1293,4 +1380,3 @@
     }
     restore_flags(flags);
 }
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
--- a/drivers/net/pcmcia/nmclan_cs.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/net/pcmcia/nmclan_cs.c	Sun Nov 10 19:28:37 2002
@@ -106,6 +106,10 @@
 
 ---------------------------------------------------------------------------- */
 
+#define DRV_NAME	"nmclan_cs"
+#define DRV_VERSION	"0.16"
+
+
 /* ----------------------------------------------------------------------------
 Conditional Compilation Options
 ---------------------------------------------------------------------------- */
@@ -130,6 +134,9 @@
 #include <linux/interrupt.h>
 #include <linux/in.h>
 #include <linux/delay.h>
+#include <linux/ethtool.h>
+
+#include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
@@ -375,7 +382,7 @@
 static char rcsid[] =
 "nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao";
 static char *version =
-"nmclan_cs 0.16 (Roger C. Pao)";
+DRV_NAME " " DRV_VERSION " (Roger C. Pao)";
 #endif
 
 static dev_info_t dev_info="nmclan_cs";
@@ -430,8 +437,8 @@
 static struct net_device_stats *mace_get_stats(struct net_device *dev);
 static int mace_rx(struct net_device *dev, unsigned char RxCnt);
 static void restore_multicast_list(struct net_device *dev);
-
 static void set_multicast_list(struct net_device *dev);
+static int mace_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 
 static dev_link_t *nmclan_attach(void);
 static void nmclan_detach(dev_link_t *);
@@ -513,6 +520,7 @@
     dev->set_config = &mace_config;
     dev->get_stats = &mace_get_stats;
     dev->set_multicast_list = &set_multicast_list;
+    dev->do_ioctl = &mace_ioctl;
     ether_setup(dev);
     dev->open = &mace_open;
     dev->stop = &mace_close;
@@ -1001,6 +1009,66 @@
 
   return 0;
 } /* mace_close */
+
+static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr)
+{
+	u32 ethcmd;
+
+	/* dev_ioctl() in ../../net/core/dev.c has already checked
+	   capable(CAP_NET_ADMIN), so don't bother with that here.  */
+
+	if (get_user(ethcmd, (u32 *)useraddr))
+		return -EFAULT;
+
+	switch (ethcmd) {
+
+	case ETHTOOL_GDRVINFO: {
+		struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
+		strcpy (info.driver, DRV_NAME);
+		strcpy (info.version, DRV_VERSION);
+		sprintf(info.bus_info, "PCMCIA 0x%lx", dev->base_addr);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+	}
+
+#ifdef PCMCIA_DEBUG
+	/* get message-level */
+	case ETHTOOL_GMSGLVL: {
+		struct ethtool_value edata = {ETHTOOL_GMSGLVL};
+		edata.data = pc_debug;
+		if (copy_to_user(useraddr, &edata, sizeof(edata)))
+			return -EFAULT;
+		return 0;
+	}
+	/* set message-level */
+	case ETHTOOL_SMSGLVL: {
+		struct ethtool_value edata;
+		if (copy_from_user(&edata, useraddr, sizeof(edata)))
+			return -EFAULT;
+		pc_debug = edata.data;
+		return 0;
+	}
+#endif
+
+	default:
+		break;
+	}
+
+	return -EOPNOTSUPP;
+}
+
+static int mace_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
+
+	default:
+		return -EOPNOTSUPP;
+	}
+	return 0;
+}
 
 /* ----------------------------------------------------------------------------
 mace_start_xmit
diff -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
--- a/drivers/net/pcmcia/pcnet_cs.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/net/pcmcia/pcnet_cs.c	Sun Nov 10 19:28:41 2002
@@ -11,7 +11,7 @@
 
     Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
 
-    pcnet_cs.c 1.144 2001/11/07 04:06:56
+    pcnet_cs.c 1.149 2002/06/29 06:27:37
     
     The network driver code is based on Donald Becker's NE2000 code:
 
@@ -75,7 +75,7 @@
 MODULE_PARM(pc_debug, "i");
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 static char *version =
-"pcnet_cs.c 1.144 2001/11/07 04:06:56 (David Hinds)";
+"pcnet_cs.c 1.149 2002/06/29 06:27:37 (David Hinds)";
 #else
 #define DEBUG(n, args...)
 #endif
@@ -765,12 +765,13 @@
 
     strcpy(info->node.dev_name, dev->name);
     link->dev = &info->node;
-    link->state &= ~DEV_CONFIG_PENDING;
 
     if (info->flags & (IS_DL10019|IS_DL10022)) {
 	u_char id = inb(dev->base_addr + 0x1a);
 	dev->do_ioctl = &ei_ioctl;
 	mii_phy_probe(dev);
+	if ((id == 0x30) && !info->pna_phy && (info->eth_phy == 4))
+	    info->eth_phy = 0;
 	printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ",
 	       dev->name, ((info->flags & IS_DL10022) ? 22 : 19), id);
 	if (info->pna_phy)
@@ -787,12 +788,14 @@
     printk(" hw_addr ");
     for (i = 0; i < 6; i++)
 	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
 
 cs_failed:
     cs_error(link->handle, last_fn, last_ret);
 failed:
     pcnet_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
 } /* pcnet_config */
 
@@ -856,7 +859,7 @@
 	}
 	break;
     case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT;
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
 	pcnet_config(link);
 	break;
     case CS_EVENT_PM_SUSPEND:
@@ -1034,6 +1037,7 @@
 
     info->phy_id = info->eth_phy;
     info->link_status = 0x00;
+    init_timer(&info->watchdog);
     info->watchdog.function = &ei_watchdog;
     info->watchdog.data = (u_long)info;
     info->watchdog.expires = jiffies + HZ;
@@ -1051,6 +1055,7 @@
 
     DEBUG(2, "pcnet_close('%s')\n", dev->name);
 
+    ei_close(dev);
     free_irq(dev->irq, dev);
     
     link->open--;
@@ -1620,7 +1625,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "pcnet_cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &pcnet_attach, &pcnet_detach);
     return 0;
diff -Nru a/drivers/net/pcmcia/ray_cs.c b/drivers/net/pcmcia/ray_cs.c
--- a/drivers/net/pcmcia/ray_cs.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/net/pcmcia/ray_cs.c	Sun Nov 10 19:28:39 2002
@@ -2,7 +2,7 @@
  *
  * A  PCMCIA client driver for the Raylink wireless LAN card.
  * The starting point for this module was the skeleton.c in the
- * PCMCIA 2.9.12 package written by David Hinds, dhinds@allegro.stanford.edu
+ * PCMCIA 2.9.12 package written by David Hinds, dahinds@users.sourceforge.net
  *
  *
  * Copyright (c) 1998  Corey Thomas (corey@world.std.com)
diff -Nru a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
--- a/drivers/net/pcmcia/smc91c92_cs.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/net/pcmcia/smc91c92_cs.c	Sun Nov 10 19:28:40 2002
@@ -8,8 +8,8 @@
 
     Copyright (C) 1999 David A. Hinds -- dahinds@users.sourceforge.net
 
-    smc91c92_cs.c 1.2 2002/09/28 15:00:00
-    
+    smc91c92_cs.c 1.122 2002/10/25 06:26:39
+
     This driver contains code written by Donald Becker
     (becker@scyld.com), Rowan Hughes (x-csrdh@jcu.edu.au),
     David Hinds (dahinds@users.sourceforge.net), and Erik Stahlman
@@ -18,7 +18,7 @@
     incorporated some parts of his driver here.  I (Dave) wrote most
     of the PCMCIA glue code, and the Ositech support code.  Kelly
     Stephens (kstephen@holli.com) added support for the Motorola
-    Mariner, with help from Allen Brost. 
+    Mariner, with help from Allen Brost.
 
     This software may be used and distributed according to the terms of
     the GNU General Public License, incorporated herein by reference.
@@ -92,7 +92,7 @@
 #endif
 
 #define DRV_NAME	"smc91c92_cs"
-#define DRV_VERSION	"1.2"
+#define DRV_VERSION	"1.122"
 
 /*====================================================================*/
 
@@ -130,6 +130,8 @@
     u_short			fast_poll;
     u_short			link_status;
     struct mii_if_info		mii_if;
+    int				duplex;
+    int				rx_ovrn;
 };
 
 /* Special definitions for Megahertz multifunction cards */
@@ -257,7 +259,7 @@
 #define	MULTICAST2	2
 #define	MULTICAST4	4
 #define	MULTICAST6	6
-#define MGMT    	8 
+#define MGMT    	8
 #define REVISION	0x0a
 
 /* Transmit status bits. */
@@ -287,22 +289,22 @@
 static int smc91c92_event(event_t event, int priority,
 			  event_callback_args_t *args);
 
-static int smc91c92_open(struct net_device *dev);
-static int smc91c92_close(struct net_device *dev);
+static int smc_open(struct net_device *dev);
+static int smc_close(struct net_device *dev);
+static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void smc_tx_timeout(struct net_device *dev);
 static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void smc_rx(struct net_device *dev);
-static struct net_device_stats *smc91c92_get_stats(struct net_device *dev);
+static struct net_device_stats *smc_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static int s9k_config(struct net_device *dev, struct ifmap *map);
 static void smc_set_xcvr(struct net_device *dev, int if_port);
 static void smc_reset(struct net_device *dev);
 static void media_check(u_long arg);
-static void smc_mdio_sync(ioaddr_t addr);
-static int smc_mdio_read(struct net_device *dev, int phy_id, int loc);
-static void smc_mdio_write(struct net_device *dev, int phy_id, int loc, int value);
-static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void mdio_sync(ioaddr_t addr);
+static int mdio_read(struct net_device *dev, int phy_id, int loc);
+static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
 static int smc_link_ok(struct net_device *dev);
 
 /*======================================================================
@@ -310,7 +312,7 @@
     This bit of code is used to avoid unregistering network devices
     at inappropriate times.  2.2 and later kernels are fairly picky
     about when this can happen.
-    
+
 ======================================================================*/
 
 static void flush_stale_links(void)
@@ -349,7 +351,7 @@
 
     DEBUG(0, "smc91c92_attach()\n");
     flush_stale_links();
-    
+
     /* Create new ethernet device */
     smc = kmalloc(sizeof(struct smc_private), GFP_KERNEL);
     if (!smc) return NULL;
@@ -375,25 +377,25 @@
 
     /* The SMC91c92-specific entries in the device structure. */
     dev->hard_start_xmit = &smc_start_xmit;
-    dev->get_stats = &smc91c92_get_stats;
+    dev->get_stats = &smc_get_stats;
     dev->set_config = &s9k_config;
     dev->set_multicast_list = &set_rx_mode;
-    dev->do_ioctl = &smc_ioctl;
     ether_setup(dev);
-    dev->open = &smc91c92_open;
-    dev->stop = &smc91c92_close;
+    dev->open = &smc_open;
+    dev->stop = &smc_close;
+    dev->do_ioctl = &smc_ioctl;
 #ifdef HAVE_TX_TIMEOUT
     dev->tx_timeout = smc_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
 #endif
     dev->priv = link->priv = link->irq.Instance = smc;
-   
+
     smc->mii_if.dev = dev;
-    smc->mii_if.mdio_read = smc_mdio_read;
-    smc->mii_if.mdio_write = smc_mdio_write;
+    smc->mii_if.mdio_read = mdio_read;
+    smc->mii_if.mdio_write = mdio_write;
     smc->mii_if.phy_id_mask = 0x1f;
     smc->mii_if.reg_num_mask = 0x1f;
-    
+
     /* Register with Card Services */
     link->next = dev_list;
     dev_list = link;
@@ -411,7 +413,7 @@
 	smc91c92_detach(link);
 	return NULL;
     }
-    
+
     return link;
 } /* smc91c92_attach */
 
@@ -430,13 +432,13 @@
     dev_link_t **linkp;
 
     DEBUG(0, "smc91c92_detach(0x%p)\n", link);
-    
+
     /* Locate device structure */
     for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
 	if (*linkp == link) break;
     if (*linkp == NULL)
 	return;
-    
+
     del_timer(&link->release);
     if (link->state & DEV_CONFIG) {
 	smc91c92_release((u_long)link);
@@ -445,16 +447,16 @@
 	    return;
 	}
     }
-    
+
     if (link->handle)
 	CardServices(DeregisterClient, link->handle);
-    
+
     /* Unlink device structure, free bits */
     *linkp = link->next;
     if (link->dev)
 	unregister_netdev(&smc->dev);
     kfree(smc);
-    
+
 } /* smc91c92_detach */
 
 /*====================================================================*/
@@ -502,14 +504,14 @@
     mhz_mfc_config() handles socket setup for multifunction (1144
     and 3288) cards.  mhz_setup() gets a card's hardware ethernet
     address.
-    
+
 ======================================================================*/
 
 static int mhz_3288_power(dev_link_t *link)
 {
     struct smc_private *smc = link->priv;
     u_char tmp;
-    
+
     /* Read the ISR twice... */
     readb(smc->base+MEGAHERTZ_ISR);
     udelay(5);
@@ -517,7 +519,7 @@
 
     /* Pause 200ms... */
     mdelay(200);
-    
+
     /* Now read and write the COR... */
     tmp = readb(smc->base + link->conf.ConfigBase + CISREG_COR);
     udelay(5);
@@ -569,7 +571,7 @@
     if (i != CS_SUCCESS)
 	return i;
     dev->base_addr = link->io.BasePort1;
-    
+
     /* Allocate a memory window, for accessing the ISR */
     req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
     req.Base = req.Size = 0;
@@ -583,12 +585,12 @@
     if (smc->manfid == MANFID_MOTOROLA)
 	mem.CardOffset = link->conf.ConfigBase;
     i = CardServices(MapMemPage, link->win, &mem);
-    
+
     if ((i == CS_SUCCESS)
 	&& (smc->manfid == MANFID_MEGAHERTZ)
 	&& (smc->cardid == PRODID_MEGAHERTZ_EM3288))
 	mhz_3288_power(link);
-    
+
     return i;
 }
 
@@ -628,7 +630,7 @@
     buf[12] = '\0';
     if (cvt_ascii_address(dev, buf) == 0)
 	return 0;
-    
+
     return -1;
 }
 
@@ -638,7 +640,7 @@
 
     mot_config() writes directly to the Mariner configuration
     registers because the CIS is just bogus.
-    
+
 ======================================================================*/
 
 static void mot_config(dev_link_t *link)
@@ -647,12 +649,12 @@
     struct net_device *dev = &smc->dev;
     ioaddr_t ioaddr = dev->base_addr;
     ioaddr_t iouart = link->io.BasePort2;
-    
+
     /* Set UART base address and force map with COR bit 1 */
     writeb(iouart & 0xff,        smc->base + MOT_UART + CISREG_IOBASE_0);
     writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1);
     writeb(MOT_NORMAL,           smc->base + MOT_UART + CISREG_COR);
-    
+
     /* Set SMC base address and force map with COR bit 1 */
     writeb(ioaddr & 0xff,        smc->base + MOT_LAN + CISREG_IOBASE_0);
     writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1);
@@ -671,7 +673,7 @@
     u_int addr;
 
     /* Read Ethernet address from Serial EEPROM */
-    
+
     for (i = 0; i < 3; i++) {
 	SMC_SELECT_BANK(2);
 	outw(MOT_EEPROM + i, ioaddr + POINTER);
@@ -691,7 +693,7 @@
 	dev->dev_addr[2*i]   = addr & 0xff;
 	dev->dev_addr[2*i+1] = (addr >> 8) & 0xff;
     }
-    
+
     return 0;
 }
 
@@ -743,7 +745,7 @@
     tuple.Attributes = tuple.TupleOffset = 0;
     tuple.TupleData = buf;
     tuple.TupleDataMax = sizeof(buf);
-    
+
     /* Check for a LAN function extension tuple */
     tuple.DesiredTuple = CISTPL_FUNCE;
     i = first_tuple(handle, &tuple, &parse);
@@ -760,7 +762,7 @@
 	    return 0;
 	}
     }
-    
+
     /* Try the third string in the Version 1 Version/ID tuple. */
     tuple.DesiredTuple = CISTPL_VERS_1;
     if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS)
@@ -780,7 +782,7 @@
     struct net_device *dev = &smc->dev;
     static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
     int i, j;
-    
+
     link->conf.Attributes |= CONF_ENABLE_SPKR;
     link->conf.Status = CCSR_AUDIO_ENA;
     link->irq.Attributes =
@@ -789,10 +791,10 @@
     link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
     link->io.NumPorts2 = 8;
     link->io.IOAddrLines = 16;
-    
+
     /* Enable Hard Decode, LAN, Modem */
     link->conf.ConfigIndex = 0x23;
-    
+
     for (i = j = 0; j < 4; j++) {
 	link->io.BasePort2 = com[j];
 	i = CardServices(RequestIO, link->handle, &link->io);
@@ -816,12 +818,12 @@
     tuple_t tuple;
     u_char buf[255];
     int i;
-    
+
     tuple.Attributes = TUPLE_RETURN_COMMON;
     tuple.TupleData = buf;
     tuple.TupleDataMax = sizeof(buf);
     tuple.TupleOffset = 0;
-    
+
     /* Read the station address from tuple 0x90, subtuple 0x04 */
     tuple.DesiredTuple = 0x90;
     i = CardServices(GetFirstTuple, handle, &tuple);
@@ -862,7 +864,7 @@
 
     This verifies that the chip is some SMC91cXX variant, and returns
     the revision code if successful.  Otherwise, it returns -ENODEV.
-    
+
 ======================================================================*/
 
 static int check_sig(dev_link_t *link)
@@ -888,7 +890,7 @@
     else
 	s &= ~CFG_16BIT;
     outb(s, ioaddr + CONFIG);
-    
+
     /* Check Base Address Register to make sure bus width is OK */
     s = inw(ioaddr + BASE_ADDR);
     if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) &&
@@ -936,7 +938,7 @@
     ioaddr_t ioaddr;
 
     DEBUG(0, "smc91c92_config(0x%p)\n", link);
-    
+
     tuple.Attributes = tuple.TupleOffset = 0;
     tuple.TupleData = (cisdata_t *)buf;
     tuple.TupleDataMax = sizeof(buf);
@@ -946,14 +948,14 @@
     CS_EXIT_TEST(i, ParseTuple, config_failed);
     link->conf.ConfigBase = parse.config.base;
     link->conf.Present = parse.config.rmask[0];
-    
+
     tuple.DesiredTuple = CISTPL_MANFID;
     tuple.Attributes = TUPLE_RETURN_COMMON;
     if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
 	smc->manfid = parse.manfid.manf;
 	smc->cardid = parse.manfid.card;
     }
-    
+
     /* Configure card */
     link->state |= DEV_CONFIG;
 
@@ -969,12 +971,12 @@
 	i = smc_config(link);
     }
     CS_EXIT_TEST(i, RequestIO, config_failed);
-    
+
     i = CardServices(RequestIRQ, link->handle, &link->irq);
     CS_EXIT_TEST(i, RequestIRQ, config_failed);
     i = CardServices(RequestConfiguration, link->handle, &link->conf);
     CS_EXIT_TEST(i, RequestConfiguration, config_failed);
-    
+
     if (smc->manfid == MANFID_MOTOROLA)
 	mot_config(link);
 
@@ -984,7 +986,7 @@
 	dev->if_port = if_port;
     else
 	printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");
-    
+
     if (register_netdev(dev) != 0) {
 	printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
 	goto config_undo;
@@ -1004,16 +1006,16 @@
     default: /* get the hw address from EEPROM */
 	i = mot_setup(link); break;
     }
-    
+
     if (i != 0) {
 	printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n");
-	link->state &= ~DEV_CONFIG_PENDING;
 	goto config_undo;
     }
 
     strcpy(smc->node.dev_name, dev->name);
     link->dev = &smc->node;
-    link->state &= ~DEV_CONFIG_PENDING;
+    smc->duplex = 0;
+    smc->rx_ovrn = 0;
 
     rev = check_sig(link);
     name = "???";
@@ -1055,12 +1057,12 @@
 	printk(" buffer, %s xcvr\n", (smc->cfg & CFG_MII_SELECT) ?
 	       "MII" : if_names[dev->if_port]);
     }
-    
+
     if (smc->cfg & CFG_MII_SELECT) {
 	SMC_SELECT_BANK(3);
 
 	for (i = 0; i < 32; i++) {
-	    j = smc_mdio_read(dev, i, 1);
+	    j = mdio_read(dev, i, 1);
 	    if ((j != 0) && (j != 0xffff)) break;
 	}
 	smc->mii_if.phy_id = (i < 32) ? i : -1;
@@ -1073,13 +1075,15 @@
 	SMC_SELECT_BANK(0);
     }
 
+    link->state &= ~DEV_CONFIG_PENDING;
     return;
-    
+
 config_undo:
     unregister_netdev(dev);
 config_failed:			/* CS_EXIT_TEST() calls jump to here... */
     smc91c92_release((u_long)link);
-    
+    link->state &= ~DEV_CONFIG_PENDING;
+
 } /* smc91c92_config */
 
 /*======================================================================
@@ -1096,14 +1100,14 @@
     struct smc_private *smc = link->priv;
 
     DEBUG(0, "smc91c92_release(0x%p)\n", link);
-    
+
     if (link->open) {
 	DEBUG(1, "smc91c92_cs: release postponed, '%s' still open\n",
 	      link->dev->dev_name);
 	link->state |= DEV_STALE_CONFIG;
 	return;
     }
-    
+
     CardServices(ReleaseConfiguration, link->handle);
     CardServices(ReleaseIO, link->handle, &link->io);
     CardServices(ReleaseIRQ, link->handle, &link->irq);
@@ -1111,7 +1115,7 @@
 	iounmap(smc->base);
 	CardServices(ReleaseWindow, link->win);
     }
-    
+
     link->state &= ~DEV_CONFIG;
 
 } /* smc91c92_release */
@@ -1131,8 +1135,8 @@
     dev_link_t *link = args->client_data;
     struct smc_private *smc = link->priv;
     struct net_device *dev = &smc->dev;
-    int i;   
- 
+    int i;
+
     DEBUG(1, "smc91c92_event(0x%06x)\n", event);
 
     switch (event) {
@@ -1144,7 +1148,7 @@
 	}
 	break;
     case CS_EVENT_CARD_INSERTION:
-	link->state |= DEV_PRESENT;
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
 	smc91c92_config(link);
 	break;
     case CS_EVENT_PM_SUSPEND:
@@ -1206,7 +1210,7 @@
 #define MDIO_DATA_WRITE1	(MDIO_DIR_WRITE | MDIO_DATA_OUT)
 #define MDIO_DATA_READ		0x02
 
-static void smc_mdio_sync(ioaddr_t addr)
+static void mdio_sync(ioaddr_t addr)
 {
     int bits;
     for (bits = 0; bits < 32; bits++) {
@@ -1215,13 +1219,13 @@
     }
 }
 
-static int smc_mdio_read(struct net_device *dev, int phy_id, int loc)
+static int mdio_read(struct net_device *dev, int phy_id, int loc)
 {
     ioaddr_t addr = dev->base_addr + MGMT;
     u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
     int i, retval = 0;
 
-    smc_mdio_sync(addr);
+    mdio_sync(addr);
     for (i = 13; i >= 0; i--) {
 	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
 	outb(dat, addr);
@@ -1235,13 +1239,13 @@
     return (retval>>1) & 0xffff;
 }
 
-static void smc_mdio_write(struct net_device *dev, int phy_id, int loc, int value)
+static void mdio_write(struct net_device *dev, int phy_id, int loc, int value)
 {
     ioaddr_t addr = dev->base_addr + MGMT;
     u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
     int i;
 
-    smc_mdio_sync(addr);
+    mdio_sync(addr);
     for (i = 31; i >= 0; i--) {
 	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
 	outb(dat, addr);
@@ -1254,10 +1258,10 @@
 }
 
 /*======================================================================
-  
+
     The driver core code, most of which should be common with a
     non-PCMCIA implementation.
-    
+
 ======================================================================*/
 
 #ifdef PCMCIA_DEBUG
@@ -1277,17 +1281,17 @@
 }
 #endif
 
-static int smc91c92_open(struct net_device *dev)
+static int smc_open(struct net_device *dev)
 {
     struct smc_private *smc = dev->priv;
     dev_link_t *link = &smc->link;
 
 #ifdef PCMCIA_DEBUG
-    DEBUG(0, "%s: smc91c92_open(%p), ID/Window %4.4x.\n",
+    DEBUG(0, "%s: smc_open(%p), ID/Window %4.4x.\n",
 	  dev->name, dev, inw(dev->base_addr + BANK_SELECT));
     if (pc_debug > 1) smc_dump(dev);
 #endif
-    
+
     /* Check that the PCMCIA card is still here. */
     if (!DEV_OK(link))
 	return -ENODEV;
@@ -1302,25 +1306,26 @@
     netif_start_queue(dev);
     smc->saved_skb = 0;
     smc->packets_waiting = 0;
-    
+
     smc_reset(dev);
+    init_timer(&smc->media);
     smc->media.function = &media_check;
     smc->media.data = (u_long)smc;
     smc->media.expires = jiffies + HZ;
     add_timer(&smc->media);
-    
+
     return 0;
-} /* smc91c92_open */
+} /* smc_open */
 
 /*====================================================================*/
 
-static int smc91c92_close(struct net_device *dev)
+static int smc_close(struct net_device *dev)
 {
     struct smc_private *smc = dev->priv;
     dev_link_t *link = &smc->link;
     ioaddr_t ioaddr = dev->base_addr;
 
-    DEBUG(0, "%s: smc91c92_close(), status %4.4x.\n",
+    DEBUG(0, "%s: smc_close(), status %4.4x.\n",
 	  dev->name, inw(ioaddr + BANK_SELECT));
 
     netif_stop_queue(dev);
@@ -1332,27 +1337,27 @@
     SMC_SELECT_BANK(0);
     mask_bits(0xff00, ioaddr + RCR);
     mask_bits(0xff00, ioaddr + TCR);
-    
+
     /* Put the chip into power-down mode. */
     SMC_SELECT_BANK(1);
     outw(CTL_POWERDOWN, ioaddr + CONTROL );
-    
+
     link->open--;
     del_timer(&smc->media);
     if (link->state & DEV_STALE_CONFIG)
 	mod_timer(&link->release, jiffies + HZ/20);
-    
+
     MOD_DEC_USE_COUNT;
-    
+
     return 0;
-} /* smc91c92_close */
+} /* smc_close */
 
 /*======================================================================
 
    Transfer a packet to the hardware and trigger the packet send.
    This may be called at either from either the Tx queue code
    or the interrupt handler.
-   
+
 ======================================================================*/
 
 static void smc_hardware_send_packet(struct net_device * dev)
@@ -1361,12 +1366,12 @@
     struct sk_buff *skb = smc->saved_skb;
     ioaddr_t ioaddr = dev->base_addr;
     u_char packet_no;
-    
+
     if (!skb) {
 	printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name);
 	return;
     }
-    
+
     /* There should be a packet slot waiting. */
     packet_no = inw(ioaddr + PNR_ARR) >> 8;
     if (packet_no & 0x80) {
@@ -1384,7 +1389,7 @@
     outw(packet_no, ioaddr + PNR_ARR);
     /* point to the beginning of the packet */
     outw(PTR_AUTOINC , ioaddr + POINTER);
-    
+
     /* Send the packet length (+6 for status, length and ctl byte)
        and the status word (set to zeros). */
     {
@@ -1402,15 +1407,15 @@
 	/* The odd last byte, if there is one, goes in the control word. */
 	outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1);
     }
-    
+
     /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */
     outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) |
 	 (inw(ioaddr + INTERRUPT) & 0xff00),
 	 ioaddr + INTERRUPT);
-    
+
     /* The chip does the rest of the work. */
     outw(MC_ENQUEUE , ioaddr + MMU_CMD);
-    
+
     smc->saved_skb = NULL;
     dev_kfree_skb_irq(skb);
     dev->trans_start = jiffies;
@@ -1444,9 +1449,9 @@
 
     netif_stop_queue(dev);
 
-    DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called,"
+    DEBUG(2, "%s: smc_start_xmit(length = %d) called,"
 	  " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));
-    
+
     if (smc->saved_skb) {
 	/* THIS SHOULD NEVER HAPPEN. */
 	smc->stats.tx_aborted_errors++;
@@ -1455,9 +1460,9 @@
 	return 1;
     }
     smc->saved_skb = skb;
-    
+
     num_pages = skb->len >> 8;
-    
+
     if (num_pages > 7) {
 	printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);
 	dev_kfree_skb (skb);
@@ -1467,9 +1472,15 @@
     }
     /* A packet is now waiting. */
     smc->packets_waiting++;
-    
+
     SMC_SELECT_BANK(2);	/* Paranoia, we should always be in window 2 */
-    
+
+    /* need MC_RESET to keep the memory consistent. errata? */
+    if (smc->rx_ovrn) {
+	outw(MC_RESET, ioaddr + MMU_CMD);
+	smc->rx_ovrn = 0;
+    }
+
     /* Allocate the memory; send the packet now if we win. */
     outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD);
     for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {
@@ -1481,18 +1492,18 @@
 	    return 0;
 	}
     }
-    
+
     /* Otherwise defer until the Tx-space-allocated interrupt. */
     DEBUG(2, "%s: memory allocation deferred.\n", dev->name);
     outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
-    
+
     return 0;
 }
 
 /*======================================================================
 
     Handle a Tx anomolous event.  Entered while in Window 2.
-    
+
 ======================================================================*/
 
 static void smc_tx_err(struct net_device * dev)
@@ -1502,13 +1513,13 @@
     int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
     int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
     int tx_status;
-    
+
     /* select this as the packet to read from */
     outw(packet_no, ioaddr + PNR_ARR);
-    
+
     /* read the first word from this packet */
     outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER);
-    
+
     tx_status = inw(ioaddr + DATA_1);
 
     smc->stats.tx_errors++;
@@ -1518,21 +1529,21 @@
 	smc->stats.tx_aborted_errors++;
 	smc->tx_err++;
     }
-    
+
     if (tx_status & TS_SUCCESS) {
 	printk(KERN_NOTICE "%s: Successful packet caused error "
 	       "interrupt?\n", dev->name);
     }
     /* re-enable transmit */
     SMC_SELECT_BANK(0);
-    outw(inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
+    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
     SMC_SELECT_BANK(2);
-    
+
     outw(MC_FREEPKT, ioaddr + MMU_CMD); 	/* Free the packet memory. */
-    
+
     /* one less packet waiting for me */
     smc->packets_waiting--;
-    
+
     outw(saved_packet, ioaddr + PNR_ARR);
     return;
 }
@@ -1544,7 +1555,7 @@
     struct smc_private *smc = dev->priv;
     ioaddr_t ioaddr = dev->base_addr;
     u_short card_stats, ephs;
-    
+
     SMC_SELECT_BANK(0);
     ephs = inw(ioaddr + EPH);
     DEBUG(2, "%s: Ethernet protocol handler interrupt, status"
@@ -1561,7 +1572,7 @@
     card_stats >>= 4;			/* excess deferred */
 #endif
     /* If we had a transmit error we must re-enable the transmitter. */
-    outw(inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
+    outw(inw(ioaddr + TCR) | TCR_ENABLE | smc->duplex, ioaddr + TCR);
 
     /* Clear a link error interrupt. */
     SMC_SELECT_BANK(1);
@@ -1572,7 +1583,7 @@
 }
 
 /*====================================================================*/
-    
+
 static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
     struct smc_private *smc = dev_id;
@@ -1584,10 +1595,10 @@
     if (!netif_device_present(dev))
 	return;
     ioaddr = dev->base_addr;
-    
+
     DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
 	  irq, ioaddr);
-    
+
     smc->watchdog = 0;
     saved_bank = inw(ioaddr + BANK_SELECT);
     if ((saved_bank & 0xff00) != 0x3300) {
@@ -1597,13 +1608,13 @@
 	      "/ejected device.\n", dev->name, irq);
 	goto irq_done;
     }
-    
+
     SMC_SELECT_BANK(2);
     saved_pointer = inw(ioaddr + POINTER);
     mask = inw(ioaddr + INTERRUPT) >> 8;
     /* clear all interrupts */
     outw(0, ioaddr + INTERRUPT);
-    
+
     do { /* read the status flag, and mask it */
 	status = inw(ioaddr + INTERRUPT) & 0xff;
 	DEBUG(3, "%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,
@@ -1629,18 +1640,20 @@
 	if (status & IM_ALLOC_INT) {
 	    /* Clear this interrupt so it doesn't happen again */
 	    mask &= ~IM_ALLOC_INT;
-	    
+	
 	    smc_hardware_send_packet(dev);
-	    
+	
 	    /* enable xmit interrupts based on this */
 	    mask |= (IM_TX_EMPTY_INT | IM_TX_INT);
-	    
+	
 	    /* and let the card send more packets to me */
 	    netif_wake_queue(dev);
 	}
 	if (status & IM_RX_OVRN_INT) {
 	    smc->stats.rx_errors++;
-	    smc->stats.rx_fifo_errors++;		
+	    smc->stats.rx_fifo_errors++;
+	    if (smc->duplex)
+		smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */
 	    outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
 	}
 	if (status & IM_EPH_INT)
@@ -1649,7 +1662,7 @@
 
     DEBUG(3, "  Restoring saved registers mask %2.2x bank %4.4x"
 	  " pointer %4.4x.\n", mask, saved_bank, saved_pointer);
-    
+
     /* restore state register */
     outw((mask<<8), ioaddr + INTERRUPT);
     outw(saved_pointer, ioaddr + POINTER);
@@ -1658,7 +1671,7 @@
     DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
 
 irq_done:
-    
+
     if ((smc->manfid == MANFID_OSITECH) &&
 	(smc->cardid != PRODID_OSITECH_SEVEN)) {
 	/* Retrigger interrupt if needed */
@@ -1691,15 +1704,15 @@
     int rx_status;
     int packet_length;	/* Caution: not frame length, rather words
 			   to transfer from the chip. */
-    
+
     /* Assertion: we are in Window 2. */
-    
+
     if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {
 	printk(KERN_ERR "%s: smc_rx() with nothing on Rx FIFO.\n",
 	       dev->name);
 	return;
     }
-    
+
     /*  Reset the read pointer, and read the status and packet length. */
     outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER);
     rx_status = inw(ioaddr + DATA_1);
@@ -1707,7 +1720,7 @@
 
     DEBUG(2, "%s: Receive status %4.4x length %d.\n",
 	  dev->name, rx_status, packet_length);
-    
+
     if (!(rx_status & RS_ERRORS)) {		
 	/* do stuff to make a new packet */
 	struct sk_buff *skb;
@@ -1725,7 +1738,7 @@
 	packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6);
 	skb_reserve(skb, 2);
 	insw(ioaddr+DATA_1, skb_put(skb, packet_length),
-		(packet_length+1)>>1);
+	     (packet_length+1)>>1);
 	skb->protocol = eth_type_trans(skb, dev);
 	
 	skb->dev = dev;
@@ -1746,31 +1759,30 @@
     }
     /* Let the MMU free the memory of this packet. */
     outw(MC_RELEASE, ioaddr + MMU_CMD);
-    
+
     return;
 }
 
 /*====================================================================*/
 
-static struct net_device_stats *smc91c92_get_stats(struct net_device *dev)
+static struct net_device_stats *smc_get_stats(struct net_device *dev)
 {
     struct smc_private *smc = (struct smc_private *)dev->priv;
     /* Nothing to update - the 91c92 is a pretty primative chip. */
     return &smc->stats;
 }
 
-
 /*======================================================================
-  
+
     Calculate values for the hardware multicast filter hash table.
-    
+
 ======================================================================*/
 
 static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
 			       u_char *multicast_table)
 {
     struct dev_mc_list	*mc_addr;
-    
+
     for (mc_addr = addrs;  mc_addr && --count > 0;  mc_addr = mc_addr->next) {
 	u_int position = ether_crc(6, mc_addr->dmi_addr);
 #ifndef final_version		/* Verify multicast address. */
@@ -1782,14 +1794,14 @@
 }
 
 /*======================================================================
-  
+
     Set the receive mode.
-    
+
     This routine is used by both the protocol level to notify us of
     promiscuous/multicast mode changes, and by the open/reset code to
     initialize the Rx registers.  We always set the multicast list and
     leave the receiver running.
-    
+
 ======================================================================*/
 
 static void set_rx_mode(struct net_device *dev)
@@ -1799,7 +1811,7 @@
     u_int multicast_table[ 2 ] = { 0, };
     unsigned long flags;
     u_short rx_cfg_setting;
-    
+
     if (dev->flags & IFF_PROMISC) {
 	printk(KERN_NOTICE "%s: setting Rx mode to promiscuous.\n", dev->name);
 	rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
@@ -1812,7 +1824,7 @@
 	}
 	rx_cfg_setting = RxStripCRC | RxEnable;
     }
-    
+
     /* Load MC table and Rx setting into the chip without interrupts. */
     spin_lock_irqsave(&smc->lock, flags);
     SMC_SELECT_BANK(3);
@@ -1822,14 +1834,14 @@
     outw(rx_cfg_setting, ioaddr + RCR);
     SMC_SELECT_BANK(2);
     spin_unlock_irqrestore(&smc->lock, flags);
- 
+
     return;
 }
 
 /*======================================================================
 
     Senses when a card's config changes. Here, it's coax or TP.
- 
+
 ======================================================================*/
 
 static int s9k_config(struct net_device *dev, struct ifmap *map)
@@ -1889,18 +1901,18 @@
     int i;
 
     DEBUG(0, "%s: smc91c92 reset called.\n", dev->name);
-    
+
     /* The first interaction must be a write to bring the chip out
        of sleep mode. */
     SMC_SELECT_BANK(0);
     /* Reset the chip. */
     outw(RCR_SOFTRESET, ioaddr + RCR);
     udelay(10);
-    
+
     /* Clear the transmit and receive configuration registers. */
     outw(RCR_CLEAR, ioaddr + RCR);
     outw(TCR_CLEAR, ioaddr + TCR);
-    
+
     /* Set the Window 1 control, configuration and station addr registers.
        No point in writing the I/O base register ;-> */
     SMC_SELECT_BANK(1);
@@ -1914,32 +1926,35 @@
 	outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) |
 	     (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00),
 	     ioaddr - 0x10 + OSITECH_AUI_PWR);
-    
+
     /* Fill in the physical address.  The databook is wrong about the order! */
     for (i = 0; i < 6; i += 2)
 	outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i],
 	     ioaddr + ADDR0 + i);
-    
+
     /* Reset the MMU */
     SMC_SELECT_BANK(2);
     outw(MC_RESET, ioaddr + MMU_CMD);
     outw(0, ioaddr + INTERRUPT);
-    
+
     /* Re-enable the chip. */
     SMC_SELECT_BANK(0);
     outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |
-	 TCR_ENABLE | TCR_PAD_EN, ioaddr + TCR);
+	 TCR_ENABLE | TCR_PAD_EN | smc->duplex, ioaddr + TCR);
     set_rx_mode(dev);
 
     if (smc->cfg & CFG_MII_SELECT) {
 	SMC_SELECT_BANK(3);
 
 	/* Reset MII */
-	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
+	mdio_write(dev, smc->mii_if.phy_id, 0, 0x8000);
+
+	/* Advertise 100F, 100H, 10F, 10H */
+	mdio_write(dev, smc->mii_if.phy_id, 4, 0x01e1);
 
 	/* Restart MII autonegotiation */
-	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
-	smc_mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
+	mdio_write(dev, smc->mii_if.phy_id, 0, 0x0000);
+	mdio_write(dev, smc->mii_if.phy_id, 0, 0x1200);
     }
 
     /* Enable interrupts. */
@@ -1951,7 +1966,7 @@
 /*======================================================================
 
     Media selection timer routine
-    
+
 ======================================================================*/
 
 static void media_check(u_long arg)
@@ -1968,12 +1983,18 @@
 	goto reschedule;
 
     SMC_SELECT_BANK(2);
+
+    /* need MC_RESET to keep the memory consistent. errata? */
+    if (smc->rx_ovrn) {
+	outw(MC_RESET, ioaddr + MMU_CMD);
+	smc->rx_ovrn = 0;
+    }
     i = inw(ioaddr + INTERRUPT);
     SMC_SELECT_BANK(0);
     media = inw(ioaddr + EPH) & EPH_LINK_OK;
     SMC_SELECT_BANK(1);
     media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1;
-    
+
     /* Check for pending interrupt with watchdog flag set: with
        this, we can limp along even if the interrupt is blocked */
     if (smc->watchdog++ && ((i>>8) & i)) {
@@ -1995,7 +2016,7 @@
 	    goto reschedule;
 
 	SMC_SELECT_BANK(3);
-	link = smc_mdio_read(dev, smc->mii_if.phy_id, 1);
+	link = mdio_read(dev, smc->mii_if.phy_id, 1);
 	if (!link || (link == 0xffff)) {
   	    printk(KERN_INFO "%s: MII is missing!\n", dev->name);
 	    smc->mii_if.phy_id = -1;
@@ -2004,21 +2025,23 @@
 
 	link &= 0x0004;
 	if (link != smc->link_status) {
-	    u_short p = smc_mdio_read(dev, smc->mii_if.phy_id, 5);
+	    u_short p = mdio_read(dev, smc->mii_if.phy_id, 5);
 	    printk(KERN_INFO "%s: %s link beat\n", dev->name,
 		(link) ? "found" : "lost");
+	    smc->duplex = (((p & 0x0100) || ((p & 0x1c0) == 0x40))
+			   ? TCR_FDUPLX : 0);
 	    if (link) {
 	        printk(KERN_INFO "%s: autonegotiation complete: "
-	   	    "%sbaseT-%cD selected\n", dev->name,
-		    ((p & 0x0180) ? "100" : "10"),
-		    (((p & 0x0100) || ((p & 0x1c0) == 0x40)) ? 'F' : 'H'));
+		       "%sbaseT-%cD selected\n", dev->name,
+		       ((p & 0x0180) ? "100" : "10"),
+		       (smc->duplex ? 'F' : 'H'));
 	    }
+	    SMC_SELECT_BANK(0);
+	    outw(inw(ioaddr + TCR) | smc->duplex, ioaddr + TCR);
 	    smc->link_status = link;
 	}
-    }
-
-    if (smc->cfg & CFG_MII_SELECT)
 	goto reschedule;
+    }
 
     /* Ignore collisions unless we've had no rx's recently */
     if (jiffies - dev->last_rx > HZ) {
@@ -2053,7 +2076,7 @@
 	}
 	smc->media_status = media;
     }
-    
+
 reschedule:
     smc->media.expires = jiffies + HZ;
     add_timer(&smc->media);
@@ -2167,7 +2190,7 @@
 	    return -EFAULT;
 	spin_lock_irq(&smc->lock);
 	if (smc->cfg & CFG_MII_SELECT)
-	    ret = mii_ethtool_sset(&smc->mii_if, &ecmd);    
+	    ret = mii_ethtool_sset(&smc->mii_if, &ecmd);
 	else
 	    ret = smc_netdev_set_ecmd(dev, &ecmd);
 	spin_unlock_irq(&smc->lock);
@@ -2194,7 +2217,7 @@
 	    return -EFAULT;
 	return 0;
     }
-    
+
     /* set message-level */
     case ETHTOOL_SMSGLVL: {
 	struct ethtool_value edata;
@@ -2211,7 +2234,7 @@
 	else
 	    return -EOPNOTSUPP;
     }
-    
+
     default:
 	break;
     }
@@ -2233,7 +2256,7 @@
     case SIOCETHTOOL:
 	rc = smc_ethtool_ioctl(dev, (void *) rq->ifr_data);
 	break;
-    
+
     default:
 	spin_lock_irq(&smc->lock);
 	rc = generic_mii_ioctl(&smc->mii_if, mii, cmd, NULL);
@@ -2255,7 +2278,7 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_ERR
 	       "smc91c92_cs: Card Services release does not match!\n");
-	return -1;
+	return -EINVAL;
     }
     register_pccard_driver(&dev_info, &smc91c92_attach, &smc91c92_detach);
     return 0;
@@ -2271,4 +2294,3 @@
 
 module_init(init_smc91c92_cs);
 module_exit(exit_smc91c92_cs);
-
diff -Nru a/drivers/net/sundance.c b/drivers/net/sundance.c
--- a/drivers/net/sundance.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/net/sundance.c	Sun Nov 10 19:28:40 2002
@@ -63,14 +63,20 @@
 	- Better rx buf size calculation (Donald Becker)
 
 	Version LK1.05 (D-Link):
-	- fix DFE-580TX packet drop issue
-	- fix reset_tx logic
+	- Fix DFE-580TX packet drop issue (for DL10050C)
+	- Fix reset_tx logic
+
+	Version LK1.06 (D-Link):
+	- Fix crash while unloading driver
+
+	Versin LK1.06b (D-Link):
+	- New tx scheme, adaptive tx_coalesce
 
 */
 
 #define DRV_NAME	"sundance"
-#define DRV_VERSION	"1.01+LK1.05"
-#define DRV_RELDATE	"28-Sep-2002"
+#define DRV_VERSION	"1.01+LK1.06b"
+#define DRV_RELDATE	"6-Nov-2002"
 
 
 /* The user-configurable values.
@@ -87,7 +93,6 @@
    This chip can receive into offset buffers, so the Alpha does not
    need a copy-align. */
 static int rx_copybreak;
-static int tx_coalesce=1;
 static int flowctrl=1;
 
 /* media[] specifies the media type the NIC operates at.
@@ -114,7 +119,7 @@
    bonding and packet priority, and more than 128 requires modifying the
    Tx error recovery.
    Large receive rings merely waste memory. */
-#define TX_RING_SIZE	64
+#define TX_RING_SIZE	32
 #define TX_QUEUE_LEN	(TX_RING_SIZE - 1) /* Limit ring entries actually used.  */
 #define RX_RING_SIZE	64
 #define RX_BUDGET	32
@@ -459,7 +464,9 @@
 	unsigned int an_enable:1;
 	unsigned int speed;
 	struct tasklet_struct rx_tasklet;
+	struct tasklet_struct tx_tasklet;
 	int budget;
+	int cur_task;
 	/* Multicast and receive mode. */
 	spinlock_t mcastlock;			/* SMP lock multicast updates. */
 	u16 mcast_filter[4];
@@ -468,6 +475,7 @@
 	int mii_preamble_required;
 	unsigned char phys[MII_CNT];		/* MII device addresses, only first one used. */
 	struct pci_dev *pci_dev;
+	unsigned char pci_rev_id;
 };
 
 /* The station address location in the EEPROM. */
@@ -489,6 +497,7 @@
 static int reset_tx (struct net_device *dev);
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *regs);
 static void rx_poll(unsigned long data);
+static void tx_poll(unsigned long data);
 static void refill_rx (struct net_device *dev);
 static void netdev_error(struct net_device *dev, int intr_status);
 static void netdev_error(struct net_device *dev, int intr_status);
@@ -557,6 +566,7 @@
 	np->msg_enable = (1 << debug) - 1;
 	spin_lock_init(&np->lock);
 	tasklet_init(&np->rx_tasklet, rx_poll, (unsigned long)dev);
+	tasklet_init(&np->tx_tasklet, tx_poll, (unsigned long)dev);
 
 	ring_space = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);
 	if (!ring_space)
@@ -588,6 +598,8 @@
 	dev->change_mtu = &change_mtu;
 	pci_set_drvdata(pdev, dev);
 
+	pci_read_config_byte(pdev, PCI_REVISION_ID, &np->pci_rev_id);
+
 	i = register_netdev(dev);
 	if (i)
 		goto err_out_unmap_rx;
@@ -650,10 +662,6 @@
 				np->an_enable = 1;
 			}
 		}
-		if (tx_coalesce < 1)
-			tx_coalesce = 1;
-		else if (tx_coalesce > TX_QUEUE_LEN - 1)
-			tx_coalesce = TX_QUEUE_LEN - 1;
 		if (flowctrl == 0)
 			np->flowctrl = 0;
 	}
@@ -867,7 +875,8 @@
 	writeb(100, ioaddr + RxDMAPollPeriod);
 	writeb(127, ioaddr + TxDMAPollPeriod);
 	/* Fix DFE-580TX packet drop issue */
-	writeb(0x01, ioaddr + DebugCtrl1);
+	if (np->pci_rev_id >= 0x14)
+		writeb(0x01, ioaddr + DebugCtrl1);
 	netif_start_queue(dev);
 
 	writew(StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
@@ -943,7 +952,9 @@
 	struct netdev_private *np = dev->priv;
 	long ioaddr = dev->base_addr;
 	long flag;
-
+	
+	netif_stop_queue(dev);
+	tasklet_disable(&np->tx_tasklet);
 	writew(0, ioaddr + IntrEnable);
 	printk(KERN_WARNING "%s: Transmit timed out, TxStatus %2.2x "
 		   "TxFrameId %2.2x,"
@@ -952,31 +963,39 @@
 
 	{
 		int i;
-		printk(KERN_DEBUG "  Rx ring %p: ", np->rx_ring);
-		for (i = 0; i < RX_RING_SIZE; i++)
-			printk(" %8.8x", (unsigned int)np->rx_ring[i].status);
-		printk("\n"KERN_DEBUG"  Tx ring %p: ", np->tx_ring);
-		for (i = 0; i < TX_RING_SIZE; i++)
-			printk(" %8.8x", np->tx_ring[i].status);
-		printk("\n");
-		printk(KERN_DEBUG "cur_tx=%d dirty_tx=%d\n", np->cur_tx, np->dirty_tx);
+		for (i=0; i<TX_RING_SIZE; i++) {
+			printk(KERN_DEBUG "%02x %08x %08x %08x(%02x) %08x %08x\n", i,
+				np->tx_ring_dma + i*sizeof(*np->tx_ring),	
+				np->tx_ring[i].next_desc,
+				np->tx_ring[i].status,
+				(np->tx_ring[i].status >> 2) & 0xff,
+				np->tx_ring[i].frag[0].addr, 
+				np->tx_ring[i].frag[0].length);
+		}
+		printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n", 
+			readl(dev->base_addr + TxListPtr), 
+			netif_queue_stopped(dev));
+		printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n", 
+			np->cur_tx, np->cur_tx % TX_RING_SIZE,
+			np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
 		printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
+		printk(KERN_DEBUG "cur_task=%d\n", np->cur_task);
 	}
 	spin_lock_irqsave(&np->lock, flag);
+
+	/* Stop and restart the chip's Tx processes . */
 	reset_tx(dev);
 	spin_unlock_irqrestore(&np->lock, flag);
 
-	/* Perhaps we should reinitialize the hardware here. */
 	dev->if_port = 0;
-	/* Stop and restart the chip's Tx processes . */
-
-	/* Trigger an immediate transmit demand. */
-	writew(DEFAULT_INTR, ioaddr + IntrEnable);
 
 	dev->trans_start = jiffies;
 	np->stats.tx_errors++;
-	if (!netif_queue_stopped(dev))
+	if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
 		netif_wake_queue(dev);
+	}
+	writew(DEFAULT_INTR, ioaddr + IntrEnable);
+	tasklet_enable(&np->tx_tasklet);
 }
 
 
@@ -988,6 +1007,7 @@
 
 	np->cur_rx = np->cur_tx = 0;
 	np->dirty_rx = np->dirty_tx = 0;
+	np->cur_task = 0;
 
 	np->rx_buf_sz = (dev->mtu <= 1520 ? PKT_BUF_SZ : dev->mtu + 16);
 
@@ -1022,39 +1042,57 @@
 	return;
 }
 
+static void tx_poll (unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct netdev_private *np = dev->priv;
+	unsigned head = np->cur_task % TX_RING_SIZE;
+	struct netdev_desc *txdesc = 
+		&np->tx_ring[(np->cur_tx - 1) % TX_RING_SIZE];
+	
+	/* Chain the next pointer */
+	for (; np->cur_tx - np->cur_task > 0; np->cur_task++) {
+		int entry = np->cur_task % TX_RING_SIZE;
+		txdesc = &np->tx_ring[entry];
+		if (np->last_tx) {
+			np->last_tx->next_desc = cpu_to_le32(np->tx_ring_dma +
+				entry*sizeof(struct netdev_desc));
+		}
+		np->last_tx = txdesc;
+	}
+	/* Indicate the latest descriptor of tx ring */
+	txdesc->status |= cpu_to_le32(DescIntrOnTx);
+
+	if (readl (dev->base_addr + TxListPtr) == 0)
+		writel (np->tx_ring_dma + head * sizeof(struct netdev_desc),
+			dev->base_addr + TxListPtr);
+	return;
+}
+
 static int
 start_tx (struct sk_buff *skb, struct net_device *dev)
 {
 	struct netdev_private *np = dev->priv;
 	struct netdev_desc *txdesc;
 	unsigned entry;
-	long ioaddr = dev->base_addr;
 
-	/* Note: Ordering is important here, set the field with the
-	   "ownership" bit last, and only then increment cur_tx. */
 	/* Calculate the next Tx descriptor entry. */
 	entry = np->cur_tx % TX_RING_SIZE;
 	np->tx_skbuff[entry] = skb;
 	txdesc = &np->tx_ring[entry];
 
 	txdesc->next_desc = 0;
-	/* Note: disable the interrupt generation here before releasing. */
-	if (entry % tx_coalesce == 0) {
-		txdesc->status = cpu_to_le32 ((entry << 2) |
-				 DescIntrOnTx | DisableAlign);
-
-	} else {
-		txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign);
-	}
+	txdesc->status = cpu_to_le32 ((entry << 2) | DisableAlign);
 	txdesc->frag[0].addr = cpu_to_le32 (pci_map_single (np->pci_dev, skb->data,
 							skb->len,
 							PCI_DMA_TODEVICE));
 	txdesc->frag[0].length = cpu_to_le32 (skb->len | LastFrag);
-	if (np->last_tx)
-		np->last_tx->next_desc = cpu_to_le32(np->tx_ring_dma +
-			entry*sizeof(struct netdev_desc));
-	np->last_tx = txdesc;
+
+	/* Increment cur_tx before tasklet_schedule() */
 	np->cur_tx++;
+	mb();
+	/* Schedule a tx_poll() task */
+	tasklet_schedule(&np->tx_tasklet);
 
 	/* On some architectures: explicitly flush cache lines here. */
 	if (np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 1
@@ -1063,23 +1101,16 @@
 	} else {
 		netif_stop_queue (dev);
 	}
-	/* Side effect: The read wakes the potentially-idle transmit channel. */
-	if (readl (dev->base_addr + TxListPtr) == 0)
-		writel (np->tx_ring_dma + entry*sizeof(*np->tx_ring),
-			dev->base_addr + TxListPtr);
-
 	dev->trans_start = jiffies;
-
 	if (netif_msg_tx_queued(np)) {
 		printk (KERN_DEBUG
 			"%s: Transmit frame #%d queued in slot %d.\n",
 			dev->name, np->cur_tx, entry);
 	}
-	if (tx_coalesce > 1)
-		writel (1000, ioaddr + DownCounter);
 	return 0;
 }
-/* Reset hardware tx and reset TxListPtr to TxFrameId */
+
+/* Reset hardware tx and free all of tx buffers */
 static int
 reset_tx (struct net_device *dev)
 {
@@ -1089,8 +1120,8 @@
 	int i;
 	int irq = in_interrupt();
 	
-	/* reset tx logic */
-	writel (0, dev->base_addr + TxListPtr);
+	/* Reset tx logic, TxListPtr will be cleaned */
+	writew (TxDisable, ioaddr + MACCtrl1);
 	writew (TxReset | DMAReset | FIFOReset | NetworkReset,
 			ioaddr + ASICCtrl + 2);
 	for (i=50; i > 0; i--) {
@@ -1114,11 +1145,13 @@
 		}
 	}
 	np->cur_tx = np->dirty_tx = 0;
+	np->cur_task = 0;
+	writew (StatsEnable | RxEnable | TxEnable, ioaddr + MACCtrl1);
 	return 0;
 }
 
-/* The interrupt handler does all of the Rx thread work and cleans up
-   after the Tx thread. */
+/* The interrupt handler cleans up after the Tx thread, 
+   and schedule a Rx thread work */
 static void intr_handler(int irq, void *dev_instance, struct pt_regs *rgs)
 {
 	struct net_device *dev = (struct net_device *)dev_instance;
@@ -1126,6 +1159,8 @@
 	long ioaddr;
 	int boguscnt = max_interrupt_work;
 	int hw_frame_id;
+	int tx_cnt;
+	int tx_status;
 
 	ioaddr = dev->base_addr;
 	np = dev->priv;
@@ -1148,15 +1183,13 @@
 				np->budget = RX_BUDGET;
 			tasklet_schedule(&np->rx_tasklet);
 		}
-
 		if (intr_status & (IntrTxDone | IntrDrvRqst)) {
-			int boguscnt = 32;
-			int tx_status = readw (ioaddr + TxStatus);
-			while (tx_status & 0x80) {
+			tx_status = readw (ioaddr + TxStatus);
+			for (tx_cnt=32; tx_status & 0x80; --tx_cnt) {
 				if (netif_msg_tx_done(np))
 					printk
 					    ("%s: Transmit status is %2.2x.\n",
-					     dev->name, tx_status);
+				     	dev->name, tx_status);
 				if (tx_status & 0x1e) {
 					np->stats.tx_errors++;
 					if (tx_status & 0x10)
@@ -1179,35 +1212,62 @@
 				/* Yup, this is a documentation bug.  It cost me *hours*. */
 				writew (0, ioaddr + TxStatus);
 				tx_status = readw (ioaddr + TxStatus);
-				if (--boguscnt < 0)
+				if (tx_cnt < 0)
 					break;
 			}
+			hw_frame_id = (tx_status >> 8) & 0xff;
+		} else 	{
+			hw_frame_id = readb(ioaddr + TxFrameId);
 		}
-		spin_lock(&np->lock);
-		hw_frame_id = readb(ioaddr + TxFrameId);
-		for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
-			int entry = np->dirty_tx % TX_RING_SIZE;
-			struct sk_buff *skb;
-			int sw_frame_id;
-			sw_frame_id = (np->tx_ring[entry].status >> 2) & 0xff;
 			
-			if (sw_frame_id == hw_frame_id)
-				break;
-			skb = np->tx_skbuff[entry];
-			/* Free the original skb. */
-			pci_unmap_single(np->pci_dev,
-				np->tx_ring[entry].frag[0].addr,
-				skb->len, PCI_DMA_TODEVICE);
-			dev_kfree_skb_irq (np->tx_skbuff[entry]);
-			np->tx_skbuff[entry] = 0;
+		if (np->pci_rev_id >= 0x14) {	
+			spin_lock(&np->lock);
+			for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
+				int entry = np->dirty_tx % TX_RING_SIZE;
+				struct sk_buff *skb;
+				int sw_frame_id;
+				sw_frame_id = (np->tx_ring[entry].status >> 2) & 0xff;
+					if (sw_frame_id == hw_frame_id &&
+						!(np->tx_ring[entry].status & 0x00010000))
+						break;
+					if (sw_frame_id == (hw_frame_id + 1) % TX_RING_SIZE)
+						break;
+				skb = np->tx_skbuff[entry];
+				/* Free the original skb. */
+				pci_unmap_single(np->pci_dev,
+					np->tx_ring[entry].frag[0].addr,
+					skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_irq (np->tx_skbuff[entry]);
+				np->tx_skbuff[entry] = 0;
+				np->tx_ring[entry].frag[0].addr = 0;
+				np->tx_ring[entry].frag[0].length = 0;
+			}
+			spin_unlock(&np->lock);
+		} else {
+			spin_lock(&np->lock);
+			for (; np->cur_tx - np->dirty_tx > 0; np->dirty_tx++) {
+				int entry = np->dirty_tx % TX_RING_SIZE;
+				struct sk_buff *skb;
+				if (!(np->tx_ring[entry].status & 0x00010000))
+					break;
+				skb = np->tx_skbuff[entry];
+				/* Free the original skb. */
+				pci_unmap_single(np->pci_dev,
+					np->tx_ring[entry].frag[0].addr,
+					skb->len, PCI_DMA_TODEVICE);
+				dev_kfree_skb_irq (np->tx_skbuff[entry]);
+				np->tx_skbuff[entry] = 0;
+				np->tx_ring[entry].frag[0].addr = 0;
+				np->tx_ring[entry].frag[0].length = 0;
+			}
+			spin_unlock(&np->lock);
 		}
-		spin_unlock(&np->lock);
+		
 		if (netif_queue_stopped(dev) &&
 			np->cur_tx - np->dirty_tx < TX_QUEUE_LEN - 4) {
-			/* The ring is no longer full, clear tbusy. */
+			/* The ring is no longer full, clear busy flag. */
 			netif_wake_queue (dev);
 		}
-
 		/* Abnormal error summary/uncommon events handlers. */
 		if (intr_status & (IntrPCIErr | LinkChange | StatsMax))
 			netdev_error(dev, intr_status);
@@ -1223,8 +1283,7 @@
 	if (netif_msg_intr(np))
 		printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n",
 			   dev->name, readw(ioaddr + IntrStatus));
-	if (np->cur_tx - np->dirty_tx > 0 && tx_coalesce > 1)
-		writel(100, ioaddr + DownCounter);
+	writel(5000, ioaddr + DownCounter);
 
 }
 
@@ -1246,7 +1305,7 @@
 		if (--boguscnt < 0) {
 			goto not_done;
 		}
-		if (!(desc->status & DescOwn))
+		if (!(frame_status & DescOwn))
 			break;
 		pkt_len = frame_status & 0x1fff;	/* Chip omits the CRC. */
 		if (netif_msg_rx_status(np))
@@ -1555,6 +1614,7 @@
 	struct netdev_private *np = dev->priv;
 	struct mii_ioctl_data *data = (struct mii_ioctl_data *) & rq->ifr_data;
 	int rc;
+	int i;
 
 	if (!netif_running(dev))
 		return -EINVAL;
@@ -1567,6 +1627,28 @@
 		rc = generic_mii_ioctl(&np->mii_if, data, cmd, NULL);
 		spin_unlock_irq(&np->lock);
 	}
+	switch (cmd) {
+		case SIOCDEVPRIVATE:
+		for (i=0; i<TX_RING_SIZE; i++) {
+			printk(KERN_DEBUG "%02x %08x %08x %08x(%02x) %08x %08x\n", i,
+				np->tx_ring_dma + i*sizeof(*np->tx_ring),	
+				np->tx_ring[i].next_desc,
+				np->tx_ring[i].status,
+				(np->tx_ring[i].status >> 2) & 0xff,
+				np->tx_ring[i].frag[0].addr, 
+				np->tx_ring[i].frag[0].length);
+		}
+		printk(KERN_DEBUG "TxListPtr=%08x netif_queue_stopped=%d\n", 
+			readl(dev->base_addr + TxListPtr), 
+			netif_queue_stopped(dev));
+		printk(KERN_DEBUG "cur_tx=%d(%02x) dirty_tx=%d(%02x)\n", 
+			np->cur_tx, np->cur_tx % TX_RING_SIZE,
+			np->dirty_tx, np->dirty_tx % TX_RING_SIZE);
+		printk(KERN_DEBUG "cur_rx=%d dirty_rx=%d\n", np->cur_rx, np->dirty_rx);
+		printk(KERN_DEBUG "cur_task=%d\n", np->cur_task);
+			return 0;
+	}
+				
 
 	return rc;
 }
@@ -1594,6 +1676,10 @@
 
 	/* Stop the chip's Tx and Rx processes. */
 	writew(TxDisable | RxDisable | StatsDisable, ioaddr + MACCtrl1);
+
+	/* Wait and kill tasklet */
+	tasklet_kill(&np->rx_tasklet);
+	tasklet_kill(&np->tx_tasklet);
 
 #ifdef __i386__
 	if (netif_msg_hw(np)) {
diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/net/tg3.c	Sun Nov 10 19:28:40 2002
@@ -2729,7 +2729,7 @@
 				 pci_unmap_addr(rxp, mapping),
 				 RX_PKT_BUF_SZ - tp->rx_offset,
 				 PCI_DMA_FROMDEVICE);
-		dev_kfree_skb(rxp->skb);
+		dev_kfree_skb_any(rxp->skb);
 		rxp->skb = NULL;
 	}
 #if TG3_MINI_RING_WORKS
@@ -2742,7 +2742,7 @@
 				 pci_unmap_addr(rxp, mapping),
 				 RX_MINI_PKT_BUF_SZ - tp->rx_offset,
 				 PCI_DMA_FROMDEVICE);
-		dev_kfree_skb(rxp->skb);
+		dev_kfree_skb_any(rxp->skb);
 		rxp->skb = NULL;
 	}
 #endif
@@ -2755,7 +2755,7 @@
 				 pci_unmap_addr(rxp, mapping),
 				 RX_JUMBO_PKT_BUF_SZ - tp->rx_offset,
 				 PCI_DMA_FROMDEVICE);
-		dev_kfree_skb(rxp->skb);
+		dev_kfree_skb_any(rxp->skb);
 		rxp->skb = NULL;
 	}
 
diff -Nru a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
--- a/drivers/net/tulip/de2104x.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/net/tulip/de2104x.c	Sun Nov 10 19:28:40 2002
@@ -2014,6 +2014,7 @@
 	dev->watchdog_timeo = TX_TIMEOUT;
 
 	dev->irq = pdev->irq;
+	init_timer(&de->media_timer);
 
 	de = dev->priv;
 	de->de21040 = ent->driver_data == 0 ? 1 : 0;
@@ -2216,6 +2217,7 @@
 	.name		= DRV_NAME,
 	.id_table	= de_pci_tbl,
 	.probe		= de_init_one,
+#warning only here to fix build.  should be __exit_p not __devexit_p.
 	.remove		= __devexit_p(de_remove_one),
 #ifdef CONFIG_PM
 	.suspend	= de_suspend,
diff -Nru a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
--- a/drivers/net/tulip/de4x5.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/net/tulip/de4x5.c	Sun Nov 10 19:28:36 2002
@@ -5291,6 +5291,7 @@
     if (dt==0) dt=1;
     
     /* Set up timer */
+    init_timer(&lp->timer);
     lp->timer.expires = jiffies + dt;
     lp->timer.function = fn;
     lp->timer.data = data;
diff -Nru a/drivers/net/wan/comx-hw-munich.c b/drivers/net/wan/comx-hw-munich.c
--- a/drivers/net/wan/comx-hw-munich.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/net/wan/comx-hw-munich.c	Sun Nov 10 19:28:38 2002
@@ -1854,6 +1854,7 @@
 
     if (board->isx21)
     {
+	init_timer(&board->modemline_timer);
 	board->modemline_timer.data = (unsigned int)board;
 	board->modemline_timer.function = pcicom_modemline;
 	board->modemline_timer.expires = jiffies + HZ;
diff -Nru a/drivers/net/wan/comx-proto-fr.c b/drivers/net/wan/comx-proto-fr.c
--- a/drivers/net/wan/comx-proto-fr.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/net/wan/comx-proto-fr.c	Sun Nov 10 19:28:38 2002
@@ -214,6 +214,7 @@
 		}
 		fr->keepa_freq = keepa;
 		fr->local_cnt = fr->remote_cnt = 0;
+		init_timer(&fr->keepa_timer);
 		fr->keepa_timer.expires = jiffies + HZ;
 		fr->keepa_timer.function = fr_keepalive_timerfun;
 		fr->keepa_timer.data = (unsigned long)dev;
diff -Nru a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
--- a/drivers/net/wireless/airo_cs.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/net/wireless/airo_cs.c	Sun Nov 10 19:28:38 2002
@@ -15,7 +15,7 @@
 
     In addition this module was derived from dummy_cs.
     The initial developer of dummy_cs is David A. Hinds
-    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.    
     
 ======================================================================*/
diff -Nru a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h
--- a/drivers/net/wireless/wavelan.p.h	Sun Nov 10 19:28:40 2002
+++ b/drivers/net/wireless/wavelan.p.h	Sun Nov 10 19:28:40 2002
@@ -143,7 +143,7 @@
  * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished this work.
  * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
  * 2.00 cards correctly (2.4 GHz with frequency selection).
- * David Hinds <dhinds@hyper.stanford.edu> integrated the whole in his
+ * David Hinds <dahinds@users.sourceforge.net> integrated the whole in his
  * PCMCIA package (and bug corrections).
  *
  * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
diff -Nru a/drivers/net/znet.c b/drivers/net/znet.c
--- a/drivers/net/znet.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/net/znet.c	Sun Nov 10 19:28:36 2002
@@ -72,7 +72,10 @@
    - Use proper resources management.
    - Use wireless/i82593.h as much as possible (structure, constants)
    - Compiles as module or build-in.
+   - Now survives unplugging/replugging cable.
 
+   Some code was taken from wavelan_cs.
+   
    Tested on a vintage Zenith Z-Note 433Lnp+. Probably broken on
    anything else. Testers (and detailed bug reports) are welcome :-).
 
@@ -105,7 +108,7 @@
 /* This include could be elsewhere, since it is not wireless specific */
 #include "wireless/i82593.h"
 
-static const char version[] __initdata = "znet.c:v1.02 9/23/94 becker@cesdis.gsfc.nasa.gov\n";
+static const char version[] __initdata = "znet.c:v1.02 9/23/94 becker@scyld.com\n";
 
 #ifndef ZNET_DEBUG
 #define ZNET_DEBUG 1
@@ -299,7 +302,7 @@
 	cfblk->cd_filter = 0;  	/* CD is recognized immediately */
 	
 	/* Byte 9 */
-	cfblk->min_fr_len = 64 >> 2; /* Minimum frame length 64 bytes */
+	cfblk->min_fr_len = ETH_ZLEN >> 2; /* Minimum frame length */
 	
 	/* Byte A */
 	cfblk->lng_typ = 1;	/* Type/length checks OFF */
@@ -544,10 +547,14 @@
 	
 	/* Check that the part hasn't reset itself, probably from suspend. */
 	outb(CR0_STATUS_0, ioaddr);
-	if (inw(ioaddr) == 0x0010
-		&& inw(ioaddr) == 0x0000
-		&& inw(ioaddr) == 0x0010)
-	  hardware_init(dev);
+	if (inw(ioaddr) == 0x0010 &&
+	    inw(ioaddr) == 0x0000 &&
+	    inw(ioaddr) == 0x0010) {
+		if (znet_debug > 1)
+			printk (KERN_WARNING "%s : waking up\n", dev->name);
+		hardware_init(dev);
+		znet_transceiver_power (dev, 1);
+	}
 
 	if (1) {
 		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
@@ -624,7 +631,9 @@
 		if ((status & SR0_INTERRUPT) == 0)
 			break;
 
-		if ((status & 0x0F) == SR0_TRANSMIT_DONE) {
+		if ((status & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
+		    (status & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
+		    (status & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE) {
 			int tx_status;
 			outb(CR0_STATUS_1, ioaddr);
 			tx_status = inw(ioaddr);
@@ -644,6 +653,15 @@
 				/* ...and the catch-all. */
 				if ((tx_status | (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL)) != (TX_LOST_CRS | TX_LOST_CTS | TX_UND_RUN | TX_HRT_BEAT | TX_MAX_COL))
 					znet->stats.tx_errors++;
+
+				/* Transceiver may be stuck if cable
+				 * was removed while emiting a
+				 * packet. Flip it off, then on to
+				 * reset it. This is very empirical,
+				 * but it seems to work. */
+				
+				znet_transceiver_power (dev, 0);
+				znet_transceiver_power (dev, 1);
 			}
 			netif_wake_queue (dev);
 		}
diff -Nru a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
--- a/drivers/oprofile/buffer_sync.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/oprofile/buffer_sync.c	Sun Nov 10 19:28:38 2002
@@ -91,7 +91,8 @@
 	err = profile_event_register(EXEC_UNMAP, &exec_unmap_nb);
 	if (err)
 		goto out3;
- 
+
+	init_timer(&sync_timer);
 	sync_timer.function = timer_ping;
 	sync_timer.expires = jiffies + DEFAULT_EXPIRE;
 	add_timer(&sync_timer);
diff -Nru a/drivers/parisc/Kconfig b/drivers/parisc/Kconfig
--- a/drivers/parisc/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/drivers/parisc/Kconfig	Sun Nov 10 19:28:40 2002
@@ -22,18 +22,22 @@
 	bool "Lasi I/O support"
 	depends on GSC
 	help
-	  Say Y here to directly support the Lasi controller chip found on
-	  PA-RISC workstations.  Linux-oriented documentation for this chip
-	  can be found at <http://www.parisc-linux.org/documentation/>.
+	  Say Y here to support the Lasi multifunction chip found in
+	  many PA-RISC workstations & servers.	It includes interfaces
+	  for a parallel port, serial port, NCR 53c710 SCSI, Apricot
+	  Ethernet, Harmony audio, PS/2 keyboard & mouse, ISDN, telephony
+	  and floppy.  Note that you must still enable all the individual
+	  drivers for these chips.
 
 config GSC_WAX
 	bool "Wax I/O support"
 	depends on GSC
 	help
-	  Say Y here to support the Wax GSC to EISA Bridge found in some older
-	  systems, including B/C/D/R class.  Some machines use Wax for other
-	  purposes, such as providing one of the serial ports or being an
-	  interface chip for an X.25 GSC card.
+	  Say Y here to support the Wax multifunction chip found in some
+	  older systems, including B/C/D/R class and 715/64, 715/80 and
+	  715/100.  Wax includes an EISA adapter, a serial port (not always
+	  used), a HIL interface chip and is also known to be used as the
+	  GSC bridge for an X.25 GSC card.
 
 config EISA
 	bool "EISA support"
@@ -64,7 +68,8 @@
 	  machines from the B132 to the C360, the J2240 and the A180.  Some
 	  GSC/HSC cards (eg gigabit & dual 100 Mbit Ethernet) have a Dino on
 	  the card, and you also need to say Y here if you have such a card.
-	  If in doubt, say Y.
+	  Note that Dino also supplies one of the serial ports on certain
+	  machines.  If in doubt, say Y.
 
 config PCI_LBA
 	bool "LBA/Elroy PCI support"
@@ -84,6 +89,8 @@
 	depends on PCI_LBA
 	default y
 
+source "drivers/pci/Kconfig"
+
 #config PCI_EPIC
 #	bool "EPIC/SAGA PCI support"
 #	depends on PCI
@@ -93,11 +100,18 @@
 	depends on PCI
 	help
 	  Say Y here to support the SuperIO chip found in Bxxxx, C3xxx and
-	  J5xxx+ machines.
-
-source "drivers/pci/Kconfig"
+	  J5xxx+ machines. This enables IDE, Floppy, Parallel Port, and
+	  Serial port on those machines.
 
 config CHASSIS_LCD_LED
 	bool "Chassis LCD and LED support"
+	help
+	  Say Y here if you want to enable support for the Heartbeat,
+	  Disk/Network activities LEDs on some PA-RISC machines,
+	  or support for the LCD that can be found on recent material.
+	
+	  This has nothing to do with LED State support for A, J and E class.
+	
+	  If unsure, say Y.
 
 endmenu
diff -Nru a/drivers/parisc/asp.c b/drivers/parisc/asp.c
--- a/drivers/parisc/asp.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/parisc/asp.c	Sun Nov 10 19:28:41 2002
@@ -125,7 +125,7 @@
 };
 
 struct parisc_driver asp_driver = {
-	name:		"Asp",
-	id_table:	asp_tbl,
-	probe:		asp_init_chip,
+	.name =		"Asp",
+	.id_table =	asp_tbl,
+	.probe =	asp_init_chip,
 };
diff -Nru a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
--- a/drivers/parisc/ccio-dma.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/parisc/ccio-dma.c	Sun Nov 10 19:28:37 2002
@@ -1596,9 +1596,9 @@
 };
 
 static struct parisc_driver ccio_driver = {
-	name:		"U2/Uturn",
-	id_table:	ccio_tbl,
-	probe:		ccio_probe,
+	.name =		"U2/Uturn",
+	.id_table =	ccio_tbl,
+	.probe =	ccio_probe,
 };
 
 /**
diff -Nru a/drivers/parisc/ccio-rm-dma.c b/drivers/parisc/ccio-rm-dma.c
--- a/drivers/parisc/ccio-rm-dma.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/parisc/ccio-rm-dma.c	Sun Nov 10 19:28:38 2002
@@ -191,9 +191,9 @@
 };
 
 static struct parisc_driver ccio_driver = {
-        name:           "U2/Uturn",
-        id_table:       ccio_tbl,
-        probe:          ccio_probe,
+	.name =		"U2/Uturn",
+	.id_table =	ccio_tbl,
+	.probe =	ccio_probe,
 };
 
 void __init ccio_init(void)
diff -Nru a/drivers/parisc/dino.c b/drivers/parisc/dino.c
--- a/drivers/parisc/dino.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/parisc/dino.c	Sun Nov 10 19:28:36 2002
@@ -917,9 +917,9 @@
 };
 
 static struct parisc_driver dino_driver = {
-	.name		= "Dino",
-	.id_table	= dino_tbl,
-	.probe		= dino_driver_callback,
+	.name =		"Dino",
+	.id_table =	dino_tbl,
+	.probe =	dino_driver_callback,
 };
 
 /*
diff -Nru a/drivers/parisc/eisa.c b/drivers/parisc/eisa.c
--- a/drivers/parisc/eisa.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/parisc/eisa.c	Sun Nov 10 19:28:36 2002
@@ -387,9 +387,9 @@
 MODULE_DEVICE_TABLE(parisc, eisa_tbl);
 
 static struct parisc_driver eisa_driver = {
-	name:		"EISA Bus Adapter",
-	id_table:	eisa_tbl,
-	probe:		eisa_probe,
+	.name =		"EISA Bus Adapter",
+	.id_table =	eisa_tbl,
+	.probe =	eisa_probe,
 };
 
 void __init eisa_init(void)
diff -Nru a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c
--- a/drivers/parisc/eisa_eeprom.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/parisc/eisa_eeprom.c	Sun Nov 10 19:28:41 2002
@@ -79,12 +79,12 @@
  *	The various file operations we support.
  */
 static struct file_operations eisa_eeprom_fops = {
-	owner:		THIS_MODULE,
-	llseek:		eisa_eeprom_llseek,
-	read:		eisa_eeprom_read,
-	ioctl:		eisa_eeprom_ioctl,
-	open:		eisa_eeprom_open,
-	release:	eisa_eeprom_release,
+	.owner =	THIS_MODULE,
+	.llseek =	eisa_eeprom_llseek,
+	.read =		eisa_eeprom_read,
+	.ioctl =	eisa_eeprom_ioctl,
+	.open =		eisa_eeprom_open,
+	.release =	eisa_eeprom_release,
 };
 
 static struct miscdevice eisa_eeprom_dev=
diff -Nru a/drivers/parisc/gsc.c b/drivers/parisc/gsc.c
--- a/drivers/parisc/gsc.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/parisc/gsc.c	Sun Nov 10 19:28:41 2002
@@ -152,10 +152,10 @@
 }
 
 struct irq_region_ops busdev_irq_ops = {
-	disable_irq:	busdev_disable_irq,
-	enable_irq:	busdev_enable_irq,
-	mask_irq:	busdev_mask_irq,
-	unmask_irq:	busdev_unmask_irq
+	.disable_irq =	busdev_disable_irq,
+	.enable_irq =	busdev_enable_irq,
+	.mask_irq =	busdev_mask_irq,
+	.unmask_irq =	busdev_unmask_irq
 };
 
 
diff -Nru a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
--- a/drivers/parisc/iosapic.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/parisc/iosapic.c	Sun Nov 10 19:28:37 2002
@@ -941,10 +941,10 @@
 
 
 static struct irq_region_ops iosapic_irq_ops = {
-	disable_irq:	iosapic_disable_irq,
-	enable_irq:	iosapic_enable_irq,
-	mask_irq:	iosapic_mask_irq,
-	unmask_irq:	iosapic_unmask_irq
+	.disable_irq =	iosapic_disable_irq,
+	.enable_irq =	iosapic_enable_irq,
+	.mask_irq =	iosapic_mask_irq,
+	.unmask_irq =	iosapic_unmask_irq
 };
 
 
diff -Nru a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c
--- a/drivers/parisc/lasi.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/parisc/lasi.c	Sun Nov 10 19:28:40 2002
@@ -139,7 +139,7 @@
 	default:
 		datareg = lasi_hpa + 0x0000C000;
 		break;
-	} /* switch() */
+	}
 
 	register_led_driver(DISPLAY_MODEL_LASI, LED_CMD_REG_NONE, (char *)datareg);
 }
@@ -239,7 +239,7 @@
 };
 
 struct parisc_driver lasi_driver = {
-	name:		"Lasi",
-	id_table:	lasi_tbl,
-	probe:		lasi_init_chip,
+	.name =		"Lasi",
+	.id_table =	lasi_tbl,
+	.probe =	lasi_init_chip,
 };
diff -Nru a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
--- a/drivers/parisc/lba_pci.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/parisc/lba_pci.c	Sun Nov 10 19:28:40 2002
@@ -627,8 +627,8 @@
 
 
 static struct pci_ops lba_cfg_ops = {
-	read:	lba_cfg_read,
-	write:	lba_cfg_write,
+	.read =		lba_cfg_read,
+	.write =	lba_cfg_write,
 };
 
 
@@ -865,8 +865,8 @@
 
 
 struct pci_bios_ops lba_bios_ops = {
-	init:		lba_bios_init,
-	fixup_bus:	lba_fixup_bus,
+	.init =		lba_bios_init,
+	.fixup_bus =	lba_fixup_bus,
 };
 
 
@@ -943,12 +943,12 @@
 
 
 static struct pci_port_ops lba_astro_port_ops = {
-	inb:	lba_astro_in8,
-	inw:	lba_astro_in16,
-	inl:	lba_astro_in32,
-	outb:	lba_astro_out8,
-	outw:	lba_astro_out16,
-	outl:	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
 };
 
 
@@ -1003,12 +1003,12 @@
 
 
 static struct pci_port_ops lba_pat_port_ops = {
-	inb:	lba_pat_in8,
-	inw:	lba_pat_in16,
-	inl:	lba_pat_in32,
-	outb:	lba_pat_out8,
-	outw:	lba_pat_out16,
-	outl:	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
 };
 
 
@@ -1462,9 +1462,9 @@
 };
 
 static struct parisc_driver lba_driver = {
-	name:		MODULE_NAME,
-	id_table:	lba_tbl,
-	probe:		lba_driver_callback
+	.name =		MODULE_NAME,
+	.id_table =	lba_tbl,
+	.probe =	lba_driver_callback
 };
 
 /*
diff -Nru a/drivers/parisc/led.c b/drivers/parisc/led.c
--- a/drivers/parisc/led.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/parisc/led.c	Sun Nov 10 19:28:38 2002
@@ -31,6 +31,7 @@
 #include <linux/reboot.h>
 #include <linux/proc_fs.h>
 #include <linux/ctype.h>
+#include <linux/blkdev.h>
 #include <asm/io.h>
 #include <asm/processor.h>
 #include <asm/hardware.h>
@@ -97,13 +98,13 @@
 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,
-      lcd_data_reg_addr:(char *) KITTYHAWK_LCD_DATA,
-      min_cmd_delay:	40,
-      reset_cmd1:	0x80,
-      reset_cmd2:	0xc0,
+	.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,
 };
 
 
@@ -403,9 +404,17 @@
 	int major, disk, total;
 	
 	total = 0;
+#ifdef 0
+	/*
+	 * this section will no longer work in 2.5, as we no longer
+	 * have either kstat.dk_drive nor DK_MAX_*.  It can probably
+	 * be rewritten to use the per-disk statistics now kept in the
+	 * gendisk, but since I have no HP machines to test it on, I'm
+	 * not really up to that.  ricklind@us.ibm.com 11/7/02
+	 */
 	for (major = 0; major < DK_MAX_MAJOR; major++) {
 	    for (disk = 0; disk < DK_MAX_DISK; disk++)
-		total += kstat.dk_drive[major][disk];
+		total += dkstat.drive[major][disk];
 	}
 	total -= diskio_total_last;
 	
@@ -416,6 +425,7 @@
 	    } else
 		led_diskio_counter += CALC_ADD(total, diskio_max, addvalue);
 	}
+#endif
 	
 	diskio_total_last += total; 
 }
diff -Nru a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
--- a/drivers/parisc/sba_iommu.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/parisc/sba_iommu.c	Sun Nov 10 19:28:40 2002
@@ -1919,9 +1919,9 @@
 int sba_driver_callback(struct parisc_device *);
 
 static struct parisc_driver sba_driver = {
-	name:		MODULE_NAME,
-	id_table:	sba_tbl,
-	probe:		sba_driver_callback,
+	.name =		MODULE_NAME,
+	.id_table =	sba_tbl,
+	.probe =	sba_driver_callback,
 };
 
 /*
diff -Nru a/drivers/parisc/superio.c b/drivers/parisc/superio.c
--- a/drivers/parisc/superio.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/parisc/superio.c	Sun Nov 10 19:28:37 2002
@@ -72,7 +72,7 @@
 #include <asm/superio.h>
 
 static struct superio_device sio_dev = {
-	iosapic_irq: -1
+	.iosapic_irq = -1
 };
 
 
@@ -318,10 +318,10 @@
 }
 
 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
+	.disable_irq =	superio_disable_irq,
+	.enable_irq =	superio_enable_irq,
+	.mask_irq =	superio_mask_irq,
+	.unmask_irq =	superio_unmask_irq
 };
 
 #ifdef DEBUG_INIT
@@ -523,9 +523,9 @@
 };
 
 static struct pci_driver superio_driver = {
-	name:		"SuperIO",
-	id_table:	superio_tbl,
-	probe:		superio_probe,
+	.name =		"SuperIO",
+	.id_table =	superio_tbl,
+	.probe =	superio_probe,
 };
 
 static int __init superio_modinit(void)
diff -Nru a/drivers/parisc/wax.c b/drivers/parisc/wax.c
--- a/drivers/parisc/wax.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/parisc/wax.c	Sun Nov 10 19:28:40 2002
@@ -135,7 +135,7 @@
 MODULE_DEVICE_TABLE(parisc, wax_tbl);
 
 struct parisc_driver wax_driver = {
-	name:		"Wax",
-	id_table:	wax_tbl,
-	probe:		wax_init_chip,
+	.name =		"Wax",
+	.id_table =	wax_tbl,
+	.probe =	wax_init_chip,
 };
diff -Nru a/drivers/parport/Kconfig b/drivers/parport/Kconfig
--- a/drivers/parport/Kconfig	Sun Nov 10 19:28:41 2002
+++ b/drivers/parport/Kconfig	Sun Nov 10 19:28:41 2002
@@ -1,6 +1,6 @@
 #
 # For a description of the syntax of this configuration file,
-# see Documentation/kbuild/config-language.txt.
+# see Documentation/kbuild/kconfig-language.txt.
 #
 # Parport configuration.
 #
@@ -38,9 +38,10 @@
 	tristate "PC-style hardware"
 	depends on PARPORT
 	---help---
-	  You should say Y here if you have a PC-style parallel port. All IBM
-	  PC compatible computers and some Alphas have PC-style parallel
-	  ports.
+	  You should say Y here if you have a PC-style parallel port. All
+	  IBM PC compatible computers and some Alphas have PC-style
+	  parallel ports.  PA-RISC owners should only say Y here if they
+	  have a SuperIO parallel port.
 
 	  This code is also available as a module.  If you want to compile it
 	  as a module ( = code which can be inserted in and removed from the
@@ -121,12 +122,9 @@
 	  called parport_atari.o. If in doubt, saying N is the safe plan.
 
 config PARPORT_GSC
-	tristate "LASI/ASP builtin parallel-port"
-	depends on GSC_LASI && PARPORT
-	help
-	  Say Y here to build in low-level parallel-support for PC-style
-	  hardware integrated in the LASI-Controller (on the GSC Bus) for
-	  HP-PARISC workstations.
+	tristate
+	depends on GSC
+	default PARPORT
 
 config PARPORT_SUNBPP
 	tristate "Sparc hardware (EXPERIMENTAL)"
diff -Nru a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
--- a/drivers/parport/parport_cs.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/parport/parport_cs.c	Sun Nov 10 19:28:41 2002
@@ -5,7 +5,7 @@
     (specifically, for the Quatech SPP-100 EPP card: other cards will
     probably require driver tweaks)
     
-    parport_cs.c 1.20 2000/11/02 23:15:05
+    parport_cs.c 1.29 2002/10/11 06:57:41
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -34,9 +34,7 @@
     
 ======================================================================*/
 
-
 #include <linux/kernel.h>
-#include <linux/version.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
@@ -58,32 +56,31 @@
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ciscode.h>
 
-#ifdef PCMCIA_DEBUG
-static int pc_debug = PCMCIA_DEBUG;
-MODULE_PARM(pc_debug, "i");
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
-static char *version =
-"parport_cs.c 1.20 2000/11/02 23:15:05 (David Hinds)";
-#else
-#define DEBUG(n, args...)
-#endif
+/*====================================================================*/
 
-#ifndef VERSION
-#define VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
-#endif
+/* Module parameters */
 
-/*====================================================================*/
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("PCMCIA parallel port card driver");
+MODULE_LICENSE("Dual MPL/GPL");
 
-/* Parameters that can be set with 'insmod' */
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
 
 /* Bit map of interrupts to choose from */
-static u_int irq_mask = 0xdeb8;
+INT_MODULE_PARM(irq_mask, 0xdeb8);
 static int irq_list[4] = { -1 };
-static int epp_mode = 1;
-
-MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
-MODULE_PARM(epp_mode, "i");
+
+INT_MODULE_PARM(epp_mode, 1);
+
+#ifdef PCMCIA_DEBUG
+INT_MODULE_PARM(pc_debug, PCMCIA_DEBUG);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"parport_cs.c 1.29 2002/10/11 06:57:41 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
 
 /*====================================================================*/
 
@@ -106,8 +103,6 @@
 static dev_info_t dev_info = "parport_cs";
 static dev_link_t *dev_list = NULL;
 
-extern struct parport_operations parport_pc_ops;
-
 /*====================================================================*/
 
 static void cs_error(client_handle_t handle, int func, int ret)
@@ -228,12 +223,6 @@
 #define CFG_CHECK(fn, args...) \
 if (CardServices(fn, args) != 0) goto next_entry
 
-static struct { u_int flag; char *name; } mode[] = {
-    { PARPORT_MODE_TRISTATE, "PS2" },
-    { PARPORT_MODE_EPP, "EPP" },
-    { PARPORT_MODE_ECP, "ECP" },
-};
-
 void parport_config(dev_link_t *link)
 {
     client_handle_t handle = link->handle;
@@ -245,7 +234,7 @@
     cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
     cistpl_cftable_entry_t dflt = { 0 };
     struct parport *p;
-    int i, last_ret, last_fn;
+    int last_ret, last_fn;
     
     DEBUG(0, "parport_config(0x%p)\n", link);
     
@@ -297,6 +286,9 @@
     CS_CHECK(RequestIRQ, handle, &link->irq);
     CS_CHECK(RequestConfiguration, handle, &link->conf);
 
+    release_region(link->io.BasePort1, link->io.NumPorts1);
+    if (link->io.NumPorts2)
+	release_region(link->io.BasePort2, link->io.NumPorts2);
     p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
 			      link->irq.AssignedIRQ, PARPORT_DMA_NONE,
 			      NULL);
@@ -307,19 +299,6 @@
 	goto failed;
     }
 
-#if (LINUX_VERSION_CODE < VERSION(2,3,6))
-#if (LINUX_VERSION_CODE >= VERSION(2,2,8))
-    p->private_data = kmalloc(sizeof(struct parport_pc_private),
-			      GFP_KERNEL);
-    ((struct parport_pc_private *)(p->private_data))->ctr = 0x0c;
-#endif
-    parport_proc_register(p);
-    p->flags |= PARPORT_FLAG_COMA;
-    parport_pc_write_econtrol(p, 0x00);
-    parport_pc_write_control(p, 0x0c);
-    parport_pc_write_data(p, 0x00);
-#endif
-
     p->modes |= PARPORT_MODE_PCSPP;
     if (epp_mode)
 	p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
@@ -329,15 +308,7 @@
     info->port = p;
     strcpy(info->node.dev_name, p->name);
     link->dev = &info->node;
-    printk(KERN_INFO "%s: PC-style PCMCIA at %#x", p->name,
-	   link->io.BasePort1);
-    if (link->io.NumPorts2)
-	printk(" & %#x", link->io.BasePort2);
-    printk(", irq %u [SPP", link->irq.AssignedIRQ);
-    for (i = 0; i < 5; i++)
-	if (p->modes & mode[i].flag) printk(",%s", mode[i].name);
-    printk("]\n");
-    
+
     link->state &= ~DEV_CONFIG_PENDING;
     return;
     
@@ -345,6 +316,7 @@
     cs_error(link->handle, last_fn, last_ret);
 failed:
     parport_cs_release((u_long)link);
+    link->state &= ~DEV_CONFIG_PENDING;
 
 } /* parport_config */
 
@@ -365,15 +337,12 @@
 
     if (info->ndev) {
 	struct parport *p = info->port;
-#if (LINUX_VERSION_CODE < VERSION(2,3,6))
-	if (!(p->flags & PARPORT_FLAG_COMA))
-	    parport_quiesce(p);
-#endif
-	parport_proc_unregister(p);
-#if (LINUX_VERSION_CODE >= VERSION(2,2,8))
-	kfree(p->private_data);
-#endif
-	parport_unregister_port(p);
+	parport_pc_unregister_port(p);
+	request_region(link->io.BasePort1, link->io.NumPorts1,
+		       info->node.dev_name);
+	if (link->io.NumPorts2)
+	    request_region(link->io.BasePort2, link->io.NumPorts2,
+			   info->node.dev_name);
     }
     info->ndev = 0;
     link->dev = NULL;
@@ -430,24 +399,6 @@
 
 /*====================================================================*/
 
-#if (LINUX_VERSION_CODE < VERSION(2,3,6))
-
-static void inc_use_count(void)
-{
-    MOD_INC_USE_COUNT;
-    parport_pc_ops.inc_use_count();
-}
-
-static void dec_use_count(void)
-{
-    MOD_DEC_USE_COUNT;
-    parport_pc_ops.dec_use_count();
-}
-
-#endif
-
-/*====================================================================*/
-
 static int __init init_parport_cs(void)
 {
     servinfo_t serv;
@@ -456,9 +407,8 @@
     if (serv.Revision != CS_RELEASE_CODE) {
 	printk(KERN_NOTICE "parport_cs: Card Services release "
 	       "does not match!\n");
-	return -1;
+	return -EINVAL;
     }
-
     register_pccard_driver(&dev_info, &parport_attach, &parport_detach);
     return 0;
 }
@@ -473,4 +423,3 @@
 
 module_init(init_parport_cs);
 module_exit(exit_parport_cs);
-MODULE_LICENSE("Dual MPL/GPL");
diff -Nru a/drivers/pci/Makefile b/drivers/pci/Makefile
--- a/drivers/pci/Makefile	Sun Nov 10 19:28:41 2002
+++ b/drivers/pci/Makefile	Sun Nov 10 19:28:41 2002
@@ -3,7 +3,7 @@
 #
 
 export-objs	:= access.o hotplug.o pci-driver.o pci.o pool.o \
-			probe.o proc.o search.o compat.o
+			probe.o proc.o search.o compat.o setup-bus.o
 
 obj-y		+= access.o probe.o pci.o pool.o quirks.o \
 			compat.o names.o pci-driver.o search.o hotplug.o
@@ -24,6 +24,11 @@
 obj-$(CONFIG_PPC32) += setup-irq.o
 obj-$(CONFIG_DDB5476) += setup-bus.o
 obj-$(CONFIG_SGI_IP27) += setup-irq.o
+
+# CompactPCI hotplug requires the pbus_* functions
+ifdef CONFIG_HOTPLUG_PCI_CPCI
+obj-y += setup-bus.o
+endif
 
 ifndef CONFIG_X86
 obj-y += syscall.o
diff -Nru a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
--- a/drivers/pci/hotplug.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/pci/hotplug.c	Sun Nov 10 19:28:41 2002
@@ -71,8 +71,7 @@
  * @bus: where to insert it
  *
  * Link the device to both the global PCI device chain and the 
- * per-bus list of devices, add the /proc entry, and notify
- * userspace (/sbin/hotplug).
+ * per-bus list of devices, add the /proc entry.
  */
 void
 pci_insert_device(struct pci_dev *dev, struct pci_bus *bus)
diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c
--- a/drivers/pci/pci.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/pci/pci.c	Sun Nov 10 19:28:38 2002
@@ -25,6 +25,49 @@
 #endif
 
 /**
+ * pci_bus_max_busnr - returns maximum PCI bus number of given bus' children
+ * @bus: pointer to PCI bus structure to search
+ *
+ * Given a PCI bus, returns the highest PCI bus number present in the set
+ * including the given PCI bus and its list of child PCI buses.
+ */
+unsigned char __devinit
+pci_bus_max_busnr(struct pci_bus* bus)
+{
+	struct list_head *tmp;
+	unsigned char max, n;
+
+	max = bus->number;
+	list_for_each(tmp, &bus->children) {
+		n = pci_bus_max_busnr(pci_bus_b(tmp));
+		if(n > max)
+			max = n;
+	}
+	return max;
+}
+
+/**
+ * pci_max_busnr - returns maximum PCI bus number
+ *
+ * Returns the highest PCI bus number present in the system global list of
+ * PCI buses.
+ */
+unsigned char __devinit
+pci_max_busnr(void)
+{
+	struct pci_bus* bus;
+	unsigned char max, n;
+
+	max = 0;
+	pci_for_each_bus(bus) {
+		n = pci_bus_max_busnr(bus);
+		if(n > max)
+			max = n;
+	}
+	return max;
+}
+
+/**
  * pci_find_capability - query for devices' capabilities 
  * @dev: PCI device to query
  * @cap: capability code
@@ -79,6 +122,49 @@
 	return 0;
 }
 
+/**
+ * pci_bus_find_capability - query for devices' capabilities 
+ * @dev: PCI device to query
+ * @cap: capability code
+ *
+ * Like pci_find_capability() but works for pci devices that do not have a
+ * pci_dev structure set up yet. 
+ * Returns the address of the requested capability structure within the
+ * device's PCI configuration space or 0 in case the device does not
+ * support it.
+ */
+int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap)
+{
+	u16 status;
+	u8 pos, id;
+	int ttl = 48;
+	struct pci_dev *dev = bus->self;
+
+	pci_bus_read_config_word(bus, devfn, PCI_STATUS, &status);
+	if (!(status & PCI_STATUS_CAP_LIST))
+		return 0;
+	switch (dev->hdr_type) {
+	case PCI_HEADER_TYPE_NORMAL:
+	case PCI_HEADER_TYPE_BRIDGE:
+		pci_bus_read_config_byte(bus, devfn, PCI_CAPABILITY_LIST, &pos);
+		break;
+	case PCI_HEADER_TYPE_CARDBUS:
+		pci_bus_read_config_byte(bus, devfn, PCI_CB_CAPABILITY_LIST, &pos);
+		break;
+	default:
+		return 0;
+	}
+	while (ttl-- && pos >= 0x40) {
+		pos &= ~3;
+		pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_ID, &id);
+		if (id == 0xff)
+			break;
+		if (id == cap)
+			return pos;
+		pci_bus_read_config_byte(bus, devfn, pos + PCI_CAP_LIST_NEXT, &pos);
+	}
+	return 0;
+}
 
 /**
  * pci_find_parent_resource - return resource region of parent bus of given region
@@ -649,7 +735,10 @@
 
 EXPORT_SYMBOL(pci_enable_device);
 EXPORT_SYMBOL(pci_disable_device);
+EXPORT_SYMBOL(pci_max_busnr);
+EXPORT_SYMBOL(pci_bus_max_busnr);
 EXPORT_SYMBOL(pci_find_capability);
+EXPORT_SYMBOL(pci_bus_find_capability);
 EXPORT_SYMBOL(pci_release_regions);
 EXPORT_SYMBOL(pci_request_regions);
 EXPORT_SYMBOL(pci_release_region);
diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids
--- a/drivers/pci/pci.ids	Sun Nov 10 19:28:40 2002
+++ b/drivers/pci/pci.ids	Sun Nov 10 19:28:40 2002
@@ -2205,7 +2205,7 @@
 	1001  FDC 37C922
 	a011  83C170QF
 	b106  SMC34C90
-10b9  Acer Laboratories Inc. [ALi]
+10b9  ALi Corporation
 	0111  C-Media CMI8738/C3DX Audio Device (OEM)
 		10b9 0111  C-Media CMI8738/C3DX Audio Device (OEM)
 	1435  M1435
@@ -2227,6 +2227,7 @@
 	1541  M1541
 		10b9 1541  ALI M1541 Aladdin V/V+ AGP System Controller
 	1543  M1543
+	1563  M1563 HyperTransport South Bridge
 	1621  M1621
 	1631  ALI M1631 PCI North Bridge Aladdin Pro III
 	1632  M1632M Northbridge+Trident
@@ -2235,7 +2236,9 @@
 	1646  M1646 Northbridge+Trident
 	1647  M1647 Northbridge [MAGiK 1 / MobileMAGiK 1]
 	1651  M1651/M1651T Northbridge [Aladdin-Pro 5/5M,Aladdin-Pro 5T/5TM]
-	1671  M1671 Northbridge [Aladdin-P4]
+	1671  M1671 P4 Northbridge
+	1681  M1681 P4 HyperTransport Northbridge
+	1687  M1687 K8 HyperTransport Northbridge
 	3141  M3141
 	3143  M3143
 	3145  M3145
@@ -2256,6 +2259,7 @@
 	5239  USB 2.0 Controller
 	5243  M1541 PCI to AGP Controller
 	5247  PCI to AGP Controller
+	5249  HTT to PCI Bridge
 	5251  M5251 P1394 OHCI 1.0 Controller
 	5253  M5253 P1394 OHCI 1.1 Controller
 	5261  M5261 Ethernet Controller
diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c
--- a/drivers/pci/probe.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/pci/probe.c	Sun Nov 10 19:28:40 2002
@@ -254,7 +254,7 @@
  * them, we proceed to assigning numbers to the remaining buses in
  * order to avoid overlaps between old and new bus numbers.
  */
-static int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
+int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass)
 {
 	unsigned int buses;
 	unsigned short cr;
@@ -480,8 +480,7 @@
 
 		/*
 		 * Link the device to both the global PCI device chain and
-		 * the per-bus list of devices and call /sbin/hotplug if we
-		 * should.
+		 * the per-bus list of devices and add the /proc entry.
 		 */
 		pci_insert_device (dev, bus);
 
@@ -596,4 +595,5 @@
 EXPORT_SYMBOL(pci_do_scan_bus);
 EXPORT_SYMBOL(pci_scan_slot);
 EXPORT_SYMBOL(pci_scan_bus);
+EXPORT_SYMBOL(pci_scan_bridge);
 #endif
diff -Nru a/drivers/pci/quirks.c b/drivers/pci/quirks.c
--- a/drivers/pci/quirks.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/pci/quirks.c	Sun Nov 10 19:28:36 2002
@@ -23,7 +23,7 @@
 
 /* Deal with broken BIOS'es that neglect to enable passive release,
    which can cause problems in combination with the 82441FX/PPro MTRRs */
-static void __init quirk_passive_release(struct pci_dev *dev)
+static void __devinit quirk_passive_release(struct pci_dev *dev)
 {
 	struct pci_dev *d = NULL;
 	unsigned char dlc;
@@ -50,7 +50,7 @@
 
 int isa_dma_bridge_buggy;		/* Exported */
     
-static void __init quirk_isa_dma_hangs(struct pci_dev *dev)
+static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev)
 {
 	if (!isa_dma_bridge_buggy) {
 		isa_dma_bridge_buggy=1;
@@ -64,7 +64,7 @@
  *	Chipsets where PCI->PCI transfers vanish or hang
  */
 
-static void __init quirk_nopcipci(struct pci_dev *dev)
+static void __devinit quirk_nopcipci(struct pci_dev *dev)
 {
 	if((pci_pci_problems&PCIPCI_FAIL)==0)
 	{
@@ -77,7 +77,7 @@
  *	Triton requires workarounds to be used by the drivers
  */
  
-static void __init quirk_triton(struct pci_dev *dev)
+static void __devinit quirk_triton(struct pci_dev *dev)
 {
 	if((pci_pci_problems&PCIPCI_TRITON)==0)
 	{
@@ -96,7 +96,7 @@
  *	Updated based on further information from the site and also on
  *	information provided by VIA 
  */
-static void __init quirk_vialatency(struct pci_dev *dev)
+static void __devinit quirk_vialatency(struct pci_dev *dev)
 {
 	struct pci_dev *p;
 	u8 rev;
@@ -150,7 +150,7 @@
  *	VIA Apollo VP3 needs ETBF on BT848/878
  */
  
-static void __init quirk_viaetbf(struct pci_dev *dev)
+static void __devinit quirk_viaetbf(struct pci_dev *dev)
 {
 	if((pci_pci_problems&PCIPCI_VIAETBF)==0)
 	{
@@ -158,7 +158,7 @@
 		pci_pci_problems|=PCIPCI_VIAETBF;
 	}
 }
-static void __init quirk_vsfx(struct pci_dev *dev)
+static void __devinit quirk_vsfx(struct pci_dev *dev)
 {
 	if((pci_pci_problems&PCIPCI_VSFX)==0)
 	{
@@ -173,7 +173,7 @@
  *	at least
  */
  
-static void __init quirk_natoma(struct pci_dev *dev)
+static void __devinit quirk_natoma(struct pci_dev *dev)
 {
 	if((pci_pci_problems&PCIPCI_NATOMA)==0)
 	{
@@ -187,7 +187,7 @@
  *  If it's needed, re-allocate the region.
  */
 
-static void __init quirk_s3_64M(struct pci_dev *dev)
+static void __devinit quirk_s3_64M(struct pci_dev *dev)
 {
 	struct resource *r = &dev->resource[0];
 
@@ -197,7 +197,7 @@
 	}
 }
 
-static void __init quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr)
+static void __devinit quirk_io_region(struct pci_dev *dev, unsigned region, unsigned size, int nr)
 {
 	region &= ~(size-1);
 	if (region) {
@@ -222,7 +222,7 @@
  *	0xE0 (64 bytes of ACPI registers)
  *	0xE2 (32 bytes of SMB registers)
  */
-static void __init quirk_ali7101_acpi(struct pci_dev *dev)
+static void __devinit quirk_ali7101_acpi(struct pci_dev *dev)
 {
 	u16 region;
 
@@ -237,7 +237,7 @@
  *	0x40 (64 bytes of ACPI registers)
  *	0x90 (32 bytes of SMB registers)
  */
-static void __init quirk_piix4_acpi(struct pci_dev *dev)
+static void __devinit quirk_piix4_acpi(struct pci_dev *dev)
 {
 	u32 region;
 
@@ -251,7 +251,7 @@
  * VIA ACPI: One IO region pointed to by longword at
  *	0x48 or 0x20 (256 bytes of ACPI registers)
  */
-static void __init quirk_vt82c586_acpi(struct pci_dev *dev)
+static void __devinit quirk_vt82c586_acpi(struct pci_dev *dev)
 {
 	u8 rev;
 	u32 region;
@@ -270,7 +270,7 @@
  *	0x70 (128 bytes of hardware monitoring register)
  *	0x90 (16 bytes of SMB registers)
  */
-static void __init quirk_vt82c686_acpi(struct pci_dev *dev)
+static void __devinit quirk_vt82c686_acpi(struct pci_dev *dev)
 {
 	u16 hm;
 	u32 smb;
@@ -297,7 +297,7 @@
  * TODO: When we have device-specific interrupt routers,
  * this code will go away from quirks.
  */
-static void __init quirk_via_ioapic(struct pci_dev *dev)
+static void __devinit quirk_via_ioapic(struct pci_dev *dev)
 {
 	u8 tmp;
 	
@@ -338,7 +338,7 @@
  * value of the ACPI SCI interrupt is only done for convenience.
  *	-jgarzik
  */
-static void __init quirk_via_acpi(struct pci_dev *d)
+static void __devinit quirk_via_acpi(struct pci_dev *d)
 {
 	/*
 	 * VIA ACPI device: SCI IRQ line in PCI config byte 0x42
@@ -350,7 +350,7 @@
 		d->irq = irq;
 }
 
-static void __init quirk_via_irqpic(struct pci_dev *dev)
+static void __devinit quirk_via_irqpic(struct pci_dev *dev)
 {
 	u8 irq, new_irq = dev->irq & 0xf;
 
@@ -377,7 +377,7 @@
  *
  * We mask out all r/wc bits, too.
  */
-static void __init quirk_piix3_usb(struct pci_dev *dev)
+static void __devinit quirk_piix3_usb(struct pci_dev *dev)
 {
 	u16 legsup;
 
@@ -392,7 +392,7 @@
  * We need to switch it off to be able to recognize the real
  * type of the chip.
  */
-static void __init quirk_vt82c598_id(struct pci_dev *dev)
+static void __devinit quirk_vt82c598_id(struct pci_dev *dev)
 {
 	pci_write_config_byte(dev, 0xfc, 0);
 	pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
@@ -404,7 +404,7 @@
  * do this even if the Linux CardBus driver is not loaded, because
  * the Linux i82365 driver does not (and should not) handle CardBus.
  */
-static void __init quirk_cardbus_legacy(struct pci_dev *dev)
+static void __devinit quirk_cardbus_legacy(struct pci_dev *dev)
 {
 	if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class)
 		return;
@@ -421,7 +421,7 @@
  * of course. However the advice is demonstrably good even if so..
  */
  
-static void __init quirk_amd_ioapic(struct pci_dev *dev)
+static void __devinit quirk_amd_ioapic(struct pci_dev *dev)
 {
 	u8 rev;
 
@@ -441,7 +441,7 @@
  * who turn it off!
  */
  
-static void __init quirk_amd_ordering(struct pci_dev *dev)
+static void __devinit quirk_amd_ordering(struct pci_dev *dev)
 {
 	u32 pcic;
 	pci_read_config_dword(dev, 0x4C, &pcic);
@@ -464,14 +464,14 @@
  *	nothing gets put too close to it.
  */
 
-static void __init quirk_dunord ( struct pci_dev * dev )
+static void __devinit quirk_dunord ( struct pci_dev * dev )
 {
 	struct resource * r = & dev -> resource [ 1 ];
 	r -> start = 0;
 	r -> end = 0xffffff;
 }
 
-static void __init quirk_transparent_bridge(struct pci_dev *dev)
+static void __devinit quirk_transparent_bridge(struct pci_dev *dev)
 {
 	dev->transparent = 1;
 }
@@ -480,7 +480,7 @@
  *  The main table of quirks.
  */
 
-static struct pci_fixup pci_fixups[] __initdata = {
+static struct pci_fixup pci_fixups[] __devinitdata = {
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_DUNORD,	PCI_DEVICE_ID_DUNORD_I3000,	quirk_dunord },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82441,	quirk_passive_release },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82441,	quirk_passive_release },
diff -Nru a/drivers/pci/search.c b/drivers/pci/search.c
--- a/drivers/pci/search.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/pci/search.c	Sun Nov 10 19:28:36 2002
@@ -1,6 +1,45 @@
 #include <linux/pci.h>
 #include <linux/module.h>
 
+static struct pci_bus *
+pci_do_find_bus(struct pci_bus* bus, unsigned char busnr)
+{
+	struct pci_bus* child;
+	struct list_head *tmp;
+
+	if(bus->number == busnr)
+		return bus;
+
+	list_for_each(tmp, &bus->children) {
+		child = pci_do_find_bus(pci_bus_b(tmp), busnr);
+		if(child)
+			return child;
+	}
+	return NULL;
+}
+
+/**
+ * pci_find_bus - locate PCI bus from a given bus number
+ * @busnr: number of desired PCI bus
+ *
+ * Given a PCI bus number, the desired PCI bus is located in system
+ * global list of PCI buses.  If the bus is found, a pointer to its
+ * data structure is returned.  If no bus is found, %NULL is returned.
+ */
+struct pci_bus *
+pci_find_bus(unsigned char busnr)
+{
+	struct pci_bus* bus;
+	struct pci_bus* tmp_bus;
+
+	pci_for_each_bus(bus) {
+		tmp_bus = pci_do_find_bus(bus, busnr);
+		if(tmp_bus)
+			return tmp_bus;
+	}
+	return NULL;
+}
+
 /**
  * pci_find_slot - locate PCI device from a given PCI slot
  * @bus: number of PCI bus on which desired PCI device resides
@@ -104,6 +143,7 @@
 	return NULL;
 }
 
+EXPORT_SYMBOL(pci_find_bus);
 EXPORT_SYMBOL(pci_find_class);
 EXPORT_SYMBOL(pci_find_device);
 EXPORT_SYMBOL(pci_find_slot);
diff -Nru a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
--- a/drivers/pci/setup-bus.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/pci/setup-bus.c	Sun Nov 10 19:28:41 2002
@@ -19,6 +19,7 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
@@ -35,7 +36,7 @@
 
 #define ROUND_UP(x, a)		(((x) + (a) - 1) & ~((a) - 1))
 
-static int __init
+static int __devinit
 pbus_assign_resources_sorted(struct pci_bus *bus)
 {
 	struct list_head *ln;
@@ -85,7 +86,7 @@
    requires that if there is no I/O ports or memory behind the
    bridge, corresponding range must be turned off by writing base
    value greater than limit to the bridge's base/limit registers.  */
-static void __init
+static void __devinit
 pci_setup_bridge(struct pci_bus *bus)
 {
 	struct pbus_set_ranges_data ranges;
@@ -168,7 +169,7 @@
 /* Check whether the bridge supports optional I/O and
    prefetchable memory ranges. If not, the respective
    base/limit registers must be read-only and read as 0. */
-static void __init
+static void __devinit
 pci_bridge_check_ranges(struct pci_bus *bus)
 {
 	u16 io;
@@ -210,7 +211,7 @@
    since these windows have 4K granularity and the IO ranges
    of non-bridge PCI devices are limited to 256 bytes.
    We must be careful with the ISA aliasing though. */
-static void __init
+static void __devinit
 pbus_size_io(struct pci_bus *bus)
 {
 	struct list_head *ln;
@@ -259,7 +260,7 @@
 
 /* Calculate the size of the bus and minimal alignment which
    guarantees that all child resources fit in this size. */
-static void __init
+static void __devinit
 pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type)
 {
 	struct list_head *ln;
@@ -331,7 +332,7 @@
 	b_res->end = size + min_align - 1;
 }
 
-void __init
+void __devinit
 pbus_size_bridges(struct pci_bus *bus)
 {
 	struct list_head *ln;
@@ -357,8 +358,9 @@
 	}
 	pbus_size_mem(bus, mask, type);
 }
+EXPORT_SYMBOL(pbus_size_bridges);
 
-void __init
+void __devinit
 pbus_assign_resources(struct pci_bus *bus)
 {
 	struct list_head *ln;
@@ -379,6 +381,7 @@
 		pci_setup_bridge(b);
 	}
 }
+EXPORT_SYMBOL(pbus_assign_resources);
 
 void __init
 pci_assign_unassigned_resources(void)
diff -Nru a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
--- a/drivers/pcmcia/cardbus.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/pcmcia/cardbus.c	Sun Nov 10 19:28:38 2002
@@ -2,7 +2,7 @@
   
     Cardbus device configuration
     
-    cardbus.c 1.63 1999/11/08 20:47:02
+    cardbus.c 1.87 2002/10/24 06:11:41
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -15,7 +15,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
@@ -175,8 +175,8 @@
     
 =====================================================================*/
 
-void read_cb_mem(socket_info_t * s, u_char fn, int space,
-		 u_int addr, u_int len, void *ptr)
+int read_cb_mem(socket_info_t * s, u_char fn, int space,
+		u_int addr, u_int len, void *ptr)
 {
 	struct pci_dev *dev;
 	struct resource *res;
@@ -194,7 +194,7 @@
 			goto fail;
 		for (; len; addr++, ptr++, len--)
 			pci_readb(dev, addr, (u_char *) ptr);
-		return;
+		return 0;
 	}
 
 	res = dev->resource + space - 1;
@@ -214,11 +214,11 @@
 		goto fail;
 
 	memcpy_fromio(ptr, s->cb_cis_virt + addr, len);
-	return;
+	return 0;
 
 fail:
 	memset(ptr, 0xff, len);
-	return;
+	return -1;
 }
 
 /*=====================================================================
diff -Nru a/drivers/pcmcia/cirrus.h b/drivers/pcmcia/cirrus.h
--- a/drivers/pcmcia/cirrus.h	Sun Nov 10 19:28:37 2002
+++ b/drivers/pcmcia/cirrus.h	Sun Nov 10 19:28:37 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Nru a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
--- a/drivers/pcmcia/cistpl.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/pcmcia/cistpl.c	Sun Nov 10 19:28:38 2002
@@ -2,7 +2,7 @@
 
     PCMCIA Card Information Structure parser
 
-    cistpl.c 1.97 2001/10/04 03:33:49
+    cistpl.c 1.99 2002/10/24 06:11:48
 
     The contents of this file are subject to the Mozilla Public
     License Version 1.1 (the "License"); you may not use this file
@@ -109,8 +109,8 @@
     }
 }
 
-void read_cis_mem(socket_info_t *s, int attr, u_int addr,
-		  u_int len, void *ptr)
+int read_cis_mem(socket_info_t *s, int attr, u_int addr,
+		 u_int len, void *ptr)
 {
     pccard_mem_map *mem = &s->cis_mem;
     u_char *sys, *buf = ptr;
@@ -118,7 +118,7 @@
     DEBUG(3, "cs: read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
     if (setup_cis_mem(s) != 0) {
 	memset(ptr, 0xff, len);
-	return;
+	return -1;
     }
     mem->flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
 
@@ -156,6 +156,7 @@
     DEBUG(3, "cs:  %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
 	  *(u_char *)(ptr+0), *(u_char *)(ptr+1),
 	  *(u_char *)(ptr+2), *(u_char *)(ptr+3));
+    return 0;
 }
 
 void write_cis_mem(socket_info_t *s, int attr, u_int addr,
@@ -270,7 +271,7 @@
 	if (find_mem_region(&s->cis_mem.sys_start, s->cap.map_size,
 			    s->cap.map_size, low, "card services", s)) {
 	    printk(KERN_NOTICE "cs: unable to map card memory!\n");
-	    return CS_OUT_OF_RESOURCE;
+	    return -1;
 	}
 	s->cis_mem.sys_stop = s->cis_mem.sys_start+s->cap.map_size-1;
 	s->cis_virt = bus_ioremap(s->cap.bus, s->cis_mem.sys_start,
@@ -303,7 +304,7 @@
 static void read_cis_cache(socket_info_t *s, int attr, u_int addr,
 			   u_int len, void *ptr)
 {
-    int i;
+    int i, ret;
     char *caddr;
 
     if (s->fake_cis) {
@@ -326,12 +327,12 @@
     }
 #ifdef CONFIG_CARDBUS
     if (s->state & SOCKET_CARDBUS)
-	read_cb_mem(s, 0, attr, addr, len, ptr);
+	ret = read_cb_mem(s, 0, attr, addr, len, ptr);
     else
 #endif
-	read_cis_mem(s, attr, addr, len, ptr);
+	ret = read_cis_mem(s, attr, addr, len, ptr);
     /* Copy data into the cache, if there is room */
-    if ((i < MAX_CIS_TABLE) &&
+    if ((ret == 0) && (i < MAX_CIS_TABLE) &&
 	(caddr+len < s->cis_cache+MAX_CIS_DATA)) {
 	s->cis_table[i].addr = addr;
 	s->cis_table[i].len = len;
diff -Nru a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
--- a/drivers/pcmcia/cs_internal.h	Sun Nov 10 19:28:36 2002
+++ b/drivers/pcmcia/cs_internal.h	Sun Nov 10 19:28:36 2002
@@ -1,5 +1,5 @@
 /*
- * cs_internal.h 1.54 2000/10/26 20:10:55
+ * cs_internal.h 1.57 2002/10/24 06:11:43
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -202,13 +202,13 @@
 void cb_release(socket_info_t *s);
 void cb_enable(socket_info_t *s);
 void cb_disable(socket_info_t *s);
-void read_cb_mem(socket_info_t *s, u_char fn, int space,
-		 u_int addr, u_int len, void *ptr);
+int read_cb_mem(socket_info_t *s, u_char fn, int space,
+		u_int addr, u_int len, void *ptr);
 void cb_release_cis_mem(socket_info_t *s);
 
 /* In cistpl.c */
-void read_cis_mem(socket_info_t *s, int attr,
-		  u_int addr, u_int len, void *ptr);
+int read_cis_mem(socket_info_t *s, int attr,
+		 u_int addr, u_int len, void *ptr);
 void write_cis_mem(socket_info_t *s, int attr,
 		   u_int addr, u_int len, void *ptr);
 void release_cis_mem(socket_info_t *s);
diff -Nru a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
--- a/drivers/pcmcia/ds.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/pcmcia/ds.c	Sun Nov 10 19:28:40 2002
@@ -316,6 +316,7 @@
 	s->state &= ~SOCKET_PRESENT;
 	if (!(s->state & SOCKET_REMOVAL_PENDING)) {
 	    s->state |= SOCKET_REMOVAL_PENDING;
+	    init_timer(&s->removal);
 	    s->removal.expires = jiffies + HZ/10;
 	    add_timer(&s->removal);
 	}
diff -Nru a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
--- a/drivers/pcmcia/i82365.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/pcmcia/i82365.c	Sun Nov 10 19:28:41 2002
@@ -15,7 +15,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
@@ -1003,6 +1003,7 @@
 static void pcic_interrupt_wrapper(u_long data)
 {
     pcic_interrupt(0, NULL, NULL);
+    init_timer(&poll_timer);
     poll_timer.expires = jiffies + poll_interval;
     add_timer(&poll_timer);
 }
diff -Nru a/drivers/pcmcia/i82365.h b/drivers/pcmcia/i82365.h
--- a/drivers/pcmcia/i82365.h	Sun Nov 10 19:28:37 2002
+++ b/drivers/pcmcia/i82365.h	Sun Nov 10 19:28:37 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Nru a/drivers/pcmcia/o2micro.h b/drivers/pcmcia/o2micro.h
--- a/drivers/pcmcia/o2micro.h	Sun Nov 10 19:28:41 2002
+++ b/drivers/pcmcia/o2micro.h	Sun Nov 10 19:28:41 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Nru a/drivers/pcmcia/ricoh.h b/drivers/pcmcia/ricoh.h
--- a/drivers/pcmcia/ricoh.h	Sun Nov 10 19:28:39 2002
+++ b/drivers/pcmcia/ricoh.h	Sun Nov 10 19:28:39 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Nru a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
--- a/drivers/pcmcia/sa1100_generic.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/pcmcia/sa1100_generic.c	Sun Nov 10 19:28:40 2002
@@ -334,6 +334,7 @@
 static void sa1100_pcmcia_poll_event(unsigned long dummy)
 {
   DEBUG(4, "%s(): polling for events\n", __FUNCTION__);
+  init_timer(&poll_timer);
   poll_timer.function = sa1100_pcmcia_poll_event;
   poll_timer.expires = jiffies + SA1100_PCMCIA_POLL_PERIOD;
   add_timer(&poll_timer);
diff -Nru a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
--- a/drivers/pcmcia/tcic.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/pcmcia/tcic.c	Sun Nov 10 19:28:40 2002
@@ -15,7 +15,7 @@
     rights and limitations under the License.
 
     The initial developer of the original code is David A. Hinds
-    <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
     are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
 
     Alternatively, the contents of this file may be used under the
@@ -67,7 +67,7 @@
 #define DEBUG(n, args...)
 #endif
 
-MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>");
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
 MODULE_DESCRIPTION("Databook TCIC-2 PCMCIA socket driver");
 MODULE_LICENSE("Dual MPL/GPL");
 
diff -Nru a/drivers/pcmcia/tcic.h b/drivers/pcmcia/tcic.h
--- a/drivers/pcmcia/tcic.h	Sun Nov 10 19:28:41 2002
+++ b/drivers/pcmcia/tcic.h	Sun Nov 10 19:28:41 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Nru a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h
--- a/drivers/pcmcia/ti113x.h	Sun Nov 10 19:28:39 2002
+++ b/drivers/pcmcia/ti113x.h	Sun Nov 10 19:28:39 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Nru a/drivers/pcmcia/topic.h b/drivers/pcmcia/topic.h
--- a/drivers/pcmcia/topic.h	Sun Nov 10 19:28:41 2002
+++ b/drivers/pcmcia/topic.h	Sun Nov 10 19:28:41 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Nru a/drivers/pcmcia/vg468.h b/drivers/pcmcia/vg468.h
--- a/drivers/pcmcia/vg468.h	Sun Nov 10 19:28:39 2002
+++ b/drivers/pcmcia/vg468.h	Sun Nov 10 19:28:39 2002
@@ -12,7 +12,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Nru a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c
--- a/drivers/sbus/char/aurora.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/sbus/char/aurora.c	Sun Nov 10 19:28:37 2002
@@ -883,8 +883,8 @@
 #ifdef AURORA_INT_DEBUG
 static void aurora_timer (unsigned long ignored);
 
-static struct timer_list
-aurora_poll_timer = { NULL, NULL, 0, 0, aurora_timer };
+static struct timer_list aurora_poll_timer =
+			TIMER_INITIALIZER(aurora_timer, 0, 0);
 
 static void
 aurora_timer (unsigned long ignored)
diff -Nru a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
--- a/drivers/sbus/char/bpp.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/sbus/char/bpp.c	Sun Nov 10 19:28:36 2002
@@ -303,6 +303,7 @@
 
 static void snooze(unsigned long snooze_time, unsigned minor)
 {
+      init_timer(&instances[minor].timer_list);
       instances[minor].timer_list.expires = jiffies + snooze_time + 1;
       instances[minor].timer_list.data    = minor;
       add_timer(&instances[minor].timer_list);
diff -Nru a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c
--- a/drivers/sbus/char/cpwatchdog.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/sbus/char/cpwatchdog.c	Sun Nov 10 19:28:41 2002
@@ -685,6 +685,7 @@
 
 	if(tripped) {
 		/* there is at least one timer brokenstopped-- reschedule */
+		init_timer(&wd_timer);
 		wd_timer.expires = WD_BTIMEOUT;
 		add_timer(&wd_timer);
 	}
diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
--- a/drivers/scsi/Kconfig	Sun Nov 10 19:28:41 2002
+++ b/drivers/scsi/Kconfig	Sun Nov 10 19:28:41 2002
@@ -85,23 +85,6 @@
 	  drives (and HP Writers). If you have such a drive and get the first
 	  session only, try saying Y here; everybody else says N.
 
-config SR_EXTRA_DEVS
-	int "Maximum number of CDROM devices that can be loaded as modules"
-	depends on BLK_DEV_SR
-	default "2"
-	---help---
-	  This controls the amount of additional space allocated in tables for
-	  drivers that are loaded as modules after the kernel is booted. In
-	  the event that the SCSI core itself was loaded as a module, this
-	  value is the number of additional CD-ROMs that can be loaded after
-	  the first host driver is loaded.
-
-	  Admittedly this isn't pretty, but there are tons of race conditions
-	  involved with resizing the internal arrays on the fly.  Someday this
-	  flag will go away, and everything will work automatically.
-
-	  If you don't understand what's going on, go with the default.
-
 config CHR_DEV_SG
 	tristate "SCSI generic support"
 	depends on SCSI
diff -Nru a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
--- a/drivers/scsi/NCR5380.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/scsi/NCR5380.c	Sun Nov 10 19:28:38 2002
@@ -345,6 +345,51 @@
 	}
 }
 
+/**
+ *	NCR5380_poll_politely	-	wait for NCR5380 status bits
+ *	@instance: controller to poll
+ *	@reg: 5380 register to poll
+ *	@bit: Bitmask to check
+ *	@val: Value required to exit
+ *
+ *	Polls the NCR5380 in a reasonably efficient manner waiting for
+ *	an event to occur, after a short quick poll we begin giving the
+ *	CPU back in non IRQ contexts
+ *
+ *	Returns the value of the register or a negative error code.
+ */
+ 
+static int NCR5380_poll_politely(struct Scsi_Host *instance, int reg, int bit, int val, int t)
+{
+	NCR5380_local_declare();
+	int n = 500;		/* At about 8uS a cycle for the cpu access */
+	unsigned long end = jiffies + t;
+	int r;
+	
+	NCR5380_setup(instance);
+
+	while( n-- > 0)
+	{
+		r = NCR5380_read(reg);
+		if((r & bit) == val)
+			return r;
+		cpu_relax();
+	}
+	
+	/* t time yet ? */
+	while(time_before(jiffies, end))
+	{
+		r = NCR5380_read(reg);
+		if((r & bit) == val)
+			return r; 
+		if(!in_interrupt())
+			yield();
+		else
+			cpu_relax();
+	}
+	return -ETIMEDOUT;
+}
+
 static struct {
 	unsigned char value;
 	const char *name;
@@ -679,8 +724,11 @@
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL);
 
 	while (probe_irq == IRQ_NONE && time_before(jiffies, timeout))
-		barrier();
-
+	{
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	
 	NCR5380_write(SELECT_ENABLE_REG, 0);
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
@@ -1026,11 +1074,7 @@
 		case 5:
 			printk(KERN_INFO "scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no);
 			timeout = jiffies + 5 * HZ;
-			while (time_before(jiffies, timeout) && (NCR5380_read(STATUS_REG) & SR_BSY))
-			{
-				set_current_state(TASK_UNINTERRUPTIBLE);
-				schedule_timeout(1);
-			}
+			NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, 0, 5*HZ);
 			break;
 		case 2:
 			printk(KERN_WARNING "scsi%d: bus busy, attempting abort\n", instance->host_no);
@@ -1057,8 +1101,7 @@
  *      twiddling done to the host specific fields of cmd.  If the 
  *      main coroutine is not running, it is restarted.
  *
- *	Locks: host lock taken by caller. Called functions drop and
- *	retake this lock. Called functions take dma lock.
+ *	Locks: host lock taken by caller
  */
 
 static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) 
@@ -1164,7 +1207,8 @@
 
 	instance = hostdata->host;
 
-	spin_lock_irqsave(instance->host_lock, flags);
+	if(instance->irq != IRQ_NONE)
+		spin_lock_irqsave(instance->host_lock, flags);
 
 	do {
 		/* Lock held here */
@@ -1243,12 +1287,9 @@
 				   do not respond to commands immediately
 				   after a scan */
 				printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", instance->host_no, tmp->target);
-				//spin_lock_irq(&io_request_lock);
 				LIST(tmp, hostdata->issue_queue);
 				tmp->host_scribble = (unsigned char *) hostdata->issue_queue;
 				hostdata->issue_queue = tmp;
-				//spin_unlock_irq(&io_request_lock);
-
 				hostdata->time_expires = jiffies + USLEEP_WAITLONG;
 				NCR5380_set_timer(instance);
 			}
@@ -1267,7 +1308,8 @@
 			break;
 	} while (!done);
 	
-	spin_unlock_irqrestore(instance->host_lock, flags);
+	if(instance->irq != IRQ_NONE)
+		spin_unlock_irqrestore(instance->host_lock, flags);
 }
 
 #ifndef DONT_USE_INTR
@@ -1341,24 +1383,9 @@
 							hostdata->dmalen = 0;
 
 							(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-#if NCR_TIMEOUT
-							{
-								unsigned long timeout = jiffies + NCR_TIMEOUT;
-
-								spin_unlock_irq(instance->host_lock);
-								/* FIXME: prove timer is always running here! */
-								while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK && time_before(jiffies, timeout))
-									cpu_relax();
-								spin_lock_irq(instance->host_lock);
-
-								if (time_after_eq(jiffies, timeout))
-									printk("scsi%d: timeout at NCR5380.c:%d\n", host->host_no, __LINE__);
-							}
 							
-#else /* NCR_TIMEOUT */
-							while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK)
-								cpu_relax();
-#endif
+							/* FIXME: we need to poll briefly then defer a workqueue task ! */
+							NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_ACK, 0, 2*HZ);
 
 							NCR5380_write(MODE_REG, MR_BASE);
 							NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@@ -1438,7 +1465,7 @@
  *      If failed (no target) : cmd->scsi_done() will be called, and the 
  *              cmd->result host byte set to DID_BAD_TARGET.
  *
- *	Locks: caller holds hostdata lock
+ *	Locks: caller holds hostdata lock in IRQ mode
  */
  
 static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) 
@@ -1451,8 +1478,11 @@
 	unsigned long timeout;
 	unsigned char value;
 	NCR5380_setup(instance);
+	int err;
 
 	if (hostdata->selecting) {
+		if(instance->irq != IRQ_NONE)
+			spin_unlock_irq(instance->host_lock);
 		goto part2;	/* RvC: sorry prof. Dijkstra, but it keeps the
 				   rest of the code nearly the same */
 	}
@@ -1476,29 +1506,22 @@
 	NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
 	NCR5380_write(MODE_REG, MR_ARBITRATE);
 
-	/* Wait for arbitration logic to complete */
-#if NCR_TIMEOUT
-	{
-		unsigned long timeout = jiffies + 2 * NCR_TIMEOUT;
-
+	if(instance->irq != IRQ_NONE)
 		spin_unlock_irq(instance->host_lock);
 
-		while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
-		       && time_before(jiffies, timeout))
-		       	cpu_relax();
+	/* We can be relaxed here, interrupts are on, we are
+	   in workqueue context, the birds are singing in the trees */
 
+	err = NCR5380_poll_politely(instance, INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS, ICR_ARBITRATION_PROGRESS, 5*HZ);
+	if(instance->irq != IRQ_NONE)
 		spin_lock_irq(instance->host_lock);
 
-		if (time_after_eq(jiffies, timeout)) {
-			printk("scsi: arbitration timeout at %d\n", __LINE__);
-			NCR5380_write(MODE_REG, MR_BASE);
-			NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-			return -1;
-		}
+	if (err < 0) {
+		printk(KERN_DEBUG "scsi: arbitration timeout at %d\n", __LINE__);
+		NCR5380_write(MODE_REG, MR_BASE);
+		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		goto failed;
 	}
-#else				/* NCR_TIMEOUT */
-	while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS));
-#endif
 
 	dprintk(NDEBUG_ARBITRATION, ("scsi%d : arbitration complete\n", instance->host_no));
 
@@ -1515,7 +1538,7 @@
 	if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
 		NCR5380_write(MODE_REG, MR_BASE);
 		dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no));
-		return -1;
+		goto failed;
 	}
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL);
 
@@ -1528,7 +1551,7 @@
 		NCR5380_write(MODE_REG, MR_BASE);
 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 		dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", instance->host_no));
-		return -1;
+		goto failed;
 	}
 	/* 
 	 * Again, bus clear + bus settle time is 1.2us, however, this is 
@@ -1613,8 +1636,7 @@
 	   we poll only once ech clock tick */
 	value = NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO);
 
-	/* FIXME HZ=100 assumption ? */
-	if (!value && (hostdata->select_time < 25)) {
+	if (!value && (hostdata->select_time < HZ/4)) {
 		/* RvC: we still must wait for a device response */
 		hostdata->select_time++;	/* after 25 ticks the device has failed */
 		hostdata->time_expires = jiffies + 1;
@@ -1627,6 +1649,8 @@
 					   waiting period */
 	if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		if(instance->irq != IRQ_NONE)
+			spin_lock_irq(instance->host_lock);
 		NCR5380_reselect(instance);
 		printk("scsi%d : reselection after won arbitration?\n", instance->host_no);
 		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
@@ -1645,13 +1669,15 @@
 	if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 		if (hostdata->targets_present & (1 << cmd->target)) {
-			printk("scsi%d : weirdness\n", instance->host_no);
+			printk(KERN_DEBUG "scsi%d : weirdness\n", instance->host_no);
 			if (hostdata->restart_select)
-				printk("\trestart select\n");
+				printk(KERN_DEBUG "\trestart select\n");
 			NCR5380_dprint(NDEBUG_SELECTION, instance);
 			NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 			return -1;
 		}
+		if(instance->irq != IRQ_NONE)
+			spin_lock_irq(instance->host_lock);
 		cmd->result = DID_BAD_TARGET << 16;
 		collect_stats(hostdata, cmd);
 		cmd->scsi_done(cmd);
@@ -1678,29 +1704,21 @@
 	 */
 
 	/* Wait for start of REQ/ACK handshake */
-#ifdef NCR_TIMEOUT
-	{
-		unsigned long timeout = jiffies + NCR_TIMEOUT;
-
-		spin_unlock_irq(instance->host_lock);
-		while (!(NCR5380_read(STATUS_REG) & SR_REQ) && time_before(jiffies, timeout))
-			cpu_relax();
-		spin_lock_irq(instance->host_lock);
-
-		if (time_after_eq(jiffies, timeout)) {
-			printk("scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__);
-			NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-			return -1;
-		}
+	
+	err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
+	
+	if(err)
+	{	printk(KERN_ERR "scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__);
+		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		goto failed;
 	}
-#else				/* NCR_TIMEOUT */
-	while (!(NCR5380_read(STATUS_REG) & SR_REQ))
-		cpu_relax();
-#endif				/* def NCR_TIMEOUT */
 
 	dprintk(NDEBUG_SELECTION, ("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->target));
 	tmp[0] = IDENTIFY(((instance->irq == IRQ_NONE) ? 0 : 1), cmd->lun);
 
+	if(instance->irq != IRQ_NONE)
+		spin_lock_irq(instance->host_lock);
+		
 	len = 1;
 	cmd->tag = 0;
 
@@ -1717,6 +1735,13 @@
 
 
 	return 0;
+
+	/* Selection failed */
+failed:
+	if(instance->irq != IRQ_NONE)
+		spin_lock_irq(instance->host_lock);
+	return -1;
+
 }
 
 /* 
@@ -1786,6 +1811,7 @@
 		 *      if breaking is not allowed, we keep polling as long as needed
 		 */
 
+		/* FIXME */
 		while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && !break_allowed);
 		if (!(tmp & SR_REQ)) {
 			/* timeout condition */
@@ -1832,8 +1858,8 @@
 			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
 		}
 
-		while (NCR5380_read(STATUS_REG) & SR_REQ);
-
+		/* FIXME - if this fails bus reset ?? */
+		NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 5*HZ);
 		dprintk(NDEBUG_HANDSHAKE, ("scsi%d : req false, handshake complete\n", instance->host_no));
 
 /*
@@ -1905,8 +1931,9 @@
 
 static int do_abort(struct Scsi_Host *host) {
 	NCR5380_local_declare();
-	unsigned char tmp, *msgptr, phase;
+	unsigned char *msgptr, phase, tmp;
 	int len;
+	int rc;
 	NCR5380_setup(host);
 
 
@@ -1923,15 +1950,21 @@
 	 * the target sees, so we just handshake.
 	 */
 
-	while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ)
-		cpu_relax();
+	rc = NCR5380_poll_politely(host, STATUS_REG, SR_REQ, SR_REQ, 60 * HZ);
+	
+	if(rc < 0)
+		return -1;
 
+	tmp = (unsigned char)rc;
+	
 	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
 
 	if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
-		while (NCR5380_read(STATUS_REG) & SR_REQ);
+		rc = NCR5380_poll_politely(host, STATUS_REG, SR_REQ, 0, 3*HZ);
 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+		if(rc == -1)
+			return -1;
 	}
 	tmp = ABORT;
 	msgptr = &tmp;
@@ -2245,7 +2278,7 @@
  * XXX Note : we need to watch for bus free or a reset condition here 
  *      to recover from an unexpected bus free condition.
  *
- * Locks: io_request_lock held by caller
+ * Locks: io_request_lock held by caller in IRQ mode
  */
 
 static void NCR5380_information_transfer(struct Scsi_Host *instance) {
@@ -2503,7 +2536,8 @@
 
 						/* Enable reselect interrupts */
 						NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-						/* Wait for bus free to avoid nasty timeouts */
+						/* Wait for bus free to avoid nasty timeouts - FIXME timeout !*/
+						/* NCR538_poll_politely(instance, STATUS_REG, SR_BSY, 0, 30 * HZ); */
 						while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
 							barrier();
 						return;
@@ -2658,7 +2692,7 @@
  *      
  * Inputs : instance - this instance of the NCR5380.
  *
- * Locks: io_request_lock held by caller
+ * Locks: io_request_lock held by caller if IRQ driven
  */
 
 static void NCR5380_reselect(struct Scsi_Host *instance) {
@@ -2696,16 +2730,19 @@
 
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
 
-	while (NCR5380_read(STATUS_REG) & SR_SEL);
+	/* FIXME: timeout too long, must fail to workqueue */	
+	if(NCR5380_poll_politely(instance, STATUS_REG, SR_SEL, 0, 2*HZ)<0)
+		abort = 1;
+		
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
 	/*
 	 * Wait for target to go into MSGIN.
-	 * FIXME: timeout needed
+	 * FIXME: timeout needed and fail to work queeu
 	 */
 
-	while (!(NCR5380_read(STATUS_REG) & SR_REQ))
-		cpu_relax();
+	if(NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 2*HZ))
+		abort = 1;
 
 	len = 1;
 	data = msg;
@@ -2713,7 +2750,7 @@
 	NCR5380_transfer_pio(instance, &phase, &len, &data);
 
 	if (!msg[0] & 0x80) {
-		printk("scsi%d : expecting IDENTIFY message, got ", instance->host_no);
+		printk(KERN_ERR "scsi%d : expecting IDENTIFY message, got ", instance->host_no);
 		print_msg(msg);
 		abort = 1;
 	} else {
@@ -2747,7 +2784,7 @@
 				break;
 			}
 		if (!tmp) {
-			printk("scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", instance->host_no, target_mask, lun);
+			printk(KERN_ERR "scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", instance->host_no, target_mask, lun);
 			/* 
 			 * Since we have an established nexus that we can't do anything with,
 			 * we must abort it.  
@@ -2790,9 +2827,11 @@
 	 *
 	 * We should use the Last Byte Sent bit, unfortunately this is 
 	 * not available on the 5380/5381 (only the various CMOS chips)
+	 *
+	 * FIXME: timeout, and need to handle long timeout/irq case
 	 */
 
-	while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK);
+	NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, BASR_ACK, 0, 5*HZ);
 
 	NCR5380_write(MODE_REG, MR_BASE);
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
@@ -2827,21 +2866,15 @@
  *	a problem, we could implement longjmp() / setjmp(), setjmp()
  *	called where the loop started in NCR5380_main().
  *
- * Locks: host lock taken by function
+ * Locks: host lock taken by caller
  */
 
-#ifndef NCR5380_abort
-static
-#endif
-int NCR5380_abort(Scsi_Cmnd * cmd) {
+static int NCR5380_abort(Scsi_Cmnd * cmd) {
 	NCR5380_local_declare();
 	struct Scsi_Host *instance = cmd->host;
-	unsigned long flags;
 	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
 	Scsi_Cmnd *tmp, **prev;
 	
-	spin_lock_irqsave(instance->host_lock, flags);
-
 	printk(KERN_WARNING "scsi%d : aborting command\n", instance->host_no);
 	print_Scsi_Cmnd(cmd);
 
@@ -2884,7 +2917,6 @@
  * aborted flag and get back into our main loop.
  */
 
-		spin_unlock_irqrestore(instance->host_lock, flags);
 		return 0;
 	}
 #endif
@@ -2894,8 +2926,6 @@
  *          from the issue queue.
  */
  
- 	/* FIXME: check - I think we need the hostdata lock here */
-	/* KLL */
 	dprintk(NDEBUG_ABORT, ("scsi%d : abort going into loop.\n", instance->host_no));
 	for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble)
 		if (cmd == tmp) {
@@ -2905,7 +2935,6 @@
 			tmp->result = DID_ABORT << 16;
 			dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no));
 			tmp->done(tmp);
-			spin_unlock_irqrestore(instance->host_lock, flags);
 			return SUCCESS;
 		}
 #if (NDEBUG  & NDEBUG_ABORT)
@@ -2927,7 +2956,6 @@
 
 	if (hostdata->connected) {
 		dprintk(NDEBUG_ABORT, ("scsi%d : abort failed, command connected.\n", instance->host_no));
-		spin_unlock_irqrestore(instance->host_lock, flags);
 		return FAILED;
 	}
 /*
@@ -2972,7 +3000,6 @@
 					tmp->host_scribble = NULL;
 					tmp->result = DID_ABORT << 16;
 					tmp->done(tmp);
-					spin_unlock_irqrestore(instance->host_lock, flags);
 					return SUCCESS;
 				}
 		}
@@ -2985,7 +3012,6 @@
  * so we won't panic, but we will notify the user in case something really
  * broke.
  */
-	spin_unlock_irqrestore(instance->host_lock, flags);
 	printk(KERN_WARNING "scsi%d : warning : SCSI command probably completed successfully\n"
 			"         before abortion\n", instance->host_no);
 	return FAILED;
@@ -2999,22 +3025,15 @@
  *
  * Returns : SUCCESS
  *
- * Locks: host lock taken by function
+ * Locks: host lock taken by caller
  */
 
-#ifndef NCR5380_bus_reset
-static
-#endif
-int NCR5380_bus_reset(Scsi_Cmnd * cmd) {
-	unsigned long flags;
-	struct Scsi_Host *instance = cmd->host;
+static int NCR5380_bus_reset(Scsi_Cmnd * cmd) {
 	NCR5380_local_declare();
 	NCR5380_setup(cmd->host);
 
-	spin_lock_irqsave(instance->host_lock, flags);
 	NCR5380_print_status(cmd->host);
 	do_reset(cmd->host);
-	spin_unlock_irqrestore(instance->host_lock, flags);
 	return SUCCESS;
 }
 
@@ -3028,12 +3047,7 @@
  * Locks: io_request_lock held by caller
  */
 
-#ifndef NCR5380_device_reset
-static
-#endif
-int NCR5380_device_reset(Scsi_Cmnd * cmd) {
-	NCR5380_local_declare();
-	NCR5380_setup(cmd->host);
+static int NCR5380_device_reset(Scsi_Cmnd * cmd) {
 	return FAILED;
 }
 
@@ -3047,11 +3061,6 @@
  * Locks: io_request_lock held by caller
  */
 
-#ifndef NCR5380_host_reset
-static
-#endif
-int NCR5380_host_reset(Scsi_Cmnd * cmd) {
-	NCR5380_local_declare();
-	NCR5380_setup(cmd->host);
+static int NCR5380_host_reset(Scsi_Cmnd * cmd) {
 	return FAILED;
 }
diff -Nru a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
--- a/drivers/scsi/NCR53c406a.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/scsi/NCR53c406a.c	Sun Nov 10 19:28:39 2002
@@ -677,22 +677,6 @@
 	NCR53c406a_intr(0, NULL, NULL);
 }
 
-static int NCR53c406a_command(Scsi_Cmnd * SCpnt)
-{
-	DEB(printk("NCR53c406a_command called\n"));
-	NCR53c406a_queue(SCpnt, internal_done);
-	if (irq_level)
-		while (!internal_done_flag)
-			cpu_relax();
-	else			/* interrupts not supported */
-		while (!internal_done_flag)
-			wait_intr();
-
-	internal_done_flag = 0;
-	return internal_done_errcode;
-}
-
-
 static int NCR53c406a_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
 {
 	int i;
@@ -726,6 +710,21 @@
 	return 0;
 }
 
+static int NCR53c406a_command(Scsi_Cmnd * SCpnt)
+{
+	DEB(printk("NCR53c406a_command called\n"));
+	NCR53c406a_queue(SCpnt, internal_done);
+	if (irq_level)
+		while (!internal_done_flag)
+			cpu_relax();
+	else			/* interrupts not supported */
+		while (!internal_done_flag)
+			wait_intr();
+
+	internal_done_flag = 0;
+	return internal_done_errcode;
+}
+
 static int NCR53c406a_abort(Scsi_Cmnd * SCpnt)
 {
 	DEB(printk("NCR53c406a_abort called\n"));
@@ -755,7 +754,7 @@
 	return FAILED;
 }
 
-static int NCR53c406a_biosparm(struct scsi_disk *disk,
+static int NCR53c406a_biosparm(struct scsi_device *disk,
                                struct block_device *dev,
 			       sector_t capacity, int *info_array)
 {
@@ -1065,8 +1064,30 @@
 
 MODULE_LICENSE("GPL");
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = NCR53c406a;
+/* NOTE:  scatter-gather support only works in PIO mode.
+ * Use SG_NONE if DMA mode is enabled!
+ */
+
+static Scsi_Host_Template driver_template = 
+{
+     proc_name:         	"NCR53c406a"		/* proc_name */,        
+     name:              	"NCR53c406a"		/* name */,             
+     detect:            	NCR53c406a_detect	/* detect */,           
+     info:              	NCR53c406a_info		/* info */,             
+     command:           	NCR53c406a_command	/* command */,          
+     queuecommand:      	NCR53c406a_queue	/* queuecommand */,     
+     eh_abort_handler:  	NCR53c406a_abort	/* abort */,            
+     eh_bus_reset_handler:      NCR53c406a_bus_reset	/* reset */,            
+     eh_device_reset_handler:   NCR53c406a_device_reset	/* reset */,            
+     eh_host_reset_handler:     NCR53c406a_host_reset	/* reset */,            
+     bios_param:        	NCR53c406a_biosparm	/* biosparm */,         
+     can_queue:         	1			/* can_queue */,        
+     this_id:           	7			/* SCSI ID of the chip */,
+     sg_tablesize:      	32			/*SG_ALL*/ /*SG_NONE*/, 
+     cmd_per_lun:       	1			/* commands per lun */, 
+     unchecked_isa_dma: 	1			/* unchecked_isa_dma */,
+     use_clustering:    	ENABLE_CLUSTERING                               
+};
 
 #include "scsi_module.c"
 
diff -Nru a/drivers/scsi/NCR53c406a.h b/drivers/scsi/NCR53c406a.h
--- a/drivers/scsi/NCR53c406a.h	Sun Nov 10 19:28:38 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,58 +0,0 @@
-#ifndef _NCR53C406A_H
-#define _NCR53C406A_H
-
-/*
- *  NCR53c406a.h
- * 
- *  Copyright (C) 1994 Normunds Saumanis (normunds@rx.tech.swh.lv)
- *
- *  This program is free software; you can redistribute 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.
- *
- */
-
-#ifndef NULL
-#define NULL 0
-#endif
-
-/* NOTE:  scatter-gather support only works in PIO mode.
- * Use SG_NONE if DMA mode is enabled!
- */
-#define NCR53c406a { \
-     proc_name:         	"NCR53c406a"		/* proc_name */,        \
-     name:              	"NCR53c406a"		/* name */,             \
-     detect:            	NCR53c406a_detect	/* detect */,           \
-     info:              	NCR53c406a_info		/* info */,             \
-     command:           	NCR53c406a_command	/* command */,          \
-     queuecommand:      	NCR53c406a_queue	/* queuecommand */,     \
-     eh_abort_handler:  	NCR53c406a_abort	/* abort */,            \
-     eh_bus_reset_handler:      NCR53c406a_bus_reset	/* reset */,            \
-     eh_device_reset_handler:   NCR53c406a_device_reset	/* reset */,            \
-     eh_host_reset_handler:     NCR53c406a_host_reset	/* reset */,            \
-     bios_param:        	NCR53c406a_biosparm	/* biosparm */,         \
-     can_queue:         	1			/* can_queue */,        \
-     this_id:           	7			/* SCSI ID of the chip */, \
-     sg_tablesize:      	32			/*SG_ALL*/ /*SG_NONE*/, \
-     cmd_per_lun:       	1			/* commands per lun */, \
-     unchecked_isa_dma: 	1			/* unchecked_isa_dma */, \
-     use_clustering:    	ENABLE_CLUSTERING                               \
-}
-
-static int NCR53c406a_detect(Scsi_Host_Template *);
-static const char *NCR53c406a_info(struct Scsi_Host *);
-static int NCR53c406a_command(Scsi_Cmnd *);
-static int NCR53c406a_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-static int NCR53c406a_abort(Scsi_Cmnd *);
-static int NCR53c406a_bus_reset(Scsi_Cmnd *);
-static int NCR53c406a_device_reset(Scsi_Cmnd *);
-static int NCR53c406a_host_reset(Scsi_Cmnd *);
-static int NCR53c406a_biosparm(Disk *, struct block_device *, sector_t, int[]);
-
-#endif				/* _NCR53C406A_H */
diff -Nru a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
--- a/drivers/scsi/aha1740.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/scsi/aha1740.c	Sun Nov 10 19:28:38 2002
@@ -20,6 +20,14 @@
  *
  * aha1740_makecode may still need even more work
  * if it doesn't work for your devices, take a look.
+ *
+ * Reworked for new_eh and new locking by Alan Cox <alan@redhat.com>
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
  */
 
 #include <linux/module.h>
@@ -68,7 +76,7 @@
 /* One for each IRQ level (9-15) */
 static struct Scsi_Host * aha_host[8] = {NULL, };
 
-int aha1740_proc_info(char *buffer, char **start, off_t offset,
+static int aha1740_proc_info(char *buffer, char **start, off_t offset,
 		      int length, int hostno, int inout)
 {
     int len;
@@ -76,7 +84,7 @@
     struct aha1740_hostdata *host;
 
     if (inout)
-	return(-ENOSYS);
+	return-ENOSYS;
 
     for (len = 0; len < 8; len++) {
 	shpnt = aha_host[len];
@@ -103,7 +111,7 @@
 }
 
 
-int aha1740_makecode(unchar *sense, unchar *status)
+static int aha1740_makecode(unchar *sense, unchar *status)
 {
     struct statusword
     {
@@ -179,7 +187,7 @@
     return status[3] | retval << 16;
 }
 
-int aha1740_test_port(unsigned int base)
+static int aha1740_test_port(unsigned int base)
 {
     char name[4], tmp;
 
@@ -212,7 +220,7 @@
 }
 
 /* A "high" level interrupt handler */
-void aha1740_intr_handle(int irq, void *dev_id, struct pt_regs * regs)
+static void aha1740_intr_handle(int irq, void *dev_id, struct pt_regs * regs)
 {
     struct Scsi_Host *host = aha_host[irq - 9];
     void (*my_done)(Scsi_Cmnd *);
@@ -303,7 +311,7 @@
     spin_unlock_irqrestore(host->host_lock, flags);
 }
 
-int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
 {
     unchar direction;
     unchar *cmd = (unchar *) SCpnt->cmnd;
@@ -317,16 +325,6 @@
 
     if(*cmd == REQUEST_SENSE)
     {
-#if 0
-	/* scsi_request_sense() provides a buffer of size 256,
-	   so there is no reason to expect equality */
-
-	if (bufflen != sizeof(SCpnt->sense_buffer))
-	{
-	    printk("Wrong buffer length supplied for request sense (%d)\n",
-		   bufflen);
-	}
-#endif	
 	SCpnt->result = 0;
 	done(SCpnt); 
 	return 0;
@@ -486,7 +484,7 @@
     SCpnt->SCp.Status++;
 }
 
-int aha1740_command(Scsi_Cmnd * SCpnt)
+static int aha1740_command(Scsi_Cmnd * SCpnt)
 {
     aha1740_queuecommand(SCpnt, internal_done);
     SCpnt->SCp.Status = 0;
@@ -501,7 +499,7 @@
 /* Query the board for its irq_level.  Nothing else matters
    in enhanced mode on an EISA bus. */
 
-void aha1740_getconfig(unsigned int base, unsigned int *irq_level,
+static void aha1740_getconfig(unsigned int base, unsigned int *irq_level,
 		       unsigned int *translation)
 {
     static int intab[] = { 9, 10, 11, 12, 0, 14, 15, 0 };
@@ -511,7 +509,7 @@
     outb(inb(INTDEF(base)) | 0x10, INTDEF(base));
 }
 
-int aha1740_detect(Scsi_Host_Template * tpnt)
+static int aha1740_detect(Scsi_Host_Template * tpnt)
 {
     int count = 0, slot;
 
@@ -540,8 +538,8 @@
 	    outb(G2CNTRL_HRST, G2CNTRL(slotbase));
 	    outb(0, G2CNTRL(slotbase));
 	}
-	printk("Configuring aha174x at IO:%x, IRQ %d\n", slotbase, irq_level);
-	printk("aha174x: Extended translation %sabled.\n",
+	printk(KERN_INFO "Configuring aha174x at IO:%x, IRQ %d\n", slotbase, irq_level);
+	printk(KERN_INFO "aha174x: Extended translation %sabled.\n",
 	       translation ? "en" : "dis");
 	DEB(printk("aha1740_detect: enable interrupt channel %d\n",irq_level));
 	if (request_irq(irq_level,aha1740_intr_handle,0,"aha1740",NULL)) {
@@ -572,31 +570,7 @@
     return count;
 }
 
-/* Note:  They following two functions do not apply very well to the Adaptec,
-   which basically manages its own affairs quite well without our interference,
-   so I haven't put anything into them.  I can faintly imagine someone with a
-   *very* badly behaved SCSI target (perhaps an old tape?) wanting the abort(),
-   but it hasn't happened yet, and doing aborts brings the Adaptec to its
-   knees.  I cannot (at this moment in time) think of any reason to reset the
-   card once it's running.  So there. */
-
-int aha1740_abort(Scsi_Cmnd * SCpnt)
-{
-    DEB(printk("aha1740_abort called\n"));
-    return SCSI_ABORT_SNOOZE;
-}
-
-/* We do not implement a reset function here, but the upper level code assumes
-   that it will get some kind of response for the command in SCpnt.  We must
-   oblige, or the command will hang the scsi system */
-
-int aha1740_reset(Scsi_Cmnd * SCpnt, unsigned int ignored)
-{
-    DEB(printk("aha1740_reset called\n"));
-    return SCSI_RESET_PUNT;
-}
-
-int aha1740_biosparam(struct scsi_device *sdev, struct block_device *dev,
+static int aha1740_biosparam(struct scsi_device *sdev, struct block_device *dev,
 		sector_t capacity, int* ip)
 {
     int size = capacity;
diff -Nru a/drivers/scsi/aha1740.h b/drivers/scsi/aha1740.h
--- a/drivers/scsi/aha1740.h	Sun Nov 10 19:28:40 2002
+++ b/drivers/scsi/aha1740.h	Sun Nov 10 19:28:40 2002
@@ -13,8 +13,8 @@
 #include <linux/types.h>
 
 /* Eisa Enhanced mode operation - slot locating and addressing */
-#define MINEISA 1   /* I don't have an EISA Spec to know these ranges, so I */
-#define MAXEISA 8   /* Just took my machine's specifications.  Adjust to fit.*/
+#define MINEISA 1		/* I don't have an EISA Spec to know these ranges, so I */
+#define MAXEISA 8		/* Just took my machine's specifications.  Adjust to fit. */
 		    /* I just saw an ad, and bumped this from 6 to 8 */
 #define	SLOTBASE(x)	((x << 12) + 0xc80)
 #define SLOTSIZE	0x5c
@@ -75,14 +75,14 @@
 #define	ATTN_START	0x40	/* Start CCB */
 #define	ATTN_ABORT	0x50	/* Abort CCB */
 
-#define G2CNTRL_HRST	0x80		/* Hard Reset */
-#define G2CNTRL_IRST	0x40		/* Clear EISA Interrupt */
-#define G2CNTRL_HRDY	0x20		/* Sets HOST ready */
+#define G2CNTRL_HRST	0x80	/* Hard Reset */
+#define G2CNTRL_IRST	0x40	/* Clear EISA Interrupt */
+#define G2CNTRL_HRDY	0x20	/* Sets HOST ready */
 
 /* This is used with scatter-gather */
 struct aha1740_chain {
-  u32  dataptr;		/* Location of data */
-  u32  datalen;		/* Size of this part of chain */
+	u32 dataptr;		/* Location of data */
+	u32 datalen;		/* Size of this part of chain */
 };
 
 /* These belong in scsi.h */
@@ -107,40 +107,40 @@
 #define MAX_STATUS 32
 
 struct ecb {			/* Enhanced Control Block 6.1 */
-  u16	cmdw;			/* Command Word */
-  /* Flag Word 1 */
-  u16		cne:1,		/* Control Block Chaining */
-	:6,	di:1,		/* Disable Interrupt */
-	:2,	ses:1,		/* Suppress Underrun error */
-	:1,	sg:1,		/* Scatter/Gather */
-	:1,	dsb:1,		/* Disable Status Block */
-		ars:1;		/* Automatic Request Sense */
-  /* Flag Word 2 */
-  u16		lun:3,		/* Logical Unit */
-		tag:1,		/* Tagged Queuing */
-		tt:2,		/* Tag Type */
-		nd:1,		/* No Disconnect */
-	:1,	dat:1,		/* Data transfer - check direction */
-		dir:1,		/* Direction of transfer 1 = datain */
-		st:1,		/* Suppress Transfer */
-		chk:1,		/* Calculate Checksum */
-	:2,	rec:1,	:1;	/* Error Recovery */
-  u16	nil0;			/* nothing */
-  u32	dataptr;		/* Data or Scatter List ptr */
-  u32	datalen;		/* Data or Scatter List len */
-  u32	statusptr;		/* Status Block ptr */
-  u32	linkptr;		/* Chain Address */
-  u32	nil1;			/* nothing */
-  u32	senseptr;		/* Sense Info Pointer */
-  u8	senselen;		/* Sense Length */
-  u8	cdblen;			/* CDB Length */
-  u16	datacheck;		/* Data checksum */
-  u8	cdb[MAX_CDB];		/* CDB area */
+	u16 cmdw;		/* Command Word */
+	/* Flag Word 1 */
+	u16 cne:1,		/* Control Block Chaining */
+	:6, di:1,		/* Disable Interrupt */
+	:2, ses:1,		/* Suppress Underrun error */
+	:1, sg:1,		/* Scatter/Gather */
+	:1, dsb:1,		/* Disable Status Block */
+	 ars:1;			/* Automatic Request Sense */
+	/* Flag Word 2 */
+	u16 lun:3,		/* Logical Unit */
+	 tag:1,			/* Tagged Queuing */
+	 tt:2,			/* Tag Type */
+	 nd:1,			/* No Disconnect */
+	:1, dat:1,		/* Data transfer - check direction */
+	 dir:1,			/* Direction of transfer 1 = datain */
+	 st:1,			/* Suppress Transfer */
+	 chk:1,			/* Calculate Checksum */
+	:2, rec:1,:1;		/* Error Recovery */
+	u16 nil0;		/* nothing */
+	u32 dataptr;		/* Data or Scatter List ptr */
+	u32 datalen;		/* Data or Scatter List len */
+	u32 statusptr;		/* Status Block ptr */
+	u32 linkptr;		/* Chain Address */
+	u32 nil1;		/* nothing */
+	u32 senseptr;		/* Sense Info Pointer */
+	u8 senselen;		/* Sense Length */
+	u8 cdblen;		/* CDB Length */
+	u16 datacheck;		/* Data checksum */
+	u8 cdb[MAX_CDB];	/* CDB area */
 /* Hardware defined portion ends here, rest is driver defined */
-  u8	sense[MAX_SENSE];	/* Sense area */ 
-  u8	status[MAX_STATUS];	/* Status area */
-  Scsi_Cmnd *SCpnt;		/* Link to the SCSI Command Block */
-  void (*done)(Scsi_Cmnd *);	/* Completion Function */
+	u8 sense[MAX_SENSE];	/* Sense area */
+	u8 status[MAX_STATUS];	/* Status area */
+	Scsi_Cmnd *SCpnt;	/* Link to the SCSI Command Block */
+	void (*done) (Scsi_Cmnd *);	/* Completion Function */
 };
 
 #define	AHA1740CMD_NOP	 0x00	/* No OP */
@@ -152,32 +152,22 @@
 #define AHA1740CMD_RINQ  0x0a	/* Read Host Adapter Inquiry Data */
 #define AHA1740CMD_TARG  0x10	/* Target SCSI Command */
 
-int aha1740_detect(Scsi_Host_Template *);
-int aha1740_command(Scsi_Cmnd *);
-int aha1740_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int aha1740_abort(Scsi_Cmnd *);
-int aha1740_reset(Scsi_Cmnd *, unsigned int);
-int aha1740_biosparam(struct scsi_device *, struct block_device *,
-		sector_t, int*);
-int aha1740_proc_info(char *buffer, char **start, off_t offset,
-                               int length, int hostno, int inout);
+static int aha1740_detect(Scsi_Host_Template *);
+static int aha1740_command(Scsi_Cmnd *);
+static int aha1740_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+static int aha1740_biosparam(struct scsi_device *, struct block_device *, sector_t, int *);
+static int aha1740_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
 
 #define AHA1740_ECBS 32
 #define AHA1740_SCATTER 16
 #define AHA1740_CMDLUN 1
 
-#ifndef NULL
-	#define NULL 0
-#endif
-
 #define AHA1740 {  proc_name:      "aha1740",				\
 		   proc_info:      aha1740_proc_info,	                \
 		   name:           "Adaptec 174x (EISA)",		\
 		   detect:         aha1740_detect,			\
 		   command:        aha1740_command,			\
 		   queuecommand:   aha1740_queuecommand,		\
-		   abort:          aha1740_abort,			\
-		   reset:          aha1740_reset,			\
 		   bios_param:     aha1740_biosparam,                   \
 		   can_queue:      AHA1740_ECBS, 			\
 		   this_id:        7, 					\
diff -Nru a/drivers/scsi/aic7xxx_old/aic7xxx.h b/drivers/scsi/aic7xxx_old/aic7xxx.h
--- a/drivers/scsi/aic7xxx_old/aic7xxx.h	Sun Nov 10 19:28:36 2002
+++ b/drivers/scsi/aic7xxx_old/aic7xxx.h	Sun Nov 10 19:28:36 2002
@@ -38,6 +38,9 @@
 	slave_attach: aic7xxx_slave_attach,			\
 	slave_detach: aic7xxx_slave_detach,			\
 	bios_param: aic7xxx_biosparam,				\
+	eh_abort_handler: aic7xxx_abort,			\
+	eh_device_reset_handler: aic7xxx_bus_device_reset,	\
+	eh_host_reset_handler: aic7xxx_reset,			\
 	can_queue: 255,		/* max simultaneous cmds      */\
 	this_id: -1,		/* scsi id of host adapter    */\
 	sg_tablesize: 0,	/* max scatter-gather cmds    */\
@@ -55,6 +58,9 @@
 extern int aic7xxx_release(struct Scsi_Host *);
 extern int aic7xxx_slave_attach(Scsi_Device *);
 extern void aic7xxx_slave_detach(Scsi_Device *);
+extern int aic7xxx_abort(Scsi_Cmnd *);
+extern int aic7xxx_bus_device_reset(Scsi_Cmnd *);
+extern int aic7xxx_reset(Scsi_Cmnd *);
 
 extern const char *aic7xxx_info(struct Scsi_Host *);
 
diff -Nru a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
--- a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c	Sun Nov 10 19:28:41 2002
@@ -33,7 +33,7 @@
 
 #define	BLS	(&aic7xxx_buffer[size])
 #define HDRB \
-"             0 - 4K     4 - 16K    16 - 64K   64 - 256K   256K - 1M    1M+"
+"               0 - 4K   4 - 16K   16 - 64K  64 - 256K  256K - 1M        1M+"
 
 #ifdef PROC_DEBUG
 extern int vsprintf(char *, const char *, va_list);
@@ -90,7 +90,6 @@
   int    size = 0;
   unsigned char i;
   unsigned char tindex;
-  struct list_head *list_item;
 
   HBAptr = NULL;
 
@@ -132,10 +131,8 @@
    */
 
   size = 4096;
-  list_for_each(list_item, &p->aic_devs)
-  {
+  list_for_each_entry(aic_dev, &p->aic_devs, list)
     size += 512;
-  }
   if (aic7xxx_buffer_size != size)
   {
     if (aic7xxx_buffer != NULL) 
@@ -158,13 +155,6 @@
   size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
   size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
   size += sprintf(BLS, "\n");
-  size += sprintf(BLS, "Compile Options:\n");
-#ifdef CONFIG_AIC7XXX_OLD_TCQ_ON_BY_DEFAULT
-  size += sprintf(BLS, "  TCQ Enabled By Default : Enabled\n");
-#else
-  size += sprintf(BLS, "  TCQ Enabled By Default : Disabled\n");
-#endif
-  size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Adapter Configuration:\n");
   size += sprintf(BLS, "           SCSI Adapter: %s\n",
       board_names[p->board_name_index]);
@@ -263,7 +253,7 @@
   {
     size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
   }
-  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", AIC7XXX_CMDS_PER_DEVICE);
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", aic7xxx_default_queue_depth);
   size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
                        "instance %d:\n", p->instance);
   size += sprintf(BLS, "      {");
@@ -273,9 +263,8 @@
 
   size += sprintf(BLS, "\n");
   size += sprintf(BLS, "Statistics:\n\n");
-  list_for_each(list_item, &p->aic_devs)
+  list_for_each_entry(aic_dev, &p->aic_devs, list)
   {
-    aic_dev = list_entry(list_item, struct aic_dev_data, list);
     sdptr = aic_dev->SDptr;
     tindex = sdptr->channel << 3 | sdptr->id;
     size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
@@ -322,24 +311,32 @@
                     p->user[tindex].offset,
                     p->user[tindex].width,
                     p->user[tindex].options);
-    size += sprintf(BLS, "  Total transfers %ld (%ld reads and %ld writes)\n",
-      aic_dev->r_total + aic_dev->w_total, aic_dev->r_total, aic_dev->w_total);
+    if(sdptr->simple_tags)
+    {
+      size += sprintf(BLS, "  Tagged Command Queueing Enabled, Ordered Tags %s\n", sdptr->ordered_tags ? "Enabled" : "Disabled");
+    }
+    if(aic_dev->barrier_total)
+      size += sprintf(BLS, "  Total transfers %ld:\n    (%ld/%ld/%ld/%ld reads/writes/REQ_BARRIER/Ordered Tags)\n",
+        aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total,
+        aic_dev->barrier_total, aic_dev->ordered_total);
+    else
+      size += sprintf(BLS, "  Total transfers %ld:\n    (%ld/%ld reads/writes)\n",
+        aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total);
     size += sprintf(BLS, "%s\n", HDRB);
     size += sprintf(BLS, "   Reads:");
     for (i = 0; i < NUMBER(aic_dev->r_bins); i++)
     {
-      size += sprintf(BLS, " %7ld", aic_dev->r_bins[i]);
+      size += sprintf(BLS, " %10ld", aic_dev->r_bins[i]);
     }
     size += sprintf(BLS, "\n");
     size += sprintf(BLS, "  Writes:");
     for (i = 0; i < NUMBER(aic_dev->w_bins); i++)
     {
-      size += sprintf(BLS, " %7ld", aic_dev->w_bins[i]);
+      size += sprintf(BLS, " %10ld", aic_dev->w_bins[i]);
     }
     size += sprintf(BLS, "\n");
     size += sprintf(BLS, "\n\n");
   }
-
   if (size >= aic7xxx_buffer_size)
   {
     printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n");
diff -Nru a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
--- a/drivers/scsi/aic7xxx_old.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/scsi/aic7xxx_old.c	Sun Nov 10 19:28:39 2002
@@ -252,7 +252,7 @@
 
 #include <linux/config.h>        /* for CONFIG_PCI */
 
-#define AIC7XXX_C_VERSION  "5.2.5"
+#define AIC7XXX_C_VERSION  "5.2.6"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -274,30 +274,20 @@
 #endif
 
 /*
- * You can try raising me if tagged queueing is enabled, or lowering
- * me if you only have 4 SCBs.
+ * You can try raising me for better performance or lowering me if you have
+ * flaky devices that go off the scsi bus when hit with too many tagged
+ * commands (like some IBM SCSI-3 LVD drives).
  */
 #define AIC7XXX_CMDS_PER_DEVICE 32
 
-/*
- * *** Determining commands per LUN ***
- * 
- * When AIC7XXX_CMDS_PER_DEVICE is not defined, the driver will use its
- * own algorithm to determine the commands/LUN.  If SCB paging is
- * enabled, which is always now, the default is 8 commands per lun
- * that indicates it supports tagged queueing.  All non-tagged devices
- * use an internal queue depth of 3, with no more than one of those
- * three commands active at one time.
- */
-
 typedef struct
 {
   unsigned char tag_commands[16];   /* Allow for wide/twin adapters. */
 } adapter_tag_info_t;
 
 /*
- * Make a define that will tell the driver not to use tagged queueing
- * by default.
+ * Make a define that will tell the driver not to the default tag depth
+ * everywhere.
  */
 #define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
                               0, 0, 0, 0, 0, 0, 0, 0}
@@ -878,7 +868,6 @@
   volatile unsigned short  temp_q_depth;
   unsigned short           max_q_depth;
   volatile unsigned char   active_cmds;
-  unsigned char            cmds_sent;
   /*
    * Statistics Kept:
    *
@@ -891,6 +880,9 @@
    */
   long w_total;                          /* total writes */
   long r_total;                          /* total reads */
+  long barrier_total;			 /* total num of REQ_BARRIER commands */
+  long ordered_total;			 /* How many REQ_BARRIER commands we
+					    used ordered tags to satisfy */
   long w_bins[6];                       /* binned write */
   long r_bins[6];                       /* binned reads */
   transinfo_type	cur;
@@ -998,7 +990,7 @@
   unsigned short           sc_size;
   struct aic7xxx_host     *next;             /* allow for multiple IRQs */
   struct Scsi_Host        *host;             /* pointer to scsi host */
-  struct list_head	   aic_devs;	     /* all aic devs on host */
+  struct list_head	   aic_devs;	     /* all aic_dev structs on host */
   int                      host_no;          /* SCSI host number */
   unsigned long            mbase;            /* I/O memory address */
   ahc_chip                 chip;             /* chip type */
@@ -1066,6 +1058,10 @@
  *       rule are noted in the comments.
  */
 
+/*
+ * Use this as the default queue depth when setting tagged queueing on.
+ */
+static unsigned int aic7xxx_default_queue_depth = AIC7XXX_CMDS_PER_DEVICE;
 
 /*
  * Skip the scsi bus reset.  Non 0 make us skip the reset at startup.  This
@@ -1369,6 +1365,7 @@
     { "pci_parity", &aic7xxx_pci_parity },
     { "dump_card", &aic7xxx_dump_card },
     { "dump_sequencer", &aic7xxx_dump_sequencer },
+    { "default_queue_depth", &aic7xxx_default_queue_depth },
     { "scbram", &aic7xxx_scbram },
     { "seltime", &aic7xxx_seltime },
     { "tag_info",    NULL }
@@ -2636,6 +2633,7 @@
 static void
 aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
+  aic7xxx_position(cmd) = SCB_LIST_NULL;
   cmd->host_scribble = (char *)p->completeq.head;
   p->completeq.head = cmd;
 }
@@ -2869,6 +2867,12 @@
       aic_dev->r_total++;
       ptr = aic_dev->r_bins;
     }
+    if(cmd->device->simple_tags && cmd->request->flags & REQ_HARDBARRIER)
+    {
+      aic_dev->barrier_total++;
+      if(scb->tag_action == MSG_ORDERED_Q_TAG)
+        aic_dev->ordered_total++;
+    }
     x = scb->sg_length;
     x >>= 10;
     for(i=0; i<6; i++)
@@ -3130,23 +3134,41 @@
 {
   struct aic7xxx_scb *scbp, *prev_scbp;
   struct scsi_device *sd;
-  unsigned char active_scb, tcl;
+  unsigned char active_scb, tcl, scb_tag;
   int i = 0, init_lists = FALSE;
-  struct list_head *list_item, *list_head;
-  struct aic_dev_data *aic_dev;
+  struct aic_dev_data *aic_dev, *remove_aic_dev = NULL;
 
   /*
    * Restore this when we're done
    */
   active_scb = aic_inb(p, SCBPTR);
+  /*
+   * If we are still scanning devices, this device may not be linked into
+   * our host controller yet.  So, we grab the temporary aic_dev that we
+   * allocate during the device scan (by getting device->hostdata for the
+   * active device) and if the list struct in the aic_dev is empty, we
+   * add it to p->aic_devs.  Then at the end of the function, if we added
+   * the aic_dev to our host struct so our loop would work, then we just
+   * remove it.
+   */
+  scb_tag = aic_inb(p, SCB_TAG);
+  if(scb_tag < p->scb_data->numscbs)
+  {
+    scbp = p->scb_data->scb_array[scb_tag];
+    remove_aic_dev = (struct aic_dev_data *)scbp->cmd->device->hostdata;
+    if(list_empty(&remove_aic_dev->list))
+      list_add_tail(&remove_aic_dev->list, &p->aic_devs);
+    else
+      remove_aic_dev = NULL;
+  }
 
   if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
   {
-    printk(INFO_LEAD "Reset device, active_scb %d\n",
-         p->host_no, channel, target, lun, active_scb);
-    printk(INFO_LEAD "Current scb_tag %d, SEQADDR 0x%x, LASTPHASE "
+    printk(INFO_LEAD "Reset device, hardware_scb %d, aic_dev %p,\n",
+         p->host_no, channel, target, lun, active_scb, remove_aic_dev);
+    printk(INFO_LEAD "Current scb %d, SEQADDR 0x%x, LASTPHASE "
            "0x%x\n",
-         p->host_no, channel, target, lun, aic_inb(p, SCB_TAG),
+         p->host_no, channel, target, lun, scb_tag,
          aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
          aic_inb(p, LASTPHASE));
     printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
@@ -3157,13 +3179,15 @@
          p->host_no, channel, target, lun, aic_inb(p, SSTAT0),
          aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
   }
+
   /*
    * Deal with the busy target and linked next issues.
    */
-  list_head = &p->aic_devs;
-  list_for_each(list_item, list_head)
+  list_for_each_entry(aic_dev, &p->aic_devs, list)
   {
-    aic_dev = list_entry(list_item, struct aic_dev_data, list);
+    if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+      printk(INFO_LEAD "processing aic_dev %p\n", p->host_no, channel, target,
+		    lun, aic_dev);
     sd = aic_dev->SDptr;
 
     if((target != ALL_TARGETS && target != sd->id) ||
@@ -3205,6 +3229,8 @@
       }
     }
   }
+  if (remove_aic_dev)
+    list_del(&remove_aic_dev->list);
 
   if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
     printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun );
@@ -6526,22 +6552,19 @@
 
 /*+F*************************************************************************
  * Function:
- *   aic7xxx_init_aic_dev
+ *   aic7xxx_init_transinfo
  *
  * Description:
- *   Set up the initial aic_dev values from the BIOS settings and data
- *   we got back from INQUIRY commands.
+ *   Set up the initial aic_dev values from the BIOS settings and from
+ *   INQUIRY results
  *-F*************************************************************************/
 static void
-aic7xxx_init_aic_dev(struct aic7xxx_host *p, struct aic_dev_data *aic_dev)
+aic7xxx_init_transinfo(struct aic7xxx_host *p, struct aic_dev_data *aic_dev)
 {
-  struct scsi_device *sdpnt = aic_dev->SDptr;
+  Scsi_Device *sdpnt = aic_dev->SDptr;
   unsigned char tindex;
 
   tindex = sdpnt->id | (sdpnt->channel << 3);
-
-  scbq_init(&aic_dev->delayed_scbs);
-
   if (!(aic_dev->flags & DEVICE_DTR_SCANNED))
   {
     aic_dev->flags |= DEVICE_DTR_SCANNED;
@@ -6599,13 +6622,42 @@
 
 /*+F*************************************************************************
  * Function:
+ *   aic7xxx_alloc_aic_dev
+ *
+ * Description:
+ *   Set up the initial aic_dev struct pointers
+ *-F*************************************************************************/
+static struct aic_dev_data *
+aic7xxx_alloc_aic_dev(struct aic7xxx_host *p, Scsi_Device *SDptr)
+{
+  struct aic_dev_data *aic_dev;
+
+  aic_dev = kmalloc(sizeof(struct aic_dev_data), GFP_ATOMIC | GFP_KERNEL);
+  if(!aic_dev)
+    return aic_dev;
+  memset(aic_dev, 0, sizeof(struct aic_dev_data));
+  SDptr->hostdata = aic_dev;
+  aic_dev->SDptr = SDptr;
+  aic_dev->max_q_depth = 1;
+  aic_dev->temp_q_depth = 1;
+  scbq_init(&aic_dev->delayed_scbs);
+  INIT_LIST_HEAD(&aic_dev->list);
+  return aic_dev;
+}
+
+/*+F*************************************************************************
+ * Function:
  *   aic7xxx_device_queue_depth
  *
  * Description:
  *   Determines the queue depth for a given device.  There are two ways
  *   a queue depth can be obtained for a tagged queueing device.  One
  *   way is the default queue depth which is determined by whether
- *   AIC7XXX_CMDS_PER_DEVICE is defined.  If it is defined, then it is used
+ *   aic7xxx_default_queue_depth.  The other is by the aic7xxx_tag_info
+ *   array.
+ *
+ *   If tagged queueing isn't supported on the device, then we set the
+ *   depth to p->host->hostt->cmd_per_lun for internal driver queueing.
  *   as the default queue depth.  Otherwise, we use either 4 or 8 as the
  *   default queue depth (dependent on the number of hardware SCBs).
  *   The other way we determine queue depth is through the use of the
@@ -6617,7 +6669,7 @@
 static void
 aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
 {
-  int default_depth = p->host->hostt->cmd_per_lun;
+  int tag_enabled = FALSE;
   struct aic_dev_data *aic_dev = device->hostdata;
   unsigned char tindex;
 
@@ -6626,14 +6678,9 @@
   if (device->simple_tags)
     return; // We've already enabled this device
 
-  aic_dev->temp_q_depth = 1;
-  aic_dev->max_q_depth = 1;
-
   if (device->tagged_supported)
   {
-    int tag_enabled = TRUE;
-
-    default_depth = AIC7XXX_CMDS_PER_DEVICE;
+    tag_enabled = TRUE;
 
     if (!(p->discenable & (1 << tindex)))
     {
@@ -6641,6 +6688,7 @@
         printk(INFO_LEAD "Disconnection disabled, unable to "
              "enable tagged queueing.\n",
              p->host_no, device->channel, device->id, device->lun);
+      tag_enabled = FALSE;
     }
     else
     {
@@ -6655,7 +6703,8 @@
                            " the aic7xxx.c source file.\n");
           print_warning = FALSE;
         }
-        aic_dev->max_q_depth = aic_dev->temp_q_depth = default_depth;
+        aic_dev->max_q_depth = aic_dev->temp_q_depth =
+		aic7xxx_default_queue_depth;
       }
       else
       {
@@ -6666,7 +6715,8 @@
         }
         else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
         {
-          aic_dev->max_q_depth = aic_dev->temp_q_depth = default_depth;
+          aic_dev->max_q_depth = aic_dev->temp_q_depth =
+		  aic7xxx_default_queue_depth;
         }
         else
         {
@@ -6674,18 +6724,28 @@
             aic7xxx_tag_info[p->instance].tag_commands[tindex];
         }
       }
-      if (tag_enabled)
-      {
-        if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
-        {
-              printk(INFO_LEAD "Enabled tagged queuing, queue depth %d.\n",
-                p->host_no, device->channel, device->id,
-                device->lun, aic_dev->max_q_depth);
-        }
-	scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, aic_dev->max_q_depth);
-      }
     }
   }
+  if (tag_enabled)
+  {
+    if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+    {
+          printk(INFO_LEAD "Tagged queuing enabled, queue depth %d.\n",
+            p->host_no, device->channel, device->id,
+            device->lun, aic_dev->max_q_depth);
+    }
+    scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, aic_dev->max_q_depth);
+  }
+  else
+  {
+    if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+    {
+          printk(INFO_LEAD "Tagged queuing disabled, queue depth %d.\n",
+            p->host_no, device->channel, device->id,
+            device->lun, device->host->cmd_per_lun);
+    }
+    scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
+  }
   return;
 }
 
@@ -6722,28 +6782,22 @@
   struct aic7xxx_host *p = (struct aic7xxx_host *) sdpnt->host->hostdata;
   struct aic_dev_data *aic_dev;
   int scbnum;
-  struct list_head *list_ptr, *list_head;
 
-  if(!sdpnt->hostdata) {
-    sdpnt->hostdata = kmalloc(sizeof(struct aic_dev_data), GFP_ATOMIC);
-    if(!sdpnt->hostdata)
-      return 1;
-    memset(sdpnt->hostdata, 0, sizeof(struct aic_dev_data));
-  }
+  aic_dev = (struct aic_dev_data *)sdpnt->hostdata;
 
-  aic_dev = sdpnt->hostdata;
-  aic_dev->SDptr = sdpnt;
-
-  aic7xxx_init_aic_dev(p, aic_dev);
+  if(!aic_dev) {
+    aic_dev = aic7xxx_alloc_aic_dev(p, sdpnt);
+  }
+  if(!aic_dev)
+    return 1;
   
-  list_add(&aic_dev->list, &p->aic_devs);
-
+  aic7xxx_init_transinfo(p, aic_dev);
   aic7xxx_device_queue_depth(p, sdpnt);
+  if(list_empty(&aic_dev->list))
+    list_add_tail(&aic_dev->list, &p->aic_devs);
 
   scbnum = 0;
-  list_head = &p->aic_devs;
-  list_for_each(list_ptr, list_head) {
-    aic_dev = list_entry(list_ptr, struct aic_dev_data, list);
+  list_for_each_entry(aic_dev, &p->aic_devs, list) {
     scbnum += aic_dev->max_q_depth;
   }
   while (scbnum > p->scb_data->numscbs)
@@ -7878,6 +7932,7 @@
   p->completeq.tail = NULL;
   scbq_init(&p->scb_data->free_scbs);
   scbq_init(&p->waiting_scbs);
+  INIT_LIST_HEAD(&p->aic_devs);
 
   /*
    * We currently have no commands of any type
@@ -10117,30 +10172,6 @@
   return (found);
 }
 
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-/*+F*************************************************************************
- * Function:
- *   aic7xxx_print_scb
- *
- * Description:
- *   Dump the byte codes for an about to be sent SCB.
- *-F*************************************************************************/
-static void
-aic7xxx_print_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
-  int i;
-  unsigned char *x;  
-
-  x = (unsigned char *)&scb->hscb->control;
-
-  for(i=0; i<32; i++)
-  {
-    printk("%02x ", x[i]);
-  }
-  printk("\n");
-}
-#endif
-
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_buildscb
@@ -10157,6 +10188,7 @@
   struct aic_dev_data *aic_dev = cmd->device->hostdata;
   struct scsi_device *sdptr = cmd->device;
   unsigned char tindex = TARGET_INDEX(cmd);
+  struct request *req = cmd->request;
 
   mask = (0x01 << tindex);
   hscb = scb->hscb;
@@ -10171,15 +10203,16 @@
   if (p->discenable & mask)
   {
     hscb->control |= DISCENB;
-    if ( (sdptr->simple_tags) &&
-         (cmd->cmnd[0] != TEST_UNIT_READY) )
+    /* We always force TEST_UNIT_READY to untagged */
+    if (cmd->cmnd[0] != TEST_UNIT_READY && sdptr->simple_tags)
     {
-      aic_dev->cmds_sent++;
-      if (aic_dev->cmds_sent >= 254 && sdptr->ordered_tags)
+      if (req->flags & REQ_HARDBARRIER)
       {
-        aic_dev->cmds_sent = 0;
-        hscb->control |= MSG_ORDERED_Q_TAG;
-        scb->tag_action = MSG_ORDERED_Q_TAG;
+	if(sdptr->ordered_tags)
+	{
+          hscb->control |= MSG_ORDERED_Q_TAG;
+          scb->tag_action = MSG_ORDERED_Q_TAG;
+	}
       }
       else
       {
@@ -10306,19 +10339,25 @@
   struct aic7xxx_host *p;
   struct aic7xxx_scb *scb;
   struct aic_dev_data *aic_dev;
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
-  int tindex = TARGET_INDEX(cmd);
-#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-  unsigned long cpu_flags = 0;
-#endif
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
+
+  aic_dev = cmd->device->hostdata;  
+  if(!aic_dev) {
+    aic_dev = aic7xxx_alloc_aic_dev(p, cmd->device);
+    if(!aic_dev)
+      return 1;
+  }
+  else
+  {
+    aic_dev = AIC_DEV(cmd);
+  }
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
   /*
    * Check to see if channel was scanned.
    */
   
-#ifdef AIC7XXX_VERBOSE_DEBUGGING
   if (!(p->flags & AHC_A_SCANNED) && (cmd->channel == 0))
   {
     if (aic7xxx_verbose & VERBOSE_PROBE2)
@@ -10337,25 +10376,15 @@
     }
   }
 
-  if (p->dev_active_cmds[tindex] > (cmd->device->queue_depth + 1))
+  if (aic_dev->active_cmds > aic_dev->max_q_depth)
   {
     printk(WARN_LEAD "Commands queued exceeds queue "
            "depth, active=%d\n",
            p->host_no, CTL_OF_CMD(cmd), 
-           p->dev_active_cmds[tindex]);
-    if ( p->dev_active_cmds[tindex] > 220 )
-      p->dev_active_cmds[tindex] = 0;
+           aic_dev->active_cmds);
   }
 #endif
 
-  if(!cmd->device->hostdata) {
-    aic_dev = kmalloc(sizeof(struct aic_dev_data), GFP_ATOMIC);
-    if(!aic_dev)
-      return 1;
-    memset(aic_dev, 0, sizeof(struct aic_dev_data));
-    cmd->device->hostdata = aic_dev;
-  }
-
   scb = scbq_remove_head(&p->scb_data->free_scbs);
   if (scb == NULL)
   {
@@ -10369,13 +10398,13 @@
     }
   }
   scb->cmd = cmd;
-  aic7xxx_position(cmd) = scb->hscb->tag;
 
   /*
    * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
    * is set up properly, and the parity error flag is reset, then send
    * the SCB to the sequencer and watch the fun begin.
    */
+  aic7xxx_position(cmd) = scb->hscb->tag;
   cmd->scsi_done = fn;
   cmd->result = DID_OK;
   memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
@@ -10392,10 +10421,7 @@
   scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
 
   scbq_insert_tail(&p->waiting_scbs, scb);
-  if ( (p->flags & (AHC_IN_ISR | AHC_IN_ABORT | AHC_IN_RESET)) == 0)
-  {
-    aic7xxx_run_waiting_queues(p);
-  }
+  aic7xxx_run_waiting_queues(p);
   return (0);
 }
 
@@ -10410,21 +10436,40 @@
  *   aborted, then we will reset the channel and have all devices renegotiate.
  *   Returns an enumerated type that indicates the status of the operation.
  *-F*************************************************************************/
-static int
-aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
+int
+aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
 {
+  struct aic7xxx_host  *p;
   struct aic7xxx_scb   *scb;
   struct aic7xxx_hwscb *hscb;
-  int result = -1;
   int channel;
   unsigned char saved_scbptr, lastphase;
   unsigned char hscb_index;
   int disconnected;
-  struct aic_dev_data *aic_dev = AIC_DEV(cmd);
+  struct aic_dev_data *aic_dev;
+
+  if(cmd == NULL)
+  {
+    printk(KERN_ERR "aic7xxx_bus_device_reset: called with NULL cmd!\n");
+    return FAILED;
+  }
+  p = (struct aic7xxx_host *)cmd->host->hostdata;
+  aic_dev = AIC_DEV(cmd);
+  if(aic7xxx_position(cmd) < p->scb_data->numscbs)
+    scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  else
+    return FAILED;
 
-  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
   hscb = scb->hscb;
 
+  aic7xxx_isr(p->irq, (void *)p, NULL);
+  aic7xxx_done_cmds_complete(p);
+  /* If the command was already complete or just completed, then we didn't
+   * do a reset, return FAILED */
+  if(!scb->flags & SCB_ACTIVE)
+    return FAILED;
+
+  pause_sequencer(p);
   lastphase = aic_inb(p, LASTPHASE);
   if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
   {
@@ -10494,101 +10539,95 @@
       printk(WARN_LEAD "Invalid SCB ID %d is active, "
              "SCB flags = 0x%x.\n", p->host_no,
             CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags);
-      return(SCSI_RESET_ERROR);
+      unpause_sequencer(p, FALSE);
+      return FAILED;
     }
     if (scb->hscb->tag == aic_inb(p, SCB_TAG))
     { 
-      if ( (lastphase != P_MESGOUT) && (lastphase != P_MESGIN) )
-      {
-        if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-          printk(INFO_LEAD "Device reset message in "
-                "message buffer\n", p->host_no, CTL_OF_SCB(scb));
-        scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
-        aic7xxx_error(cmd) = DID_RESET;
-        aic_dev->flags |= BUS_DEVICE_RESET_PENDING;
-        /* Send the abort message to the active SCB. */
-        aic_outb(p, HOST_MSG, MSG_OUT);
-        aic_outb(p, lastphase | ATNO, SCSISIGO);
-        return(SCSI_RESET_PENDING);
-      }
-      else
+      if ( (lastphase == P_MESGOUT) || (lastphase == P_MESGIN) )
       {
-        /* We want to send out the message, but it could screw an already */
-        /* in place and being used message.  Instead, we return an error  */
-        /* to try and start the bus reset phase since this command is     */
-        /* probably hung (aborts failed, and now reset is failing).  We   */
-        /* also make sure to set BUS_DEVICE_RESET_PENDING so we won't try */
-        /* any more on this device, but instead will escalate to a bus or */
-        /* host reset (additionally, we won't try to abort any more).     */
         printk(WARN_LEAD "Device reset, Message buffer "
                 "in use\n", p->host_no, CTL_OF_SCB(scb));
-        scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
-        aic7xxx_error(cmd) = DID_RESET;
-        aic_dev->flags |= BUS_DEVICE_RESET_PENDING;
-        return(SCSI_RESET_ERROR);
+        unpause_sequencer(p, FALSE);
+	return FAILED;
       }
+	
+      if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+        printk(INFO_LEAD "Device reset message in "
+              "message buffer\n", p->host_no, CTL_OF_SCB(scb));
+      scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+      aic7xxx_error(cmd) = DID_RESET;
+      aic_dev->flags |= BUS_DEVICE_RESET_PENDING;
+      /* Send the abort message to the active SCB. */
+      aic_outb(p, HOST_MSG, MSG_OUT);
+      aic_outb(p, lastphase | ATNO, SCSISIGO);
+      unpause_sequencer(p, FALSE);
+      spin_unlock_irq(p->host->host_lock);
+      scsi_sleep(HZ);
+      spin_lock_irq(p->host->host_lock);
+      if(aic_dev->flags & BUS_DEVICE_RESET_PENDING)
+        return FAILED;
+      else
+        return SUCCESS;
     }
   } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */
-  hscb_index = aic7xxx_find_scb(p, scb);
-  if (hscb_index == SCB_LIST_NULL)
-  {
-    disconnected = (aic7xxx_scb_on_qoutfifo(p, scb)) ? FALSE : TRUE;
-  }
-  else
-  {
-    aic_outb(p, hscb_index, SCBPTR);
-    if (aic_inb(p, SCB_CONTROL) & DISCONNECTED)
-    {
-      disconnected = TRUE;
-    }
-  }
-  if (disconnected)
+  /*
+   * Simply set the MK_MESSAGE flag and the SEQINT handler will do
+   * the rest on a reconnect/connect.
+   */
+  scb->hscb->control |= MK_MESSAGE;
+  scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+  aic_dev->flags |= BUS_DEVICE_RESET_PENDING;
+  /*
+   * Check to see if the command is on the qinfifo.  If it is, then we will
+   * not need to queue the command again since the card should start it soon
+   */
+  if (aic7xxx_search_qinfifo(p, cmd->channel, cmd->target, cmd->lun, hscb->tag,
+			  0, TRUE, NULL) == 0)
   {
-        /*
-         * Simply set the MK_MESSAGE flag and the SEQINT handler will do
-         * the rest on a reconnect.
-         */
-    scb->hscb->control |= MK_MESSAGE;
-    scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
-    aic_dev->flags |= BUS_DEVICE_RESET_PENDING;
-    if (hscb_index != SCB_LIST_NULL)
+    disconnected = TRUE;
+    if ((hscb_index = aic7xxx_find_scb(p, scb)) != SCB_LIST_NULL)
     {
       unsigned char scb_control;
 
       aic_outb(p, hscb_index, SCBPTR);
       scb_control = aic_inb(p, SCB_CONTROL);
+      /*
+       * If the DISCONNECTED bit is not set in SCB_CONTROL, then we are
+       * actually on the waiting list, not disconnected, and we don't
+       * need to requeue the command.
+       */
+      disconnected = (scb_control & DISCONNECTED);
       aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL);
     }
-        /*
-         * Actually requeue this SCB in case we can select the
-         * device before it reconnects.  If the transaction we
-         * want to abort is not tagged, then this will be the only
-         * outstanding command and we can simply shove it on the
-         * qoutfifo and be done.  If it is tagged, then it goes right
-         * in with all the others, no problem :)  We need to add it
-         * to the qinfifo and let the sequencer know it is there.
-         * Now, the only problem left to deal with is, *IF* this
-         * command completes, in spite of the MK_MESSAGE bit in the
-         * control byte, then we need to pick that up in the interrupt
-         * routine and clean things up.  This *shouldn't* ever happen.
-         */
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-      printk(INFO_LEAD "Queueing device reset "
-           "command.\n", p->host_no, CTL_OF_SCB(scb));
-    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
-    if (p->features & AHC_QUEUE_REGS)
-      aic_outb(p, p->qinfifonext, HNSCB_QOFF);
-    else
-      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
-    scb->flags |= SCB_QUEUED_ABORT;
-    result = SCSI_RESET_PENDING;
-  }
-  else if (result == -1)
-  {
-    result = SCSI_RESET_ERROR;
+    if (disconnected)
+    {
+      /*
+       * Actually requeue this SCB in case we can select the
+       * device before it reconnects.  This can result in the command
+       * being on the qinfifo twice, but we don't care because it will
+       * all get cleaned up if/when the reset takes place.
+       */
+      if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+        printk(INFO_LEAD "Queueing device reset command.\n", p->host_no,
+		      CTL_OF_SCB(scb));
+      p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+      if (p->features & AHC_QUEUE_REGS)
+        aic_outb(p, p->qinfifonext, HNSCB_QOFF);
+      else
+        aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+      scb->flags |= SCB_QUEUED_ABORT;
+    }
   }
   aic_outb(p, saved_scbptr, SCBPTR);
-  return (result);
+  unpause_sequencer(p, FALSE);
+  spin_unlock_irq(p->host->host_lock);
+  scsi_sleep(HZ/4);
+  spin_lock_irq(p->host->host_lock);
+  if(aic_dev->flags & BUS_DEVICE_RESET_PENDING)
+    return FAILED;
+  else
+    return SUCCESS;
 }
 
 
@@ -10630,12 +10669,30 @@
 {
   struct aic7xxx_scb  *scb = NULL;
   struct aic7xxx_host *p;
-  struct aic_dev_data *aic_dev = AIC_DEV(cmd);
-  int    result, found=0;
-  unsigned char tmp_char, saved_hscbptr, next_hscbptr, prev_hscbptr;
+  int    found=0, disconnected;
+  unsigned char saved_hscbptr, hscbptr, scb_control;
+  struct aic_dev_data *aic_dev;
 
-  p = (struct aic7xxx_host *) cmd->host->hostdata;
-  scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  if(cmd == NULL)
+  {
+    printk(KERN_ERR "aic7xxx_abort: called with NULL cmd!\n");
+    return FAILED;
+  }
+  p = (struct aic7xxx_host *)cmd->host->hostdata;
+  aic_dev = AIC_DEV(cmd);
+  if(aic7xxx_position(cmd) < p->scb_data->numscbs)
+    scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  else
+    return FAILED;
+
+  aic7xxx_isr(p->irq, (void *)p, NULL);
+  aic7xxx_done_cmds_complete(p);
+  /* If the command was already complete or just completed, then we didn't
+   * do a reset, return FAILED */
+  if(!scb->flags & SCB_ACTIVE)
+    return FAILED;
+
+  pause_sequencer(p);
 
   /*
    * I added a new config option to the driver: "panic_on_abort" that will
@@ -10648,92 +10705,6 @@
   if (aic7xxx_panic_on_abort)
     aic7xxx_panic_abort(p, cmd);
 
-/*
- *  Run the isr to grab any command in the QOUTFIFO and any other misc.
- *  assundry tasks.  This should also set up the bh handler if there is
- *  anything to be done, but it won't run until we are done here since
- *  we are following a straight code path without entering the scheduler
- *  code.
- */
-  pause_sequencer(p);
-  while ( (aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
-  {
-    aic7xxx_isr(p->irq, p, (void *)NULL);
-    pause_sequencer(p);
-  }
-  aic7xxx_done_cmds_complete(p);
-
-  if (scb == NULL)
-  {
-    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
-      printk(INFO_LEAD "Abort called with bogus Scsi_Cmnd "
-        "pointer.\n", p->host_no, CTL_OF_CMD(cmd));
-    unpause_sequencer(p, FALSE);
-    return(SCSI_ABORT_NOT_RUNNING);
-  }
-  if (scb->cmd != cmd)  /*  Hmmm...either this SCB is currently free with a */
-  {                     /*  NULL cmd pointer (NULLed out when freed) or it  */
-                        /*  has already been recycled for another command   */
-                        /*  Either way, this SCB has nothing to do with this*/
-                        /*  command and we need to deal with cmd without    */
-                        /*  touching the SCB.                               */
-                        /*  The theory here is to return a value that will  */
-                        /*  make the queued for complete command actually   */
-                        /*  finish successfully, or to indicate that we     */
-                        /*  don't have this cmd any more and the mid level  */
-                        /*  code needs to find it.                          */
-    if (aic7xxx_verbose & VERBOSE_ABORT_MID)
-      printk(INFO_LEAD "Abort called for already completed"
-        " command.\n", p->host_no, CTL_OF_CMD(cmd));
-    unpause_sequencer(p, FALSE);
-    return(SCSI_ABORT_NOT_RUNNING);
-  }
-    
-/*   At this point we know the following:
- *     the SCB pointer is valid
- *     the command pointer passed in to us and the scb->cmd pointer match
- *     this then means that the command we need to abort is the same as the
- *     command held by the scb pointer and is a valid abort request.
- *   Now, we just have to figure out what to do from here.  Current plan is:
- *     if we have already been here on this command, escalate to a reset
- *     if scb is on waiting list or QINFIFO, send it back as aborted, but
- *       we also need to be aware of the possibility that we could be using
- *       a faked negotiation command that is holding this command up,  if
- *       so we need to take care of that command instead, which means we
- *       would then treat this one like it was sitting around disconnected
- *       instead.
- *     if scb is on WAITING_SCB list in sequencer, free scb and send back
- *     if scb is disconnected and not completed, abort with abort message
- *     if scb is currently running, then it may be causing the bus to hang
- *       so we want a return value that indicates a reset would be appropriate
- *       if the command does not finish shortly
- *     if scb is already complete but not on completeq, we're screwed because
- *       this can't happen (except if the command is in the QOUTFIFO, in which
- *       case we would like it to complete successfully instead of having to
- *       to be re-done)
- *   All other scenarios already dealt with by previous code.
- */
-
-  if ( scb->flags & (SCB_ABORT | SCB_RESET | SCB_QUEUED_ABORT) )
-  {
-    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-      printk(INFO_LEAD "SCB aborted once already, "
-        "escalating.\n", p->host_no, CTL_OF_SCB(scb));
-    unpause_sequencer(p, FALSE);
-    return(SCSI_ABORT_SNOOZE);
-  }
-  if ( (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) || 
-          (aic_dev->flags & BUS_DEVICE_RESET_PENDING) )
-  {
-    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-      printk(INFO_LEAD "Reset/Abort pending for this "
-        "device, not wasting our time.\n", p->host_no, CTL_OF_SCB(scb));
-    unpause_sequencer(p, FALSE);
-    return(SCSI_ABORT_PENDING);
-  }
-
-  found = 0;
-  p->flags |= AHC_IN_ABORT;
   if (aic7xxx_verbose & VERBOSE_ABORT)
   {
     printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE "
@@ -10750,56 +10721,8 @@
          aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
   }
 
-/*
- *   First, let's check to see if the currently running command is our target
- *    since if it is, the return is fairly easy and quick since we don't want
- *    to touch the command in case it might complete, but we do want a timeout
- *    in case it's actually hung, so we really do nothing, but tell the mid
- *    level code to reset the timeout.
- */
-
-  if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
-  {
-   /*
-    *  Check to see if the sequencer is just sitting on this command, or
-    *   if it's actively being run.
-    */
-    result = aic_inb(p, LASTPHASE);
-    switch (result)
-    {
-      case P_DATAOUT:    /*    For any of these cases, we can assume we are */
-      case P_DATAIN:     /*    an active command and act according.  For    */
-      case P_COMMAND:    /*    anything else we are going to fall on through*/
-      case P_STATUS:     /*    The SCSI_ABORT_SNOOZE will give us two abort */
-      case P_MESGOUT:    /*    chances to finish and then escalate to a     */
-      case P_MESGIN:     /*    reset call                                   */
-        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-          printk(INFO_LEAD "SCB is currently active.  "
-                "Waiting on completion.\n", p->host_no, CTL_OF_SCB(scb));
-        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
-           "0x%x\n", p->host_no, CTL_OF_SCB(scb),
-           aic_inb(p, SCSISIGI),
-           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
-           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
-        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
-           p->host_no, CTL_OF_SCB(scb),
-           (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
-           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
-           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
-        unpause_sequencer(p, FALSE);
-        p->flags &= ~AHC_IN_ABORT;
-        scb->flags |= SCB_RECOVERY_SCB; /*  Note the fact that we've been  */
-        p->flags |= AHC_ABORT_PENDING;  /*  here so we will know not to    */
-        return(SCSI_ABORT_PENDING);     /*  one doesn't complete and clear */
-        break;                          /*  out.                           */
-      default:
-        break;
-    }
-  }
-
-  if ((found == 0) && (scb->flags & SCB_WAITINGQ))
+  if (scb->flags & SCB_WAITINGQ)
   {
-
     if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
       printk(INFO_LEAD "SCB found on waiting list and "
           "aborted.\n", p->host_no, CTL_OF_SCB(scb));
@@ -10809,95 +10732,123 @@
     p->activescbs++;
     scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
     scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
-    found = 1;
+    goto success;
   }
 
 /*
  *  We just checked the waiting_q, now for the QINFIFO
  */
-  if ( found == 0 )
-  {
-    if ( ((found = aic7xxx_search_qinfifo(p, cmd->target, 
-                     cmd->channel,
+  if ( ((found = aic7xxx_search_qinfifo(p, cmd->target, cmd->channel,
                      cmd->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
                      FALSE, NULL)) != 0) &&
                     (aic7xxx_verbose & VERBOSE_ABORT_PROCESS))
-      printk(INFO_LEAD "SCB found in QINFIFO and "
-        "aborted.\n", p->host_no, CTL_OF_SCB(scb));
+  {
+    printk(INFO_LEAD "SCB found in QINFIFO and aborted.\n", p->host_no,
+		    CTL_OF_SCB(scb));
+    goto success;
   }
 
 /*
  *  QINFIFO, waitingq, completeq done.  Next, check WAITING_SCB list in card
  */
 
-  if ( found == 0 )
+  saved_hscbptr = aic_inb(p, SCBPTR);
+  if ((hscbptr = aic7xxx_find_scb(p, scb)) != SCB_LIST_NULL)
   {
-    unsigned char scb_next_ptr;
-    prev_hscbptr = SCB_LIST_NULL;
-    saved_hscbptr = aic_inb(p, SCBPTR);
-    next_hscbptr = aic_inb(p, WAITING_SCBH);
-    while ( next_hscbptr != SCB_LIST_NULL )
-    {
-      aic_outb(p,  next_hscbptr, SCBPTR );
-      if ( scb->hscb->tag == aic_inb(p, SCB_TAG) )
+    aic_outb(p, hscbptr, SCBPTR);
+    scb_control = aic_inb(p, SCB_CONTROL);
+    disconnected = scb_control & DISCONNECTED;
+    /*
+     * If the DISCONNECTED bit is not set in SCB_CONTROL, then we are
+     * either currently active or on the waiting list.
+     */
+    if(!disconnected && aic_inb(p, LASTPHASE) == P_BUSFREE) {
+      if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+        printk(INFO_LEAD "SCB found on hardware waiting"
+          " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
+      /* If we are the only waiting command, stop the selection engine */
+      if (aic_inb(p, WAITING_SCBH) == hscbptr && aic_inb(p, SCB_NEXT) ==
+			SCB_LIST_NULL)
+      {
+        aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+        aic_outb(p, CLRSELTIMEO, CLRSINT1);
+	aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+      }
+      else
       {
-        found = 1;
-        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
-          printk(INFO_LEAD "SCB found on hardware waiting"
-            " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
-        if ( prev_hscbptr == SCB_LIST_NULL )
-        {
-            aic_outb(p, aic_inb(p, SCB_NEXT), WAITING_SCBH);
-            /* stop the selection since we just
-             * grabbed the scb out from under the
-             * card
-             */
-            aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
-            aic_outb(p, CLRSELTIMEO, CLRSINT1);
-        }
-        else
-        {
-            scb_next_ptr = aic_inb(p, SCB_NEXT);
-            aic_outb(p, prev_hscbptr, SCBPTR);
-            aic_outb(p, scb_next_ptr, SCB_NEXT);
-            aic_outb(p, next_hscbptr, SCBPTR);
-        }
-        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
-        aic_outb(p, 0, SCB_CONTROL);
-        aic7xxx_add_curscb_to_free_list(p);
-        scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
-        break;
+	unsigned char prev, next;
+	prev = SCB_LIST_NULL;
+	next = aic_inb(p, WAITING_SCBH);
+	while(next != SCB_LIST_NULL)
+	{
+	  aic_outb(p, next, SCBPTR);
+	  if (next == hscbptr)
+	  {
+	    next = aic_inb(p, SCB_NEXT);
+	    if (prev != SCB_LIST_NULL)
+	    {
+	      aic_outb(p, prev, SCBPTR);
+	      aic_outb(p, next, SCB_NEXT);
+	    }
+	    else
+	      aic_outb(p, next, WAITING_SCBH);
+	    aic_outb(p, hscbptr, SCBPTR);
+	    next = SCB_LIST_NULL;
+	  }
+	  else
+	  {
+	    prev = next;
+	    next = aic_inb(p, SCB_NEXT);
+	  }
+	}
       }
-      prev_hscbptr = next_hscbptr;
-      next_hscbptr = aic_inb(p, SCB_NEXT);
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+      aic_outb(p, 0, SCB_CONTROL);
+      aic7xxx_add_curscb_to_free_list(p);
+      scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
+      goto success;
+    }
+    else if (!disconnected)
+    {
+      /*
+       * We are the currently active command
+       */
+      if((aic_inb(p, LASTPHASE) == P_MESGIN) ||
+	 (aic_inb(p, LASTPHASE) == P_MESGOUT))
+      {
+	/*
+	 * Message buffer busy, unable to abort
+	 */
+	printk(INFO_LEAD "message buffer busy, unable to abort.\n",
+			  p->host_no, CTL_OF_SCB(scb));
+	unpause_sequencer(p, FALSE);
+	return FAILED;
+      }
+      /* Fallthrough to below, set ATNO after we set SCB_CONTROL */
+    } 
+    aic_outb(p,  scb_control | MK_MESSAGE, SCB_CONTROL);
+    if(!disconnected)
+    {
+      aic_outb(p, HOST_MSG, MSG_OUT);
+      aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
     }
-    aic_outb(p,  saved_hscbptr, SCBPTR );
+    aic_outb(p, saved_hscbptr, SCBPTR);
+  } 
+  else
+  {
+    /*
+     * The scb isn't in the card at all and it is active and it isn't in
+     * any of the queues, so it must be disconnected and paged out.  Fall
+     * through to the code below.
+     */
+    disconnected = 1;
   }
         
-/*
- *  Hmmm...completeq, QOUTFIFO, QINFIFO, WAITING_SCBH, waitingq all checked.
- *  OK...the sequencer's paused, interrupts are off, and we haven't found the
- *  command anyplace where it could be easily aborted.  Time for the hard
- *  work.  We also know the command is valid.  This essentially means the
- *  command is disconnected, or connected but not into any phases yet, which
- *  we know due to the tests we ran earlier on the current active scb phase.
- *  At this point we can queue the abort tag and go on with life.
- */
-
-  if ( found == 0 )
-  {
-    p->flags |= AHC_ABORT_PENDING;
-    scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
-    scb->hscb->control |= MK_MESSAGE;
-    result=aic7xxx_find_scb(p, scb);
-    if ( result != SCB_LIST_NULL ) 
-    {
-      saved_hscbptr = aic_inb(p, SCBPTR);
-      aic_outb(p, result, SCBPTR);
-      tmp_char = aic_inb(p, SCB_CONTROL);
-      aic_outb(p,  tmp_char | MK_MESSAGE, SCB_CONTROL);
-      aic_outb(p, saved_hscbptr, SCBPTR);
-    }
+  p->flags |= AHC_ABORT_PENDING;
+  scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
+  scb->hscb->control |= MK_MESSAGE;
+  if(disconnected)
+  {
     if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
       printk(INFO_LEAD "SCB disconnected.  Queueing Abort"
         " SCB.\n", p->host_no, CTL_OF_SCB(scb));
@@ -10907,31 +10858,30 @@
     else
       aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
   }
-  if (found)
-  {
-    aic7xxx_run_done_queue(p, TRUE);
-    aic7xxx_run_waiting_queues(p);
+  unpause_sequencer(p, FALSE);
+  spin_unlock_irq(p->host->host_lock);
+  scsi_sleep(HZ/4);
+  spin_lock_irq(p->host->host_lock);
+  if (p->flags & AHC_ABORT_PENDING)
+  {
+    if (aic7xxx_verbose & VERBOSE_ABORT_RETURN)
+      printk(INFO_LEAD "Abort never delivered, returning FAILED\n", p->host_no,
+		    CTL_OF_CMD(cmd));
+    p->flags &= ~AHC_ABORT_PENDING;
+    return FAILED;
   }
-  p->flags &= ~AHC_IN_ABORT;
+  if (aic7xxx_verbose & VERBOSE_ABORT_RETURN)
+    printk(INFO_LEAD "Abort successful.\n", p->host_no, CTL_OF_CMD(cmd));
+  return SUCCESS;
+
+success:
+  if (aic7xxx_verbose & VERBOSE_ABORT_RETURN)
+    printk(INFO_LEAD "Abort successful.\n", p->host_no, CTL_OF_CMD(cmd));
+  aic7xxx_run_done_queue(p, TRUE);
   unpause_sequencer(p, FALSE);
-
-/*
- *  On the return value.  If we found the command and aborted it, then we know
- *  it's already sent back and there is no reason for a further timeout, so
- *  we use SCSI_ABORT_SUCCESS.  On the queued abort side, we aren't so certain
- *  there hasn't been a bus hang or something that might keep the abort from
- *  from completing.  Therefore, we use SCSI_ABORT_PENDING.  The first time this
- *  is passed back, the timeout on the command gets extended, the second time
- *  we pass this back, the mid level SCSI code calls our reset function, which
- *  would shake loose a hung bus.
- */
-  if ( found != 0 )
-    return(SCSI_ABORT_SUCCESS);
-  else
-    return(SCSI_ABORT_PENDING); 
+  return SUCCESS;
 }
 
-
 /*+F*************************************************************************
  * Function:
  *   aic7xxx_reset
@@ -10943,38 +10893,24 @@
  *   the SCSI bus reset line.
  *-F*************************************************************************/
 int
-aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
+aic7xxx_reset(Scsi_Cmnd *cmd)
 {
-  struct aic7xxx_scb *scb = NULL;
+  struct aic7xxx_scb *scb;
   struct aic7xxx_host *p;
   struct aic_dev_data *aic_dev;
-  int    tindex;
-  int    result = -1;
-#define DEVICE_RESET 0x01
-#define BUS_RESET    0x02
-#define HOST_RESET   0x04
-#define RESET_DELAY  0x08
-  int        action;
-
-
-  if ( cmd == NULL )
-  {
-    printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd "
-      "pointer, failing.\n");
-    return(SCSI_RESET_SNOOZE);
-  }
 
   p = (struct aic7xxx_host *) cmd->host->hostdata;
   aic_dev = AIC_DEV(cmd);
-  if(aic_dev)
+  if(aic7xxx_position(cmd) < p->scb_data->numscbs)
   {
     scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+    if (scb->cmd != cmd)
+      scb = NULL;
   }
   else
   {
     scb = NULL;
   }
-  tindex = TARGET_INDEX(cmd);
 
   /*
    * I added a new config option to the driver: "panic_on_abort" that will
@@ -10989,44 +10925,6 @@
 
   pause_sequencer(p);
 
-  if(flags & SCSI_RESET_SYNCHRONOUS)
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_MID)
-      printk(INFO_LEAD "Reset called for a SYNCHRONOUS reset, flags 0x%x, "
-           "cmd->result 0x%x.\n", p->host_no, CTL_OF_CMD(cmd), flags,
-           cmd->result);
-    scb = NULL;
-    action = HOST_RESET;
-  }
-  else if ((scb == NULL) || (scb->cmd != cmd))
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_MID)
-      printk(INFO_LEAD "Reset called with bogus Scsi_Cmnd"
-           "->SCB mapping, failing.\n", p->host_no, CTL_OF_CMD(cmd));
-    aic7xxx_done_cmds_complete(p);
-    aic7xxx_run_waiting_queues(p);
-    unpause_sequencer(p, FALSE);
-    return(SCSI_RESET_NOT_RUNNING);
-  }
-  else
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_MID)
-      printk(INFO_LEAD "Reset called, scb %d, flags "
-        "0x%x\n", p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags);
-    if ( flags & SCSI_RESET_SUGGEST_HOST_RESET )
-    {
-      action = HOST_RESET;
-    }
-    else if ( flags & SCSI_RESET_SUGGEST_BUS_RESET )
-    {
-      action = BUS_RESET;
-    }
-    else 
-    {
-      action = DEVICE_RESET;
-    }
-  }
-
   while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
   {
     aic7xxx_isr(p->irq, p, (void *)NULL );
@@ -11040,134 +10938,32 @@
      * We just completed the command when we ran the isr stuff, so we no
      * longer have it.
      */
-    aic7xxx_run_waiting_queues(p);
     unpause_sequencer(p, FALSE);
-    return(SCSI_RESET_SUCCESS);
+    return SUCCESS;
   }
     
-  if ( (action & DEVICE_RESET) && 
-        (aic_dev->flags & BUS_DEVICE_RESET_PENDING) )
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-      printk(INFO_LEAD "Bus device reset already sent to "
-        "device, escalating.\n", p->host_no, CTL_OF_CMD(cmd));
-    action = BUS_RESET;
-  }
-  if ( (action & DEVICE_RESET) &&
-       (scb->flags & SCB_QUEUED_ABORT) )
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-    {
-      printk(INFO_LEAD "Have already attempted to reach "
-        "device with queued\n", p->host_no, CTL_OF_CMD(cmd));
-      printk(INFO_LEAD "message, will escalate to bus "
-        "reset.\n", p->host_no, CTL_OF_CMD(cmd));
-    }
-    action = BUS_RESET;
-  }
-  if ( (action & DEVICE_RESET) && 
-       (p->flags & (AHC_RESET_PENDING | AHC_ABORT_PENDING)) )
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-     printk(INFO_LEAD "Bus device reset stupid when "
-        "other action has failed.\n", p->host_no, CTL_OF_CMD(cmd));
-    action = BUS_RESET;
-  }
-  if ( (action & BUS_RESET) && !(p->features & AHC_TWIN) )
-  {
-    action = HOST_RESET;
-  }
-  if ( (aic_dev->flags & DEVICE_RESET_DELAY) &&
-       !(action & (HOST_RESET | BUS_RESET)))
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-    {
-      printk(INFO_LEAD "Reset called too soon after last "
-        "reset without requesting\n", p->host_no, CTL_OF_CMD(cmd));
-      printk(INFO_LEAD "bus or host reset, escalating.\n", p->host_no,
-        CTL_OF_CMD(cmd));
-    }
-    action = BUS_RESET;
-  }
-  if ( (p->flags & AHC_RESET_DELAY) &&
-       (action & (HOST_RESET | BUS_RESET)) )
-  {
-    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
-      printk(INFO_LEAD "Reset called too soon after "
-        "last bus reset, delaying.\n", p->host_no, CTL_OF_CMD(cmd));
-    action = RESET_DELAY;
-  }
 /*
  *  By this point, we want to already know what we are going to do and
  *  only have the following code implement our course of action.
  */
-  switch (action)
+  aic7xxx_reset_channel(p, cmd->channel, TRUE);
+  if (p->features & AHC_TWIN)
   {
-    case RESET_DELAY:
-      aic7xxx_run_waiting_queues(p);
-      unpause_sequencer(p, FALSE);
-      if(scb == NULL)
-        return(SCSI_RESET_PUNT);
-      else
-        return(SCSI_RESET_PENDING);
-      break;
-    case DEVICE_RESET:
-      p->flags |= AHC_IN_RESET;
-      result = aic7xxx_bus_device_reset(p, cmd);
-      aic7xxx_run_done_queue(p, TRUE);
-      /*  We can't rely on run_waiting_queues to unpause the sequencer for
-       *  PCI based controllers since we use AAP */
-      aic7xxx_run_waiting_queues(p);
-      unpause_sequencer(p, FALSE);
-      p->flags &= ~AHC_IN_RESET;
-      return(result);
-      break;
-    case BUS_RESET:
-    case HOST_RESET:
-    default:
-      p->flags |= AHC_IN_RESET | AHC_RESET_DELAY;
-      aic7xxx_reset_channel(p, cmd->channel, TRUE);
-      if ( (p->features & AHC_TWIN) && (action & HOST_RESET) )
-      {
-        aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
-        restart_sequencer(p);
-      }
-      if (action != HOST_RESET)
-        result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
-      else
-      {
-        result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
-        aic_outb(p,  aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE),
-          SIMODE1);
-        aic7xxx_clear_intstat(p);
-        p->flags &= ~AHC_HANDLING_REQINITS;
-        p->msg_type = MSG_TYPE_NONE;
-        p->msg_index = 0;
-        p->msg_len = 0;
-      }
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,95)
-      if(flags & SCSI_RESET_SYNCHRONOUS)
-      {
-        cmd->result = DID_RESET << 16;
-        cmd->done(cmd);
-      }
-#endif
-      aic7xxx_run_done_queue(p, TRUE);
-      p->flags &= ~AHC_IN_RESET;
-      /*
-       * We can't rely on run_waiting_queues to unpause the sequencer for
-       * PCI based controllers since we use AAP.  NOTE: this also sets
-       * the timer for the one command we might have queued in the case
-       * of a synch reset.
-       */
-      aic7xxx_run_waiting_queues(p);
-      unpause_sequencer(p, FALSE);
-      if(scb == NULL)
-        return(SCSI_RESET_SUCCESS|SCSI_RESET_HOST_RESET);
-      else
-        return(result);
-      break;
+    aic7xxx_reset_channel(p, cmd->channel ^ 0x01, TRUE);
+    restart_sequencer(p);
   }
+  aic_outb(p,  aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1);
+  aic7xxx_clear_intstat(p);
+  p->flags &= ~AHC_HANDLING_REQINITS;
+  p->msg_type = MSG_TYPE_NONE;
+  p->msg_index = 0;
+  p->msg_len = 0;
+  aic7xxx_run_done_queue(p, TRUE);
+  unpause_sequencer(p, FALSE);
+  spin_unlock_irq(p->host->host_lock);
+  scsi_sleep(2 * HZ);
+  spin_lock_irq(p->host->host_lock);
+  return SUCCESS;
 }
 
 /*+F*************************************************************************
diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c
--- a/drivers/scsi/eata.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/scsi/eata.c	Sun Nov 10 19:28:41 2002
@@ -476,7 +476,6 @@
 #include <linux/blk.h>
 #include "scsi.h"
 #include "hosts.h"
-#include "sd.h"
 #include <asm/dma.h>
 #include <asm/irq.h>
 #include "eata.h"
@@ -1838,7 +1837,7 @@
 		sector_t capacity, int *dkinfo) {
    int size = capacity;
 
-   if (ext_tran || (scsicam_bios_param(disk, bdev, dkinfo) < 0)) {
+   if (ext_tran || (scsicam_bios_param(bdev, capacity, dkinfo) < 0)) {
       dkinfo[0] = 255;
       dkinfo[1] = 63;
       dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
diff -Nru a/drivers/scsi/eata.h b/drivers/scsi/eata.h
--- a/drivers/scsi/eata.h	Sun Nov 10 19:28:37 2002
+++ b/drivers/scsi/eata.h	Sun Nov 10 19:28:37 2002
@@ -18,8 +18,6 @@
                 detect:                  eata2x_detect,                      \
                 release:                 eata2x_release,                     \
                 queuecommand:            eata2x_queuecommand,                \
-                abort:                   NULL,                               \
-                reset:                   NULL,                               \
                 eh_abort_handler:        eata2x_eh_abort,                    \
                 eh_device_reset_handler: NULL,                               \
                 eh_bus_reset_handler:    NULL,                               \
diff -Nru a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
--- a/drivers/scsi/eata_pio.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/scsi/eata_pio.c	Sun Nov 10 19:28:40 2002
@@ -14,6 +14,9 @@
  *             neuffer@goofy.zdv.uni-mainz.de               *
  *             a.arnold@kfa-juelich.de                      * 
  *                                                          *
+ *  Updated 2002 by Alan Cox <alan@redhat.com> for Linux    *
+ *  2.5.x and the newer locking and error handling          *
+ *                                                          *
  *  This program is free software; you can redistribute it  *
  *  and/or modify it under the terms of the GNU General     *
  *  Public License as published by the Free Software        *
@@ -30,15 +33,23 @@
  *  Public License along with this kernel; if not, write to *
  *  the Free Software Foundation, Inc., 675 Mass Ave,       *
  *  Cambridge, MA 02139, USA.                               *
+ *							    *
+ *  For the avoidance of doubt the "preferred form" of this *
+ *  code is one which is in an open non patent encumbered   *
+ *  format. Where cryptographic key signing forms part of   *
+ *  the process of creating an executable the information   *
+ *  including keys needed to generate an equivalently       *
+ *  functional executable are deemed to be part of the 	    *
+ *  source code are deemed to be part of the source code.   *
  *                                                          *
  ************************************************************
- *  last change: 96/07/16                  OS: Linux 2.0.8  *
+ *  last change: 2002/11/02               OS: Linux 2.5.45  *
  ************************************************************/
 
 /* Look in eata_pio.h for configuration information */
 
 #include <linux/module.h>
- 
+
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/string.h>
@@ -57,902 +68,830 @@
 #include <linux/blk.h>
 #include <linux/spinlock.h>
 
-static uint ISAbases[MAXISA] =
-{0x1F0, 0x170, 0x330, 0x230};
-static uint ISAirqs[MAXISA] =
-{14,12,15,11};
-static unchar EISAbases[] =
-{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+static uint ISAbases[MAXISA] =	{
+	 0x1F0, 0x170, 0x330, 0x230
+};
+
+static uint ISAirqs[MAXISA] = {
+	14, 12, 15, 11
+};
+
+static unsigned char EISAbases[] = { 
+	1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1 
+};
+
 static uint registered_HBAs = 0;
-static struct Scsi_Host *last_HBA = NULL;
-static struct Scsi_Host *first_HBA = NULL;
-static unchar reg_IRQ[] =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-static unchar reg_IRQL[] =
-{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static struct Scsi_Host *last_HBA;
+static struct Scsi_Host *first_HBA;
+static unsigned char reg_IRQ[];
+static unsigned char reg_IRQL[];
 
-static ulong int_counter = 0;
-static ulong queue_counter = 0;
+static unsigned long int_counter = 0;
+static unsigned long queue_counter = 0;
 
 #include "eata_pio_proc.c"
- 
-#ifdef MODULE
-int eata_pio_release(struct Scsi_Host *sh)
-{
-    if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq, NULL);
-    else reg_IRQ[sh->irq]--;
-    if (SD(sh)->channel == 0) {
-	if (sh->io_port && sh->n_io_port)
-	    release_region(sh->io_port, sh->n_io_port);
-    }
-    return(TRUE);
-}
-#endif
 
-void IncStat(Scsi_Pointer *SCp, uint Increment)
+static int eata_pio_release(struct Scsi_Host *sh)
 {
-    SCp->ptr+=Increment; 
-    if ((SCp->this_residual-=Increment)==0)
-    {
-	if ((--SCp->buffers_residual)==0) SCp->Status=FALSE;
+	if (sh->irq && reg_IRQ[sh->irq] == 1)
+		free_irq(sh->irq, NULL);
 	else
+		reg_IRQ[sh->irq]--;
+	if (SD(sh)->channel == 0) {
+		if (sh->io_port && sh->n_io_port)
+			release_region(sh->io_port, sh->n_io_port);
+	}
+	return (TRUE);
+}
+
+static void IncStat(Scsi_Pointer * SCp, uint Increment)
+{
+	SCp->ptr += Increment;
+	if ((SCp->this_residual -= Increment) == 0) {
+		if ((--SCp->buffers_residual) == 0)
+			SCp->Status = FALSE;
+		else {
+			SCp->buffer++;
+			SCp->ptr = page_address(SCp->buffer->page) + SCp->buffer->offset;
+			SCp->this_residual = SCp->buffer->length;
+		}
+	}
+}
+
+static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs);
+
+static void do_eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct Scsi_Host *dev = dev_id;
+
+	spin_lock_irqsave(dev->host_lock, flags);
+	eata_pio_int_handler(irq, dev_id, regs);
+	spin_unlock_irqrestore(dev->host_lock, flags);
+}
+
+static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	uint eata_stat = 0xfffff;
+	Scsi_Cmnd *cmd;
+	hostdata *hd;
+	struct eata_ccb *cp;
+	uint base;
+	uint x, z;
+	struct Scsi_Host *sh;
+	unsigned short zwickel = 0;
+	unsigned char stat, odd;
+
+	for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) 
 	{
-	    SCp->buffer++;
-	    SCp->ptr=page_address(SCp->buffer->page) + SCp->buffer->offset;
-	    SCp->this_residual=SCp->buffer->length;
-	}
-    }
-}
-
-void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs);
-
-void do_eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
-{
-    unsigned long flags;
-    struct Scsi_Host *dev = dev_id;
-    
-    spin_lock_irqsave(dev->host_lock, flags);
-    eata_pio_int_handler(irq, dev_id, regs);
-    spin_unlock_irqrestore(dev->host_lock, flags);
-}
-
-void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs * regs)
-{
-    uint eata_stat = 0xfffff;
-    Scsi_Cmnd *cmd;
-    hostdata *hd;
-    struct eata_ccb *cp;
-    uint base;
-    uint x,z;
-    struct Scsi_Host *sh;
-    ushort zwickel=0;
-    unchar stat,odd;
-    
-    for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) {
-	if (sh->irq != irq)
-	    continue;
-	if (inb((uint)sh->base + HA_RSTATUS) & HA_SBUSY)
-	    continue;
-	
-	int_counter++;
-	
-	hd=SD(sh);
-	
-	cp = &hd->ccb[0];
-	cmd = cp->cmd;
-	base = (uint) cmd->host->base;
-	
-	do
-	{
-	    stat=inb(base+HA_RSTATUS);
-	    if (stat&HA_SDRQ) {
-		if (cp->DataIn)
-		{
-		    z=256; odd=FALSE;
-		    while ((cmd->SCp.Status)&&((z>0)||(odd)))
-		    {
-			if (odd) 
-			{ 
-			    *(cmd->SCp.ptr)=zwickel>>8; 
-			    IncStat(&cmd->SCp,1);
-			    odd=FALSE;
-			}
-			x=min_t(unsigned int,z,cmd->SCp.this_residual/2);
-			insw(base+HA_RDATA,cmd->SCp.ptr,x);
-			z-=x; 
-			IncStat(&cmd->SCp,2*x);
-			if ((z>0)&&(cmd->SCp.this_residual==1))
-			{
-			    zwickel=inw(base+HA_RDATA); 
-			    *(cmd->SCp.ptr)=zwickel&0xff;
-			    IncStat(&cmd->SCp,1); z--; 
-			    odd=TRUE;
+		if (sh->irq != irq)
+			continue;
+		if (inb((uint) sh->base + HA_RSTATUS) & HA_SBUSY)
+			continue;
+
+		int_counter++;
+
+		hd = SD(sh);
+
+		cp = &hd->ccb[0];
+		cmd = cp->cmd;
+		base = (uint) cmd->host->base;
+
+		do {
+			stat = inb(base + HA_RSTATUS);
+			if (stat & HA_SDRQ) {
+				if (cp->DataIn) {
+					z = 256;
+					odd = FALSE;
+					while ((cmd->SCp.Status) && ((z > 0) || (odd))) {
+						if (odd) {
+							*(cmd->SCp.ptr) = zwickel >> 8;
+							IncStat(&cmd->SCp, 1);
+							odd = FALSE;
+						}
+						x = min_t(unsigned int, z, cmd->SCp.this_residual / 2);
+						insw(base + HA_RDATA, cmd->SCp.ptr, x);
+						z -= x;
+						IncStat(&cmd->SCp, 2 * x);
+						if ((z > 0) && (cmd->SCp.this_residual == 1)) {
+							zwickel = inw(base + HA_RDATA);
+							*(cmd->SCp.ptr) = zwickel & 0xff;
+							IncStat(&cmd->SCp, 1);
+							z--;
+							odd = TRUE;
+						}
+					}
+					while (z > 0) {
+						zwickel = inw(base + HA_RDATA);
+						z--;
+					}
+				} else {	/* cp->DataOut */
+
+					odd = FALSE;
+					z = 256;
+					while ((cmd->SCp.Status) && ((z > 0) || (odd))) {
+						if (odd) {
+							zwickel += *(cmd->SCp.ptr) << 8;
+							IncStat(&cmd->SCp, 1);
+							outw(zwickel, base + HA_RDATA);
+							z--;
+							odd = FALSE;
+						}
+						x = min_t(unsigned int, z, cmd->SCp.this_residual / 2);
+						outsw(base + HA_RDATA, cmd->SCp.ptr, x);
+						z -= x;
+						IncStat(&cmd->SCp, 2 * x);
+						if ((z > 0) && (cmd->SCp.this_residual == 1)) {
+							zwickel = *(cmd->SCp.ptr);
+							zwickel &= 0xff;
+							IncStat(&cmd->SCp, 1);
+							odd = TRUE;
+						}
+					}
+					while (z > 0 || odd) {
+						outw(zwickel, base + HA_RDATA);
+						z--;
+						odd = FALSE;
+					}
+				}
 			}
-		    }
-		    while (z>0) {
-			zwickel=inw(base+HA_RDATA); 
-			z--;
-		    } 
-		}
-		else /* cp->DataOut */
-		{
-		    odd=FALSE; z=256;
-		    while ((cmd->SCp.Status)&&((z>0)||(odd)))
-		    {
-			if (odd)
-			{
-			    zwickel+=*(cmd->SCp.ptr)<<8; 
-			    IncStat(&cmd->SCp,1);
-			    outw(zwickel,base+HA_RDATA); 
-			    z--; 
-			    odd=FALSE; 
-			}
-			x=min_t(unsigned int,z,cmd->SCp.this_residual/2);
-			outsw(base+HA_RDATA,cmd->SCp.ptr,x);
-			z-=x; 
-			IncStat(&cmd->SCp,2*x);
-			if ((z>0)&&(cmd->SCp.this_residual==1))
-			{
-			    zwickel=*(cmd->SCp.ptr); 
-			    zwickel&=0xff;
-			    IncStat(&cmd->SCp,1); 
-			    odd=TRUE;
-			}  
-		    }
-		    while (z>0||odd) {
-			outw(zwickel,base+HA_RDATA); 
-			z--; 
-			odd=FALSE;
-		    }
-		}
-	    }
-	}
-	while ((stat&HA_SDRQ)||((stat&HA_SMORE)&&hd->moresupport));
-	
-	/* terminate handler if HBA goes busy again, i.e. transfers
-	 * more data */
-	
-	if (stat&HA_SBUSY) break;
-	
-	/* OK, this is quite stupid, but I haven't found any correct
-	 * way to get HBA&SCSI status so far */
-	
-	if (!(inb(base+HA_RSTATUS)&HA_SERROR))
-	{
-	    cmd->result=(DID_OK<<16); 
-	    hd->devflags|=(1<<cp->cp_id);
-	}
-	else if (hd->devflags&1<<cp->cp_id) 
-	    cmd->result=(DID_OK<<16)+0x02;
-	else cmd->result=(DID_NO_CONNECT<<16);
-	
-	if (cp->status == LOCKED) {
-	    cp->status = FREE;
-	    eata_stat = inb(base + HA_RSTATUS);
-	    printk(KERN_CRIT "eata_pio: int_handler, freeing locked "
-                   "queueslot\n");
-	    return;
-	}
-	
+		}
+		while ((stat & HA_SDRQ) || ((stat & HA_SMORE) && hd->moresupport));
+
+		/* terminate handler if HBA goes busy again, i.e. transfers
+		 * more data */
+
+		if (stat & HA_SBUSY)
+			break;
+
+		/* OK, this is quite stupid, but I haven't found any correct
+		 * way to get HBA&SCSI status so far */
+
+		if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {
+			cmd->result = (DID_OK << 16);
+			hd->devflags |= (1 << cp->cp_id);
+		} else if (hd->devflags & 1 << cp->cp_id)
+			cmd->result = (DID_OK << 16) + 0x02;
+		else
+			cmd->result = (DID_NO_CONNECT << 16);
+
+		if (cp->status == LOCKED) {
+			cp->status = FREE;
+			eata_stat = inb(base + HA_RSTATUS);
+			printk(KERN_CRIT "eata_pio: int_handler, freeing locked " "queueslot\n");
+			return;
+		}
 #if DBG_INTR2
-	if (stat != 0x50) 
-	    printk(KERN_DEBUG "stat: %#.2x, result: %#.8x\n", stat, 
-                   cmd->result); 
+		if (stat != 0x50)
+			printk(KERN_DEBUG "stat: %#.2x, result: %#.8x\n", stat, cmd->result);
 #endif
-	
-	cp->status = FREE;   /* now we can release the slot  */
-	
-	cmd->scsi_done(cmd);
-    }
-    
-    return;
-}
-
-inline uint eata_pio_send_command(uint base, unchar command)
-{
-    uint loop = HZ/2;
-    
-    while (inb(base + HA_RSTATUS) & HA_SBUSY)
-	if (--loop == 0)
-	    return(TRUE);
-
-    /* Enable interrupts for HBA.  It is not the best way to do it at this
-     * place, but I hope that it doesn't interfere with the IDE driver 
-     * initialization this way */
-
-    outb(HA_CTRL_8HEADS,base+HA_CTRLREG);
-    
-    outb(command, base + HA_WCOMMAND);
-    return(FALSE);
-}
-
-int eata_pio_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
-{
-    uint x, y;
-    uint base;
-    
-    hostdata *hd;
-    struct Scsi_Host *sh;
-    struct eata_ccb *cp;
-    
-    queue_counter++;
-    
-    hd = HD(cmd);
-    sh = cmd->host;
-    base = (uint) sh->base;
-    
-    /* use only slot 0, as 2001 can handle only one cmd at a time */
-    
-    y = x = 0;
-    
-    if (hd->ccb[y].status!=FREE) { 
-	
-	DBG(DBG_QUEUE, printk(KERN_EMERG "can_queue %d, x %d, y %d\n",
-                              sh->can_queue,x,y));
+
+		cp->status = FREE;	/* now we can release the slot  */
+
+		cmd->scsi_done(cmd);
+	}
+
+	return;
+}
+
+static inline uint eata_pio_send_command(uint base, unsigned char command)
+{
+	uint loop = HZ / 2;
+
+	while (inb(base + HA_RSTATUS) & HA_SBUSY)
+		if (--loop == 0)
+			return (TRUE);
+
+	/* Enable interrupts for HBA.  It is not the best way to do it at this
+	 * place, but I hope that it doesn't interfere with the IDE driver 
+	 * initialization this way */
+
+	outb(HA_CTRL_8HEADS, base + HA_CTRLREG);
+
+	outb(command, base + HA_WCOMMAND);
+	return (FALSE);
+}
+
+static int eata_pio_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+	uint x, y;
+	uint base;
+
+	hostdata *hd;
+	struct Scsi_Host *sh;
+	struct eata_ccb *cp;
+
+	queue_counter++;
+
+	hd = HD(cmd);
+	sh = cmd->host;
+	base = (uint) sh->base;
+
+	/* use only slot 0, as 2001 can handle only one cmd at a time */
+
+	y = x = 0;
+
+	if (hd->ccb[y].status != FREE) {
+
+		DBG(DBG_QUEUE, printk(KERN_EMERG "can_queue %d, x %d, y %d\n", sh->can_queue, x, y));
 #if DEBUG_EATA
-	panic(KERN_EMERG "eata_pio: run out of queue slots cmdno:%ld "
-              "intrno: %ld\n", queue_counter, int_counter);
+		panic(KERN_EMERG "eata_pio: run out of queue slots cmdno:%ld " "intrno: %ld\n", queue_counter, int_counter);
 #else
-	panic(KERN_EMERG "eata_pio: run out of queue slots....\n");
+		panic(KERN_EMERG "eata_pio: run out of queue slots....\n");
 #endif
-    }
-    
-    cp = &hd->ccb[y];
-    
-    memset(cp, 0, sizeof(struct eata_ccb));
-    memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
-	
-    cp->status = USED;      /* claim free slot */
-
-    DBG(DBG_QUEUE, printk(KERN_DEBUG "eata_pio_queue pid %ld, target: %x, lun:"
-                          " %x, y %d\n", cmd->pid, cmd->target, cmd->lun, y));
-    
-    cmd->scsi_done = (void *)done;
-    
-    /* FIXME: use passed direction flag !! */
-    switch (cmd->cmnd[0]) {
-    case CHANGE_DEFINITION: case COMPARE:         case COPY:
-    case COPY_VERIFY:       case LOG_SELECT:      case MODE_SELECT:
-    case MODE_SELECT_10:    case SEND_DIAGNOSTIC: case WRITE_BUFFER:
-    case FORMAT_UNIT:       case REASSIGN_BLOCKS: case RESERVE:
-    case SEARCH_EQUAL:      case SEARCH_HIGH:     case SEARCH_LOW:
-    case WRITE_6:           case WRITE_10:        case WRITE_VERIFY:
-    case UPDATE_BLOCK:      case WRITE_LONG:      case WRITE_SAME:      
-    case SEARCH_HIGH_12:    case SEARCH_EQUAL_12: case SEARCH_LOW_12:
-    case WRITE_12:          case WRITE_VERIFY_12: case SET_WINDOW: 
-    case MEDIUM_SCAN:       case SEND_VOLUME_TAG:            
-    case 0xea:      /* alternate number for WRITE LONG */
-	cp->DataOut = TRUE; /* Output mode */
-	break;
-    case TEST_UNIT_READY:
-    default:
-	cp->DataIn = TRUE;  /* Input mode  */
-    }
-    
-    cp->Interpret = (cmd->target == hd->hostid);
-    cp->cp_datalen = htonl((ulong)cmd->request_bufflen);
-    cp->Auto_Req_Sen = FALSE;
-    cp->cp_reqDMA = htonl(0);
-    cp->reqlen = 0;
-    
-    cp->cp_id = cmd->target;
-    cp->cp_lun = cmd->lun;
-    cp->cp_dispri = FALSE;
-    cp->cp_identify = TRUE;
-    memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
-    
-    cp->cp_statDMA = htonl(0);
-    
-    cp->cp_viraddr = cp;
-    cp->cmd = cmd;
-    cmd->host_scribble = (char *)&hd->ccb[y];   
-    
-    if (cmd->use_sg == 0)
-    { 
-	cmd->SCp.buffers_residual=1;
-	cmd->SCp.ptr = cmd->request_buffer;
-	cmd->SCp.this_residual = cmd->request_bufflen;
-	cmd->SCp.buffer = NULL;
-    } else {
-	cmd->SCp.buffer = cmd->request_buffer;
-	cmd->SCp.buffers_residual = cmd->use_sg;
-	cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
-	cmd->SCp.this_residual = cmd->SCp.buffer->length;
-    }
-    cmd->SCp.Status = (cmd->SCp.this_residual != 0);  /* TRUE as long as bytes 
-                                                       * are to transfer */ 
-    
-    if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) 
-    {
-	cmd->result = DID_BUS_BUSY << 16;
-	printk(KERN_NOTICE "eata_pio_queue target %d, pid %ld, HBA busy, "
-               "returning DID_BUS_BUSY, done.\n", cmd->target, cmd->pid);
-        done(cmd);
-        cp->status = FREE;      
-	return (0);
-    }
-    while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
-    	cpu_relax();
-    outsw(base + HA_RDATA, cp, hd->cplen);
-    outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
-    for (x = 0; x < hd->cppadlen; x++) outw(0, base + HA_RDATA);
-    
-    DBG(DBG_QUEUE,printk(KERN_DEBUG "Queued base %#.4lx pid: %ld target: %x "
-                         "lun: %x slot %d irq %d\n", (long)sh->base, cmd->pid, 
-			 cmd->target, cmd->lun, y, sh->irq));
-    
-    return (0);
-}
-
-int eata_pio_abort(Scsi_Cmnd * cmd)
-{
-    ulong flags;
-    uint loop = HZ;
-    
-    spin_lock_irqsave(cmd->host->host_lock, flags);    
-    DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_abort called pid: %ld "
-                           "target: %x lun: %x reason %x\n", cmd->pid, 
-                           cmd->target, cmd->lun, cmd->abort_reason));
-    
-    
-    while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
-	if (--loop == 0) {
-	    printk(KERN_WARNING "eata_pio: abort, timeout error.\n");
-	    spin_unlock_irqrestore(cmd->host->host_lock, flags);    
-	    return (SCSI_ABORT_ERROR);
-	}
-    if (CD(cmd)->status == FREE) {
-	DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_NOT_RUNNING\n")); 
-        spin_unlock_irqrestore(cmd->host->host_lock, flags);    
-	return (SCSI_ABORT_NOT_RUNNING);
-    }
-    if (CD(cmd)->status == USED) {
-	DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_BUSY\n"));
-        spin_unlock_irqrestore(cmd->host->host_lock, flags);    
-	return (SCSI_ABORT_BUSY);  /* SNOOZE */ 
-    }
-    if (CD(cmd)->status == RESET) {
-        spin_unlock_irqrestore(cmd->host->host_lock, flags);    
-	printk(KERN_WARNING "eata_pio: abort, command reset error.\n");
-	return (SCSI_ABORT_ERROR);
-    }
-    if (CD(cmd)->status == LOCKED) {
-        spin_unlock_irqrestore(cmd->host->host_lock, flags);    
-	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio: abort, queue slot "
-                               "locked.\n"));
-	return (SCSI_ABORT_NOT_RUNNING);
-    }
-    spin_unlock_irqrestore(cmd->host->host_lock, flags);    
-    panic("eata_pio: abort: invalid slot status\n");
-}
-
-int eata_pio_reset(Scsi_Cmnd * cmd, unsigned int dummy)
-{
-    uint x, limit = 0;
-    ulong flags;
-    unchar success = FALSE;
-    Scsi_Cmnd *sp; 
-    
-    DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset called pid:%ld target:"
-                           " %x lun: %x reason %x\n", cmd->pid, cmd->target, 
-                           cmd->lun, cmd->abort_reason));
-
-    spin_lock_irqsave(cmd->host->host_lock, flags);    
-    if (HD(cmd)->state == RESET) {
-	printk(KERN_WARNING "eata_pio_reset: exit, already in reset.\n");
-        spin_unlock_irqrestore(cmd->host->host_lock, flags);    
-	return (SCSI_RESET_ERROR);
-    }
-    
-    /* force all slots to be free */
-    
-    for (x = 0; x < cmd->host->can_queue; x++) {
-	
-	if (HD(cmd)->ccb[x].status == FREE) 
-	    continue;
-	
-	sp = HD(cmd)->ccb[x].cmd;
-	HD(cmd)->ccb[x].status = RESET;
-	printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x,
-               sp->pid);
-	
-	if (sp == NULL)
-	    panic("eata_pio_reset: slot %d, sp==NULL.\n", x);
-    }
-    
-    /* hard reset the HBA  */
-    outb(EATA_CMD_RESET, (uint) cmd->host->base+HA_WCOMMAND);
-    
-    DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: board reset done.\n"));
-    HD(cmd)->state = RESET;
-    
-    set_current_state(TASK_UNINTERRUPTIBLE);
-    schedule_timeout(3*HZ);    	
-    
-    DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, "
-                           "loops %d.\n", limit));
-    
-    for (x = 0; x < cmd->host->can_queue; x++) {
-	
-	/* Skip slots already set free by interrupt */
-	if (HD(cmd)->ccb[x].status != RESET)
-	    continue;
-	
-	sp = HD(cmd)->ccb[x].cmd;
-	sp->result = DID_RESET << 16;
-	
-	/* This mailbox is terminated */
-	printk(KERN_WARNING "eata_pio_reset: reset ccb %d.\n",x);
-	HD(cmd)->ccb[x].status = FREE;
-	
-	sp->scsi_done(sp);
-    }
-    
-    HD(cmd)->state = FALSE;
-    spin_unlock_irqrestore(cmd->host->host_lock, flags);    
-    
-    if (success) { /* hmmm... */
-	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, success.\n"));
-	return (SCSI_RESET_SUCCESS);
-    } else {
-	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, wakeup.\n"));
-	return (SCSI_RESET_PUNT);
-    }
-}
-
-char * get_pio_board_data(ulong base, uint irq, uint id, ulong cplen, ushort cppadlen)
-{
-    struct eata_ccb cp;
-    static char buff[256];
-    int z;
-    
-    memset(&cp, 0, sizeof(struct eata_ccb));
-    memset(buff, 0, sizeof(buff));
-    
-    cp.DataIn = TRUE;     
-    cp.Interpret = TRUE;   /* Interpret command */
-    
-    cp.cp_datalen = htonl(254);  
-    cp.cp_dataDMA = htonl(0);
-    
-    cp.cp_id = id;
-    cp.cp_lun = 0;
-    
-    cp.cp_cdb[0] = INQUIRY;
-    cp.cp_cdb[1] = 0;
-    cp.cp_cdb[2] = 0;
-    cp.cp_cdb[3] = 0;
-    cp.cp_cdb[4] = 254;
-    cp.cp_cdb[5] = 0;
-    
-    if (eata_pio_send_command((uint) base, EATA_CMD_PIO_SEND_CP)) 
-        return (NULL);
-    while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
-    outsw(base + HA_RDATA, &cp, cplen);
-    outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
-    for (z = 0; z < cppadlen; z++) outw(0, base + HA_RDATA);
-    
-    while (inb(base + HA_RSTATUS) & HA_SBUSY);
-    if (inb(base + HA_RSTATUS) & HA_SERROR)
-	return (NULL);
-    else if (!(inb(base + HA_RSTATUS) & HA_SDRQ))
-	return (NULL);
-    else
-    {
-	insw(base+HA_RDATA, &buff, 127);
-	while (inb(base + HA_RSTATUS)&HA_SDRQ) inw(base + HA_RDATA);
-	return (buff);
-    }
-}
-
-int get_pio_conf_PIO(u32 base, struct get_conf *buf)
-{
-    ulong loop = HZ/2;
-    int z;
-    ushort *p;
-    
-    if(check_region(base, 9))  
-	return (FALSE);
-    
-    memset(buf, 0, sizeof(struct get_conf));
-    
-    while (inb(base + HA_RSTATUS) & HA_SBUSY)
-	if (--loop == 0) 
-	    return (FALSE);
-    
-    DBG(DBG_PIO && DBG_PROBE,
-	printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#x\n", base));
-    eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG);
-
-    loop = HZ/2;
-    for (p = (ushort *) buf; 
-	 (long)p <= ((long)buf + (sizeof(struct get_conf) / 2)); p++) {
+	}
+
+	cp = &hd->ccb[y];
+
+	memset(cp, 0, sizeof(struct eata_ccb));
+	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+
+	cp->status = USED;	/* claim free slot */
+
+	DBG(DBG_QUEUE, printk(KERN_DEBUG "eata_pio_queue pid %ld, target: %x, lun:" " %x, y %d\n", cmd->pid, cmd->target, cmd->lun, y));
+
+	cmd->scsi_done = (void *) done;
+
+	if(cmd->sc_data_direction == SCSI_DATA_WRITE)
+		cp->DataOut = TRUE;	/* Output mode */
+	else
+		cp->DataIn = TRUE;	/* Input mode  */
+
+	cp->Interpret = (cmd->target == hd->hostid);
+	cp->cp_datalen = htonl((unsigned long) cmd->request_bufflen);
+	cp->Auto_Req_Sen = FALSE;
+	cp->cp_reqDMA = htonl(0);
+	cp->reqlen = 0;
+
+	cp->cp_id = cmd->target;
+	cp->cp_lun = cmd->lun;
+	cp->cp_dispri = FALSE;
+	cp->cp_identify = TRUE;
+	memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
+
+	cp->cp_statDMA = htonl(0);
+
+	cp->cp_viraddr = cp;
+	cp->cmd = cmd;
+	cmd->host_scribble = (char *) &hd->ccb[y];
+
+	if (cmd->use_sg == 0) {
+		cmd->SCp.buffers_residual = 1;
+		cmd->SCp.ptr = cmd->request_buffer;
+		cmd->SCp.this_residual = cmd->request_bufflen;
+		cmd->SCp.buffer = NULL;
+	} else {
+		cmd->SCp.buffer = cmd->request_buffer;
+		cmd->SCp.buffers_residual = cmd->use_sg;
+		cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
+		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+	}
+	cmd->SCp.Status = (cmd->SCp.this_residual != 0);	/* TRUE as long as bytes 
+								 * are to transfer */
+
+	if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) {
+		cmd->result = DID_BUS_BUSY << 16;
+		printk(KERN_NOTICE "eata_pio_queue target %d, pid %ld, HBA busy, " "returning DID_BUS_BUSY, done.\n", cmd->target, cmd->pid);
+		done(cmd);
+		cp->status = FREE;
+		return (0);
+	}
+	/* FIXME: timeout */
 	while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
-	    if (--loop == 0)
+		cpu_relax();
+	outsw(base + HA_RDATA, cp, hd->cplen);
+	outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
+	for (x = 0; x < hd->cppadlen; x++)
+		outw(0, base + HA_RDATA);
+
+	DBG(DBG_QUEUE, printk(KERN_DEBUG "Queued base %#.4lx pid: %ld target: %x " "lun: %x slot %d irq %d\n", (long) sh->base, cmd->pid, cmd->target, cmd->lun, y, sh->irq));
+
+	return (0);
+}
+
+static int eata_pio_abort(Scsi_Cmnd * cmd)
+{
+	uint loop = HZ;
+
+	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_abort called pid: %ld " "target: %x lun: %x reason %x\n", cmd->pid, cmd->target, cmd->lun, cmd->abort_reason));
+
+
+	while (inb(cmd->host->base + HA_RAUXSTAT) & HA_ABUSY)
+		if (--loop == 0) {
+			printk(KERN_WARNING "eata_pio: abort, timeout error.\n");
+			return FAILED;
+		}
+	if (CD(cmd)->status == FREE) {
+		DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_NOT_RUNNING\n"));
+		return FAILED;
+	}
+	if (CD(cmd)->status == USED) {
+		DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_BUSY\n"));
+		/* We want to sleep a bit more here */
+		return FAILED;		/* SNOOZE */
+	}
+	if (CD(cmd)->status == RESET) {
+		printk(KERN_WARNING "eata_pio: abort, command reset error.\n");
+		return FAILED;
+	}
+	if (CD(cmd)->status == LOCKED) {
+		DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio: abort, queue slot " "locked.\n"));
+		return FAILED;
+	}
+	panic("eata_pio: abort: invalid slot status\n");
+}
+
+static int eata_pio_host_reset(Scsi_Cmnd * cmd)
+{
+	uint x, limit = 0;
+	unsigned char success = FALSE;
+	Scsi_Cmnd *sp;
+	struct Scsi_Host *host = cmd->host;
+
+	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset called pid:%ld target:" " %x lun: %x reason %x\n", cmd->pid, cmd->target, cmd->lun, cmd->abort_reason));
+
+	if (HD(cmd)->state == RESET) {
+		printk(KERN_WARNING "eata_pio_reset: exit, already in reset.\n");
+		return FAILED;
+	}
+
+	/* force all slots to be free */
+
+	for (x = 0; x < cmd->host->can_queue; x++) {
+
+		if (HD(cmd)->ccb[x].status == FREE)
+			continue;
+
+		sp = HD(cmd)->ccb[x].cmd;
+		HD(cmd)->ccb[x].status = RESET;
+		printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
+
+		if (sp == NULL)
+			panic("eata_pio_reset: slot %d, sp==NULL.\n", x);
+	}
+
+	/* hard reset the HBA  */
+	outb(EATA_CMD_RESET, (uint) cmd->host->base + HA_WCOMMAND);
+
+	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: board reset done.\n"));
+	HD(cmd)->state = RESET;
+
+	spin_unlock_irq(host->host_lock);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(3 * HZ);
+	spin_lock_irq(host->host_lock);
+
+	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, " "loops %d.\n", limit));
+
+	for (x = 0; x < cmd->host->can_queue; x++) {
+
+		/* Skip slots already set free by interrupt */
+		if (HD(cmd)->ccb[x].status != RESET)
+			continue;
+
+		sp = HD(cmd)->ccb[x].cmd;
+		sp->result = DID_RESET << 16;
+
+		/* This mailbox is terminated */
+		printk(KERN_WARNING "eata_pio_reset: reset ccb %d.\n", x);
+		HD(cmd)->ccb[x].status = FREE;
+
+		sp->scsi_done(sp);
+	}
+
+	HD(cmd)->state = FALSE;
+
+	if (success) {		/* hmmm... */
+		DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, success.\n"));
+		return SUCCESS;
+	} else {
+		DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, wakeup.\n"));
+		return FAILED;
+	}
+}
+
+static char *get_pio_board_data(unsigned long base, uint irq, uint id, unsigned long cplen, unsigned short cppadlen)
+{
+	struct eata_ccb cp;
+	static char buff[256];
+	int z;
+
+	memset(&cp, 0, sizeof(struct eata_ccb));
+	memset(buff, 0, sizeof(buff));
+
+	cp.DataIn = TRUE;
+	cp.Interpret = TRUE;	/* Interpret command */
+
+	cp.cp_datalen = htonl(254);
+	cp.cp_dataDMA = htonl(0);
+
+	cp.cp_id = id;
+	cp.cp_lun = 0;
+
+	cp.cp_cdb[0] = INQUIRY;
+	cp.cp_cdb[1] = 0;
+	cp.cp_cdb[2] = 0;
+	cp.cp_cdb[3] = 0;
+	cp.cp_cdb[4] = 254;
+	cp.cp_cdb[5] = 0;
+
+	if (eata_pio_send_command((uint) base, EATA_CMD_PIO_SEND_CP))
+		return (NULL);
+	while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
+	outsw(base + HA_RDATA, &cp, cplen);
+	outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
+	for (z = 0; z < cppadlen; z++)
+		outw(0, base + HA_RDATA);
+
+	while (inb(base + HA_RSTATUS) & HA_SBUSY);
+	if (inb(base + HA_RSTATUS) & HA_SERROR)
+		return (NULL);
+	else if (!(inb(base + HA_RSTATUS) & HA_SDRQ))
+		return (NULL);
+	else {
+		insw(base + HA_RDATA, &buff, 127);
+		while (inb(base + HA_RSTATUS) & HA_SDRQ)
+			inw(base + HA_RDATA);
+		return (buff);
+	}
+}
+
+static int get_pio_conf_PIO(u32 base, struct get_conf *buf)
+{
+	unsigned long loop = HZ / 2;
+	int z;
+	unsigned short *p;
+
+	if (check_region(base, 9))
 		return (FALSE);
 
-	loop = HZ/2;
-	*p = inw(base + HA_RDATA);
-    }
-    if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {            /* Error ? */
-	if (htonl(EATA_SIGNATURE) == buf->signature) {
-	    DBG(DBG_PIO&&DBG_PROBE, printk(KERN_NOTICE "EATA Controller found "
-                                           "at %#4x EATA Level: %x\n", base, 
-					   (uint) (buf->version)));
-	    
-	    while (inb(base + HA_RSTATUS) & HA_SDRQ) 
-		inw(base + HA_RDATA);
-	    if(ALLOW_DMA_BOARDS == FALSE) {
-		for (z = 0; z < MAXISA; z++)
-		    if (base == ISAbases[z]) {
-			buf->IRQ = ISAirqs[z]; 
-			break;
-		    }
-	    }
-	    return (TRUE);
-	} 
-    } else {
-	DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during transfer "
-			      "for HBA at %x\n", base));
-    }
-    return (FALSE);
-}
-
-void print_pio_config(struct get_conf *gc)
-{
-    printk("Please check values: (read config data)\n");
-    printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n",
-	   (uint) ntohl(gc->len), gc->version,
-	   gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support);
-    printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n",
-	   gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2],
-	   gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
-    printk("IRQ:%d IRQT:%d FORCADR:%d MCH:%d RIDQ:%d\n",
-	   gc->IRQ, gc->IRQ_TR, gc->FORCADR, 
-	   gc->MAX_CHAN, gc->ID_qest);
+	memset(buf, 0, sizeof(struct get_conf));
+
+	while (inb(base + HA_RSTATUS) & HA_SBUSY)
+		if (--loop == 0)
+			return (FALSE);
+
+	DBG(DBG_PIO && DBG_PROBE, printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#x\n", base));
+	eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG);
+
+	loop = HZ / 2;
+	for (p = (unsigned short *) buf; (long) p <= ((long) buf + (sizeof(struct get_conf) / 2)); p++) {
+		while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
+			if (--loop == 0)
+				return (FALSE);
+
+		loop = HZ / 2;
+		*p = inw(base + HA_RDATA);
+	}
+	if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {	/* Error ? */
+		if (htonl(EATA_SIGNATURE) == buf->signature) {
+			DBG(DBG_PIO && DBG_PROBE, printk(KERN_NOTICE "EATA Controller found " "at %#4x EATA Level: %x\n", base, (uint) (buf->version)));
+
+			while (inb(base + HA_RSTATUS) & HA_SDRQ)
+				inw(base + HA_RDATA);
+			if (ALLOW_DMA_BOARDS == FALSE) {
+				for (z = 0; z < MAXISA; z++)
+					if (base == ISAbases[z]) {
+						buf->IRQ = ISAirqs[z];
+						break;
+					}
+			}
+			return (TRUE);
+		}
+	} else {
+		DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during transfer " "for HBA at %x\n", base));
+	}
+	return (FALSE);
+}
+
+static void print_pio_config(struct get_conf *gc)
+{
+	printk("Please check values: (read config data)\n");
+	printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n", (uint) ntohl(gc->len), gc->version, gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support);
+	printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n", gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2], gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
+	printk("IRQ:%d IRQT:%d FORCADR:%d MCH:%d RIDQ:%d\n", gc->IRQ, gc->IRQ_TR, gc->FORCADR, gc->MAX_CHAN, gc->ID_qest);
 }
 
 static uint print_selftest(uint base)
 {
-    unchar buffer[512];
+	unsigned char buffer[512];
 #ifdef VERBOSE_SETUP
-    int z;
+	int z;
 #endif
-    
-    printk("eata_pio: executing controller self test & setup...\n");
-    while (inb(base + HA_RSTATUS) & HA_SBUSY);
-    outb(EATA_CMD_PIO_SETUPTEST, base + HA_WCOMMAND);
-    do {
-	while (inb(base + HA_RSTATUS) & HA_SBUSY)
-	    /* nothing */ ;
-	if (inb(base + HA_RSTATUS) & HA_SDRQ)
-	{
-	    insw(base + HA_RDATA, &buffer, 256);
+
+	printk("eata_pio: executing controller self test & setup...\n");
+	while (inb(base + HA_RSTATUS) & HA_SBUSY);
+	outb(EATA_CMD_PIO_SETUPTEST, base + HA_WCOMMAND);
+	do {
+		while (inb(base + HA_RSTATUS) & HA_SBUSY)
+			/* nothing */ ;
+		if (inb(base + HA_RSTATUS) & HA_SDRQ) {
+			insw(base + HA_RDATA, &buffer, 256);
 #ifdef VERBOSE_SETUP
-	    /* no beeps please... */
-	    for (z = 0; z < 511 && buffer[z]; z++)
-		if (buffer[z] != 7) printk("%c", buffer[z]);
+			/* no beeps please... */
+			for (z = 0; z < 511 && buffer[z]; z++)
+				if (buffer[z] != 7)
+					printk("%c", buffer[z]);
 #endif
+		}
+	} while (inb(base + HA_RSTATUS) & (HA_SBUSY | HA_SDRQ));
+
+	return (!(inb(base + HA_RSTATUS) & HA_SERROR));
+}
+
+static int register_pio_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
+{
+	unsigned long size = 0;
+	char *buff;
+	unsigned long cplen;
+	unsigned short cppadlen;
+	struct Scsi_Host *sh;
+	hostdata *hd;
+
+	DBG(DBG_REGISTER, print_pio_config(gc));
+
+	if (gc->DMA_support == TRUE) {
+		printk("HBA at %#.4lx supports DMA. Please use EATA-DMA driver.\n", base);
+		if (ALLOW_DMA_BOARDS == FALSE)
+			return (FALSE);
 	}
-    } while (inb(base+HA_RSTATUS) & (HA_SBUSY|HA_SDRQ));
-    
-    return (!(inb(base+HA_RSTATUS) & HA_SERROR)); 
-}
-
-int register_pio_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
-{
-    ulong size = 0;
-    char *buff;
-    ulong cplen;
-    ushort cppadlen;
-    struct Scsi_Host *sh;
-    hostdata *hd;
-    
-    DBG(DBG_REGISTER, print_pio_config(gc));
-    
-    if (gc->DMA_support == TRUE) {
-	printk("HBA at %#.4lx supports DMA. Please use EATA-DMA driver.\n",base);
-	if(ALLOW_DMA_BOARDS == FALSE)
-	    return (FALSE);
-    }
-    
-    if ((buff = get_pio_board_data((uint)base, gc->IRQ, gc->scsi_id[3], 
-			       cplen   =(htonl(gc->cplen   )+1)/2, 
-			       cppadlen=(htons(gc->cppadlen)+1)/2)) == NULL)
-    {
-	printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", (ulong) base);
-	return (FALSE);
-    }
-    
-    if (print_selftest(base) == FALSE && ALLOW_DMA_BOARDS == FALSE)
-    {
-	printk("HBA at %#lx failed while performing self test & setup.\n", 
-	       (ulong) base);
-	return (FALSE);
-    }
-    
-    request_region(base, 8, "eata_pio");
-    
-    size = sizeof(hostdata) + (sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
-    
-    sh = scsi_register(tpnt, size);
-    if(sh == NULL)
-    {
-    	release_region(base, 8);
-    	return FALSE;
-    }
-    
-    if (!reg_IRQ[gc->IRQ]) {    /* Interrupt already registered ? */
-	if (!request_irq(gc->IRQ, do_eata_pio_int_handler, SA_INTERRUPT, 
-			 "EATA-PIO", sh)){
-	    reg_IRQ[gc->IRQ]++;
-	    if (!gc->IRQ_TR)
-		reg_IRQL[gc->IRQ] = TRUE;   /* IRQ is edge triggered */
+
+	if ((buff = get_pio_board_data((uint) base, gc->IRQ, gc->scsi_id[3], cplen = (htonl(gc->cplen) + 1) / 2, cppadlen = (htons(gc->cppadlen) + 1) / 2)) == NULL) {
+		printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", (unsigned long) base);
+		return (FALSE);
+	}
+
+	if (print_selftest(base) == FALSE && ALLOW_DMA_BOARDS == FALSE) {
+		printk("HBA at %#lx failed while performing self test & setup.\n", (unsigned long) base);
+		return (FALSE);
+	}
+
+	request_region(base, 8, "eata_pio");
+
+	size = sizeof(hostdata) + (sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
+
+	sh = scsi_register(tpnt, size);
+	if (sh == NULL) {
+		release_region(base, 8);
+		return FALSE;
+	}
+
+	if (!reg_IRQ[gc->IRQ]) {	/* Interrupt already registered ? */
+		if (!request_irq(gc->IRQ, do_eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", sh)) {
+			reg_IRQ[gc->IRQ]++;
+			if (!gc->IRQ_TR)
+				reg_IRQL[gc->IRQ] = TRUE;	/* IRQ is edge triggered */
+		} else {
+			printk("Couldn't allocate IRQ %d, Sorry.\n", gc->IRQ);
+			release_region(base, 8);
+			return (FALSE);
+		}
+	} else {		/* More than one HBA on this IRQ */
+		if (reg_IRQL[gc->IRQ] == TRUE) {
+			printk("Can't support more than one HBA on this IRQ,\n" "  if the IRQ is edge triggered. Sorry.\n");
+			release_region(base, 8);
+			return (FALSE);
+		} else
+			reg_IRQ[gc->IRQ]++;
+	}
+
+	hd = SD(sh);
+
+	memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)));
+	memset(hd->reads, 0, sizeof(unsigned long) * 26);
+
+	strncpy(SD(sh)->vendor, &buff[8], 8);
+	SD(sh)->vendor[8] = 0;
+	strncpy(SD(sh)->name, &buff[16], 17);
+	SD(sh)->name[17] = 0;
+	SD(sh)->revision[0] = buff[32];
+	SD(sh)->revision[1] = buff[33];
+	SD(sh)->revision[2] = buff[34];
+	SD(sh)->revision[3] = '.';
+	SD(sh)->revision[4] = buff[35];
+	SD(sh)->revision[5] = 0;
+
+	switch (ntohl(gc->len)) {
+	case 0x1c:
+		SD(sh)->EATA_revision = 'a';
+		break;
+	case 0x1e:
+		SD(sh)->EATA_revision = 'b';
+		break;
+	case 0x22:
+		SD(sh)->EATA_revision = 'c';
+		break;
+	case 0x24:
+		SD(sh)->EATA_revision = 'z';
+	default:
+		SD(sh)->EATA_revision = '?';
+	}
+
+	if (ntohl(gc->len) >= 0x22) {
+		if (gc->is_PCI == TRUE)
+			hd->bustype = IS_PCI;
+		else if (gc->is_EISA == TRUE)
+			hd->bustype = IS_EISA;
+		else
+			hd->bustype = IS_ISA;
 	} else {
-	    printk("Couldn't allocate IRQ %d, Sorry.\n", gc->IRQ);
-	    release_region(base, 8);
-	    return (FALSE);
-	}
-    } else {            /* More than one HBA on this IRQ */
-	if (reg_IRQL[gc->IRQ] == TRUE) {
-	    printk("Can't support more than one HBA on this IRQ,\n"
-		   "  if the IRQ is edge triggered. Sorry.\n");
-	    release_region(base, 8);
-	    return (FALSE);
-	} else
-	    reg_IRQ[gc->IRQ]++;
-    }
-    
-    hd = SD(sh);                   
-    
-    memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)));
-    memset(hd->reads, 0, sizeof(ulong) * 26); 
-    
-    strncpy(SD(sh)->vendor, &buff[8], 8);
-    SD(sh)->vendor[8] = 0;
-    strncpy(SD(sh)->name, &buff[16], 17);
-    SD(sh)->name[17] = 0;
-    SD(sh)->revision[0] = buff[32];
-    SD(sh)->revision[1] = buff[33];
-    SD(sh)->revision[2] = buff[34];
-    SD(sh)->revision[3] = '.';
-    SD(sh)->revision[4] = buff[35];
-    SD(sh)->revision[5] = 0;
-
-    switch (ntohl(gc->len)) {
-    case 0x1c:
-	SD(sh)->EATA_revision = 'a';
-	break;
-    case 0x1e:
-	SD(sh)->EATA_revision = 'b';
-	break;
-    case 0x22:
-	SD(sh)->EATA_revision = 'c';
-	break;
-    case 0x24:
-	SD(sh)->EATA_revision = 'z';		
-    default:
-	SD(sh)->EATA_revision = '?';
-    }
-
-    if(ntohl(gc->len) >= 0x22) {
-	if (gc->is_PCI == TRUE)
-	    hd->bustype = IS_PCI;
-	else if (gc->is_EISA == TRUE)
-	    hd->bustype = IS_EISA;
-	else
-	    hd->bustype = IS_ISA;
-    } else {
-	if (buff[21] == '4')
-	    hd->bustype = IS_PCI;
-	else if (buff[21] == '2')
-	    hd->bustype = IS_EISA;
+		if (buff[21] == '4')
+			hd->bustype = IS_PCI;
+		else if (buff[21] == '2')
+			hd->bustype = IS_EISA;
+		else
+			hd->bustype = IS_ISA;
+	}
+
+	SD(sh)->cplen = cplen;
+	SD(sh)->cppadlen = cppadlen;
+	SD(sh)->hostid = gc->scsi_id[3];
+	SD(sh)->devflags = 1 << gc->scsi_id[3];
+	SD(sh)->moresupport = gc->MORE_support;
+	sh->unique_id = base;
+	sh->base = base;
+	sh->io_port = base;
+	sh->n_io_port = 8;
+	sh->irq = gc->IRQ;
+	sh->dma_channel = PIO;
+	sh->this_id = gc->scsi_id[3];
+	sh->can_queue = 1;
+	sh->cmd_per_lun = 1;
+	sh->sg_tablesize = SG_ALL;
+
+	hd->channel = 0;
+
+	sh->max_id = 8;
+	sh->max_lun = 8;
+
+	if (gc->SECOND)
+		hd->primary = FALSE;
 	else
-	    hd->bustype = IS_ISA;
-    }
-  
-    SD(sh)->cplen=cplen;
-    SD(sh)->cppadlen=cppadlen;
-    SD(sh)->hostid=gc->scsi_id[3];
-    SD(sh)->devflags=1<<gc->scsi_id[3];
-    SD(sh)->moresupport=gc->MORE_support;
-    sh->unique_id = base;
-    sh->base = base;
-    sh->io_port = base;
-    sh->n_io_port = 8;
-    sh->irq = gc->IRQ;
-    sh->dma_channel = PIO;
-    sh->this_id = gc->scsi_id[3];
-    sh->can_queue = 1;
-    sh->cmd_per_lun = 1;
-    sh->sg_tablesize = SG_ALL;
-    
-    hd->channel = 0;
-    
-    sh->max_id = 8;
-    sh->max_lun = 8;
-
-    if (gc->SECOND)
-	hd->primary = FALSE;
-    else
-	hd->primary = TRUE;
-    
-    sh->unchecked_isa_dma = FALSE; /* We can only do PIO */
-    
-    hd->next = NULL;    /* build a linked list of all HBAs */
-    hd->prev = last_HBA;
-    if(hd->prev != NULL)
-	SD(hd->prev)->next = sh;
-    last_HBA = sh;
-    if (first_HBA == NULL)
-	first_HBA = sh;
-    registered_HBAs++;
-    return (1);
-}
-
-void find_pio_ISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
-{
-    int i;
-    
-    for (i = 0; i < MAXISA; i++) {  
-	if (ISAbases[i]) {  
-	    if (get_pio_conf_PIO(ISAbases[i], buf) == TRUE){
-		register_pio_HBA(ISAbases[i], buf, tpnt);
-	    }
-	    ISAbases[i] = 0;
+		hd->primary = TRUE;
+
+	sh->unchecked_isa_dma = FALSE;	/* We can only do PIO */
+
+	hd->next = NULL;	/* build a linked list of all HBAs */
+	hd->prev = last_HBA;
+	if (hd->prev != NULL)
+		SD(hd->prev)->next = sh;
+	last_HBA = sh;
+	if (first_HBA == NULL)
+		first_HBA = sh;
+	registered_HBAs++;
+	return (1);
+}
+
+static void find_pio_ISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
+{
+	int i;
+
+	for (i = 0; i < MAXISA; i++) {
+		if (ISAbases[i]) {
+			if (get_pio_conf_PIO(ISAbases[i], buf) == TRUE) {
+				register_pio_HBA(ISAbases[i], buf, tpnt);
+			}
+			ISAbases[i] = 0;
+		}
 	}
-    }
-    return;
+	return;
 }
 
-void find_pio_EISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
+static void find_pio_EISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
 {
-    u32 base;
-    int i;
+	u32 base;
+	int i;
 
 #if CHECKPAL
-    u8 pal1, pal2, pal3;
+	u8 pal1, pal2, pal3;
 #endif
 
-    for (i = 0; i < MAXEISA; i++) {
-	if (EISAbases[i] == TRUE) { /* Still a possibility ?          */
+	for (i = 0; i < MAXEISA; i++) {
+		if (EISAbases[i] == TRUE) {	/* Still a possibility ?          */
 
-	    base = 0x1c88 + (i * 0x1000);
+			base = 0x1c88 + (i * 0x1000);
 #if CHECKPAL
-	    pal1 = inb((u16)base - 8);
-	    pal2 = inb((u16)base - 7);
-	    pal3 = inb((u16)base - 6);
-
-	    if (((pal1 == 0x12) && (pal2 == 0x14)) ||
-		((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) ||
-		((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) {
-		DBG(DBG_PROBE, printk(KERN_NOTICE "EISA EATA id tags found: "
-                                      "%x %x %x \n",
-				      (int)pal1, (int)pal2, (int)pal3));
+			pal1 = inb((u16) base - 8);
+			pal2 = inb((u16) base - 7);
+			pal3 = inb((u16) base - 6);
+
+			if (((pal1 == 0x12) && (pal2 == 0x14)) || ((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) || ((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) {
+				DBG(DBG_PROBE, printk(KERN_NOTICE "EISA EATA id tags found: " "%x %x %x \n", (int) pal1, (int) pal2, (int) pal3));
 #endif
-		if (get_pio_conf_PIO(base, buf) == TRUE) {
-		    DBG(DBG_PROBE && DBG_EISA, print_pio_config(buf));
-		    if (buf->IRQ) {
-			register_pio_HBA(base, buf, tpnt);
-		    } else
-			printk(KERN_NOTICE "eata_dma: No valid IRQ. HBA "
-                               "removed from list\n");
-		}
-		/* Nothing found here so we take it from the list */
-		EISAbases[i] = 0;
+				if (get_pio_conf_PIO(base, buf) == TRUE) {
+					DBG(DBG_PROBE && DBG_EISA, print_pio_config(buf));
+					if (buf->IRQ) {
+						register_pio_HBA(base, buf, tpnt);
+					} else
+						printk(KERN_NOTICE "eata_dma: No valid IRQ. HBA " "removed from list\n");
+				}
+				/* Nothing found here so we take it from the list */
+				EISAbases[i] = 0;
 #if CHECKPAL
-	    }
+			}
 #endif
+		}
 	}
-    }
-    return;
+	return;
 }
 
-void find_pio_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
+static void find_pio_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
 {
 #ifndef CONFIG_PCI
-    printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
+	printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
 #else
-    struct pci_dev *dev = NULL; 
-    u32 base, x;
+	struct pci_dev *dev = NULL;
+	u32 base, x;
 
-    while ((dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) {
-	    DBG(DBG_PROBE && DBG_PCI, 
-		printk("eata_pio: find_PCI, HBA at %s\n", dev->name));
-	    if (pci_enable_device(dev))
-	    	continue;
-	    pci_set_master(dev);
-	    base = pci_resource_flags(dev, 0);
-	    if (base & IORESOURCE_MEM) {
-		printk("eata_pio: invalid base address of device %s\n", dev->name);
-		continue;
-	    }
-	    base = pci_resource_start(dev, 0);
-            /* EISA tag there ? */
-	    if ((inb(base) == 0x12) && (inb(base + 1) == 0x14))
-		continue;   /* Jep, it's forced, so move on  */
-	    base += 0x10;   /* Now, THIS is the real address */
-	    if (base != 0x1f8) {
-		/* We didn't find it in the primary search */
-		if (get_pio_conf_PIO(base, buf) == TRUE) {
-		    if (buf->FORCADR)   /* If the address is forced */
-			continue;       /* we'll find it later      */
-		    
-		    /* OK. We made it till here, so we can go now  
-		     * and register it. We  only have to check and 
-		     * eventually remove it from the EISA and ISA list 
-		     */
-		    
-		    register_pio_HBA(base, buf, tpnt);
-		    
-		    if (base < 0x1000) {
-			for (x = 0; x < MAXISA; ++x) {
-			    if (ISAbases[x] == base) {
-				ISAbases[x] = 0;
-				break;
-			    }
+	while ((dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) {
+		DBG(DBG_PROBE && DBG_PCI, printk("eata_pio: find_PCI, HBA at %s\n", dev->name));
+		if (pci_enable_device(dev))
+			continue;
+		pci_set_master(dev);
+		base = pci_resource_flags(dev, 0);
+		if (base & IORESOURCE_MEM) {
+			printk("eata_pio: invalid base address of device %s\n", dev->name);
+			continue;
+		}
+		base = pci_resource_start(dev, 0);
+		/* EISA tag there ? */
+		if ((inb(base) == 0x12) && (inb(base + 1) == 0x14))
+			continue;	/* Jep, it's forced, so move on  */
+		base += 0x10;	/* Now, THIS is the real address */
+		if (base != 0x1f8) {
+			/* We didn't find it in the primary search */
+			if (get_pio_conf_PIO(base, buf) == TRUE) {
+				if (buf->FORCADR)	/* If the address is forced */
+					continue;	/* we'll find it later      */
+
+				/* OK. We made it till here, so we can go now  
+				 * and register it. We  only have to check and 
+				 * eventually remove it from the EISA and ISA list 
+				 */
+
+				register_pio_HBA(base, buf, tpnt);
+
+				if (base < 0x1000) {
+					for (x = 0; x < MAXISA; ++x) {
+						if (ISAbases[x] == base) {
+							ISAbases[x] = 0;
+							break;
+						}
+					}
+				} else if ((base & 0x0fff) == 0x0c88) {
+					x = (base >> 12) & 0x0f;
+					EISAbases[x] = 0;
+				}
 			}
-		    } else if ((base & 0x0fff) == 0x0c88) {
-			x = (base >> 12) & 0x0f;
-			EISAbases[x] = 0;
-		    }
-		} 
 #if CHECK_BLINK
-		else if (check_blink_state(base) == TRUE) {
-		    printk("eata_pio: HBA is in BLINK state.\n"
-			   "Consult your HBAs manual to correct this.\n");
-		}
+			else if (check_blink_state(base) == TRUE) {
+				printk("eata_pio: HBA is in BLINK state.\n" "Consult your HBAs manual to correct this.\n");
+			}
 #endif
-	    }
+		}
 	}
-#endif /* #ifndef CONFIG_PCI */
+#endif				/* #ifndef CONFIG_PCI */
 }
 
 
-int eata_pio_detect(Scsi_Host_Template * tpnt)
+static int eata_pio_detect(Scsi_Host_Template * tpnt)
 {
-    struct Scsi_Host *HBA_ptr;
-    struct get_conf gc;
-    int i;
-    
-    tpnt->proc_name = "eata_pio";
-
-    find_pio_PCI(&gc, tpnt);
-
-    find_pio_EISA(&gc, tpnt);
-
-    find_pio_ISA(&gc, tpnt);
-    
-    for (i = 0; i <= MAXIRQ; i++)
-	if (reg_IRQ[i])
-	    request_irq(i, do_eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", NULL);
-    
-    HBA_ptr = first_HBA;
-  
-    if (registered_HBAs != 0) {
-	printk("EATA (Extended Attachment) PIO driver version: %d.%d%s\n"
-	       "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n"
-	       "            Alfred Arnold,   a.arnold@kfa-juelich.de\n"
-	       "This release only supports DASD devices (harddisks)\n",
-	       VER_MAJOR, VER_MINOR, VER_SUB);
-	
-	printk("Registered HBAs:\n");
-	printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr:"
-               " QS: SG: CPL:\n");
-	for (i = 1; i <= registered_HBAs; i++) {
-	    printk("scsi%-2d: %.10s v%s 2.0%c  %s %#.4x   %2d   %d   %d   %c"
-                   "  %2d  %2d  %2d\n", 
-		   HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
-		   SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')?
-		   "PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ",
-		   (uint) HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel, 
-                   HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N', 
-		   HBA_ptr->can_queue, HBA_ptr->sg_tablesize, 
-                   HBA_ptr->cmd_per_lun);
-	    HBA_ptr = SD(HBA_ptr)->next;
+	struct Scsi_Host *HBA_ptr;
+	struct get_conf gc;
+	int i;
+
+	tpnt->proc_name = "eata_pio";
+
+	find_pio_PCI(&gc, tpnt);
+
+	find_pio_EISA(&gc, tpnt);
+
+	find_pio_ISA(&gc, tpnt);
+
+	for (i = 0; i <= MAXIRQ; i++)
+		if (reg_IRQ[i])
+			request_irq(i, do_eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", NULL);
+
+	HBA_ptr = first_HBA;
+
+	if (registered_HBAs != 0) {
+		printk("EATA (Extended Attachment) PIO driver version: %d.%d%s\n"
+		       "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n" "            Alfred Arnold,   a.arnold@kfa-juelich.de\n" "This release only supports DASD devices (harddisks)\n", VER_MAJOR, VER_MINOR, VER_SUB);
+
+		printk("Registered HBAs:\n");
+		printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr:" " QS: SG: CPL:\n");
+		for (i = 1; i <= registered_HBAs; i++) {
+			printk("scsi%-2d: %.10s v%s 2.0%c  %s %#.4x   %2d   %d   %d   %c"
+			       "  %2d  %2d  %2d\n",
+			       HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
+			       SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P') ?
+			       "PCI " : (SD(HBA_ptr)->bustype == 'E') ? "EISA" : "ISA ",
+			       (uint) HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel, HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE) ? 'Y' : 'N', HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
+			HBA_ptr = SD(HBA_ptr)->next;
+		}
 	}
-    }
-    return (registered_HBAs);
+	return (registered_HBAs);
 }
 
 /* Eventually this will go into an include file, but this will be later */
diff -Nru a/drivers/scsi/eata_pio.h b/drivers/scsi/eata_pio.h
--- a/drivers/scsi/eata_pio.h	Sun Nov 10 19:28:41 2002
+++ b/drivers/scsi/eata_pio.h	Sun Nov 10 19:28:41 2002
@@ -2,7 +2,7 @@
 * Header file for eata_pio.c Linux EATA-PIO SCSI driver *
 * (c) 1993-96 Michael Neuffer  	                        *
 *********************************************************
-* last change: 96/05/05					*
+* last change: 2002/11/02				*
 ********************************************************/
 
 
@@ -14,7 +14,6 @@
 #include "hosts.h"
 #include <scsi/scsicam.h>
 
-#ifndef HOSTS_C
 #include "eata_generic.h"
 
 #define VER_MAJOR 0
@@ -25,82 +24,55 @@
  * Here you can switch parts of the code on and of			*
  ************************************************************************/
 
-#define VERBOSE_SETUP			/* show startup screen of 2001 */
+#define VERBOSE_SETUP		/* show startup screen of 2001 */
 #define ALLOW_DMA_BOARDS 1
 
 /************************************************************************
  * Debug options.							* 
  * Enable DEBUG and whichever options you require.			*
  ************************************************************************/
-#define DEBUG_EATA	1   /* Enable debug code.			*/
-#define DPT_DEBUG	0   /* Bobs special				*/
-#define DBG_DELAY	0   /* Build in delays so debug messages can be
-                             * be read before they vanish of the top of
-                             * the screen!
-                             */
-#define DBG_PROBE	0   /* Debug probe routines.			*/
-#define DBG_ISA		0   /* Trace ISA routines			*/ 
-#define DBG_EISA	0   /* Trace EISA routines			*/ 
-#define DBG_PCI		0   /* Trace PCI routines			*/ 
-#define DBG_PIO		0   /* Trace get_config_PIO			*/
-#define DBG_COM		0   /* Trace command call			*/
-#define DBG_QUEUE	0   /* Trace command queueing.			*/
-#define DBG_INTR	0   /* Trace interrupt service routine.		*/
-#define DBG_INTR2	0   /* Trace interrupt service routine.		*/
-#define DBG_PROC	0   /* Debug proc-fs related statistics		*/
+#define DEBUG_EATA	1	/* Enable debug code.                       */
+#define DPT_DEBUG	0	/* Bobs special                             */
+#define DBG_DELAY	0	/* Build in delays so debug messages can be
+				 * be read before they vanish of the top of
+				 * the screen!
+				 */
+#define DBG_PROBE	0	/* Debug probe routines.                    */
+#define DBG_ISA		0	/* Trace ISA routines                       */
+#define DBG_EISA	0	/* Trace EISA routines                      */
+#define DBG_PCI		0	/* Trace PCI routines                       */
+#define DBG_PIO		0	/* Trace get_config_PIO                     */
+#define DBG_COM		0	/* Trace command call                       */
+#define DBG_QUEUE	0	/* Trace command queueing.                  */
+#define DBG_INTR	0	/* Trace interrupt service routine.         */
+#define DBG_INTR2	0	/* Trace interrupt service routine.         */
+#define DBG_PROC	0	/* Debug proc-fs related statistics         */
 #define DBG_PROC_WRITE	0
-#define DBG_REGISTER	0   /* */
-#define DBG_ABNORM	1   /* Debug abnormal actions (reset, abort)	*/
+#define DBG_REGISTER	0	/* */
+#define DBG_ABNORM	1	/* Debug abnormal actions (reset, abort)    */
 
-#if DEBUG_EATA 
-#define DBG(x, y)   if ((x)) {y;} 
+#if DEBUG_EATA
+#define DBG(x, y)   if ((x)) {y;}
 #else
 #define DBG(x, y)
 #endif
 
-#endif /* !HOSTS_C */
+static int eata_pio_detect(Scsi_Host_Template *);
+static int eata_pio_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+static int eata_pio_abort(Scsi_Cmnd *);
+static int eata_pio_host_reset(Scsi_Cmnd *);
+static int eata_pio_proc_info(char *, char **, off_t, int, int, int);
+static int eata_pio_release(struct Scsi_Host *);
+
+#define EATA_PIO {							\
+	proc_info:         	eata_pio_proc_info, /* procinfo	  */	\
+	name:              	"EATA (Extended Attachment) PIO driver",\
+	detect:            	eata_pio_detect,			\
+	release:           	eata_pio_release,			\
+	queuecommand:      	eata_pio_queue,				\
+	eh_abort_handler:  	eata_pio_abort,				\
+	eh_host_reset_handler:	eata_pio_host_reset,			\
+	use_clustering:    	ENABLE_CLUSTERING 			\
+}
 
-int eata_pio_detect(Scsi_Host_Template *);
-const char *eata_pio_info(struct Scsi_Host *);
-int eata_pio_command(Scsi_Cmnd *);
-int eata_pio_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int eata_pio_abort(Scsi_Cmnd *);
-int eata_pio_reset(Scsi_Cmnd *, unsigned int);
-int eata_pio_proc_info(char *, char **, off_t, int, int, int);
-#ifdef MODULE
-int eata_pio_release(struct Scsi_Host *);
-#else
-#define eata_pio_release NULL  
-#endif
-
-
-#define EATA_PIO {						\
-    proc_info:         eata_pio_proc_info, /* procinfo	  */	\
-    name:              "EATA (Extended Attachment) PIO driver",	\
-    detect:            eata_pio_detect,				\
-    release:           eata_pio_release,			\
-    queuecommand:      eata_pio_queue,				\
-    abort:             eata_pio_abort,				\
-    reset:             eata_pio_reset,				\
-    unchecked_isa_dma: 1,	    /* True if ISA  */		\
-    use_clustering:    ENABLE_CLUSTERING }
-
-#endif /* _EATA_PIO_H */
-
-/*
- * Overrides for Emacs so that we almost follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only.  This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-indent-level: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * tab-width: 8
- * End:
- */
+#endif				/* _EATA_PIO_H */
diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c
--- a/drivers/scsi/esp.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/scsi/esp.c	Sun Nov 10 19:28:41 2002
@@ -1136,7 +1136,7 @@
 
 #include <asm/sun4paddr.h>
 
-int __init esp_detect(Scsi_Host_Template *tpnt)
+static int __init esp_detect(Scsi_Host_Template *tpnt)
 {
 	static struct sbus_dev esp_dev;
 	int esps_in_use = 0;
@@ -1161,7 +1161,7 @@
 
 #else /* !CONFIG_SUN4 */
 
-int __init esp_detect(Scsi_Host_Template *tpnt)
+static int __init esp_detect(Scsi_Host_Template *tpnt)
 {
 	struct sbus_bus *sbus;
 	struct sbus_dev *esp_dev, *sbdev_iter;
@@ -1385,8 +1385,8 @@
 }
 
 /* ESP proc filesystem code. */
-int esp_proc_info(char *buffer, char **start, off_t offset, int length,
-		  int hostno, int inout)
+static int esp_proc_info(char *buffer, char **start, off_t offset,
+			 int length, int hostno, int inout)
 {
 	struct esp *esp;
 
@@ -1830,7 +1830,7 @@
 }
 
 /* Queue a SCSI command delivered from the mid-level Linux SCSI code. */
-int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
 	struct esp *esp;
 
@@ -1867,7 +1867,7 @@
 }
 
 /* Only queuing supported in this ESP driver. */
-int esp_command(Scsi_Cmnd *SCpnt)
+static int esp_command(Scsi_Cmnd *SCpnt)
 {
 	struct esp *esp = (struct esp *) SCpnt->host->hostdata;
 
@@ -1932,7 +1932,7 @@
 }
 
 /* Abort a command. */
-int esp_abort(Scsi_Cmnd *SCptr)
+static int esp_abort(Scsi_Cmnd *SCptr)
 {
 	struct esp *esp = (struct esp *) SCptr->host->hostdata;
 	unsigned long flags;
@@ -2068,7 +2068,7 @@
 /* Reset ESP chip, reset hanging bus, then kill active and
  * disconnected commands for targets without soft reset.
  */
-int esp_reset(Scsi_Cmnd *SCptr)
+static int esp_reset(Scsi_Cmnd *SCptr)
 {
 	struct esp *esp = (struct esp *) SCptr->host->hostdata;
 	unsigned long flags;
@@ -4359,7 +4359,7 @@
 	spin_unlock_irqrestore(esp->ehost->host_lock, flags);
 }
 
-void esp_slave_detach(Scsi_Device* SDptr)
+static void esp_slave_detach(Scsi_Device* SDptr)
 {
 	struct esp *esp = (struct esp *) SDptr->host->hostdata;
 	esp->targets_present &= ~(1 << SDptr->id);
@@ -4368,7 +4368,27 @@
 	SDptr->hostdata = NULL;
 }
 
-static Scsi_Host_Template driver_template = SCSI_SPARC_ESP;
 
-#include "scsi_module.c"
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "esp",
+	.proc_info		= esp_proc_info,
+	.name			= "Sun ESP 100/100a/200",
+	.detect			= esp_detect,
+	.slave_detach		= esp_slave_detach,
+	.info			= esp_info,
+	.command		= esp_command,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+/* Sparc32's iommu code cannot handle highmem pages yet. */
+#ifdef CONFIG_SPARC64
+	.highmem_io		= 1,
+#endif
+};
 
+#include "scsi_module.c"
diff -Nru a/drivers/scsi/esp.h b/drivers/scsi/esp.h
--- a/drivers/scsi/esp.h	Sun Nov 10 19:28:36 2002
+++ b/drivers/scsi/esp.h	Sun Nov 10 19:28:36 2002
@@ -403,42 +403,6 @@
 #define ESP_MHZ_TO_CYCLE(mhertz)  ((1000000000) / ((mhertz) / 1000))
 #define ESP_TICK(ccf, cycle)  ((7682 * (ccf) * (cycle) / 1000))
 
-extern int esp_detect(struct SHT *);
-extern const char *esp_info(struct Scsi_Host *);
-extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-extern int esp_command(Scsi_Cmnd *);
-extern int esp_abort(Scsi_Cmnd *);
-extern int esp_reset(Scsi_Cmnd *);
-extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
-			 int hostno, int inout);
-extern void esp_slave_detach(Scsi_Device* SDptr);
-
-#ifdef CONFIG_SPARC64
-#define ESP_HIGHMEM_IO	1
-#else
-/* Sparc32's iommu code cannot handle highmem pages yet. */
-#define ESP_HIGHMEM_IO	0
-#endif
-
-#define SCSI_SPARC_ESP {					\
-		.proc_name	=	"esp",			\
-		.proc_info	=	&esp_proc_info,		\
-		.name		=	"Sun ESP 100/100a/200",	\
-		.detect		=	esp_detect,		\
-		.slave_detach	=	esp_slave_detach,	\
-		.info		=	esp_info,		\
-		.command	=	esp_command,		\
-		.queuecommand	=	esp_queue,		\
-		.eh_abort_handler =	esp_abort,		\
-		.eh_bus_reset_handler =	esp_reset,		\
-		.can_queue	=	7,			\
-		.this_id	=	7,			\
-		.sg_tablesize	=	SG_ALL,			\
-		.cmd_per_lun	=	1,			\
-		.use_clustering	=	ENABLE_CLUSTERING,	\
-		.highmem_io	=	ESP_HIGHMEM_IO,		\
-}
-
 /* For our interrupt engine. */
 #define for_each_esp(esp) \
         for((esp) = espchain; (esp); (esp) = (esp)->next)
diff -Nru a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
--- a/drivers/scsi/fd_mcs.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/scsi/fd_mcs.c	Sun Nov 10 19:28:39 2002
@@ -1325,118 +1325,115 @@
 	return FAILED;
 }
 
-static int fd_mcs_device_reset(Scsi_Cmnd * SCpnt) {
-		return FAILED;
-	}
+static int fd_mcs_device_reset(Scsi_Cmnd * SCpnt) 
+{
+	return FAILED;
+}
 
-	static int fd_mcs_bus_reset(Scsi_Cmnd * SCpnt) {
-		struct Scsi_Host *shpnt = SCpnt->host;
-		unsigned long flags;
+static int fd_mcs_bus_reset(Scsi_Cmnd * SCpnt) {
+	struct Scsi_Host *shpnt = SCpnt->host;
 
 #if DEBUG_RESET
-		static int called_once = 0;
+	static int called_once = 0;
 #endif
 
 #if ERRORS_ONLY
-		if (SCpnt)
-			printk("fd_mcs: SCSI Bus Reset\n");
+	if (SCpnt)
+		printk("fd_mcs: SCSI Bus Reset\n");
 #endif
 
 #if DEBUG_RESET
-		if (called_once)
-			fd_mcs_print_info(current_SC);
-		called_once = 1;
+	if (called_once)
+		fd_mcs_print_info(current_SC);
+	called_once = 1;
 #endif
 
-		spin_lock_irqsave(shpnt->host_lock, flags);
-
-		outb(1, SCSI_Cntl_port);
-		do_pause(2);
-		outb(0, SCSI_Cntl_port);
-		do_pause(115);
-		outb(0, SCSI_Mode_Cntl_port);
-		outb(PARITY_MASK, TMC_Cntl_port);
-
-		/* Unless this is the very first call (i.e., SCPnt == NULL), everything
-		   is probably hosed at this point.  We will, however, try to keep
-		   things going by informing the high-level code that we need help. */
-
-		spin_unlock_irqrestore(shpnt->host_lock, flags);
+	outb(1, SCSI_Cntl_port);
+	do_pause(2);
+	outb(0, SCSI_Cntl_port);
+	do_pause(115);
+	outb(0, SCSI_Mode_Cntl_port);
+	outb(PARITY_MASK, TMC_Cntl_port);
+
+	/* Unless this is the very first call (i.e., SCPnt == NULL), everything
+	   is probably hosed at this point.  We will, however, try to keep
+	   things going by informing the high-level code that we need help. */
 		return SUCCESS;
-	}
+}
 
 #include <scsi/scsi_ioctl.h>
 
-	static int fd_mcs_biosparam(Scsi_Disk * disk, struct block_device *bdev,
-				    sector_t capacity, int *info_array) {
-		unsigned char buf[512 + sizeof(int) * 2];
-		int size = capacity;
-		int *sizes = (int *) buf;
-		unsigned char *data = (unsigned char *) (sizes + 2);
-		unsigned char do_read[] = { READ_6, 0, 0, 0, 1, 0 };
-		int retcode;
-
-		/* BIOS >= 3.4 for MCA cards */
-		/* This algorithm was provided by Future Domain (much thanks!). */
-
-		sizes[0] = 0;	/* zero bytes out */
-		sizes[1] = 512;	/* one sector in */
-		memcpy(data, do_read, sizeof(do_read));
-		retcode = kernel_scsi_ioctl(disk->device, SCSI_IOCTL_SEND_COMMAND, (void *) buf);
-		if (!retcode	/* SCSI command ok */
-		    && data[511] == 0xaa && data[510] == 0x55	/* Partition table valid */
-		    && data[0x1c2]) {	/* Partition type */
-
-			/* The partition table layout is as follows:
-
-			   Start: 0x1b3h
-			   Offset: 0 = partition status
-			   1 = starting head
-			   2 = starting sector and cylinder (word, encoded)
-			   4 = partition type
-			   5 = ending head
-			   6 = ending sector and cylinder (word, encoded)
-			   8 = starting absolute sector (double word)
-			   c = number of sectors (double word)
-			   Signature: 0x1fe = 0x55aa
-
-			   So, this algorithm assumes:
-			   1) the first partition table is in use,
-			   2) the data in the first entry is correct, and
-			   3) partitions never divide cylinders
-
-			   Note that (1) may be FALSE for NetBSD (and other BSD flavors),
-			   as well as for Linux.  Note also, that Linux doesn't pay any
-			   attention to the fields that are used by this algorithm -- it
-			   only uses the absolute sector data.  Recent versions of Linux's
-			   fdisk(1) will fill this data in correctly, and forthcoming
-			   versions will check for consistency.
-
-			   Checking for a non-zero partition type is not part of the
-			   Future Domain algorithm, but it seemed to be a reasonable thing
-			   to do, especially in the Linux and BSD worlds. */
-
-			info_array[0] = data[0x1c3] + 1;	/* heads */
-			info_array[1] = data[0x1c4] & 0x3f;	/* sectors */
+static int fd_mcs_biosparam(struct scsi_device * disk, struct block_device *bdev,
+			    sector_t capacity, int *info_array) 
+{
+	unsigned char buf[512 + sizeof(int) * 2];
+	int size = capacity;
+	int *sizes = (int *) buf;
+	unsigned char *data = (unsigned char *) (sizes + 2);
+	unsigned char do_read[] = { READ_6, 0, 0, 0, 1, 0 };
+	int retcode;
+
+	/* BIOS >= 3.4 for MCA cards */
+	/* This algorithm was provided by Future Domain (much thanks!). */
+
+	sizes[0] = 0;	/* zero bytes out */
+	sizes[1] = 512;	/* one sector in */
+	memcpy(data, do_read, sizeof(do_read));
+	retcode = kernel_scsi_ioctl(disk, SCSI_IOCTL_SEND_COMMAND, (void *) buf);
+	if (!retcode	/* SCSI command ok */
+	    && data[511] == 0xaa && data[510] == 0x55	/* Partition table valid */
+	    && data[0x1c2]) {	/* Partition type */
+		/* The partition table layout is as follows:
+
+		   Start: 0x1b3h
+		   Offset: 0 = partition status
+		   1 = starting head
+		   2 = starting sector and cylinder (word, encoded)
+		   4 = partition type
+		   5 = ending head
+		   6 = ending sector and cylinder (word, encoded)
+		   8 = starting absolute sector (double word)
+		   c = number of sectors (double word)
+		   Signature: 0x1fe = 0x55aa
+
+		   So, this algorithm assumes:
+		   1) the first partition table is in use,
+		   2) the data in the first entry is correct, and
+		   3) partitions never divide cylinders
+
+		   Note that (1) may be FALSE for NetBSD (and other BSD flavors),
+		   as well as for Linux.  Note also, that Linux doesn't pay any
+		   attention to the fields that are used by this algorithm -- it
+		   only uses the absolute sector data.  Recent versions of Linux's
+		   fdisk(1) will fill this data in correctly, and forthcoming
+		   versions will check for consistency.
+
+		   Checking for a non-zero partition type is not part of the
+		   Future Domain algorithm, but it seemed to be a reasonable thing
+		   to do, especially in the Linux and BSD worlds. */
+
+		info_array[0] = data[0x1c3] + 1;	/* heads */
+		info_array[1] = data[0x1c4] & 0x3f;	/* sectors */
+	} else {
+		/* Note that this new method guarantees that there will always be
+		   less than 1024 cylinders on a platter.  This is good for drives
+		   up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
+		if ((unsigned int) size >= 0x7e0000U) 
+		{
+			info_array[0] = 0xff;	/* heads   = 255 */
+			info_array[1] = 0x3f;	/* sectors =  63 */
+		} else if ((unsigned int) size >= 0x200000U) {
+			info_array[0] = 0x80;	/* heads   = 128 */
+			info_array[1] = 0x3f;	/* sectors =  63 */
 		} else {
-
-			/* Note that this new method guarantees that there will always be
-			   less than 1024 cylinders on a platter.  This is good for drives
-			   up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
-
-			if ((unsigned int) size >= 0x7e0000U) {
-				info_array[0] = 0xff;	/* heads   = 255 */
-				info_array[1] = 0x3f;	/* sectors =  63 */
-			} else if ((unsigned int) size >= 0x200000U) {
-				info_array[0] = 0x80;	/* heads   = 128 */
-				info_array[1] = 0x3f;	/* sectors =  63 */
-			} else {
-				info_array[0] = 0x40;	/* heads   =  64 */
-				info_array[1] = 0x20;	/* sectors =  32 */
-			}
+			info_array[0] = 0x40;	/* heads   =  64 */
+			info_array[1] = 0x20;	/* sectors =  32 */
 		}
-		/* For both methods, compute the cylinders */
-		info_array[2] = (unsigned int) size / (info_array[0] * info_array[1]);
+	}
+	/* For both methods, compute the cylinders */
+	info_array[2] = (unsigned int) size / (info_array[0] * info_array[1]);
+	return 0;
+}
 
 /* Eventually this will go into an include file, but this will be later */
 	static Scsi_Host_Template driver_template = FD_MCS;
diff -Nru a/drivers/scsi/fd_mcs.h b/drivers/scsi/fd_mcs.h
--- a/drivers/scsi/fd_mcs.h	Sun Nov 10 19:28:37 2002
+++ b/drivers/scsi/fd_mcs.h	Sun Nov 10 19:28:37 2002
@@ -30,7 +30,7 @@
 static int fd_mcs_device_reset(Scsi_Cmnd *);
 static int fd_mcs_host_reset(Scsi_Cmnd *);
 static int fd_mcs_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-static int fd_mcs_biosparam(Disk *, struct block_device *,
+static int fd_mcs_biosparam(struct scsi_device *, struct block_device *,
 			    sector_t, int *);
 static int fd_mcs_proc_info(char *, char **, off_t, int, int, int);
 static const char *fd_mcs_info(struct Scsi_Host *);
diff -Nru a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
--- a/drivers/scsi/g_NCR5380.h	Sun Nov 10 19:28:36 2002
+++ b/drivers/scsi/g_NCR5380.h	Sun Nov 10 19:28:36 2002
@@ -54,7 +54,7 @@
 static int notyet_generic_proc_info (char *buffer ,char **start, off_t offset,
                      int length, int hostno, int inout);
 static const char* generic_NCR5380_info(struct Scsi_Host *);
-static int generic_NCR5380_biosparam(Disk *, struct block_device *, sector_t, int *);
+static int generic_NCR5380_biosparam(struct scsi_device *, struct block_device *, sector_t, int *);
 static int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout);
 
 #ifndef CMD_PER_LUN
diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
--- a/drivers/scsi/hosts.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/scsi/hosts.c	Sun Nov 10 19:28:36 2002
@@ -45,13 +45,9 @@
 #include "scsi.h"
 #include "hosts.h"
 
-LIST_HEAD(scsi_host_tmpl_list);
-LIST_HEAD(scsi_host_hn_list);
-
-LIST_HEAD(scsi_host_list);
-spinlock_t scsi_host_list_lock = SPIN_LOCK_UNLOCKED;
-
-struct Scsi_Device_Template * scsi_devicelist;
+static LIST_HEAD(scsi_host_hn_list);
+static LIST_HEAD(scsi_host_list);
+static spinlock_t scsi_host_list_lock = SPIN_LOCK_UNLOCKED;
 
 static int scsi_host_next_hn;		/* host_no for next new host */
 static int scsi_hosts_registered;	/* cnt of registered scsi hosts */
@@ -94,7 +90,7 @@
  * 	This is the default case for the release function.  Its completely
  *	useless for anything but old ISA adapters
  **/
-static void scsi_host_generic_release(struct Scsi_Host *shost)
+static void scsi_host_legacy_release(struct Scsi_Host *shost)
 {
 	if (shost->irq)
 		free_irq(shost->irq, NULL);
@@ -104,19 +100,35 @@
 		release_region(shost->io_port, shost->n_io_port);
 }
 
+static int scsi_remove_legacy_host(struct Scsi_Host *shost)
+{
+	int error, pcount = scsi_hosts_registered;
+
+	error = scsi_remove_host(shost);
+	if (error)
+		return error;
+
+	if (shost->hostt->release)
+		(*shost->hostt->release)(shost);
+	else
+		scsi_host_legacy_release(shost);
+
+	if (pcount == scsi_hosts_registered)
+		scsi_unregister(shost);
+	return 0;
+}
+
 /**
- * scsi_host_chk_and_release - check a scsi host for release and release
+ * scsi_remove_host - check a scsi host for release and release
  * @shost:	a pointer to a scsi host to release
  *
  * Return value:
  * 	0 on Success / 1 on Failure
  **/
-int scsi_host_chk_and_release(struct Scsi_Host *shost)
+int scsi_remove_host(struct Scsi_Host *shost)
 {
-	int pcount;
-	Scsi_Device *sdev;
-	struct Scsi_Device_Template *sdev_tp;
-	Scsi_Cmnd *scmd;
+	struct scsi_device *sdev;
+	struct scsi_cmnd *scmd;
 
 	/*
 	 * Current policy is all shosts go away on unregister.
@@ -175,10 +187,7 @@
 	 * structures
 	 */
 	for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
-		for (sdev_tp = scsi_devicelist; sdev_tp;
-		     sdev_tp = sdev_tp->next)
-			if (sdev_tp->detach)
-				(*sdev_tp->detach) (sdev);
+		scsi_detach_device(sdev);
 
 		/* If something still attached, punt */
 		if (sdev->attached) {
@@ -186,10 +195,6 @@
 			       sdev->attached);
 			return 1;
 		}
-
-		if (shost->hostt->slave_detach)
-			(*shost->hostt->slave_detach) (sdev);
-
 		devfs_unregister(sdev->de);
 		device_unregister(&sdev->sdev_driverfs_dev);
 	}
@@ -198,7 +203,6 @@
 
 	for (sdev = shost->host_queue; sdev;
 	     sdev = shost->host_queue) {
-		scsi_release_commandblocks(sdev);
 		blk_cleanup_queue(&sdev->request_queue);
 		/* Next free up the Scsi_Device structures for this host */
 		shost->host_queue = sdev->next;
@@ -207,18 +211,30 @@
 		kfree(sdev);
 	}
 
-	/* Remove the instance of the individual hosts */
-	pcount = scsi_hosts_registered;
-	if (shost->hostt->release)
-		(*shost->hostt->release) (shost);
-	else {
-		scsi_host_generic_release(shost);
-	}
+	return 0;
+}
 
-	if (pcount == scsi_hosts_registered)
-		scsi_unregister(shost);
+int scsi_add_host(struct Scsi_Host *shost)
+{
+	Scsi_Host_Template *sht = shost->hostt;
+	struct scsi_device *sdev;
+	int error = 0;
+
+	printk(KERN_INFO "scsi%d : %s\n", shost->host_no,
+			sht->info ? sht->info(shost) : sht->name);
+
+	device_register(&shost->host_driverfs_dev);
+	scan_scsis(shost, 0, 0, 0, 0);
+			
+	for (sdev = shost->host_queue; sdev; sdev = sdev->next) {
+		if (sdev->host->hostt != sht)
+			continue; /* XXX(hch): can this really happen? */
+		error = scsi_attach_device(sdev);
+		if (error)
+			break;
+	}
 
-	return 0;
+	return error;
 }
 
 /**
@@ -459,7 +475,6 @@
 	return shost;
 }
 
-
 /**
  * scsi_register_host - register a low level host driver
  * @shost_tp:	pointer to a scsi host driver template
@@ -469,13 +484,8 @@
  **/
 int scsi_register_host(Scsi_Host_Template *shost_tp)
 {
-	int cur_cnt;
-	Scsi_Device *sdev;
-	struct Scsi_Device_Template *sdev_tp;
-	struct list_head *lh;
 	struct Scsi_Host *shost;
-
-	INIT_LIST_HEAD(&shost_tp->shtp_list);
+	int cur_cnt;
 
 	/*
 	 * Check no detect routine.
@@ -503,80 +513,40 @@
 	 * registration code below.
 	 */
 	shost_tp->detect(shost_tp);
+	if (!shost_tp->present)
+		return 0;
 
-	if (shost_tp->present) {
-			/*
-			 * FIXME Who needs manual registration and why???
-			 */
-		if (cur_cnt == scsi_hosts_registered) {
-			if (shost_tp->present > 1) {
-				printk(KERN_ERR "scsi: Failure to register"
-				       "low-level scsi driver");
-				scsi_unregister_host(shost_tp);
-				return 1;
-			}
-			/*
-			 * The low-level driver failed to register a driver.
-			 * We can do this now.
-			 */
-			if(scsi_register(shost_tp, 0)==NULL) {
-				printk(KERN_ERR "scsi: register failed.\n");
-				scsi_unregister_host(shost_tp);
-				return 1;
-			}
-		}
-
-		list_add_tail(&shost_tp->shtp_list, &scsi_host_tmpl_list);
-
-		/* The next step is to call scan_scsis here.  This generates the
-		 * Scsi_Devices entries
-		 */
-		list_for_each(lh, &scsi_host_list) {
-			shost = list_entry(lh, struct Scsi_Host, sh_list);
-			if (shost->hostt == shost_tp) {
-				const char *dm_name;
-				if (shost_tp->info) {
-					dm_name = shost_tp->info(shost);
-				} else {
-					dm_name = shost_tp->name;
-				}
-				printk(KERN_INFO "scsi%d : %s\n",
-				       shost->host_no, dm_name);
-
-				/* first register parent with driverfs */
-				device_register(&shost->host_driverfs_dev);
-				scan_scsis(shost, 0, 0, 0, 0);
-			}
-		}
-
-		for (sdev_tp = scsi_devicelist; sdev_tp;
-		     sdev_tp = sdev_tp->next) {
-			if (sdev_tp->init && sdev_tp->dev_noticed)
-				(*sdev_tp->init) ();
+	if (cur_cnt == scsi_hosts_registered) {
+		if (shost_tp->present > 1) {
+			printk(KERN_ERR "scsi: Failure to register"
+			       "low-level scsi driver");
+			scsi_unregister_host(shost_tp);
+			return 1;
 		}
 
 		/*
-		 * Next we create the Scsi_Cmnd structures for this host 
+		 * The low-level driver failed to register a driver.
+		 * We can do this now.
+		 *
+	 	 * XXX Who needs manual registration and why???
 		 */
-		list_for_each(lh, &scsi_host_list) {
-			shost = list_entry(lh, struct Scsi_Host, sh_list);
-			for (sdev = shost->host_queue; sdev; sdev = sdev->next)
-				if (sdev->host->hostt == shost_tp) {
-					scsi_build_commandblocks(sdev);
-					if (sdev->current_queue_depth == 0)
-						goto out_of_space;
-					for (sdev_tp = scsi_devicelist;
-					     sdev_tp;
-					     sdev_tp = sdev_tp->next)
-						if (sdev_tp->attach)
-							(*sdev_tp->attach) (sdev);
-					if (!sdev->attached) {
-                                                scsi_release_commandblocks(sdev);
-					}
-				}
+		if (!scsi_register(shost_tp, 0)) {
+			printk(KERN_ERR "scsi: register failed.\n");
+			scsi_unregister_host(shost_tp);
+			return 1;
 		}
 	}
 
+	
+	/*
+	 * XXX(hch) use scsi_tp_for_each_host() once it propagates
+	 *	    error returns properly.
+	 */
+	list_for_each_entry(shost, &scsi_host_list, sh_list)
+		if (shost->hostt == shost_tp)
+			if (scsi_add_host(shost))
+				goto out_of_space;
+
 	return 0;
 
 out_of_space:
@@ -608,19 +578,11 @@
 
 	pcount = scsi_hosts_registered;
 
-	scsi_tp_for_each_host(shost_tp, scsi_host_chk_and_release);
+	scsi_tp_for_each_host(shost_tp, scsi_remove_legacy_host);
 
 	if (pcount != scsi_hosts_registered)
 		printk(KERN_INFO "scsi : %d host%s left.\n", scsi_hosts_registered,
 		       (scsi_hosts_registered == 1) ? "" : "s");
-
-	/*
-	 * Remove it from the list if all
-	 * hosts were successfully removed (ie preset == 0)
-	 */
-	if (!shost_tp->present) {
-		list_del(&shost_tp->shtp_list);
-	}
 
 	MOD_DEC_USE_COUNT;
 
diff -Nru a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
--- a/drivers/scsi/hosts.h	Sun Nov 10 19:28:38 2002
+++ b/drivers/scsi/hosts.h	Sun Nov 10 19:28:38 2002
@@ -57,9 +57,6 @@
 
 typedef struct	SHT
 {
-
-    struct list_head	shtp_list;
-
     /* Used with loadable modules so that we know when it is safe to unload */
     struct module * module;
 
@@ -96,12 +93,6 @@
      */
     int (* detect)(struct SHT *);
 
-    /*
-     * This function is only used by one driver and will be going away
-     * once it switches over to using the slave_detach() function instead.
-     */
-    int (*revoke)(Scsi_Device *);
-
     /* Used with loadable modules to unload the host structures.  Note:
      * there is a default action built into the modules code which may
      * be sufficient for most host adapters.  Thus you may not have to supply
@@ -192,7 +183,7 @@
 
     /*
      * Old EH handlers, no longer used. Make them warn the user of old
-     * drivers by using a wrogn type
+     * drivers by using a wrong type
      */
     int (*abort)(int);
     int (*reset)(int,int);
@@ -520,8 +511,6 @@
 	unsigned short host_registered;
 } Scsi_Host_Name;
 	
-extern struct Scsi_Device_Template * scsi_devicelist;
-
 extern void scsi_proc_host_mkdir(Scsi_Host_Template *);
 extern void scsi_proc_host_add(struct Scsi_Host *);
 extern void scsi_proc_host_rm(struct Scsi_Host *);
@@ -533,8 +522,6 @@
 extern int next_scsi_host;
 
 unsigned int scsi_init(void);
-extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int);
-extern void scsi_unregister(struct Scsi_Host *);
 extern void scsi_register_blocked_host(struct Scsi_Host *);
 extern void scsi_deregister_blocked_host(struct Scsi_Host *);
 
@@ -567,13 +554,7 @@
     const char * tag;
     struct module * module;	  /* Used for loadable modules */
     unsigned char scsi_type;
-    unsigned int nr_dev;	  /* Number currently attached */
-    unsigned int dev_noticed;	  /* Number of devices detected. */
-    unsigned int dev_max;	  /* Current size of arrays */
-    unsigned blk:1;		  /* 0 if character device */
     int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */
-    int (*init)(void);		  /* Sizes arrays based upon number of devices
-		   *  detected */
     int (*attach)(Scsi_Device *); /* Attach devices to arrays */
     void (*detach)(Scsi_Device *);
     int (*init_command)(Scsi_Cmnd *);     /* Used by new queueing code. 
@@ -585,10 +566,26 @@
 
 
 /*
- * Driver registration/unregistration.
+ * Highlevel driver registration/unregistration.
  */
 extern int scsi_register_device(struct Scsi_Device_Template *);
 extern int scsi_unregister_device(struct Scsi_Device_Template *);
+
+/*
+ * HBA allocation/freeing.
+ */
+extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int);
+extern void scsi_unregister(struct Scsi_Host *);
+
+/*
+ * HBA registration/unregistration.
+ */
+extern int scsi_add_host(struct Scsi_Host *);
+extern int scsi_remove_host(struct Scsi_Host *);
+
+/*
+ * Legacy HBA template registration/unregistration.
+ */
 extern int scsi_register_host(Scsi_Host_Template *);
 extern int scsi_unregister_host(Scsi_Host_Template *);
 
@@ -604,28 +601,6 @@
 extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *);
 extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *);
 extern void scsi_host_failed_inc_and_test(struct Scsi_Host *);
-
-/*
- * This is an ugly hack.  If we expect to be able to load devices at run time,
- * we need to leave extra room in some of the data structures.	Doing a
- * realloc to enlarge the structures would be riddled with race conditions,
- * so until a better solution is discovered, we use this crude approach
- *
- * Even bigger hack for SparcSTORAGE arrays. Those are at least 6 disks, but
- * usually up to 30 disks, so everyone would need to change this. -jj
- *
- * Note: These things are all evil and all need to go away.  My plan is to
- * tackle the character devices first, as there aren't any locking implications
- * in the block device layer.   The block devices will require more work.
- *
- * The generics driver has been updated to resize as required.  So as the tape
- * driver. Two down, two more to go.
- */
-#ifndef CONFIG_SR_EXTRA_DEVS
-#define CONFIG_SR_EXTRA_DEVS 2
-#endif
-#define SR_EXTRA_DEVS CONFIG_SR_EXTRA_DEVS
-
 
 /**
  * scsi_find_device - find a device given the host
diff -Nru a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
--- a/drivers/scsi/ibmmca.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/scsi/ibmmca.c	Sun Nov 10 19:28:37 2002
@@ -8,13 +8,19 @@
  the commandline arguments and the history of its development.
  See the WWW-page: http://www.uni-mainz.de/~langm000/linux.html for latest
  updates, info and ADF-files for adapters supported by this driver.
-*/
+
+ Alan Cox <alan@redhat.com>
+ Updated for Linux 2.5.45 to use the new error handler, cleaned up the
+ lock macros and did a few unavoidable locking tweaks, plus one locking
+ fix in the irq and completion path.
+ 
+ */
 
 #ifndef LINUX_VERSION_CODE
 #include <linux/version.h>
 #endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-#error "This driver works only with kernel 2.4.0 or higher!"
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)
+#error "This driver works only with kernel 2.5.45 or higher!"
 #endif
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -39,24 +45,21 @@
 #include <linux/config.h>
 
 /* current version of this driver-source: */
-#define IBMMCA_SCSI_DRIVER_VERSION "4.0b"
-
-#define IBMLOCK(dev) spin_lock_irqsave(dev->host_lock, flags);
-#define IBMUNLOCK(dev) spin_unlock_irqrestore(dev->host_lock, flags);
+#define IBMMCA_SCSI_DRIVER_VERSION "4.0b-ac"
 
 /* driver configuration */
-#define IM_MAX_HOSTS     8 /* maximum number of host adapters */
-#define IM_RESET_DELAY	60 /* seconds allowed for a reset */
+#define IM_MAX_HOSTS     8	/* maximum number of host adapters */
+#define IM_RESET_DELAY	60	/* seconds allowed for a reset */
 
 /* driver debugging - #undef all for normal operation */
 /* if defined: count interrupts and ignore this special one: */
-#undef	IM_DEBUG_TIMEOUT	//50            
+#undef	IM_DEBUG_TIMEOUT	//50
 #define TIMEOUT_PUN	0
 #define TIMEOUT_LUN	0
 /* verbose interrupt: */
-#undef IM_DEBUG_INT                   
+#undef IM_DEBUG_INT
 /* verbose queuecommand: */
-#undef IM_DEBUG_CMD    
+#undef IM_DEBUG_CMD
 /* verbose queucommand for specific SCSI-device type: */
 #undef IM_DEBUG_CMD_SPEC_DEV
 /* verbose device probing */
@@ -66,11 +69,11 @@
 #define IM_DEBUG_CMD_DEVICE	TYPE_TAPE
 
 /* relative addresses of hardware registers on a subsystem */
-#define IM_CMD_REG(hi)	(hosts[(hi)]->io_port)   /*Command Interface, (4 bytes long) */
-#define IM_ATTN_REG(hi)	(hosts[(hi)]->io_port+4) /*Attention (1 byte) */
-#define IM_CTR_REG(hi)	(hosts[(hi)]->io_port+5) /*Basic Control (1 byte) */
-#define IM_INTR_REG(hi)	(hosts[(hi)]->io_port+6) /*Interrupt Status (1 byte, r/o) */
-#define IM_STAT_REG(hi)	(hosts[(hi)]->io_port+7) /*Basic Status (1 byte, read only) */
+#define IM_CMD_REG(hi)	(hosts[(hi)]->io_port)	/*Command Interface, (4 bytes long) */
+#define IM_ATTN_REG(hi)	(hosts[(hi)]->io_port+4)	/*Attention (1 byte) */
+#define IM_CTR_REG(hi)	(hosts[(hi)]->io_port+5)	/*Basic Control (1 byte) */
+#define IM_INTR_REG(hi)	(hosts[(hi)]->io_port+6)	/*Interrupt Status (1 byte, r/o) */
+#define IM_STAT_REG(hi)	(hosts[(hi)]->io_port+7)	/*Basic Status (1 byte, read only) */
 
 /* basic I/O-port of first adapter */
 #define IM_IO_PORT	0x3540
@@ -116,53 +119,53 @@
 
 /*SCB (Subsystem Control Block) structure */
 struct im_scb {
-   unsigned short command; /*command word (read, etc.) */
-   unsigned short enable; /*enable word, modifies cmd */
-   union {
-      unsigned long log_blk_adr; /*block address on SCSI device */
-      unsigned char scsi_cmd_length; /*6,10,12, for other scsi cmd */
-   } u1;
-   unsigned long sys_buf_adr; /*physical system memory adr */
-   unsigned long sys_buf_length; /*size of sys mem buffer */
-   unsigned long tsb_adr; /*Termination Status Block adr */
-   unsigned long scb_chain_adr;	/*optional SCB chain address */
-   union {
-      struct {
-	 unsigned short count; /*block count, on SCSI device */
-	 unsigned short length;	/*block length, on SCSI device */
-      } blk;
-      unsigned char scsi_command[12]; /*other scsi command */
-   } u2;
+	unsigned short command;	/*command word (read, etc.) */
+	unsigned short enable;	/*enable word, modifies cmd */
+	union {
+		unsigned long log_blk_adr;	/*block address on SCSI device */
+		unsigned char scsi_cmd_length;	/*6,10,12, for other scsi cmd */
+	} u1;
+	unsigned long sys_buf_adr;	/*physical system memory adr */
+	unsigned long sys_buf_length;	/*size of sys mem buffer */
+	unsigned long tsb_adr;	/*Termination Status Block adr */
+	unsigned long scb_chain_adr;	/*optional SCB chain address */
+	union {
+		struct {
+			unsigned short count;	/*block count, on SCSI device */
+			unsigned short length;	/*block length, on SCSI device */
+		} blk;
+		unsigned char scsi_command[12];	/*other scsi command */
+	} u2;
 };
 
 /*structure scatter-gather element (for list of system memory areas) */
 struct im_sge {
-   void *address;
-   unsigned long byte_length;
+	void *address;
+	unsigned long byte_length;
 };
 
 /*structure returned by a get_pos_info command: */
 struct im_pos_info {
-   unsigned short pos_id;         /* adapter id */
-   unsigned char pos_3a;          /* pos 3 (if pos 6 = 0) */
-   unsigned char pos_2;           /* pos 2 */
-   unsigned char int_level;       /* interrupt level IRQ 11 or 14 */
-   unsigned char pos_4a;          /* pos 4 (if pos 6 = 0) */
-   unsigned short connector_size; /* MCA connector size: 16 or 32 Bit */
-   unsigned char num_luns;        /* number of supported luns per device */
-   unsigned char num_puns;        /* number of supported puns */
-   unsigned char pacing_factor;   /* pacing factor */
-   unsigned char num_ldns;        /* number of ldns available */
-   unsigned char eoi_off;         /* time EOI and interrupt inactive */
-   unsigned char max_busy;        /* time between reset and busy on */
-   unsigned short cache_stat;     /* ldn cachestat. Bit=1 = not cached */
-   unsigned short retry_stat;     /* retry status of ldns. Bit=1=disabled */
-   unsigned char pos_4b;          /* pos 4 (if pos 6 = 1) */
-   unsigned char pos_3b;          /* pos 3 (if pos 6 = 1) */
-   unsigned char pos_6;           /* pos 6 */
-   unsigned char pos_5;           /* pos 5 */ 
-   unsigned short max_overlap;    /* maximum overlapping requests */
-   unsigned short num_bus;        /* number of SCSI-busses */
+	unsigned short pos_id;	/* adapter id */
+	unsigned char pos_3a;	/* pos 3 (if pos 6 = 0) */
+	unsigned char pos_2;	/* pos 2 */
+	unsigned char int_level;	/* interrupt level IRQ 11 or 14 */
+	unsigned char pos_4a;	/* pos 4 (if pos 6 = 0) */
+	unsigned short connector_size;	/* MCA connector size: 16 or 32 Bit */
+	unsigned char num_luns;	/* number of supported luns per device */
+	unsigned char num_puns;	/* number of supported puns */
+	unsigned char pacing_factor;	/* pacing factor */
+	unsigned char num_ldns;	/* number of ldns available */
+	unsigned char eoi_off;	/* time EOI and interrupt inactive */
+	unsigned char max_busy;	/* time between reset and busy on */
+	unsigned short cache_stat;	/* ldn cachestat. Bit=1 = not cached */
+	unsigned short retry_stat;	/* retry status of ldns. Bit=1=disabled */
+	unsigned char pos_4b;	/* pos 4 (if pos 6 = 1) */
+	unsigned char pos_3b;	/* pos 3 (if pos 6 = 1) */
+	unsigned char pos_6;	/* pos 6 */
+	unsigned char pos_5;	/* pos 5 */
+	unsigned short max_overlap;	/* maximum overlapping requests */
+	unsigned short num_bus;	/* number of SCSI-busses */
 };
 
 /*values for SCB command word */
@@ -179,11 +182,11 @@
 #define IM_OTHER_SCSI_CMD_CMD  0x241f
 
 /* unused, but supported, SCB commands */
-#define IM_GET_COMMAND_COMPLETE_STATUS_CMD   0x1c07 /* command status */
-#define IM_GET_POS_INFO_CMD                  0x1c0a /* returns neat stuff */
-#define IM_READ_PREFETCH_CMD                 0x1c31 /* caching controller only */
-#define IM_FOMAT_UNIT_CMD                    0x1c16 /* format unit */
-#define IM_REASSIGN_BLOCK_CMD                0x1c18 /* in case of error */
+#define IM_GET_COMMAND_COMPLETE_STATUS_CMD   0x1c07	/* command status */
+#define IM_GET_POS_INFO_CMD                  0x1c0a	/* returns neat stuff */
+#define IM_READ_PREFETCH_CMD                 0x1c31	/* caching controller only */
+#define IM_FOMAT_UNIT_CMD                    0x1c16	/* format unit */
+#define IM_REASSIGN_BLOCK_CMD                0x1c18	/* in case of error */
 
 /*values to set bits in the enable word of SCB */
 #define IM_READ_CONTROL              0x8000
@@ -196,19 +199,19 @@
 
 /*TSB (Termination Status Block) structure */
 struct im_tsb {
-   unsigned short end_status;
-   unsigned short reserved1;
-   unsigned long residual_byte_count;
-   unsigned long sg_list_element_adr;
-   unsigned short status_length;
-   unsigned char dev_status;
-   unsigned char cmd_status;
-   unsigned char dev_error;
-   unsigned char cmd_error;
-   unsigned short reserved2;
-   unsigned short reserved3;
-   unsigned short low_of_last_scb_adr;
-   unsigned short high_of_last_scb_adr;
+	unsigned short end_status;
+	unsigned short reserved1;
+	unsigned long residual_byte_count;
+	unsigned long sg_list_element_adr;
+	unsigned short status_length;
+	unsigned char dev_status;
+	unsigned char cmd_status;
+	unsigned char dev_error;
+	unsigned char cmd_error;
+	unsigned short reserved2;
+	unsigned short reserved3;
+	unsigned short low_of_last_scb_adr;
+	unsigned short high_of_last_scb_adr;
 };
 
 /*subsystem uses interrupt request level 14 */
@@ -247,7 +250,7 @@
 /* for probing on feature-command: */
 static unsigned int global_command_error_excuse = 0;
 /* global setting by command line for adapter_speed */
-static int global_adapter_speed = 0; /* full speed by default */
+static int global_adapter_speed = 0;	/* full speed by default */
 
 /* Panel / LED on, do it right for F/W addressin, too. adisplay will
  * just ignore ids>7, as the panel has only 7 digits available */
@@ -269,8 +272,8 @@
 
 /*list of supported subsystems */
 struct subsys_list_struct {
-   unsigned short mca_id;
-   char *description;
+	unsigned short mca_id;
+	char *description;
 };
 
 /* types of different supported hardware that goes to hostdata special */
@@ -286,11 +289,11 @@
 
 /* List of possible IBM-SCSI-adapters */
 struct subsys_list_struct subsys_list[] = {
- {0x8efc,"IBM SCSI-2 F/W Adapter"}, /* special = 0 */
- {0x8efd,"IBM 7568 Industrial Computer SCSI Adapter w/Cache"}, /* special = 1 */
- {0x8ef8,"IBM Expansion Unit SCSI Controller"},/* special = 2 */
- {0x8eff,"IBM SCSI Adapter w/Cache"}, /* special = 3 */
- {0x8efe,"IBM SCSI Adapter"}, /* special = 4 */
+	{0x8efc, "IBM SCSI-2 F/W Adapter"},	/* special = 0 */
+	{0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/Cache"},	/* special = 1 */
+	{0x8ef8, "IBM Expansion Unit SCSI Controller"},	/* special = 2 */
+	{0x8eff, "IBM SCSI Adapter w/Cache"},	/* special = 3 */
+	{0x8efe, "IBM SCSI Adapter"},	/* special = 4 */
 };
 
 /* Max number of logical devices (can be up from 0 to 14).  15 is the address
@@ -299,80 +302,80 @@
 
 /*local data for a logical device */
 struct logical_device {
-   struct im_scb scb; /* SCSI-subsystem-control-block structure */
-   struct im_tsb tsb; /* SCSI command complete status block structure */
-   struct im_sge sge[16]; /* scatter gather list structure */
-   unsigned char buf[256]; /* SCSI command return data buffer */
-   Scsi_Cmnd *cmd;  /* SCSI-command that is currently in progress */
-   int device_type; /* type of the SCSI-device. See include/scsi/scsi.h
-		       for interpretation of the possible values */
-   int block_length; /* blocksize of a particular logical SCSI-device */
-   int cache_flag; /* 1 if this is uncached, 0 if cache is present for ldn */
-   int retry_flag; /* 1 if adapter retry is disabled, 0 if enabled */
+	struct im_scb scb;	/* SCSI-subsystem-control-block structure */
+	struct im_tsb tsb;	/* SCSI command complete status block structure */
+	struct im_sge sge[16];	/* scatter gather list structure */
+	unsigned char buf[256];	/* SCSI command return data buffer */
+	Scsi_Cmnd *cmd;		/* SCSI-command that is currently in progress */
+	int device_type;	/* type of the SCSI-device. See include/scsi/scsi.h
+				   for interpretation of the possible values */
+	int block_length;	/* blocksize of a particular logical SCSI-device */
+	int cache_flag;		/* 1 if this is uncached, 0 if cache is present for ldn */
+	int retry_flag;		/* 1 if adapter retry is disabled, 0 if enabled */
 };
 
 /* statistics of the driver during operations (for proc_info) */
 struct Driver_Statistics {
-   /* SCSI statistics on the adapter */
-   int ldn_access[MAX_LOG_DEV+1];         /* total accesses on a ldn */
-   int ldn_read_access[MAX_LOG_DEV+1];    /* total read-access on a ldn */
-   int ldn_write_access[MAX_LOG_DEV+1];   /* total write-access on a ldn */
-   int ldn_inquiry_access[MAX_LOG_DEV+1]; /* total inquiries on a ldn */
-   int ldn_modeselect_access[MAX_LOG_DEV+1]; /* total mode selects on ldn */
-   int scbs;                              /* short SCBs queued */
-   int long_scbs;                         /* long SCBs queued */
-   int total_accesses;                    /* total accesses on all ldns */
-   int total_interrupts;                  /* total interrupts (should be
-					     same as total_accesses) */
-   int total_errors;                      /* command completed with error */
-   /* dynamical assignment statistics */
-   int total_scsi_devices;                /* number of physical pun,lun */
-   int dyn_flag;                          /* flag showing dynamical mode */
-   int dynamical_assignments;             /* number of remappings of ldns */
-   int ldn_assignments[MAX_LOG_DEV+1];    /* number of remappings of each
-					     ldn */
+	/* SCSI statistics on the adapter */
+	int ldn_access[MAX_LOG_DEV + 1];	/* total accesses on a ldn */
+	int ldn_read_access[MAX_LOG_DEV + 1];	/* total read-access on a ldn */
+	int ldn_write_access[MAX_LOG_DEV + 1];	/* total write-access on a ldn */
+	int ldn_inquiry_access[MAX_LOG_DEV + 1];	/* total inquiries on a ldn */
+	int ldn_modeselect_access[MAX_LOG_DEV + 1];	/* total mode selects on ldn */
+	int scbs;		/* short SCBs queued */
+	int long_scbs;		/* long SCBs queued */
+	int total_accesses;	/* total accesses on all ldns */
+	int total_interrupts;	/* total interrupts (should be
+				   same as total_accesses) */
+	int total_errors;	/* command completed with error */
+	/* dynamical assignment statistics */
+	int total_scsi_devices;	/* number of physical pun,lun */
+	int dyn_flag;		/* flag showing dynamical mode */
+	int dynamical_assignments;	/* number of remappings of ldns */
+	int ldn_assignments[MAX_LOG_DEV + 1];	/* number of remappings of each
+						   ldn */
 };
 
 /* data structure for each host adapter */
 struct ibmmca_hostdata {
-   /* array of logical devices: */
-   struct logical_device _ld[MAX_LOG_DEV+1];   
-   /* array to convert (pun, lun) into logical device number: */
-   unsigned char _get_ldn[16][8];
-   /*array that contains the information about the physical SCSI-devices
-    attached to this host adapter: */
-   unsigned char _get_scsi[16][8];
-   /* used only when checking logical devices: */
-   int _local_checking_phase_flag;
-   /* report received interrupt: */
-   int _got_interrupt;
-   /* report termination-status of SCSI-command: */
-   int _stat_result;
-   /* reset status (used only when doing reset): */
-   int _reset_status;
-   /* code of the last SCSI command (needed for panic info): */
-   int _last_scsi_command[MAX_LOG_DEV+1];
-   /* identifier of the last SCSI-command type */
-   int _last_scsi_type[MAX_LOG_DEV+1];
-   /* last blockcount */
-   int _last_scsi_blockcount[MAX_LOG_DEV+1];
-   /* last locgical block address */
-   unsigned long _last_scsi_logical_block[MAX_LOG_DEV+1];
-   /* Counter that points on the next reassignable ldn for dynamical
-      remapping. The default value is 7, that is the first reassignable
-      number in the list at boottime: */
-   int _next_ldn;
-   /* Statistics-structure for this IBM-SCSI-host: */
-   struct Driver_Statistics _IBM_DS;
-   /* This hostadapters pos-registers pos2 until pos6 */
-   unsigned int _pos[8];
-   /* assign a special variable, that contains dedicated info about the
-    adaptertype */
-   int _special;
-   /* connector size on the MCA bus */
-   int _connector_size;
-   /* synchronous SCSI transfer rate bitpattern */
-   int _adapter_speed;
+	/* array of logical devices: */
+	struct logical_device _ld[MAX_LOG_DEV + 1];
+	/* array to convert (pun, lun) into logical device number: */
+	unsigned char _get_ldn[16][8];
+	/*array that contains the information about the physical SCSI-devices
+	   attached to this host adapter: */
+	unsigned char _get_scsi[16][8];
+	/* used only when checking logical devices: */
+	int _local_checking_phase_flag;
+	/* report received interrupt: */
+	int _got_interrupt;
+	/* report termination-status of SCSI-command: */
+	int _stat_result;
+	/* reset status (used only when doing reset): */
+	int _reset_status;
+	/* code of the last SCSI command (needed for panic info): */
+	int _last_scsi_command[MAX_LOG_DEV + 1];
+	/* identifier of the last SCSI-command type */
+	int _last_scsi_type[MAX_LOG_DEV + 1];
+	/* last blockcount */
+	int _last_scsi_blockcount[MAX_LOG_DEV + 1];
+	/* last locgical block address */
+	unsigned long _last_scsi_logical_block[MAX_LOG_DEV + 1];
+	/* Counter that points on the next reassignable ldn for dynamical
+	   remapping. The default value is 7, that is the first reassignable
+	   number in the list at boottime: */
+	int _next_ldn;
+	/* Statistics-structure for this IBM-SCSI-host: */
+	struct Driver_Statistics _IBM_DS;
+	/* This hostadapters pos-registers pos2 until pos6 */
+	unsigned int _pos[8];
+	/* assign a special variable, that contains dedicated info about the
+	   adaptertype */
+	int _special;
+	/* connector size on the MCA bus */
+	int _connector_size;
+	/* synchronous SCSI transfer rate bitpattern */
+	int _adapter_speed;
 };
 
 /* macros to access host data structure */
@@ -457,9 +460,10 @@
 
 /* host information */
 static int found = 0;
-static struct Scsi_Host *hosts[IM_MAX_HOSTS+1] = {
-   NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
-static unsigned int pos[8]; /* whole pos register-line for diagnosis */
+static struct Scsi_Host *hosts[IM_MAX_HOSTS + 1] = {
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+static unsigned int pos[8];	/* whole pos register-line for diagnosis */
 /* Taking into account the additions, made by ZP Gu.
  * This selects now the preset value from the configfile and
  * offers the 'normal' commandline option to be accepted */
@@ -469,12 +473,11 @@
 static char ibm_ansi_order = 0;
 #endif
 
-static void interrupt_handler (int, void *, struct pt_regs *);
-static void issue_cmd (int, unsigned long, unsigned char);
-static void internal_done (Scsi_Cmnd * cmd);
-static void check_devices (int, int);
-static int immediate_assign(int, unsigned int, unsigned int, unsigned int,
-                            unsigned int);
+static void interrupt_handler(int, void *, struct pt_regs *);
+static void issue_cmd(int, unsigned long, unsigned char);
+static void internal_done(Scsi_Cmnd * cmd);
+static void check_devices(int, int);
+static int immediate_assign(int, unsigned int, unsigned int, unsigned int, unsigned int);
 static int immediate_feature(int, unsigned int, unsigned int);
 #ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
 static int immediate_reset(int, unsigned int);
@@ -487,2083 +490,1994 @@
 static char *ibmrate(unsigned int, int);
 static int probe_display(int);
 static int probe_bus_mode(int);
-static int device_exists (int, int, int *, int *);
-static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *,
-					 int, int, int, char *);
+static int device_exists(int, int, int *, int *);
+static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *, int, int, int, char *);
 static int option_setup(char *);
 /* local functions needed for proc_info */
 static int ldn_access_load(int, int);
 static int ldn_access_total_read_write(int);
 
-static void interrupt_handler (int irq, void *dev_id, struct pt_regs *regs)
+static void interrupt_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
-   int host_index, ihost_index;
-   unsigned int intr_reg;
-   unsigned int cmd_result;
-   unsigned int ldn;
-   unsigned long flags;
-   Scsi_Cmnd *cmd;
-   int lastSCSI;
-   struct Scsi_Host *dev = dev_id;
-
-   IBMLOCK(dev)
-   /* search for one adapter-response on shared interrupt */
-   for (host_index=0;
-	hosts[host_index] && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST);
-	host_index++);
-   /* return if some other device on this IRQ caused the interrupt */
-   if (!hosts[host_index]) {
-      IBMUNLOCK(dev)
-      return;
-   }
-
-   /* the reset-function already did all the job, even ints got
-      renabled on the subsystem, so just return */
-   if ((reset_status(host_index) == IM_RESET_NOT_IN_PROGRESS_NO_INT)||
-       (reset_status(host_index) == IM_RESET_FINISHED_OK_NO_INT)) {
-      reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS;
-      IBMUNLOCK(dev)
-      return;
-   }
-
-   /*must wait for attention reg not busy, then send EOI to subsystem */
-   while (1) {
-      if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY)) break;
-      IBMUNLOCK(dev) /* cycle interrupt */
-      cpu_relax();
-      IBMLOCK(dev)
-   }
-   ihost_index=host_index;
-   /*get command result and logical device */
-   intr_reg = (unsigned char)(inb (IM_INTR_REG(ihost_index)));
-   cmd_result = intr_reg & 0xf0;
-   ldn = intr_reg & 0x0f;
-   /* get the last_scsi_command here */
-   lastSCSI = last_scsi_command(ihost_index)[ldn];
-   outb (IM_EOI | ldn, IM_ATTN_REG(ihost_index));
-   IBMUNLOCK(dev)
-   /*these should never happen (hw fails, or a local programming bug) */
-   if (!global_command_error_excuse) {
-      switch (cmd_result) {
-	 /* Prevent from Ooopsing on error to show the real reason */
-       case IM_ADAPTER_HW_FAILURE:
-       case IM_SOFTWARE_SEQUENCING_ERROR:
-       case IM_CMD_ERROR:
-	 printk("\nIBM MCA SCSI: Fatal Subsystem ERROR!\n");
-	 printk("              Last cmd=0x%x, ena=%x, len=",lastSCSI,
-		ld(ihost_index)[ldn].scb.enable);
-	 if (ld(ihost_index)[ldn].cmd)
-	   printk("%ld/%ld,",(long)(ld(ihost_index)[ldn].cmd->request_bufflen),
-		  (long)(ld(ihost_index)[ldn].scb.sys_buf_length));
-	 else
-	   printk("none,");
-	 if (ld(ihost_index)[ldn].cmd)
-	   printk("Blocksize=%d",ld(ihost_index)[ldn].scb.u2.blk.length);
-	 else
-	   printk("Blocksize=none");
-	 printk(", host=0x%x, ldn=0x%x\n",ihost_index, ldn);
-	 if (ld(ihost_index)[ldn].cmd) {
-	    printk("Blockcount=%d/%d\n",last_scsi_blockcount(ihost_index)[ldn],
-		   ld(ihost_index)[ldn].scb.u2.blk.count);
-	    printk("Logical block=%lx/%lx\n",last_scsi_logical_block(ihost_index)[ldn],
-		   ld(ihost_index)[ldn].scb.u1.log_blk_adr);
-	 }
-	 printk("Reason given: %s\n",
-		(cmd_result==IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" :
-		(cmd_result==IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" :
-		(cmd_result==IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN");
-	 /* if errors appear, enter this section to give detailed info */
-	 printk("IBM MCA SCSI: Subsystem Error-Status follows:\n");
-	 printk("              Command Type................: %x\n",
-		last_scsi_type(ihost_index)[ldn]);
-	 printk("              Attention Register..........: %x\n",
-		inb (IM_ATTN_REG(ihost_index)));
-	 printk("              Basic Control Register......: %x\n",
-		inb (IM_CTR_REG(ihost_index)));
-	 printk("              Interrupt Status Register...: %x\n",
-		intr_reg);
-	 printk("              Basic Status Register.......: %x\n",
-		inb (IM_STAT_REG(ihost_index)));
-	 if ((last_scsi_type(ihost_index)[ldn]==IM_SCB)||
-	     (last_scsi_type(ihost_index)[ldn]==IM_LONG_SCB)) {
-	    printk("              SCB-Command.................: %x\n",
-		   ld(ihost_index)[ldn].scb.command);
-	    printk("              SCB-Enable..................: %x\n",
-		   ld(ihost_index)[ldn].scb.enable);
-	    printk("              SCB-logical block address...: %lx\n",
-		   ld(ihost_index)[ldn].scb.u1.log_blk_adr);
-	    printk("              SCB-system buffer address...: %lx\n",
-		   ld(ihost_index)[ldn].scb.sys_buf_adr);
-	    printk("              SCB-system buffer length....: %lx\n",
-		   ld(ihost_index)[ldn].scb.sys_buf_length);
-	    printk("              SCB-tsb address.............: %lx\n",
-		   ld(ihost_index)[ldn].scb.tsb_adr);
-	    printk("              SCB-Chain address...........: %lx\n",
-		   ld(ihost_index)[ldn].scb.scb_chain_adr);
-	    printk("              SCB-block count.............: %x\n",
-		   ld(ihost_index)[ldn].scb.u2.blk.count);
-	    printk("              SCB-block length............: %x\n",
-		   ld(ihost_index)[ldn].scb.u2.blk.length);
-	 }
-	 printk("              Send this report to the maintainer.\n");
-	 panic("IBM MCA SCSI: Fatal errormessage from the subsystem (0x%X,0x%X)!\n",
-	       lastSCSI,cmd_result);
-	 break;
-      }
-   } else {
-      /* The command error handling is made silent, but we tell the
-       * calling function, that there is a reported error from the
-       * adapter. */
-      switch (cmd_result) {
-       case IM_ADAPTER_HW_FAILURE: case IM_SOFTWARE_SEQUENCING_ERROR:
-       case IM_CMD_ERROR: global_command_error_excuse = CMD_FAIL; break;
-       default: global_command_error_excuse = 0; break;
-      }
-   }
-   /* if no panic appeared, increase the interrupt-counter */
-   IBM_DS(ihost_index).total_interrupts++;
-   /*only for local checking phase */
-   if (local_checking_phase_flag(ihost_index)) {
-      stat_result(ihost_index) = cmd_result;
-      got_interrupt(ihost_index) = 1;
-      reset_status(ihost_index) = IM_RESET_FINISHED_OK;
-      last_scsi_command(ihost_index)[ldn] = NO_SCSI;
-      return;
-   }
-   /* handling of commands coming from upper level of scsi driver */
-   if (last_scsi_type(ihost_index)[ldn] == IM_IMM_CMD) {
-      /* verify ldn, and may handle rare reset immediate command */
-      if ((reset_status(ihost_index) == IM_RESET_IN_PROGRESS)&&
-	  (last_scsi_command(ihost_index)[ldn] == IM_RESET_IMM_CMD)) {
-	 if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
-	    disk_rw_in_progress = 0;
-	    PS2_DISK_LED_OFF ();
-	    reset_status(ihost_index) = IM_RESET_FINISHED_FAIL;
-	 } else {
-	    /*reset disk led counter, turn off disk led */
-	    disk_rw_in_progress = 0;
-	    PS2_DISK_LED_OFF ();
-	    reset_status(ihost_index) = IM_RESET_FINISHED_OK;
-	 }
-	 stat_result(ihost_index) = cmd_result;
-	 last_scsi_command(ihost_index)[ldn] = NO_SCSI;
-	 last_scsi_type(ihost_index)[ldn] = 0;
-	 return;
-      } else if (last_scsi_command(ihost_index)[ldn] == IM_ABORT_IMM_CMD) {
-	 /* react on SCSI abort command */
+	int host_index, ihost_index;
+	unsigned int intr_reg;
+	unsigned int cmd_result;
+	unsigned int ldn;
+	Scsi_Cmnd *cmd;
+	int lastSCSI;
+	struct Scsi_Host *dev = dev_id;
+
+	spin_lock(dev->host_lock);
+	    /* search for one adapter-response on shared interrupt */
+	    for (host_index = 0; hosts[host_index] && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST); host_index++);
+	/* return if some other device on this IRQ caused the interrupt */
+	if (!hosts[host_index]) {
+		spin_unlock(dev->host_lock);
+		return;
+	}
+
+	/* the reset-function already did all the job, even ints got
+	   renabled on the subsystem, so just return */
+	if ((reset_status(host_index) == IM_RESET_NOT_IN_PROGRESS_NO_INT) || (reset_status(host_index) == IM_RESET_FINISHED_OK_NO_INT)) {
+		reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS;
+		spin_unlock(dev->host_lock);
+		return;
+	}
+
+	/*must wait for attention reg not busy, then send EOI to subsystem */
+	while (1) {
+		if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+			break;
+		cpu_relax();
+	}
+	ihost_index = host_index;
+	/*get command result and logical device */
+	intr_reg = (unsigned char) (inb(IM_INTR_REG(ihost_index)));
+	cmd_result = intr_reg & 0xf0;
+	ldn = intr_reg & 0x0f;
+	/* get the last_scsi_command here */
+	lastSCSI = last_scsi_command(ihost_index)[ldn];
+	outb(IM_EOI | ldn, IM_ATTN_REG(ihost_index));
+	
+	/*these should never happen (hw fails, or a local programming bug) */
+	if (!global_command_error_excuse) {
+		switch (cmd_result) {
+			/* Prevent from Ooopsing on error to show the real reason */
+		case IM_ADAPTER_HW_FAILURE:
+		case IM_SOFTWARE_SEQUENCING_ERROR:
+		case IM_CMD_ERROR:
+			printk(KERN_ERR "IBM MCA SCSI: Fatal Subsystem ERROR!\n");
+			printk(KERN_ERR "              Last cmd=0x%x, ena=%x, len=", lastSCSI, ld(ihost_index)[ldn].scb.enable);
+			if (ld(ihost_index)[ldn].cmd)
+				printk("%ld/%ld,", (long) (ld(ihost_index)[ldn].cmd->request_bufflen), (long) (ld(ihost_index)[ldn].scb.sys_buf_length));
+			else
+				printk("none,");
+			if (ld(ihost_index)[ldn].cmd)
+				printk("Blocksize=%d", ld(ihost_index)[ldn].scb.u2.blk.length);
+			else
+				printk("Blocksize=none");
+			printk(", host=0x%x, ldn=0x%x\n", ihost_index, ldn);
+			if (ld(ihost_index)[ldn].cmd) {
+				printk(KERN_ERR "Blockcount=%d/%d\n", last_scsi_blockcount(ihost_index)[ldn], ld(ihost_index)[ldn].scb.u2.blk.count);
+				printk(KERN_ERR "Logical block=%lx/%lx\n", last_scsi_logical_block(ihost_index)[ldn], ld(ihost_index)[ldn].scb.u1.log_blk_adr);
+			}
+			printk(KERN_ERR "Reason given: %s\n", (cmd_result == IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" : (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" : (cmd_result == IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN");
+			/* if errors appear, enter this section to give detailed info */
+			printk(KERN_ERR "IBM MCA SCSI: Subsystem Error-Status follows:\n");
+			printk(KERN_ERR "              Command Type................: %x\n", last_scsi_type(ihost_index)[ldn]);
+			printk(KERN_ERR "              Attention Register..........: %x\n", inb(IM_ATTN_REG(ihost_index)));
+			printk(KERN_ERR "              Basic Control Register......: %x\n", inb(IM_CTR_REG(ihost_index)));
+			printk(KERN_ERR "              Interrupt Status Register...: %x\n", intr_reg);
+			printk(KERN_ERR "              Basic Status Register.......: %x\n", inb(IM_STAT_REG(ihost_index)));
+			if ((last_scsi_type(ihost_index)[ldn] == IM_SCB) || (last_scsi_type(ihost_index)[ldn] == IM_LONG_SCB)) {
+				printk(KERN_ERR "              SCB-Command.................: %x\n", ld(ihost_index)[ldn].scb.command);
+				printk(KERN_ERR "              SCB-Enable..................: %x\n", ld(ihost_index)[ldn].scb.enable);
+				printk(KERN_ERR "              SCB-logical block address...: %lx\n", ld(ihost_index)[ldn].scb.u1.log_blk_adr);
+				printk(KERN_ERR "              SCB-system buffer address...: %lx\n", ld(ihost_index)[ldn].scb.sys_buf_adr);
+				printk(KERN_ERR "              SCB-system buffer length....: %lx\n", ld(ihost_index)[ldn].scb.sys_buf_length);
+				printk(KERN_ERR "              SCB-tsb address.............: %lx\n", ld(ihost_index)[ldn].scb.tsb_adr);
+				printk(KERN_ERR "              SCB-Chain address...........: %lx\n", ld(ihost_index)[ldn].scb.scb_chain_adr);
+				printk(KERN_ERR "              SCB-block count.............: %x\n", ld(ihost_index)[ldn].scb.u2.blk.count);
+				printk(KERN_ERR "              SCB-block length............: %x\n", ld(ihost_index)[ldn].scb.u2.blk.length);
+			}
+			printk(KERN_ERR "              Send this report to the maintainer.\n");
+			panic("IBM MCA SCSI: Fatal error message from the subsystem (0x%X,0x%X)!\n", lastSCSI, cmd_result);
+			break;
+		}
+	} else {
+		/* The command error handling is made silent, but we tell the
+		 * calling function, that there is a reported error from the
+		 * adapter. */
+		switch (cmd_result) {
+		case IM_ADAPTER_HW_FAILURE:
+		case IM_SOFTWARE_SEQUENCING_ERROR:
+		case IM_CMD_ERROR:
+			global_command_error_excuse = CMD_FAIL;
+			break;
+		default:
+			global_command_error_excuse = 0;
+			break;
+		}
+	}
+	/* if no panic appeared, increase the interrupt-counter */
+	IBM_DS(ihost_index).total_interrupts++;
+	/*only for local checking phase */
+	if (local_checking_phase_flag(ihost_index)) {
+		stat_result(ihost_index) = cmd_result;
+		got_interrupt(ihost_index) = 1;
+		reset_status(ihost_index) = IM_RESET_FINISHED_OK;
+		last_scsi_command(ihost_index)[ldn] = NO_SCSI;
+		spin_unlock(dev->host_lock);
+		return;
+	}
+	/* handling of commands coming from upper level of scsi driver */
+	if (last_scsi_type(ihost_index)[ldn] == IM_IMM_CMD) {
+		/* verify ldn, and may handle rare reset immediate command */
+		if ((reset_status(ihost_index) == IM_RESET_IN_PROGRESS) && (last_scsi_command(ihost_index)[ldn] == IM_RESET_IMM_CMD)) {
+			if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
+				disk_rw_in_progress = 0;
+				PS2_DISK_LED_OFF();
+				reset_status(ihost_index) = IM_RESET_FINISHED_FAIL;
+			} else {
+				/*reset disk led counter, turn off disk led */
+				disk_rw_in_progress = 0;
+				PS2_DISK_LED_OFF();
+				reset_status(ihost_index) = IM_RESET_FINISHED_OK;
+			}
+			stat_result(ihost_index) = cmd_result;
+			last_scsi_command(ihost_index)[ldn] = NO_SCSI;
+			last_scsi_type(ihost_index)[ldn] = 0;
+			spin_unlock(dev->host_lock);
+			return;
+		} else if (last_scsi_command(ihost_index)[ldn] == IM_ABORT_IMM_CMD) {
+			/* react on SCSI abort command */
 #ifdef IM_DEBUG_PROBE
-	 printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n");
+			printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n");
 #endif
-	 disk_rw_in_progress = 0;
-	 PS2_DISK_LED_OFF();
-	 cmd = ld(ihost_index)[ldn].cmd;
-	 ld(ihost_index)[ldn].cmd = NULL;
-	 if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
-	   cmd->result = DID_NO_CONNECT << 16;
-	 else
-	   cmd->result = DID_ABORT << 16;
-	 stat_result(ihost_index) = cmd_result;
-	 last_scsi_command(ihost_index)[ldn] = NO_SCSI;
-	 last_scsi_type(ihost_index)[ldn] = 0;
-	 if (cmd->scsi_done)
-	   (cmd->scsi_done)(cmd); /* should be the internal_done */
-	 return;
-      } else {
-	 disk_rw_in_progress = 0;
-	 PS2_DISK_LED_OFF ();
-	 reset_status(ihost_index) = IM_RESET_FINISHED_OK;
-	 stat_result(ihost_index) = cmd_result;
-	 last_scsi_command(ihost_index)[ldn] = NO_SCSI;
-	 return;
-      }
-   }
-   last_scsi_command(ihost_index)[ldn] = NO_SCSI;
-   last_scsi_type(ihost_index)[ldn] = 0;
-   cmd = ld(ihost_index)[ldn].cmd;
-   ld(ihost_index)[ldn].cmd = NULL;
+			disk_rw_in_progress = 0;
+			PS2_DISK_LED_OFF();
+			cmd = ld(ihost_index)[ldn].cmd;
+			ld(ihost_index)[ldn].cmd = NULL;
+			if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
+				cmd->result = DID_NO_CONNECT << 16;
+			else
+				cmd->result = DID_ABORT << 16;
+			stat_result(ihost_index) = cmd_result;
+			last_scsi_command(ihost_index)[ldn] = NO_SCSI;
+			last_scsi_type(ihost_index)[ldn] = 0;
+			if (cmd->scsi_done)
+				(cmd->scsi_done) (cmd);	/* should be the internal_done */
+			spin_unlock(dev->host_lock);
+			return;
+		} else {
+			disk_rw_in_progress = 0;
+			PS2_DISK_LED_OFF();
+			reset_status(ihost_index) = IM_RESET_FINISHED_OK;
+			stat_result(ihost_index) = cmd_result;
+			last_scsi_command(ihost_index)[ldn] = NO_SCSI;
+			spin_unlock(dev->host_lock);
+			return;
+		}
+	}
+	last_scsi_command(ihost_index)[ldn] = NO_SCSI;
+	last_scsi_type(ihost_index)[ldn] = 0;
+	cmd = ld(ihost_index)[ldn].cmd;
+	ld(ihost_index)[ldn].cmd = NULL;
 #ifdef IM_DEBUG_TIMEOUT
-   if (cmd) {
-      if ((cmd->target == TIMEOUT_PUN)&&(cmd->lun == TIMEOUT_LUN)) {
-	 printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n",
-		cmd->target, cmd->lun);
-	 return;
-      }
-   }
+	if (cmd) {
+		if ((cmd->target == TIMEOUT_PUN) && (cmd->lun == TIMEOUT_LUN)) {
+			printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n", cmd->target, cmd->lun);
+			return;
+		}
+	}
 #endif
-   /*if no command structure, just return, else clear cmd */
-   if (!cmd) return;
+	/*if no command structure, just return, else clear cmd */
+	if (!cmd)
+	{
+		spin_unlock(dev->host_lock);
+		return;
+	}
 
 #ifdef IM_DEBUG_INT
-   printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n",
-	  cmd->cmnd[0], intr_reg,
-	  ld(ihost_index)[ldn].tsb.dev_status,
-	  ld(ihost_index)[ldn].tsb.cmd_status,
-	  ld(ihost_index)[ldn].tsb.dev_error,
-	  ld(ihost_index)[ldn].tsb.cmd_error);
-#endif
-   /*if this is end of media read/write, may turn off PS/2 disk led */
-   if ((ld(ihost_index)[ldn].device_type!=TYPE_NO_LUN)&&
-       (ld(ihost_index)[ldn].device_type!=TYPE_NO_DEVICE)) {
-      /* only access this, if there was a valid device addressed */
-      if (--disk_rw_in_progress == 0) PS2_DISK_LED_OFF ();
-   }
-
-   /* IBM describes the status-mask to be 0x1e, but this is not conform
-    * with SCSI-definition, I suppose, the reason for it is that IBM
-    * adapters do not support CMD_TERMINATED, TASK_SET_FULL and
-    * ACA_ACTIVE as returning statusbyte information. (ML) */
-   if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
-      cmd->result = (unsigned char)(ld(ihost_index)[ldn].tsb.dev_status & 0x1e);
-      IBM_DS(ihost_index).total_errors++;
-   } else
-     cmd->result = 0;
-   /* write device status into cmd->result, and call done function */
-   if (lastSCSI == NO_SCSI) { /* unexpected interrupt :-( */
-      cmd->result |= DID_BAD_INTR << 16;
-      printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n");
-   } else /* things went right :-) */
-     cmd->result |= DID_OK << 16;
-   if (cmd->scsi_done) (cmd->scsi_done)(cmd);
-   return;
-}
-
-static void issue_cmd (int host_index, unsigned long cmd_reg,
-		       unsigned char attn_reg)
-{
-   unsigned long flags;
-   /* must wait for attention reg not busy */
-   while (1) {
-      IBMLOCK(hosts[host_index])
-      if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY)) break;
-      IBMUNLOCK(hosts[host_index])
-   }
-   /* write registers and enable system interrupts */
-   outl (cmd_reg, IM_CMD_REG(host_index));
-   outb (attn_reg, IM_ATTN_REG(host_index));
-   IBMUNLOCK(hosts[host_index])
-   return;
+	printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", cmd->cmnd[0], intr_reg, ld(ihost_index)[ldn].tsb.dev_status, ld(ihost_index)[ldn].tsb.cmd_status, ld(ihost_index)[ldn].tsb.dev_error, ld(ihost_index)[ldn].tsb.cmd_error);
+#endif
+	/*if this is end of media read/write, may turn off PS/2 disk led */
+	if ((ld(ihost_index)[ldn].device_type != TYPE_NO_LUN) && (ld(ihost_index)[ldn].device_type != TYPE_NO_DEVICE)) {
+		/* only access this, if there was a valid device addressed */
+		if (--disk_rw_in_progress == 0)
+			PS2_DISK_LED_OFF();
+	}
+
+	/* IBM describes the status-mask to be 0x1e, but this is not conform
+	 * with SCSI-definition, I suppose, the reason for it is that IBM
+	 * adapters do not support CMD_TERMINATED, TASK_SET_FULL and
+	 * ACA_ACTIVE as returning statusbyte information. (ML) */
+	if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
+		cmd->result = (unsigned char) (ld(ihost_index)[ldn].tsb.dev_status & 0x1e);
+		IBM_DS(ihost_index).total_errors++;
+	} else
+		cmd->result = 0;
+	/* write device status into cmd->result, and call done function */
+	if (lastSCSI == NO_SCSI) {	/* unexpected interrupt :-( */
+		cmd->result |= DID_BAD_INTR << 16;
+		printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n");
+	} else			/* things went right :-) */
+		cmd->result |= DID_OK << 16;
+	if (cmd->scsi_done)
+		(cmd->scsi_done) (cmd);
+	spin_unlock(dev->host_lock);
+	return;
+}
+
+static void issue_cmd(int host_index, unsigned long cmd_reg, unsigned char attn_reg)
+{
+	unsigned long flags;
+	/* must wait for attention reg not busy */
+	while (1) {
+		spin_lock_irqsave(hosts[host_index]->host_lock, flags);
+		if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+			break;
+		spin_unlock_irqrestore(hosts[host_index]->host_lock, flags);
+	}
+	/* write registers and enable system interrupts */
+	outl(cmd_reg, IM_CMD_REG(host_index));
+	outb(attn_reg, IM_ATTN_REG(host_index));
+	spin_unlock_irqrestore(hosts[host_index]->host_lock, flags);
 }
 
-static void internal_done (Scsi_Cmnd * cmd)
+static void internal_done(Scsi_Cmnd * cmd)
 {
-   cmd->SCp.Status++;
-   return;
+	cmd->SCp.Status++;
+	return;
 }
 
 /* SCSI-SCB-command for device_inquiry */
 static int device_inquiry(int host_index, int ldn)
 {
-   int retr;
-   struct im_scb *scb;
-   struct im_tsb *tsb;
-   unsigned char *buf;
-
-   scb = &(ld(host_index)[ldn].scb);
-   tsb = &(ld(host_index)[ldn].tsb);
-   buf = (unsigned char *)(&(ld(host_index)[ldn].buf));
-   ld(host_index)[ldn].tsb.dev_status = 0; /* prepare statusblock */
-   for (retr=0; retr<3; retr++) {
-      /* fill scb with inquiry command */
-      scb->command = IM_DEVICE_INQUIRY_CMD | IM_NO_DISCONNECT;
-      scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
-      last_scsi_command(host_index)[ldn] = IM_DEVICE_INQUIRY_CMD;
-      last_scsi_type(host_index)[ldn] = IM_SCB;
-      scb->sys_buf_adr = isa_virt_to_bus(buf);
-      scb->sys_buf_length = 255; /* maximum bufferlength gives max info */
-      scb->tsb_adr = isa_virt_to_bus(tsb);
-      /* issue scb to passed ldn, and busy wait for interrupt */
-      got_interrupt(host_index) = 0;
-      issue_cmd (host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
-      while (!got_interrupt(host_index))
-	barrier ();
-
-      /*if command succesful, break */
-      if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)||
-	  (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
-	return 1;
-   }
-   /*if all three retries failed, return "no device at this ldn" */
-   if (retr >= 3)
-     return 0;
-   else
-     return 1;
+	int retr;
+	struct im_scb *scb;
+	struct im_tsb *tsb;
+	unsigned char *buf;
+
+	scb = &(ld(host_index)[ldn].scb);
+	tsb = &(ld(host_index)[ldn].tsb);
+	buf = (unsigned char *) (&(ld(host_index)[ldn].buf));
+	ld(host_index)[ldn].tsb.dev_status = 0;	/* prepare statusblock */
+	for (retr = 0; retr < 3; retr++) {
+		/* fill scb with inquiry command */
+		scb->command = IM_DEVICE_INQUIRY_CMD | IM_NO_DISCONNECT;
+		scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
+		last_scsi_command(host_index)[ldn] = IM_DEVICE_INQUIRY_CMD;
+		last_scsi_type(host_index)[ldn] = IM_SCB;
+		scb->sys_buf_adr = isa_virt_to_bus(buf);
+		scb->sys_buf_length = 255;	/* maximum bufferlength gives max info */
+		scb->tsb_adr = isa_virt_to_bus(tsb);
+		/* issue scb to passed ldn, and busy wait for interrupt */
+		got_interrupt(host_index) = 0;
+		issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
+		while (!got_interrupt(host_index))
+			barrier();
+
+		/*if command succesful, break */
+		if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+			return 1;
+	}
+	/*if all three retries failed, return "no device at this ldn" */
+	if (retr >= 3)
+		return 0;
+	else
+		return 1;
 }
 
 static int read_capacity(int host_index, int ldn)
 {
-   int retr;
-   struct im_scb *scb;
-   struct im_tsb *tsb;
-   unsigned char *buf;
-
-   scb = &(ld(host_index)[ldn].scb);
-   tsb = &(ld(host_index)[ldn].tsb);
-   buf = (unsigned char *)(&(ld(host_index)[ldn].buf));
-   ld(host_index)[ldn].tsb.dev_status = 0;
-   for (retr=0; retr<3; retr++) {
-      /*fill scb with read capacity command */
-      scb->command = IM_READ_CAPACITY_CMD;
-      scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
-      last_scsi_command(host_index)[ldn] = IM_READ_CAPACITY_CMD;
-      last_scsi_type(host_index)[ldn] = IM_SCB;
-      scb->sys_buf_adr = isa_virt_to_bus(buf);
-      scb->sys_buf_length = 8;
-      scb->tsb_adr = isa_virt_to_bus(tsb);
-      /*issue scb to passed ldn, and busy wait for interrupt */
-      got_interrupt(host_index) = 0;
-      issue_cmd (host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
-      while (!got_interrupt(host_index))
-	barrier ();
-
-      /*if got capacity, get block length and return one device found */
-      if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)||
-	  (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
-	return 1;
-   }
-   /*if all three retries failed, return "no device at this ldn" */
-   if (retr >= 3)
-     return 0;
-   else
-     return 1;
+	int retr;
+	struct im_scb *scb;
+	struct im_tsb *tsb;
+	unsigned char *buf;
+
+	scb = &(ld(host_index)[ldn].scb);
+	tsb = &(ld(host_index)[ldn].tsb);
+	buf = (unsigned char *) (&(ld(host_index)[ldn].buf));
+	ld(host_index)[ldn].tsb.dev_status = 0;
+	for (retr = 0; retr < 3; retr++) {
+		/*fill scb with read capacity command */
+		scb->command = IM_READ_CAPACITY_CMD;
+		scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
+		last_scsi_command(host_index)[ldn] = IM_READ_CAPACITY_CMD;
+		last_scsi_type(host_index)[ldn] = IM_SCB;
+		scb->sys_buf_adr = isa_virt_to_bus(buf);
+		scb->sys_buf_length = 8;
+		scb->tsb_adr = isa_virt_to_bus(tsb);
+		/*issue scb to passed ldn, and busy wait for interrupt */
+		got_interrupt(host_index) = 0;
+		issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
+		while (!got_interrupt(host_index))
+			barrier();
+
+		/*if got capacity, get block length and return one device found */
+		if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+			return 1;
+	}
+	/*if all three retries failed, return "no device at this ldn" */
+	if (retr >= 3)
+		return 0;
+	else
+		return 1;
 }
 
 static int get_pos_info(int host_index)
 {
-   int retr;
-   struct im_scb *scb;
-   struct im_tsb *tsb;
-   unsigned char *buf;
-
-   scb = &(ld(host_index)[MAX_LOG_DEV].scb);
-   tsb = &(ld(host_index)[MAX_LOG_DEV].tsb);
-   buf = (unsigned char *)(&(ld(host_index)[MAX_LOG_DEV].buf));
-   ld(host_index)[MAX_LOG_DEV].tsb.dev_status = 0;
-   for (retr=0; retr<3; retr++) {
-      /*fill scb with get_pos_info command */
-      scb->command = IM_GET_POS_INFO_CMD;
-      scb->enable = IM_READ_CONTROL | IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
-      last_scsi_command(host_index)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD;
-      last_scsi_type(host_index)[MAX_LOG_DEV] = IM_SCB;
-      scb->sys_buf_adr = isa_virt_to_bus(buf);
-      if (special(host_index)==IBM_SCSI2_FW)
-	scb->sys_buf_length = 256; /* get all info from F/W adapter */
-      else
-	scb->sys_buf_length = 18; /* get exactly 18 bytes for other SCSI */
-      scb->tsb_adr = isa_virt_to_bus(tsb);
-      /*issue scb to ldn=15, and busy wait for interrupt */
-      got_interrupt(host_index) = 0;
-      issue_cmd (host_index, isa_virt_to_bus(scb), IM_SCB | MAX_LOG_DEV);
-      while (!got_interrupt(host_index))
-	barrier ();
-
-      /*if got POS-stuff, get block length and return one device found */
-      if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED)||
-	  (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
-	return 1;
-   }
-   /* if all three retries failed, return "no device at this ldn" */
-   if (retr >= 3)
-     return 0;
-   else
-     return 1;
+	int retr;
+	struct im_scb *scb;
+	struct im_tsb *tsb;
+	unsigned char *buf;
+
+	scb = &(ld(host_index)[MAX_LOG_DEV].scb);
+	tsb = &(ld(host_index)[MAX_LOG_DEV].tsb);
+	buf = (unsigned char *) (&(ld(host_index)[MAX_LOG_DEV].buf));
+	ld(host_index)[MAX_LOG_DEV].tsb.dev_status = 0;
+	for (retr = 0; retr < 3; retr++) {
+		/*fill scb with get_pos_info command */
+		scb->command = IM_GET_POS_INFO_CMD;
+		scb->enable = IM_READ_CONTROL | IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
+		last_scsi_command(host_index)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD;
+		last_scsi_type(host_index)[MAX_LOG_DEV] = IM_SCB;
+		scb->sys_buf_adr = isa_virt_to_bus(buf);
+		if (special(host_index) == IBM_SCSI2_FW)
+			scb->sys_buf_length = 256;	/* get all info from F/W adapter */
+		else
+			scb->sys_buf_length = 18;	/* get exactly 18 bytes for other SCSI */
+		scb->tsb_adr = isa_virt_to_bus(tsb);
+		/*issue scb to ldn=15, and busy wait for interrupt */
+		got_interrupt(host_index) = 0;
+		issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | MAX_LOG_DEV);
+		
+		/* FIXME: timeout */
+		while (!got_interrupt(host_index))
+			barrier();
+
+		/*if got POS-stuff, get block length and return one device found */
+		if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+			return 1;
+	}
+	/* if all three retries failed, return "no device at this ldn" */
+	if (retr >= 3)
+		return 0;
+	else
+		return 1;
 }
 
 /* SCSI-immediate-command for assign. This functions maps/unmaps specific
  ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the
  subsystem and for dynamical remapping od ldns. */
-static int immediate_assign(int host_index, unsigned int pun,
-                            unsigned int lun, unsigned int ldn,
-                            unsigned int operation)
-{
-   int retr;
-   unsigned long imm_cmd;
-
-   for (retr=0; retr<3; retr++) {
-      /* select mutation level of the SCSI-adapter */
-      switch (special(host_index)) {
-       case IBM_SCSI2_FW:
-	 imm_cmd = (unsigned long)(IM_ASSIGN_IMM_CMD);
-	 imm_cmd |= (unsigned long)((lun & 7) << 24);
-	 imm_cmd |= (unsigned long)((operation & 1) << 23);
-	 imm_cmd |= (unsigned long)((pun & 7)<< 20)|((pun & 8)<< 24);
-	 imm_cmd |= (unsigned long)((ldn & 15) << 16);
-	 break;
-       default:
-	 imm_cmd = inl(IM_CMD_REG(host_index));
-	 imm_cmd &= (unsigned long)(0xF8000000); /* keep reserved bits */
-	 imm_cmd |= (unsigned long)(IM_ASSIGN_IMM_CMD);
-	 imm_cmd |= (unsigned long)((lun & 7) << 24);
-	 imm_cmd |= (unsigned long)((operation & 1) << 23);
-	 imm_cmd |= (unsigned long)((pun & 7) << 20);
-	 imm_cmd |= (unsigned long)((ldn & 15) << 16);
-	 break;
-      }
-      last_scsi_command(host_index)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD;
-      last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
-      got_interrupt(host_index) = 0;
-      issue_cmd (host_index, (unsigned long)(imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
-      while (!got_interrupt(host_index))
-	barrier ();
-
-      /*if command succesful, break */
-      if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
-	return 1;
-   }
-   if (retr >= 3)
-     return 0;
-   else
-     return 1;
-}
-
-static int immediate_feature(int host_index, unsigned int speed,
-			     unsigned int timeout)
-{
-   int retr;
-   unsigned long imm_cmd;
-
-   for (retr=0; retr<3; retr++) {
-      /* select mutation level of the SCSI-adapter */
-      imm_cmd  = IM_FEATURE_CTR_IMM_CMD;
-      imm_cmd |= (unsigned long)((speed & 0x7) << 29);
-      imm_cmd |= (unsigned long)((timeout & 0x1fff) << 16);
-      last_scsi_command(host_index)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD;
-      last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
-      got_interrupt(host_index) = 0;
-      /* we need to run into command errors in order to probe for the
-       * right speed! */
-      global_command_error_excuse = 1;
-      issue_cmd (host_index, (unsigned long)(imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
-      while (!got_interrupt(host_index))
-	barrier ();
-      if (global_command_error_excuse == CMD_FAIL) {
-	 global_command_error_excuse = 0;
-	 return 2;
-      } else
-	global_command_error_excuse = 0;
-      /*if command succesful, break */
-      if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
-	return 1;
-   }
-   if (retr >= 3)
-     return 0;
-   else
-     return 1;
+static int immediate_assign(int host_index, unsigned int pun, unsigned int lun, unsigned int ldn, unsigned int operation)
+{
+	int retr;
+	unsigned long imm_cmd;
+
+	for (retr = 0; retr < 3; retr++) {
+		/* select mutation level of the SCSI-adapter */
+		switch (special(host_index)) {
+		case IBM_SCSI2_FW:
+			imm_cmd = (unsigned long) (IM_ASSIGN_IMM_CMD);
+			imm_cmd |= (unsigned long) ((lun & 7) << 24);
+			imm_cmd |= (unsigned long) ((operation & 1) << 23);
+			imm_cmd |= (unsigned long) ((pun & 7) << 20) | ((pun & 8) << 24);
+			imm_cmd |= (unsigned long) ((ldn & 15) << 16);
+			break;
+		default:
+			imm_cmd = inl(IM_CMD_REG(host_index));
+			imm_cmd &= (unsigned long) (0xF8000000);	/* keep reserved bits */
+			imm_cmd |= (unsigned long) (IM_ASSIGN_IMM_CMD);
+			imm_cmd |= (unsigned long) ((lun & 7) << 24);
+			imm_cmd |= (unsigned long) ((operation & 1) << 23);
+			imm_cmd |= (unsigned long) ((pun & 7) << 20);
+			imm_cmd |= (unsigned long) ((ldn & 15) << 16);
+			break;
+		}
+		last_scsi_command(host_index)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD;
+		last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
+		got_interrupt(host_index) = 0;
+		issue_cmd(host_index, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
+		while (!got_interrupt(host_index))
+			barrier();
+
+		/*if command succesful, break */
+		if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+			return 1;
+	}
+	if (retr >= 3)
+		return 0;
+	else
+		return 1;
+}
+
+static int immediate_feature(int host_index, unsigned int speed, unsigned int timeout)
+{
+	int retr;
+	unsigned long imm_cmd;
+
+	for (retr = 0; retr < 3; retr++) {
+		/* select mutation level of the SCSI-adapter */
+		imm_cmd = IM_FEATURE_CTR_IMM_CMD;
+		imm_cmd |= (unsigned long) ((speed & 0x7) << 29);
+		imm_cmd |= (unsigned long) ((timeout & 0x1fff) << 16);
+		last_scsi_command(host_index)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD;
+		last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
+		got_interrupt(host_index) = 0;
+		/* we need to run into command errors in order to probe for the
+		 * right speed! */
+		global_command_error_excuse = 1;
+		issue_cmd(host_index, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
+		
+		/* FIXME: timeout */
+		while (!got_interrupt(host_index))
+			barrier();
+		if (global_command_error_excuse == CMD_FAIL) {
+			global_command_error_excuse = 0;
+			return 2;
+		} else
+			global_command_error_excuse = 0;
+		/*if command succesful, break */
+		if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+			return 1;
+	}
+	if (retr >= 3)
+		return 0;
+	else
+		return 1;
 }
 
 #ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
 static int immediate_reset(int host_index, unsigned int ldn)
 {
-   int retries;
-   int ticks;
-   unsigned long imm_command;
-
-   for (retries=0; retries<3; retries ++) {
-      imm_command = inl(IM_CMD_REG(host_index));
-      imm_command &= (unsigned long)(0xFFFF0000); /* keep reserved bits */
-      imm_command |= (unsigned long)(IM_RESET_IMM_CMD);
-      last_scsi_command(host_index)[ldn] = IM_RESET_IMM_CMD;
-      last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
-      got_interrupt(host_index) = 0;
-      reset_status(host_index) = IM_RESET_IN_PROGRESS;
-      issue_cmd (host_index, (unsigned long)(imm_command), IM_IMM_CMD | ldn);
-      ticks = IM_RESET_DELAY*HZ;
-      while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks) {
-	 udelay((1+999/HZ)*1000);
-	 barrier();
-      }
-      /* if reset did not complete, just complain */
-      if (!ticks) {
-	 printk("IBM MCA SCSI: reset did not complete within %d seconds.\n",
-		IM_RESET_DELAY);
-	 reset_status(host_index) = IM_RESET_FINISHED_OK;
-	 /* did not work, finish */
-	 return 1;
-      }
-      /*if command succesful, break */
-      if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
-	return 1;
-   }
-   if (retries >= 3)
-     return 0;
-   else
-     return 1;
+	int retries;
+	int ticks;
+	unsigned long imm_command;
+
+	for (retries = 0; retries < 3; retries++) {
+		imm_command = inl(IM_CMD_REG(host_index));
+		imm_command &= (unsigned long) (0xFFFF0000);	/* keep reserved bits */
+		imm_command |= (unsigned long) (IM_RESET_IMM_CMD);
+		last_scsi_command(host_index)[ldn] = IM_RESET_IMM_CMD;
+		last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
+		got_interrupt(host_index) = 0;
+		reset_status(host_index) = IM_RESET_IN_PROGRESS;
+		issue_cmd(host_index, (unsigned long) (imm_command), IM_IMM_CMD | ldn);
+		ticks = IM_RESET_DELAY * HZ;
+		while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks) {
+			udelay((1 + 999 / HZ) * 1000);
+			barrier();
+		}
+		/* if reset did not complete, just complain */
+		if (!ticks) {
+			printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY);
+			reset_status(host_index) = IM_RESET_FINISHED_OK;
+			/* did not work, finish */
+			return 1;
+		}
+		/*if command succesful, break */
+		if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+			return 1;
+	}
+	if (retries >= 3)
+		return 0;
+	else
+		return 1;
 }
 #endif
 
 /* type-interpreter for physical device numbers */
 static char *ti_p(int dev)
 {
-   switch (dev) {
-    case TYPE_IBM_SCSI_ADAPTER: return("A");
-    case TYPE_DISK:             return("D");
-    case TYPE_TAPE:             return("T");
-    case TYPE_PROCESSOR:        return("P");
-    case TYPE_WORM:             return("W");
-    case TYPE_ROM:              return("R");
-    case TYPE_SCANNER:          return("S");
-    case TYPE_MOD:              return("M");
-    case TYPE_MEDIUM_CHANGER:   return("C");
-    case TYPE_NO_LUN:           return("+"); /* show NO_LUN */
-   }
-   return("-"); /* TYPE_NO_DEVICE and others */
+	switch (dev) {
+	case TYPE_IBM_SCSI_ADAPTER:
+		return ("A");
+	case TYPE_DISK:
+		return ("D");
+	case TYPE_TAPE:
+		return ("T");
+	case TYPE_PROCESSOR:
+		return ("P");
+	case TYPE_WORM:
+		return ("W");
+	case TYPE_ROM:
+		return ("R");
+	case TYPE_SCANNER:
+		return ("S");
+	case TYPE_MOD:
+		return ("M");
+	case TYPE_MEDIUM_CHANGER:
+		return ("C");
+	case TYPE_NO_LUN:
+		return ("+");	/* show NO_LUN */
+	}
+	return ("-");		/* TYPE_NO_DEVICE and others */
 }
 
 /* interpreter for logical device numbers (ldn) */
 static char *ti_l(int val)
 {
-   const char hex[16] = "0123456789abcdef";
-   static char answer[2];
+	const char hex[16] = "0123456789abcdef";
+	static char answer[2];
 
-   answer[1] = (char)(0x0);
-   if (val<=MAX_LOG_DEV) answer[0] = hex[val]; else answer[0] = '-';
-   return (char *)&answer;
+	answer[1] = (char) (0x0);
+	if (val <= MAX_LOG_DEV)
+		answer[0] = hex[val];
+	else
+		answer[0] = '-';
+	return (char *) &answer;
 }
 
 /* transfers bitpattern of the feature command to values in MHz */
 static char *ibmrate(unsigned int speed, int i)
 {
-   switch (speed) {
-    case 0: return i ? "5.00" : "10.00";
-    case 1: return i ? "4.00" : "8.00";
-    case 2: return i ? "3.33" : "6.66";
-    case 3: return i ? "2.86" : "5.00";
-    case 4: return i ? "2.50" : "4.00";
-    case 5: return i ? "2.22" : "3.10";
-    case 6: return i ? "2.00" : "2.50";
-    case 7: return i ? "1.82" : "2.00";
-   }
-   return "---";
+	switch (speed) {
+	case 0:
+		return i ? "5.00" : "10.00";
+	case 1:
+		return i ? "4.00" : "8.00";
+	case 2:
+		return i ? "3.33" : "6.66";
+	case 3:
+		return i ? "2.86" : "5.00";
+	case 4:
+		return i ? "2.50" : "4.00";
+	case 5:
+		return i ? "2.22" : "3.10";
+	case 6:
+		return i ? "2.00" : "2.50";
+	case 7:
+		return i ? "1.82" : "2.00";
+	}
+	return "---";
 }
 
 static int probe_display(int what)
 {
-   static int rotator = 0;
-   const char rotor[] = "|/-\\";
+	static int rotator = 0;
+	const char rotor[] = "|/-\\";
 
-   if (!(display_mode & LED_DISP))
-     return 0;
-   if (!what) {
-      outl(0x20202020,MOD95_LED_PORT);
-      outl(0x20202020,MOD95_LED_PORT+4);
-   } else {
-      outb('S',MOD95_LED_PORT+7); outb('C',MOD95_LED_PORT+6);
-      outb('S',MOD95_LED_PORT+5); outb('I',MOD95_LED_PORT+4);
-      outb('i',MOD95_LED_PORT+3); outb('n',MOD95_LED_PORT+2);
-      outb('i',MOD95_LED_PORT+1); outb((char)(rotor[rotator]),MOD95_LED_PORT);
-      rotator++;
-      if (rotator>3) rotator=0;
-   }
-   return 0;
+	if (!(display_mode & LED_DISP))
+		return 0;
+	if (!what) {
+		outl(0x20202020, MOD95_LED_PORT);
+		outl(0x20202020, MOD95_LED_PORT + 4);
+	} else {
+		outb('S', MOD95_LED_PORT + 7);
+		outb('C', MOD95_LED_PORT + 6);
+		outb('S', MOD95_LED_PORT + 5);
+		outb('I', MOD95_LED_PORT + 4);
+		outb('i', MOD95_LED_PORT + 3);
+		outb('n', MOD95_LED_PORT + 2);
+		outb('i', MOD95_LED_PORT + 1);
+		outb((char) (rotor[rotator]), MOD95_LED_PORT);
+		rotator++;
+		if (rotator > 3)
+			rotator = 0;
+	}
+	return 0;
 }
 
 static int probe_bus_mode(int host_index)
 {
-   struct im_pos_info *info;
-   int num_bus = 0;
-   int ldn;
-
-   info = (struct im_pos_info *)(&(ld(host_index)[MAX_LOG_DEV].buf));
-   if (get_pos_info(host_index)) {
-      if (info->connector_size & 0xf000)
-	subsystem_connector_size(host_index)=16;
-      else
-	subsystem_connector_size(host_index)=32;
-      num_bus |= (info->pos_4b & 8) >> 3;
-      for (ldn=0; ldn<=MAX_LOG_DEV; ldn++) {
-	 if ((special(host_index)==IBM_SCSI_WCACHE)||
-	     (special(host_index)==IBM_7568_WCACHE)) {
-	    if (!((info->cache_stat >> ldn) & 1))
-	      ld(host_index)[ldn].cache_flag = 0;
-	 }
-	 if (!((info->retry_stat >> ldn) & 1))
-	   ld(host_index)[ldn].retry_flag = 0;
-      }
+	struct im_pos_info *info;
+	int num_bus = 0;
+	int ldn;
+
+	info = (struct im_pos_info *) (&(ld(host_index)[MAX_LOG_DEV].buf));
+	if (get_pos_info(host_index)) {
+		if (info->connector_size & 0xf000)
+			subsystem_connector_size(host_index) = 16;
+		else
+			subsystem_connector_size(host_index) = 32;
+		num_bus |= (info->pos_4b & 8) >> 3;
+		for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
+			if ((special(host_index) == IBM_SCSI_WCACHE) || (special(host_index) == IBM_7568_WCACHE)) {
+				if (!((info->cache_stat >> ldn) & 1))
+					ld(host_index)[ldn].cache_flag = 0;
+			}
+			if (!((info->retry_stat >> ldn) & 1))
+				ld(host_index)[ldn].retry_flag = 0;
+		}
 #ifdef IM_DEBUG_PROBE
-      printk("IBM MCA SCSI: SCSI-Cache bits: ");
-      for (ldn=0; ldn<=MAX_LOG_DEV; ldn++) {
-	 printk("%d",ld(host_index)[ldn].cache_flag);
-      }
-      printk("\nIBM MCA SCSI: SCSI-Retry bits: ");
-      for (ldn=0; ldn<=MAX_LOG_DEV; ldn++) {
-	 printk("%d",ld(host_index)[ldn].retry_flag);
-      }
-      printk("\n");
+		printk("IBM MCA SCSI: SCSI-Cache bits: ");
+		for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
+			printk("%d", ld(host_index)[ldn].cache_flag);
+		}
+		printk("\nIBM MCA SCSI: SCSI-Retry bits: ");
+		for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
+			printk("%d", ld(host_index)[ldn].retry_flag);
+		}
+		printk("\n");
 #endif
-   }
-   return num_bus;
+	}
+	return num_bus;
 }
 
 /* probing scsi devices */
-static void check_devices (int host_index, int adaptertype)
+static void check_devices(int host_index, int adaptertype)
 {
-   int id, lun, ldn, ticks;
-   int count_devices; /* local counter for connected device */
-   int max_pun;
-   int num_bus;
-   int speedrun; /* local adapter_speed check variable */
-
-   /* assign default values to certain variables */
-   ticks = 0;
-   count_devices = 0;
-   IBM_DS(host_index).dyn_flag = 0; /* normally no need for dynamical ldn management */
-   IBM_DS(host_index).total_errors = 0; /* set errorcounter to 0 */
-   next_ldn(host_index) = 7; /* next ldn to be assigned is 7, because 0-6 is 'hardwired'*/
-
-   /* initialize the very important driver-informational arrays/structs */
-   memset (ld(host_index), 0, sizeof(ld(host_index)));
-   for (ldn=0; ldn<=MAX_LOG_DEV; ldn++) {
-      last_scsi_command(host_index)[ldn] = NO_SCSI; /* emptify last SCSI-command storage */
-      last_scsi_type(host_index)[ldn] = 0;
-      ld(host_index)[ldn].cache_flag = 1;
-      ld(host_index)[ldn].retry_flag = 1;
-   }
-   memset (get_ldn(host_index), TYPE_NO_DEVICE, sizeof(get_ldn(host_index))); /* this is essential ! */
-   memset (get_scsi(host_index), TYPE_NO_DEVICE, sizeof(get_scsi(host_index))); /* this is essential ! */
-   for (lun=0; lun<8; lun++) {
-      /* mark the adapter at its pun on all luns*/
-      get_scsi(host_index)[subsystem_pun(host_index)][lun] = TYPE_IBM_SCSI_ADAPTER;
-      get_ldn(host_index)[subsystem_pun(host_index)][lun] = MAX_LOG_DEV; /* make sure, the subsystem
-									  ldn is active for all
-									  luns. */
-   }
-   probe_display(0); /* Supercool display usage during SCSI-probing. */
-                     /* This makes sense, when booting without any */
-                     /* monitor connected on model XX95. */
-
-   /* STEP 1: */
-   adapter_speed(host_index) = global_adapter_speed;
-   speedrun = adapter_speed(host_index);
-   while (immediate_feature(host_index,speedrun,adapter_timeout)==2) {
-      probe_display(1);
-      if (speedrun==7)
-	panic("IBM MCA SCSI: Cannot set Synchronous-Transfer-Rate!\n");
-      speedrun++;
-      if (speedrun>7)
-	speedrun=7;
-   }
-   adapter_speed(host_index) = speedrun;
-   /* Get detailed information about the current adapter, necessary for
-    * device operations: */
-   num_bus=probe_bus_mode(host_index);
-
-   /* num_bus contains only valid data for the F/W adapter! */
-   if (adaptertype==IBM_SCSI2_FW) { /* F/W SCSI adapter: */
-      /* F/W adapter PUN-space extension evaluation: */
-      if (num_bus) {
-	 printk("IBM MCA SCSI: Seperate bus mode (wide-addressing enabled)\n");
-	 subsystem_maxid(host_index) = 16;
-      }	else {
-	 printk("IBM MCA SCSI: Combined bus mode (wide-addressing disabled)\n");
-	 subsystem_maxid(host_index) = 8;
-      }
-      printk("IBM MCA SCSI: Sync.-Rate (F/W: 20, Int.: 10, Ext.: %s) MBytes/s\n",
-	     ibmrate(speedrun,adaptertype));
-   } else /* all other IBM SCSI adapters: */
-     printk("IBM MCA SCSI: Synchronous-SCSI-Transfer-Rate: %s MBytes/s\n",
-	    ibmrate(speedrun,adaptertype));
+	int id, lun, ldn, ticks;
+	int count_devices;	/* local counter for connected device */
+	int max_pun;
+	int num_bus;
+	int speedrun;		/* local adapter_speed check variable */
+
+	/* assign default values to certain variables */
+	ticks = 0;
+	count_devices = 0;
+	IBM_DS(host_index).dyn_flag = 0;	/* normally no need for dynamical ldn management */
+	IBM_DS(host_index).total_errors = 0;	/* set errorcounter to 0 */
+	next_ldn(host_index) = 7;	/* next ldn to be assigned is 7, because 0-6 is 'hardwired' */
+
+	/* initialize the very important driver-informational arrays/structs */
+	memset(ld(host_index), 0, sizeof(ld(host_index)));
+	for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
+		last_scsi_command(host_index)[ldn] = NO_SCSI;	/* emptify last SCSI-command storage */
+		last_scsi_type(host_index)[ldn] = 0;
+		ld(host_index)[ldn].cache_flag = 1;
+		ld(host_index)[ldn].retry_flag = 1;
+	}
+	memset(get_ldn(host_index), TYPE_NO_DEVICE, sizeof(get_ldn(host_index)));	/* this is essential ! */
+	memset(get_scsi(host_index), TYPE_NO_DEVICE, sizeof(get_scsi(host_index)));	/* this is essential ! */
+	for (lun = 0; lun < 8; lun++) {
+		/* mark the adapter at its pun on all luns */
+		get_scsi(host_index)[subsystem_pun(host_index)][lun] = TYPE_IBM_SCSI_ADAPTER;
+		get_ldn(host_index)[subsystem_pun(host_index)][lun] = MAX_LOG_DEV;	/* make sure, the subsystem
+											   ldn is active for all
+											   luns. */
+	}
+	probe_display(0);	/* Supercool display usage during SCSI-probing. */
+	/* This makes sense, when booting without any */
+	/* monitor connected on model XX95. */
+
+	/* STEP 1: */
+	adapter_speed(host_index) = global_adapter_speed;
+	speedrun = adapter_speed(host_index);
+	while (immediate_feature(host_index, speedrun, adapter_timeout) == 2) {
+		probe_display(1);
+		if (speedrun == 7)
+			panic("IBM MCA SCSI: Cannot set Synchronous-Transfer-Rate!\n");
+		speedrun++;
+		if (speedrun > 7)
+			speedrun = 7;
+	}
+	adapter_speed(host_index) = speedrun;
+	/* Get detailed information about the current adapter, necessary for
+	 * device operations: */
+	num_bus = probe_bus_mode(host_index);
+
+	/* num_bus contains only valid data for the F/W adapter! */
+	if (adaptertype == IBM_SCSI2_FW) {	/* F/W SCSI adapter: */
+		/* F/W adapter PUN-space extension evaluation: */
+		if (num_bus) {
+			printk(KERN_INFO "IBM MCA SCSI: Seperate bus mode (wide-addressing enabled)\n");
+			subsystem_maxid(host_index) = 16;
+		} else {
+			printk(KERN_INFO "IBM MCA SCSI: Combined bus mode (wide-addressing disabled)\n");
+			subsystem_maxid(host_index) = 8;
+		}
+		printk(KERN_INFO "IBM MCA SCSI: Sync.-Rate (F/W: 20, Int.: 10, Ext.: %s) MBytes/s\n", ibmrate(speedrun, adaptertype));
+	} else			/* all other IBM SCSI adapters: */
+		printk(KERN_INFO "IBM MCA SCSI: Synchronous-SCSI-Transfer-Rate: %s MBytes/s\n", ibmrate(speedrun, adaptertype));
 
-   /* assign correct PUN device space */
-   max_pun = subsystem_maxid(host_index);
+	/* assign correct PUN device space */
+	max_pun = subsystem_maxid(host_index);
 
 #ifdef IM_DEBUG_PROBE
-   printk("IBM MCA SCSI: Current SCSI-host index: %d\n",host_index);
-   printk("IBM MCA SCSI: Removing default logical SCSI-device mapping.");
+	printk("IBM MCA SCSI: Current SCSI-host index: %d\n", host_index);
+	printk("IBM MCA SCSI: Removing default logical SCSI-device mapping.");
 #else
-   printk("IBM MCA SCSI: Dev. Order: %s, Mapping (takes <2min): ",
-	  (ibm_ansi_order) ? "ANSI" : "New");
+	printk(KERN_INFO "IBM MCA SCSI: Dev. Order: %s, Mapping (takes <2min): ", (ibm_ansi_order) ? "ANSI" : "New");
 #endif
-   for (ldn=0; ldn<MAX_LOG_DEV; ldn++) {
-      probe_display(1);
+	for (ldn = 0; ldn < MAX_LOG_DEV; ldn++) {
+		probe_display(1);
 #ifdef IM_DEBUG_PROBE
-      printk(".");
+		printk(".");
 #endif
-      immediate_assign(host_index,0,0,ldn,REMOVE_LDN); /* remove ldn (wherever)*/
-   }
-   lun = 0; /* default lun is 0 */
+		immediate_assign(host_index, 0, 0, ldn, REMOVE_LDN);	/* remove ldn (wherever) */
+	}
+	lun = 0;		/* default lun is 0 */
 #ifndef IM_DEBUG_PROBE
-   printk("cleared,");
+	printk("cleared,");
 #endif
-   /* STEP 2: */
+	/* STEP 2: */
 #ifdef IM_DEBUG_PROBE
-   printk("\nIBM MCA SCSI: Scanning SCSI-devices.");
+	printk("\nIBM MCA SCSI: Scanning SCSI-devices.");
 #endif
-   for (id=0; id<max_pun ; id++)
+	for (id = 0; id < max_pun; id++)
 #ifdef CONFIG_SCSI_MULTI_LUN
-     for (lun=0; lun<8; lun++)
+		for (lun = 0; lun < 8; lun++)
 #endif
-     {
-	probe_display(1);
+		{
+			probe_display(1);
 #ifdef IM_DEBUG_PROBE
-	printk(".");
+			printk(".");
 #endif
-	if (id != subsystem_pun(host_index)) {
-	   /* if pun is not the adapter: */
-	   /* set ldn=0 to pun,lun*/
-	   immediate_assign(host_index,id,lun,PROBE_LDN,SET_LDN);
-	   if (device_inquiry(host_index, PROBE_LDN)) { /* probe device */
-	      get_scsi(host_index)[id][lun]=
-		(unsigned char)(ld(host_index)[PROBE_LDN].buf[0]);
-	      /* entry, even for NO_LUN */
-	      if (ld(host_index)[PROBE_LDN].buf[0] != TYPE_NO_LUN)
-		count_devices++; /* a existing device is found */
-	   }
-	   /* remove ldn */
-	   immediate_assign(host_index,id,lun,PROBE_LDN,REMOVE_LDN);
-	}
-     }
+			if (id != subsystem_pun(host_index)) {
+				/* if pun is not the adapter: */
+				/* set ldn=0 to pun,lun */
+				immediate_assign(host_index, id, lun, PROBE_LDN, SET_LDN);
+				if (device_inquiry(host_index, PROBE_LDN)) {	/* probe device */
+					get_scsi(host_index)[id][lun] = (unsigned char) (ld(host_index)[PROBE_LDN].buf[0]);
+					/* entry, even for NO_LUN */
+					if (ld(host_index)[PROBE_LDN].buf[0] != TYPE_NO_LUN)
+						count_devices++;	/* a existing device is found */
+				}
+				/* remove ldn */
+				immediate_assign(host_index, id, lun, PROBE_LDN, REMOVE_LDN);
+			}
+		}
 #ifndef IM_DEBUG_PROBE
-   printk("scanned,");
+	printk("scanned,");
 #endif
-   /* STEP 3: */
+	/* STEP 3: */
 #ifdef IM_DEBUG_PROBE
-   printk("\nIBM MCA SCSI: Mapping SCSI-devices.");
+	printk("\nIBM MCA SCSI: Mapping SCSI-devices.");
 #endif
-   ldn = 0;
-   lun = 0;
+	ldn = 0;
+	lun = 0;
 #ifdef CONFIG_SCSI_MULTI_LUN
-   for (lun=0; lun<8 && ldn<MAX_LOG_DEV; lun++)
+	for (lun = 0; lun < 8 && ldn < MAX_LOG_DEV; lun++)
 #endif
-     for (id=0; id<max_pun && ldn<MAX_LOG_DEV; id++) {
-	probe_display(1);
+		for (id = 0; id < max_pun && ldn < MAX_LOG_DEV; id++) {
+			probe_display(1);
 #ifdef IM_DEBUG_PROBE
-	printk(".");
+			printk(".");
 #endif
-	if (id != subsystem_pun(host_index)) {
-	   if (get_scsi(host_index)[id][lun] != TYPE_NO_LUN &&
-	       get_scsi(host_index)[id][lun] != TYPE_NO_DEVICE) {
-	      /* Only map if accepted type. Always enter for
-	       lun == 0 to get no gaps into ldn-mapping for ldn<7. */
-	      immediate_assign(host_index,id,lun,ldn,SET_LDN);
-	      get_ldn(host_index)[id][lun]=ldn; /* map ldn */
-	      if (device_exists (host_index, ldn,
-				 &ld(host_index)[ldn].block_length,
-				 &ld(host_index)[ldn].device_type)) {
+			if (id != subsystem_pun(host_index)) {
+				if (get_scsi(host_index)[id][lun] != TYPE_NO_LUN && get_scsi(host_index)[id][lun] != TYPE_NO_DEVICE) {
+					/* Only map if accepted type. Always enter for
+					   lun == 0 to get no gaps into ldn-mapping for ldn<7. */
+					immediate_assign(host_index, id, lun, ldn, SET_LDN);
+					get_ldn(host_index)[id][lun] = ldn;	/* map ldn */
+					if (device_exists(host_index, ldn, &ld(host_index)[ldn].block_length, &ld(host_index)[ldn].device_type)) {
 #ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
-		 printk("resetting device at ldn=%x ... ",ldn);
-		 immediate_reset(host_index,ldn);
+						printk("resetting device at ldn=%x ... ", ldn);
+						immediate_reset(host_index, ldn);
 #endif
-		 ldn++;
-	      } else {
-		 /* device vanished, probably because we don't know how to
-		  * handle it or because it has problems */
-		 if (lun > 0) {
-		    /* remove mapping */
-		    get_ldn(host_index)[id][lun]=TYPE_NO_DEVICE;
-		    immediate_assign(host_index,0,0,ldn,REMOVE_LDN);
-		 } else ldn++;
-	      }
-	   } else if (lun == 0) {
-	      /* map lun == 0, even if no device exists */
-	      immediate_assign(host_index,id,lun,ldn,SET_LDN);
-	      get_ldn(host_index)[id][lun]=ldn; /* map ldn */
-	      ldn++;
-	   }
-	}
-     }
-   /* STEP 4: */
-
-   /* map remaining ldns to non-existing devices */
-   for (lun=1; lun<8 && ldn<MAX_LOG_DEV; lun++)
-     for (id=0; id<max_pun && ldn<MAX_LOG_DEV; id++) {
-	if (get_scsi(host_index)[id][lun] == TYPE_NO_LUN ||
-	    get_scsi(host_index)[id][lun] == TYPE_NO_DEVICE) {
-	   probe_display(1);
-	   /* Map remaining ldns only to NON-existing pun,lun
-	    combinations to make sure an inquiry will fail.
-	    For MULTI_LUN, it is needed to avoid adapter autonome
-	    SCSI-remapping. */
-	   immediate_assign(host_index,id,lun,ldn,SET_LDN);
-	   get_ldn(host_index)[id][lun]=ldn;
-	   ldn++;
-	}
-     }
+						ldn++;
+					} else {
+						/* device vanished, probably because we don't know how to
+						 * handle it or because it has problems */
+						if (lun > 0) {
+							/* remove mapping */
+							get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE;
+							immediate_assign(host_index, 0, 0, ldn, REMOVE_LDN);
+						} else
+							ldn++;
+					}
+				} else if (lun == 0) {
+					/* map lun == 0, even if no device exists */
+					immediate_assign(host_index, id, lun, ldn, SET_LDN);
+					get_ldn(host_index)[id][lun] = ldn;	/* map ldn */
+					ldn++;
+				}
+			}
+		}
+	/* STEP 4: */
+
+	/* map remaining ldns to non-existing devices */
+	for (lun = 1; lun < 8 && ldn < MAX_LOG_DEV; lun++)
+		for (id = 0; id < max_pun && ldn < MAX_LOG_DEV; id++) {
+			if (get_scsi(host_index)[id][lun] == TYPE_NO_LUN || get_scsi(host_index)[id][lun] == TYPE_NO_DEVICE) {
+				probe_display(1);
+				/* Map remaining ldns only to NON-existing pun,lun
+				   combinations to make sure an inquiry will fail.
+				   For MULTI_LUN, it is needed to avoid adapter autonome
+				   SCSI-remapping. */
+				immediate_assign(host_index, id, lun, ldn, SET_LDN);
+				get_ldn(host_index)[id][lun] = ldn;
+				ldn++;
+			}
+		}
 #ifndef IM_DEBUG_PROBE
-   printk("mapped.");
+	printk("mapped.");
 #endif
-   printk("\n");
+	printk("\n");
 #ifdef IM_DEBUG_PROBE
-   if (ibm_ansi_order)
-     printk("IBM MCA SCSI: Device order: IBM/ANSI (pun=7 is first).\n");
-   else
-     printk("IBM MCA SCSI: Device order: New Industry Standard (pun=0 is first).\n");
+	if (ibm_ansi_order)
+		printk("IBM MCA SCSI: Device order: IBM/ANSI (pun=7 is first).\n");
+	else
+		printk("IBM MCA SCSI: Device order: New Industry Standard (pun=0 is first).\n");
 #endif
 
 #ifdef IM_DEBUG_PROBE
-   /* Show the physical and logical mapping during boot. */
-   printk("IBM MCA SCSI: Determined SCSI-device-mapping:\n");
-   printk("    Physical SCSI-Device Map               Logical SCSI-Device Map\n");
-   printk("ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
-   for (id=0; id<max_pun; id++) {
-      printk("%2d     ",id);
-      for (lun=0; lun<8; lun++)
-	printk("%2s ",ti_p(get_scsi(host_index)[id][lun]));
-      printk("      %2d     ",id);
-      for (lun=0; lun<8; lun++)
-	printk("%2s ",ti_l(get_ldn(host_index)[id][lun]));
-      printk("\n");
-   }
-#endif
-
-   /* assign total number of found SCSI-devices to the statistics struct */
-   IBM_DS(host_index).total_scsi_devices = count_devices;
-
-   /* decide for output in /proc-filesystem, if the configuration of
-      SCSI-devices makes dynamical reassignment of devices necessary */
-   if (count_devices>=MAX_LOG_DEV)
-     IBM_DS(host_index).dyn_flag = 1; /* dynamical assignment is necessary */
-   else
-     IBM_DS(host_index).dyn_flag = 0; /* dynamical assignment is not necessary */
-
-   /* If no SCSI-devices are assigned, return 1 in order to cause message. */
-   if (ldn == 0)
-     printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n");
-
-   /* reset the counters for statistics on the current adapter */
-   IBM_DS(host_index).scbs = 0;
-   IBM_DS(host_index).long_scbs = 0;
-   IBM_DS(host_index).total_accesses = 0;
-   IBM_DS(host_index).total_interrupts = 0;
-   IBM_DS(host_index).dynamical_assignments = 0;
-   memset (IBM_DS(host_index).ldn_access, 0x0,
-	   sizeof (IBM_DS(host_index).ldn_access));
-   memset (IBM_DS(host_index).ldn_read_access, 0x0,
-	   sizeof (IBM_DS(host_index).ldn_read_access));
-   memset (IBM_DS(host_index).ldn_write_access, 0x0,
-	   sizeof (IBM_DS(host_index).ldn_write_access));
-   memset (IBM_DS(host_index).ldn_inquiry_access, 0x0,
-	   sizeof (IBM_DS(host_index).ldn_inquiry_access));
-   memset (IBM_DS(host_index).ldn_modeselect_access, 0x0,
-	   sizeof (IBM_DS(host_index).ldn_modeselect_access));
-   memset (IBM_DS(host_index).ldn_assignments, 0x0,
-	   sizeof (IBM_DS(host_index).ldn_assignments));
-   probe_display(0);
-   return;
-}
-
-static int device_exists (int host_index, int ldn, int *block_length,
-			  int *device_type)
-{
-   unsigned char *buf;
-   /* if no valid device found, return immediately with 0 */
-   if (!(device_inquiry(host_index, ldn)))
-     return 0;
-   buf = (unsigned char *)(&(ld(host_index)[ldn].buf));
-   if (*buf == TYPE_ROM) {
-      *device_type = TYPE_ROM;
-      *block_length = 2048; /* (standard blocksize for yellow-/red-book) */
-      return 1;
-   }
-   if (*buf == TYPE_WORM) {
-      *device_type = TYPE_WORM;
-      *block_length = 2048;
-      return 1;
-   }
-   if (*buf == TYPE_DISK) {
-      *device_type = TYPE_DISK;
-      if (read_capacity( host_index, ldn)) {
-	 *block_length = *(buf+7) + (*(buf+6) << 8) +
-	   (*(buf+5) << 16) + (*(buf+4) << 24);
-	 return 1;
-      } else
-	return 0;
-   }
-   if (*buf == TYPE_MOD) {
-      *device_type = TYPE_MOD;
-      if (read_capacity( host_index, ldn)) {
-	 *block_length = *(buf+7) + (*(buf+6) << 8) +
-	   (*(buf+5) << 16) + (*(buf+4) << 24);
-	 return 1;
-      } else
+	/* Show the physical and logical mapping during boot. */
+	printk("IBM MCA SCSI: Determined SCSI-device-mapping:\n");
+	printk("    Physical SCSI-Device Map               Logical SCSI-Device Map\n");
+	printk("ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
+	for (id = 0; id < max_pun; id++) {
+		printk("%2d     ", id);
+		for (lun = 0; lun < 8; lun++)
+			printk("%2s ", ti_p(get_scsi(host_index)[id][lun]));
+		printk("      %2d     ", id);
+		for (lun = 0; lun < 8; lun++)
+			printk("%2s ", ti_l(get_ldn(host_index)[id][lun]));
+		printk("\n");
+	}
+#endif
+
+	/* assign total number of found SCSI-devices to the statistics struct */
+	IBM_DS(host_index).total_scsi_devices = count_devices;
+
+	/* decide for output in /proc-filesystem, if the configuration of
+	   SCSI-devices makes dynamical reassignment of devices necessary */
+	if (count_devices >= MAX_LOG_DEV)
+		IBM_DS(host_index).dyn_flag = 1;	/* dynamical assignment is necessary */
+	else
+		IBM_DS(host_index).dyn_flag = 0;	/* dynamical assignment is not necessary */
+
+	/* If no SCSI-devices are assigned, return 1 in order to cause message. */
+	if (ldn == 0)
+		printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n");
+
+	/* reset the counters for statistics on the current adapter */
+	IBM_DS(host_index).scbs = 0;
+	IBM_DS(host_index).long_scbs = 0;
+	IBM_DS(host_index).total_accesses = 0;
+	IBM_DS(host_index).total_interrupts = 0;
+	IBM_DS(host_index).dynamical_assignments = 0;
+	memset(IBM_DS(host_index).ldn_access, 0x0, sizeof(IBM_DS(host_index).ldn_access));
+	memset(IBM_DS(host_index).ldn_read_access, 0x0, sizeof(IBM_DS(host_index).ldn_read_access));
+	memset(IBM_DS(host_index).ldn_write_access, 0x0, sizeof(IBM_DS(host_index).ldn_write_access));
+	memset(IBM_DS(host_index).ldn_inquiry_access, 0x0, sizeof(IBM_DS(host_index).ldn_inquiry_access));
+	memset(IBM_DS(host_index).ldn_modeselect_access, 0x0, sizeof(IBM_DS(host_index).ldn_modeselect_access));
+	memset(IBM_DS(host_index).ldn_assignments, 0x0, sizeof(IBM_DS(host_index).ldn_assignments));
+	probe_display(0);
+	return;
+}
+
+static int device_exists(int host_index, int ldn, int *block_length, int *device_type)
+{
+	unsigned char *buf;
+	/* if no valid device found, return immediately with 0 */
+	if (!(device_inquiry(host_index, ldn)))
+		return 0;
+	buf = (unsigned char *) (&(ld(host_index)[ldn].buf));
+	if (*buf == TYPE_ROM) {
+		*device_type = TYPE_ROM;
+		*block_length = 2048;	/* (standard blocksize for yellow-/red-book) */
+		return 1;
+	}
+	if (*buf == TYPE_WORM) {
+		*device_type = TYPE_WORM;
+		*block_length = 2048;
+		return 1;
+	}
+	if (*buf == TYPE_DISK) {
+		*device_type = TYPE_DISK;
+		if (read_capacity(host_index, ldn)) {
+			*block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24);
+			return 1;
+		} else
+			return 0;
+	}
+	if (*buf == TYPE_MOD) {
+		*device_type = TYPE_MOD;
+		if (read_capacity(host_index, ldn)) {
+			*block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24);
+			return 1;
+		} else
+			return 0;
+	}
+	if (*buf == TYPE_TAPE) {
+		*device_type = TYPE_TAPE;
+		*block_length = 0;	/* not in use (setting by mt and mtst in op.) */
+		return 1;
+	}
+	if (*buf == TYPE_PROCESSOR) {
+		*device_type = TYPE_PROCESSOR;
+		*block_length = 0;	/* they set their stuff on drivers */
+		return 1;
+	}
+	if (*buf == TYPE_SCANNER) {
+		*device_type = TYPE_SCANNER;
+		*block_length = 0;	/* they set their stuff on drivers */
+		return 1;
+	}
+	if (*buf == TYPE_MEDIUM_CHANGER) {
+		*device_type = TYPE_MEDIUM_CHANGER;
+		*block_length = 0;	/* One never knows, what to expect on a medium
+					   changer device. */
+		return 1;
+	}
 	return 0;
-   }
-   if (*buf == TYPE_TAPE) {
-      *device_type = TYPE_TAPE;
-      *block_length = 0; /* not in use (setting by mt and mtst in op.) */
-      return 1;
-   }
-   if (*buf == TYPE_PROCESSOR) {
-      *device_type = TYPE_PROCESSOR;
-      *block_length = 0; /* they set their stuff on drivers */
-      return 1;
-   }
-   if (*buf == TYPE_SCANNER) {
-      *device_type = TYPE_SCANNER;
-      *block_length = 0; /* they set their stuff on drivers */
-      return 1;
-   }
-   if (*buf == TYPE_MEDIUM_CHANGER) {
-      *device_type = TYPE_MEDIUM_CHANGER;
-      *block_length = 0; /* One never knows, what to expect on a medium
-			    changer device. */
-      return 1;
-   }
-   return 0;
-}
-
-void internal_ibmmca_scsi_setup (char *str, int *ints)
-{
-   int i, j, io_base, id_base;
-   char *token;
-
-   io_base = 0;
-   id_base = 0;
-   if (str) {
-      token = strtok(str,",");
-      j = 0;
-      while (token) {
-	 if (!strcmp(token,"activity")) display_mode |= LED_ACTIVITY;
-	 if (!strcmp(token,"display")) display_mode |= LED_DISP;
-	 if (!strcmp(token,"adisplay")) display_mode |= LED_ADISP;
-	 if (!strcmp(token,"normal")) ibm_ansi_order = 0;
-	 if (!strcmp(token,"ansi")) ibm_ansi_order = 1;
-	 if (!strcmp(token,"fast")) global_adapter_speed = 0;
-	 if (!strcmp(token,"medium")) global_adapter_speed = 4;
-	 if (!strcmp(token,"slow")) global_adapter_speed = 7;
-	 if ((*token == '-') || (isdigit(*token))) {
-	    if (!(j%2) && (io_base < IM_MAX_HOSTS))
-	      io_port[io_base++] = simple_strtoul(token,NULL,0);
-	    if ((j%2) && (id_base < IM_MAX_HOSTS))
-	      scsi_id[id_base++] = simple_strtoul(token,NULL,0);
-	    j++;
-	 }
-	 token = strtok(NULL,",");
-      }
-   } else if (ints) {
-      for (i = 0; i < IM_MAX_HOSTS && 2*i+2 < ints[0]; i++) {
-	 io_port[i] = ints[2*i+2];
-	 scsi_id[i] = ints[2*i+2];
-      }
-   }
-   return;
-}
-
-static int ibmmca_getinfo (char *buf, int slot, void *dev_id)
-{
-   struct Scsi_Host *shpnt;
-   int len, speciale, connectore, k;
-   unsigned int pos[8];
-   unsigned long flags;
-   struct Scsi_Host *dev = dev_id;
-
-   IBMLOCK(dev)
-   shpnt = dev; /* assign host-structure to local pointer */
-   len = 0; /* set filled text-buffer index to 0 */
-   /* get the _special contents of the hostdata structure */
-   speciale = ((struct ibmmca_hostdata *)shpnt->hostdata)->_special;
-   connectore = ((struct ibmmca_hostdata *)shpnt->hostdata)->_connector_size;
-   for (k=2;k<4;k++)
-     pos[k] = ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos[k];
-   if (speciale == FORCED_DETECTION) { /* forced detection */
-      len += sprintf (buf+len,
-		      "Adapter category: forced detected\n"
-		      "***************************************\n"
-		      "***  Forced detected SCSI Adapter   ***\n"
-		      "***  No chip-information available  ***\n"
-		      "***************************************\n");
-   } else if (speciale == INTEGRATED_SCSI) {
-      /* if the integrated subsystem has been found automatically: */
-      len += sprintf (buf+len,
-		      "Adapter category: integrated\n"
-		      "Chip revision level: %d\n"
-		      "Chip status: %s\n"
-		      "8 kByte NVRAM status: %s\n",
-		      ((pos[2] & 0xf0) >> 4),
-		      (pos[2] & 1) ? "enabled" : "disabled",
-		      (pos[2] & 2) ? "locked" : "accessible");
-   } else if ((speciale>=0)&&
-	      (speciale<(sizeof(subsys_list)/sizeof(struct subsys_list_struct)))) {
-      /* if the subsystem is a slot adapter */
-      len += sprintf (buf+len,
-		      "Adapter category: slot-card\n"
-		      "ROM Segment Address: ");
-      if ((pos[2] & 0xf0) == 0xf0)
-	len += sprintf (buf+len, "off\n");
-      else
-	len += sprintf (buf+len, "0x%x\n",
-			((pos[2] & 0xf0) << 13) + 0xc0000);
-      len += sprintf (buf + len, "Chip status: %s\n",
-		      (pos[2] & 1) ? "enabled" : "disabled");
-      len += sprintf (buf + len, "Adapter I/O Offset: 0x%x\n",
-		      ((pos[2] & 0x0e) << 2));
-   } else {
-      len += sprintf (buf + len, "Adapter category: unknown\n");
-   }
-   /* common subsystem information to write to the slotn file */
-   len += sprintf (buf + len, "Subsystem PUN: %d\n", shpnt->this_id);
-   len += sprintf (buf + len, "I/O base address range: 0x%x-0x%x\n",
-		   (unsigned int)(shpnt->io_port),
-		   (unsigned int)(shpnt->io_port+7));
-   len += sprintf (buf + len, "MCA-slot size: %d bits",connectore);
-   /* Now make sure, the bufferlength is devidable by 4 to avoid
-    * paging problems of the buffer. */
-   while ( len % sizeof( int ) != ( sizeof ( int ) - 1 ) )
-     len += sprintf (buf+len, " ");
-   len += sprintf (buf+len, "\n");
-   IBMUNLOCK(shpnt)
-   return len;
-}
-
-int ibmmca_detect (Scsi_Host_Template * scsi_template)
-{
-   struct Scsi_Host *shpnt;
-   int port, id, i, j, k, list_size, slot;
-   int devices_on_irq_11 = 0;
-   int devices_on_irq_14 = 0;
-   int IRQ14_registered = 0;
-   int IRQ11_registered = 0;
-
-   found = 0; /* make absolutely sure, that found is set to 0 */
-
-   /* First of all, print the version number of the driver. This is
-    * important to allow better user bugreports in case of already
-    * having problems with the MCA_bus probing. */
-   printk("IBM MCA SCSI: Version %s\n",IBMMCA_SCSI_DRIVER_VERSION);
-   /* if this is not MCA machine, return "nothing found" */
-   if (!MCA_bus) {
-      printk("IBM MCA SCSI:  No Microchannel-bus present --> Aborting.\n"
-	     "      	     This machine does not have any IBM MCA-bus\n"
-	     "    	     or the MCA-Kernel-support is not enabled!\n");
-      return 0;
-   }
+}
+
+static void internal_ibmmca_scsi_setup(char *str, int *ints)
+{
+	int i, j, io_base, id_base;
+	char *token;
+
+	io_base = 0;
+	id_base = 0;
+	if (str) {
+		token = strtok(str, ",");
+		j = 0;
+		while (token) {
+			if (!strcmp(token, "activity"))
+				display_mode |= LED_ACTIVITY;
+			if (!strcmp(token, "display"))
+				display_mode |= LED_DISP;
+			if (!strcmp(token, "adisplay"))
+				display_mode |= LED_ADISP;
+			if (!strcmp(token, "normal"))
+				ibm_ansi_order = 0;
+			if (!strcmp(token, "ansi"))
+				ibm_ansi_order = 1;
+			if (!strcmp(token, "fast"))
+				global_adapter_speed = 0;
+			if (!strcmp(token, "medium"))
+				global_adapter_speed = 4;
+			if (!strcmp(token, "slow"))
+				global_adapter_speed = 7;
+			if ((*token == '-') || (isdigit(*token))) {
+				if (!(j % 2) && (io_base < IM_MAX_HOSTS))
+					io_port[io_base++] = simple_strtoul(token, NULL, 0);
+				if ((j % 2) && (id_base < IM_MAX_HOSTS))
+					scsi_id[id_base++] = simple_strtoul(token, NULL, 0);
+				j++;
+			}
+			token = strtok(NULL, ",");
+		}
+	} else if (ints) {
+		for (i = 0; i < IM_MAX_HOSTS && 2 * i + 2 < ints[0]; i++) {
+			io_port[i] = ints[2 * i + 2];
+			scsi_id[i] = ints[2 * i + 2];
+		}
+	}
+	return;
+}
+
+static int ibmmca_getinfo(char *buf, int slot, void *dev_id)
+{
+	struct Scsi_Host *shpnt;
+	int len, speciale, connectore, k;
+	unsigned int pos[8];
+	unsigned long flags;
+	struct Scsi_Host *dev = dev_id;
+
+	spin_lock_irqsave(dev->host_lock, flags);
+	
+	shpnt = dev;		/* assign host-structure to local pointer */
+	len = 0;		/* set filled text-buffer index to 0 */
+	/* get the _special contents of the hostdata structure */
+	speciale = ((struct ibmmca_hostdata *) shpnt->hostdata)->_special;
+	connectore = ((struct ibmmca_hostdata *) shpnt->hostdata)->_connector_size;
+	for (k = 2; k < 4; k++)
+		pos[k] = ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k];
+	if (speciale == FORCED_DETECTION) {	/* forced detection */
+		len += sprintf(buf + len,
+			       "Adapter category: forced detected\n" "***************************************\n" "***  Forced detected SCSI Adapter   ***\n" "***  No chip-information available  ***\n" "***************************************\n");
+	} else if (speciale == INTEGRATED_SCSI) {
+		/* if the integrated subsystem has been found automatically: */
+		len += sprintf(buf + len,
+			       "Adapter category: integrated\n" "Chip revision level: %d\n" "Chip status: %s\n" "8 kByte NVRAM status: %s\n", ((pos[2] & 0xf0) >> 4), (pos[2] & 1) ? "enabled" : "disabled", (pos[2] & 2) ? "locked" : "accessible");
+	} else if ((speciale >= 0) && (speciale < (sizeof(subsys_list) / sizeof(struct subsys_list_struct)))) {
+		/* if the subsystem is a slot adapter */
+		len += sprintf(buf + len, "Adapter category: slot-card\n" "ROM Segment Address: ");
+		if ((pos[2] & 0xf0) == 0xf0)
+			len += sprintf(buf + len, "off\n");
+		else
+			len += sprintf(buf + len, "0x%x\n", ((pos[2] & 0xf0) << 13) + 0xc0000);
+		len += sprintf(buf + len, "Chip status: %s\n", (pos[2] & 1) ? "enabled" : "disabled");
+		len += sprintf(buf + len, "Adapter I/O Offset: 0x%x\n", ((pos[2] & 0x0e) << 2));
+	} else {
+		len += sprintf(buf + len, "Adapter category: unknown\n");
+	}
+	/* common subsystem information to write to the slotn file */
+	len += sprintf(buf + len, "Subsystem PUN: %d\n", shpnt->this_id);
+	len += sprintf(buf + len, "I/O base address range: 0x%x-0x%x\n", (unsigned int) (shpnt->io_port), (unsigned int) (shpnt->io_port + 7));
+	len += sprintf(buf + len, "MCA-slot size: %d bits", connectore);
+	/* Now make sure, the bufferlength is devidable by 4 to avoid
+	 * paging problems of the buffer. */
+	while (len % sizeof(int) != (sizeof(int) - 1))
+		len += sprintf(buf + len, " ");
+	len += sprintf(buf + len, "\n");
+	
+	spin_unlock_irqrestore(shpnt->host_lock, flags);
+	
+	return len;
+}
+
+int ibmmca_detect(Scsi_Host_Template * scsi_template)
+{
+	struct Scsi_Host *shpnt;
+	int port, id, i, j, k, list_size, slot;
+	int devices_on_irq_11 = 0;
+	int devices_on_irq_14 = 0;
+	int IRQ14_registered = 0;
+	int IRQ11_registered = 0;
+
+	found = 0;		/* make absolutely sure, that found is set to 0 */
+
+	/* First of all, print the version number of the driver. This is
+	 * important to allow better user bugreports in case of already
+	 * having problems with the MCA_bus probing. */
+	printk(KERN_INFO "IBM MCA SCSI: Version %s\n", IBMMCA_SCSI_DRIVER_VERSION);
+	/* if this is not MCA machine, return "nothing found" */
+	if (!MCA_bus) {
+		printk(KERN_INFO "IBM MCA SCSI:  No Microchannel-bus present --> Aborting.\n" "      	     This machine does not have any IBM MCA-bus\n" "    	     or the MCA-Kernel-support is not enabled!\n");
+		return 0;
+	}
 
 #ifdef MODULE
-   /* If the driver is run as module, read from conf.modules or cmd-line */
-   if (boot_options) option_setup(boot_options);
-#endif
+	/* If the driver is run as module, read from conf.modules or cmd-line */
+	if (boot_options)
+		option_setup(boot_options);
+#endif
+
+	/* get interrupt request level */
+	if (request_irq(IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmcascsi", hosts)) {
+		printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ);
+		return 0;
+	} else
+		IRQ14_registered++;
+
+	/* if ibmmcascsi setup option was passed to kernel, return "found" */
+	for (i = 0; i < IM_MAX_HOSTS; i++)
+		if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8) {
+			printk("IBM MCA SCSI: forced detected SCSI Adapter, io=0x%x, scsi id=%d.\n", io_port[i], scsi_id[i]);
+			if ((shpnt = ibmmca_register(scsi_template, io_port[i], scsi_id[i], FORCED_DETECTION, "forced detected SCSI Adapter"))) {
+				for (k = 2; k < 7; k++)
+					((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = 0;
+				((struct ibmmca_hostdata *) shpnt->hostdata)->_special = FORCED_DETECTION;
+				mca_set_adapter_name(MCA_INTEGSCSI, "forced detected SCSI Adapter");
+				mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, shpnt);
+				mca_mark_as_used(MCA_INTEGSCSI);
+				devices_on_irq_14++;
+			}
+		}
+	if (found)
+		return found;
+
+	/* The POS2-register of all PS/2 model SCSI-subsystems has the following
+	 * interpretation of bits:
+	 *                             Bit 7 - 4 : Chip Revision ID (Release)
+	 *                             Bit 3 - 2 : Reserved
+	 *                             Bit 1     : 8k NVRAM Disabled
+	 *                             Bit 0     : Chip Enable (EN-Signal)
+	 * The POS3-register is interpreted as follows:
+	 *                             Bit 7 - 5 : SCSI ID
+	 *                             Bit 4     : Reserved = 0
+	 *                             Bit 3 - 0 : Reserved = 0
+	 * (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common
+	 * Interfaces (1991)").
+	 * In short words, this means, that IBM PS/2 machines only support
+	 * 1 single subsystem by default. The slot-adapters must have another
+	 * configuration on pos2. Here, one has to assume the following
+	 * things for POS2-register:
+	 *                             Bit 7 - 4 : Chip Revision ID (Release)
+	 *                             Bit 3 - 1 : port offset factor
+	 *                             Bit 0     : Chip Enable (EN-Signal)
+	 * As I found a patch here, setting the IO-registers to 0x3540 forced,
+	 * as there was a 0x05 in POS2 on a model 56, I assume, that the
+	 * port 0x3540 must be fix for integrated SCSI-controllers.
+	 * Ok, this discovery leads to the following implementation: (M.Lang) */
+
+	/* first look for the IBM SCSI integrated subsystem on the motherboard */
+	for (j = 0; j < 8; j++)	/* read the pos-information */
+		pos[j] = mca_read_stored_pos(MCA_INTEGSCSI, j);
+	/* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present, but
+	 * if we ignore the settings of all surrounding pos registers, it is not
+	 * completely sufficient to only check pos2 and pos3. */
+	/* Therefore, now the following if statement is used to
+	 * make sure, we see a real integrated onboard SCSI-interface and no
+	 * internal system information, which gets mapped to some pos registers
+	 * on models 95xx. */
+	if ((!pos[0] && !pos[1] && pos[2] > 0 && pos[3] > 0 && !pos[4] && !pos[5] && !pos[6] && !pos[7]) || (pos[0] == 0xff && pos[1] == 0xff && pos[2] < 0xff && pos[3] < 0xff && pos[4] == 0xff && pos[5] == 0xff && pos[6] == 0xff && pos[7] == 0xff)) {
+		if ((pos[2] & 1) == 1)	/* is the subsystem chip enabled ? */
+			port = IM_IO_PORT;
+		else {		/* if disabled, no IRQs will be generated, as the chip won't
+				 * listen to the incoming commands and will do really nothing,
+				 * except for listening to the pos-register settings. If this
+				 * happens, I need to hugely think about it, as one has to
+				 * write something to the MCA-Bus pos register in order to
+				 * enable the chip. Normally, IBM-SCSI won't pass the POST,
+				 * when the chip is disabled (see IBM tech. ref.). */
+			port = IM_IO_PORT;	/* anyway, set the portnumber and warn */
+			printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n" "              SCSI-operations may not work.\n");
+		}
+		id = (pos[3] & 0xe0) >> 5;	/* this is correct and represents the PUN */
+		/* give detailed information on the subsystem. This helps me
+		 * additionally during debugging and analyzing bug-reports. */
+		printk(KERN_INFO "IBM MCA SCSI: IBM Integrated SCSI Controller ffound, io=0x%x, scsi id=%d,\n", port, id);
+		printk(KERN_INFO "              chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n", ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible", (pos[2] & 1) ? "enabled." : "disabled.");
+
+		/* register the found integrated SCSI-subsystem */
+		if ((shpnt = ibmmca_register(scsi_template, port, id, INTEGRATED_SCSI, "IBM Integrated SCSI Controller"))) 
+		{
+			for (k = 2; k < 7; k++)
+				((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
+			((struct ibmmca_hostdata *) shpnt->hostdata)->_special = INTEGRATED_SCSI;
+			mca_set_adapter_name(MCA_INTEGSCSI, "IBM Integrated SCSI Controller");
+			mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, shpnt);
+			mca_mark_as_used(MCA_INTEGSCSI);
+			devices_on_irq_14++;
+		}
+	}
+
+	/* now look for other adapters in MCA slots, */
+	/* determine the number of known IBM-SCSI-subsystem types */
+	/* see the pos[2] dependence to get the adapter port-offset. */
+	list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
+	for (i = 0; i < list_size; i++) {
+		/* scan each slot for a fitting adapter id */
+		slot = 0;	/* start at slot 0 */
+		while ((slot = mca_find_adapter(subsys_list[i].mca_id, slot))
+		       != MCA_NOTFOUND) {	/* scan through all slots */
+			for (j = 0; j < 8; j++)	/* read the pos-information */
+				pos[j] = mca_read_stored_pos(slot, j);
+			if ((pos[2] & 1) == 1)
+				/* is the subsystem chip enabled ? */
+				/* (explanations see above) */
+				port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+			else {
+				/* anyway, set the portnumber and warn */
+				port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+				printk(KERN_WARNING "IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
+				printk(KERN_WARNING "              SCSI-operations may not work.\n");
+			}
+			if ((i == IBM_SCSI2_FW) && (pos[6] != 0)) {
+				printk(KERN_ERR "IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
+				printk(KERN_ERR "              Impossible to determine adapter PUN!\n");
+				printk(KERN_ERR "              Guessing adapter PUN = 7.\n");
+				id = 7;
+			} else {
+				id = (pos[3] & 0xe0) >> 5;	/* get subsystem PUN */
+				if (i == IBM_SCSI2_FW) {
+					id |= (pos[3] & 0x10) >> 1;	/* get subsystem PUN high-bit
+									 * for F/W adapters */
+				}
+			}
+			if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0)) {
+				/* IRQ11 is used by SCSI-2 F/W Adapter/A */
+				printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
+				/* get interrupt request level */
+				if (request_irq(IM_IRQ_FW, interrupt_handler, SA_SHIRQ, "ibmmcascsi", hosts)) {
+					printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ_FW);
+				} else
+					IRQ11_registered++;
+			}
+			printk(KERN_INFO "IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n", subsys_list[i].description, slot + 1, port, id);
+			if ((pos[2] & 0xf0) == 0xf0)
+				printk(KERN_DEBUG"              ROM Addr.=off,");
+			else
+				printk(KERN_DEBUG "              ROM Addr.=0x%x,", ((pos[2] & 0xf0) << 13) + 0xc0000);
+			printk(KERN_DEBUG " port-offset=0x%x, subsystem=%s\n", ((pos[2] & 0x0e) << 2), (pos[2] & 1) ? "enabled." : "disabled.");
+
+			/* register the hostadapter */
+			if ((shpnt = ibmmca_register(scsi_template, port, id, i, subsys_list[i].description))) {
+				for (k = 2; k < 8; k++)
+					((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
+				((struct ibmmca_hostdata *) shpnt->hostdata)->_special = i;
+				mca_set_adapter_name(slot, subsys_list[i].description);
+				mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmmca_getinfo, shpnt);
+				mca_mark_as_used(slot);
+				if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0))
+					devices_on_irq_11++;
+				else
+					devices_on_irq_14++;
+			}
+			slot++;	/* advance to next slot */
+		}		/* advance to next adapter id in the list of IBM-SCSI-subsystems */
+	}
+
+	/* now check for SCSI-adapters, mapped to the integrated SCSI
+	 * area. E.g. a W/Cache in MCA-slot 9(!). Do the check correct here,
+	 * as this is a known effect on some models 95xx. */
+	list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
+	for (i = 0; i < list_size; i++) {
+		/* scan each slot for a fitting adapter id */
+		slot = mca_find_adapter(subsys_list[i].mca_id, MCA_INTEGSCSI);
+		if (slot != MCA_NOTFOUND) {	/* scan through all slots */
+			for (j = 0; j < 8; j++)	/* read the pos-information */
+				pos[j] = mca_read_stored_pos(slot, j);
+			if ((pos[2] & 1) == 1) {	/* is the subsystem chip enabled ? */
+				/* (explanations see above) */
+				port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+			} else {	/* anyway, set the portnumber and warn */
+				port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+				printk(KERN_WARNING "IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
+				printk(KERN_WARNING "              SCSI-operations may not work.\n");
+			}
+			if ((i == IBM_SCSI2_FW) && (pos[6] != 0)) {
+				printk(KERN_ERR "IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
+				printk(KERN_ERR  "              Impossible to determine adapter PUN!\n");
+				printk(KERN_ERR "              Guessing adapter PUN = 7.\n");
+				id = 7;
+			} else {
+				id = (pos[3] & 0xe0) >> 5;	/* get subsystem PUN */
+				if (i == IBM_SCSI2_FW)
+					id |= (pos[3] & 0x10) >> 1;	/* get subsystem PUN high-bit
+									 * for F/W adapters */
+			}
+			if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0)) {
+				/* IRQ11 is used by SCSI-2 F/W Adapter/A */
+				printk(KERN_DEBUG  "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
+				/* get interrupt request level */
+				if (request_irq(IM_IRQ_FW, interrupt_handler, SA_SHIRQ, "ibmmcascsi", hosts))
+					printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ_FW);
+				else
+					IRQ11_registered++;
+			}
+			printk(KERN_INFO "IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n", subsys_list[i].description, slot + 1, port, id);
+			if ((pos[2] & 0xf0) == 0xf0)
+				printk(KERN_DEBUG "              ROM Addr.=off,");
+			else
+				printk(KERN_DEBUG "              ROM Addr.=0x%x,", ((pos[2] & 0xf0) << 13) + 0xc0000);
+			printk(KERN_DEBUG " port-offset=0x%x, subsystem=%s\n", ((pos[2] & 0x0e) << 2), (pos[2] & 1) ? "enabled." : "disabled.");
+
+			/* register the hostadapter */
+			if ((shpnt = ibmmca_register(scsi_template, port, id, i, subsys_list[i].description))) {
+				for (k = 2; k < 7; k++)
+					((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
+				((struct ibmmca_hostdata *) shpnt->hostdata)->_special = i;
+				mca_set_adapter_name(slot, subsys_list[i].description);
+				mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmmca_getinfo, shpnt);
+				mca_mark_as_used(slot);
+				if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0))
+					devices_on_irq_11++;
+				else
+					devices_on_irq_14++;
+			}
+			slot++;	/* advance to next slot */
+		}		/* advance to next adapter id in the list of IBM-SCSI-subsystems */
+	}
+	if (IRQ11_registered && !devices_on_irq_11)
+		free_irq(IM_IRQ_FW, hosts);	/* no devices on IRQ 11 */
+	if (IRQ14_registered && !devices_on_irq_14)
+		free_irq(IM_IRQ, hosts);	/* no devices on IRQ 14 */
+	if (!devices_on_irq_11 && !devices_on_irq_14)
+		printk(KERN_WARNING "IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n");
+	return found;		/* return the number of found SCSI hosts. Should be 1 or 0. */
+}
+
+static struct Scsi_Host *ibmmca_register(Scsi_Host_Template * scsi_template, int port, int id, int adaptertype, char *hostname)
+{
+	struct Scsi_Host *shpnt;
+	int i, j;
+	unsigned int ctrl;
+
+	/* check I/O region */
+	if (!request_region(port, IM_N_IO_PORT, hostname)) {
+		printk(KERN_ERR "IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x (%d ports).\n", port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT);
+		return NULL;
+	}
+
+	/* register host */
+	shpnt = scsi_register(scsi_template, sizeof(struct ibmmca_hostdata));
+	if (!shpnt) {
+		printk(KERN_ERR "IBM MCA SCSI: Unable to register host.\n");
+		release_region(port, IM_N_IO_PORT);
+		return NULL;
+	}
 
-   /* get interrupt request level */
-   if (request_irq (IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmcascsi",
-		    hosts)) {
-      printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ);
-      return 0;
-   } else
-     IRQ14_registered++;
-
-   /* if ibmmcascsi setup option was passed to kernel, return "found" */
-   for (i = 0; i < IM_MAX_HOSTS; i++)
-     if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8) {
-	printk("IBM MCA SCSI: forced detected SCSI Adapter, io=0x%x, scsi id=%d.\n",
-	       io_port[i], scsi_id[i]);
-	if ((shpnt = ibmmca_register(scsi_template, io_port[i], scsi_id[i],
-		     FORCED_DETECTION, "forced detected SCSI Adapter"))) {
-	   for (k=2;k<7;k++)
-	     ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos[k] = 0;
-	   ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = FORCED_DETECTION;
-	   mca_set_adapter_name(MCA_INTEGSCSI, "forced detected SCSI Adapter");
-	   mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo,
-				  shpnt);
-	   mca_mark_as_used(MCA_INTEGSCSI);
-	   devices_on_irq_14++;
-	}
-     }
-   if (found) return found;
-
-   /* The POS2-register of all PS/2 model SCSI-subsystems has the following
-    * interpretation of bits:
-    *                             Bit 7 - 4 : Chip Revision ID (Release)
-    *                             Bit 3 - 2 : Reserved
-    *                             Bit 1     : 8k NVRAM Disabled
-    *                             Bit 0     : Chip Enable (EN-Signal)
-    * The POS3-register is interpreted as follows:
-    *                             Bit 7 - 5 : SCSI ID
-    *                             Bit 4     : Reserved = 0
-    *                             Bit 3 - 0 : Reserved = 0
-    * (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common
-    * Interfaces (1991)").
-    * In short words, this means, that IBM PS/2 machines only support
-    * 1 single subsystem by default. The slot-adapters must have another
-    * configuration on pos2. Here, one has to assume the following
-    * things for POS2-register:
-    *                             Bit 7 - 4 : Chip Revision ID (Release)
-    *                             Bit 3 - 1 : port offset factor
-    *                             Bit 0     : Chip Enable (EN-Signal)
-    * As I found a patch here, setting the IO-registers to 0x3540 forced,
-    * as there was a 0x05 in POS2 on a model 56, I assume, that the
-    * port 0x3540 must be fix for integrated SCSI-controllers.
-    * Ok, this discovery leads to the following implementation: (M.Lang) */
-
-   /* first look for the IBM SCSI integrated subsystem on the motherboard */
-   for (j=0;j<8;j++) /* read the pos-information */
-     pos[j] = mca_read_stored_pos(MCA_INTEGSCSI,j);
-   /* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present, but
-    * if we ignore the settings of all surrounding pos registers, it is not
-    * completely sufficient to only check pos2 and pos3. */
-   /* Therefore, now the following if statement is used to
-    * make sure, we see a real integrated onboard SCSI-interface and no
-    * internal system information, which gets mapped to some pos registers
-    * on models 95xx. */
-   if ((!pos[0] && !pos[1] && pos[2]>0 && pos[3]>0 && !pos[4] && !pos[5] && !pos[6] && !pos[7]) ||
-       (pos[0]==0xff && pos[1]==0xff && pos[2]<0xff && pos[3]<0xff && pos[4]==0xff && pos[5]==0xff && pos[6]==0xff && pos[7]==0xff)) {
-      if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
-	port = IM_IO_PORT;
-      else { /* if disabled, no IRQs will be generated, as the chip won't
-	      * listen to the incoming commands and will do really nothing,
-	      * except for listening to the pos-register settings. If this
-	      * happens, I need to hugely think about it, as one has to
-	      * write something to the MCA-Bus pos register in order to
-	      * enable the chip. Normally, IBM-SCSI won't pass the POST,
-	      * when the chip is disabled (see IBM tech. ref.). */
-	 port = IM_IO_PORT; /* anyway, set the portnumber and warn */
-	 printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n"
-		"              SCSI-operations may not work.\n");
-      }
-      id = (pos[3] & 0xe0) >> 5; /* this is correct and represents the PUN */
-      /* give detailed information on the subsystem. This helps me
-       * additionally during debugging and analyzing bug-reports. */
-      printk("IBM MCA SCSI: IBM Integrated SCSI Controller found, io=0x%x, scsi id=%d,\n"
-	     "              chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n",
-	     port, id,
-	     ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible",
-	     (pos[2] & 1) ? "enabled." : "disabled.");
-
-      /* register the found integrated SCSI-subsystem */
-      if ((shpnt = ibmmca_register(scsi_template, port, id, INTEGRATED_SCSI,
-				   "IBM Integrated SCSI Controller"))) {
-	 for (k=2;k<7;k++)
-	   ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos[k] = pos[k];
-	 ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = INTEGRATED_SCSI;
-	 mca_set_adapter_name(MCA_INTEGSCSI, "IBM Integrated SCSI Controller");
-	 mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo,
-				shpnt);
-	 mca_mark_as_used(MCA_INTEGSCSI);
-	 devices_on_irq_14++;
-      }
-   }
-
-   /* now look for other adapters in MCA slots, */
-   /* determine the number of known IBM-SCSI-subsystem types */
-   /* see the pos[2] dependence to get the adapter port-offset. */
-   list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
-   for (i = 0; i < list_size; i++) {
-      /* scan each slot for a fitting adapter id */
-      slot = 0; /* start at slot 0 */
-      while ((slot = mca_find_adapter(subsys_list[i].mca_id, slot))
-	     != MCA_NOTFOUND) { /* scan through all slots */
-	 for (j=0;j<8;j++) /* read the pos-information */
-	   pos[j] = mca_read_stored_pos(slot, j);
-	 if ((pos[2] & 1) == 1) /* is the subsystem chip enabled ? */
-	   /* (explanations see above) */
-	   port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
-	 else {
-	    /* anyway, set the portnumber and warn */
-	    port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
-	    printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n"
-		   "              SCSI-operations may not work.\n");
-	 }
-	 if ((i==IBM_SCSI2_FW)&&(pos[6]!=0)) {
-	    printk("IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n"
-		   "              Impossible to determine adapter PUN!\n"
-		   "              Guessing adapter PUN = 7.\n");
-	    id = 7;
-	 } else {
-	    id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
-	    if (i==IBM_SCSI2_FW) {
-	       id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit
-					    * for F/W adapters */
-	    }
-	 }
-	 if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0)) {
-	    /* IRQ11 is used by SCSI-2 F/W Adapter/A */
-	    printk("IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
-	    /* get interrupt request level */
-	    if (request_irq (IM_IRQ_FW, interrupt_handler, SA_SHIRQ,
-			     "ibmmcascsi", hosts)) {
-	       printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n",
-		      IM_IRQ_FW);
-	    } else
-	      IRQ11_registered++;
-	 }
-	 printk("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n",
-		subsys_list[i].description, slot + 1, port, id);
-	 if ((pos[2] & 0xf0) == 0xf0)
-	   printk("              ROM Addr.=off,");
-	 else
-	   printk("              ROM Addr.=0x%x,",
-		  ((pos[2] & 0xf0) << 13) + 0xc0000);
-	 printk(" port-offset=0x%x, subsystem=%s\n",
-		((pos[2] & 0x0e) << 2),
-		(pos[2] & 1) ? "enabled." : "disabled.");
-
-	 /* register the hostadapter */
-	 if ((shpnt = ibmmca_register(scsi_template, port, id, i,
-				      subsys_list[i].description))) {
-	    for (k=2;k<8;k++)
-	      ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos[k] = pos[k];
-	    ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = i;
-	    mca_set_adapter_name (slot, subsys_list[i].description);
-	    mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo,
-				    shpnt);
-	    mca_mark_as_used(slot);
-	    if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0))
-	      devices_on_irq_11++;
-	    else
-	      devices_on_irq_14++;
-	 }
-	 slot++; /* advance to next slot */
-      } /* advance to next adapter id in the list of IBM-SCSI-subsystems*/
-   }
-
-   /* now check for SCSI-adapters, mapped to the integrated SCSI
-    * area. E.g. a W/Cache in MCA-slot 9(!). Do the check correct here,
-    * as this is a known effect on some models 95xx. */
-   list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
-   for (i = 0; i < list_size; i++) {
-      /* scan each slot for a fitting adapter id */
-      slot = mca_find_adapter(subsys_list[i].mca_id, MCA_INTEGSCSI);
-      if (slot != MCA_NOTFOUND) { /* scan through all slots */
-	 for (j=0;j<8;j++) /* read the pos-information */
-	   pos[j] = mca_read_stored_pos(slot, j);
-	 if ((pos[2] & 1) == 1) { /* is the subsystem chip enabled ? */
-	    /* (explanations see above) */
-	    port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
-	 } else { /* anyway, set the portnumber and warn */
-	    port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
-	    printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n"
-		   "              SCSI-operations may not work.\n");
-	 }
-	 if ((i==IBM_SCSI2_FW)&&(pos[6]!=0)) {
-	    printk("IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n"
-		   "              Impossible to determine adapter PUN!\n"
-		   "              Guessing adapter PUN = 7.\n");
-	    id = 7;
-	 } else {
-	    id = (pos[3] & 0xe0) >> 5; /* get subsystem PUN */
-	    if (i==IBM_SCSI2_FW)
-	      id |= (pos[3] & 0x10) >> 1; /* get subsystem PUN high-bit
-					   * for F/W adapters */
-	 }
-	 if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0)) {
-	    /* IRQ11 is used by SCSI-2 F/W Adapter/A */
-	    printk("IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
-	    /* get interrupt request level */
-	    if (request_irq (IM_IRQ_FW, interrupt_handler, SA_SHIRQ,
-			     "ibmmcascsi", hosts))
-	      printk("IBM MCA SCSI: Unable to get shared IRQ %d.\n",
-		     IM_IRQ_FW);
-	    else
-	      IRQ11_registered++;
-	 }
-	 printk("IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n",
-		subsys_list[i].description, slot + 1, port, id);
-	 if ((pos[2] & 0xf0) == 0xf0)
-	   printk("              ROM Addr.=off,");
-	 else
-	   printk("              ROM Addr.=0x%x,",
-		  ((pos[2] & 0xf0) << 13) + 0xc0000);
-	 printk(" port-offset=0x%x, subsystem=%s\n",
-		((pos[2] & 0x0e) << 2),
-		(pos[2] & 1) ? "enabled." : "disabled.");
-
-	 /* register the hostadapter */
-	 if ((shpnt = ibmmca_register(scsi_template, port, id, i,
-				      subsys_list[i].description))) {
-	    for (k=2;k<7;k++)
-	      ((struct ibmmca_hostdata *)shpnt->hostdata)->_pos[k] = pos[k];
-	    ((struct ibmmca_hostdata *)shpnt->hostdata)->_special = i;
-	    mca_set_adapter_name (slot, subsys_list[i].description);
-	    mca_set_adapter_procfn (slot, (MCA_ProcFn) ibmmca_getinfo, shpnt);
-	    mca_mark_as_used(slot);
-	    if ((i==IBM_SCSI2_FW)&&(pos[4] & 0x01)&&(pos[6]==0))
-	      devices_on_irq_11++;
-	    else
-	      devices_on_irq_14++;
-	 }
-	 slot++; /* advance to next slot */
-      } /* advance to next adapter id in the list of IBM-SCSI-subsystems*/
-   }
-   if ( IRQ11_registered && !devices_on_irq_11 )
-     free_irq(IM_IRQ_FW, hosts); /* no devices on IRQ 11 */
-   if ( IRQ14_registered && !devices_on_irq_14 )
-     free_irq(IM_IRQ, hosts); /* no devices on IRQ 14 */
-   if ( !devices_on_irq_11 && !devices_on_irq_14 )
-     printk("IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n");
-   return found; /* return the number of found SCSI hosts. Should be 1 or 0. */
-}
-
-static struct Scsi_Host *
-ibmmca_register(Scsi_Host_Template * scsi_template, int port, int id,
-		int adaptertype, char *hostname)
-{
-   struct Scsi_Host *shpnt;
-   int i, j;
-   unsigned int ctrl;
-
-   /* check I/O region */
-   if (check_region(port, IM_N_IO_PORT)) {
-      printk("IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x (%d ports).\n",
-	     port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT);
-      return NULL;
-   }
-
-   /* register host */
-   shpnt = scsi_register(scsi_template, sizeof(struct ibmmca_hostdata));
-   if (!shpnt) {
-      printk("IBM MCA SCSI: Unable to register host.\n");
-      return NULL;
-   }
-
-   /* request I/O region */
-   request_region(port, IM_N_IO_PORT, hostname);
-   hosts[found] = shpnt; /* add new found hostadapter to the list */
-   special(found) = adaptertype; /* important assignment or else crash! */
-   subsystem_connector_size(found) = 0; /* preset slot-size */
-   shpnt->irq = IM_IRQ; /* assign necessary stuff for the adapter */
-   shpnt->io_port = port;
-   shpnt->n_io_port = IM_N_IO_PORT;
-   shpnt->this_id = id;
-   shpnt->max_id = 8; /* 8 PUNs are default */
-   /* now, the SCSI-subsystem is connected to Linux */
+	/* request I/O region */
+	hosts[found] = shpnt;	/* add new found hostadapter to the list */
+	special(found) = adaptertype;	/* important assignment or else crash! */
+	subsystem_connector_size(found) = 0;	/* preset slot-size */
+	shpnt->irq = IM_IRQ;	/* assign necessary stuff for the adapter */
+	shpnt->io_port = port;
+	shpnt->n_io_port = IM_N_IO_PORT;
+	shpnt->this_id = id;
+	shpnt->max_id = 8;	/* 8 PUNs are default */
+	/* now, the SCSI-subsystem is connected to Linux */
 
-   ctrl = (unsigned int)(inb(IM_CTR_REG(found))); /* get control-register status */
+	ctrl = (unsigned int) (inb(IM_CTR_REG(found)));	/* get control-register status */
 #ifdef IM_DEBUG_PROBE
-   printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n",
-	  ctrl,inb(IM_STAT_REG(found)));
-   printk("IBM MCA SCSI: This adapters' POS-registers: ");
-   for (i=0;i<8;i++)
-     printk("%x ",pos[i]);
-   printk("\n");
-#endif
-   reset_status(found) = IM_RESET_NOT_IN_PROGRESS;
-
-   for (i = 0; i < 16; i++) /* reset the tables */
-     for (j = 0; j < 8; j++)
-     get_ldn(found)[i][j] = MAX_LOG_DEV;
-
-   /* check which logical devices exist */
-   /* after this line, local interrupting is possible: */
-   local_checking_phase_flag(found) = 1;
-   check_devices(found,adaptertype); /* call by value, using the global variable hosts*/
-   local_checking_phase_flag(found) = 0;
-   found++; /* now increase index to be prepared for next found subsystem */
-   /* an ibm mca subsystem has been detected */
-   return shpnt;
-}
-
-int ibmmca_command (Scsi_Cmnd * cmd)
-{
-  ibmmca_queuecommand (cmd, internal_done);
-  cmd->SCp.Status = 0;
-  while (!cmd->SCp.Status) barrier ();
-  return cmd->result;
-}
-
-int ibmmca_release(struct Scsi_Host *shpnt)
-{
-  release_region(shpnt->io_port, shpnt->n_io_port);
-  if (!(--found)) free_irq(shpnt->irq, hosts);
-  return 0;
+	printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n", ctrl, inb(IM_STAT_REG(found)));
+	printk("IBM MCA SCSI: This adapters' POS-registers: ");
+	for (i = 0; i < 8; i++)
+		printk("%x ", pos[i]);
+	printk("\n");
+#endif
+	reset_status(found) = IM_RESET_NOT_IN_PROGRESS;
+
+	for (i = 0; i < 16; i++)	/* reset the tables */
+		for (j = 0; j < 8; j++)
+			get_ldn(found)[i][j] = MAX_LOG_DEV;
+
+	/* check which logical devices exist */
+	/* after this line, local interrupting is possible: */
+	local_checking_phase_flag(found) = 1;
+	check_devices(found, adaptertype);	/* call by value, using the global variable hosts */
+	local_checking_phase_flag(found) = 0;
+	found++;		/* now increase index to be prepared for next found subsystem */
+	/* an ibm mca subsystem has been detected */
+	return shpnt;
+}
+
+static int ibmmca_command(Scsi_Cmnd * cmd)
+{
+	ibmmca_queuecommand(cmd, internal_done);
+	cmd->SCp.Status = 0;
+	while (!cmd->SCp.Status)
+		barrier();
+	return cmd->result;
+}
+
+static int ibmmca_release(struct Scsi_Host *shpnt)
+{
+	release_region(shpnt->io_port, shpnt->n_io_port);
+	if (!(--found))
+		free_irq(shpnt->irq, hosts);
+	return 0;
 }
 
 /* The following routine is the SCSI command queue for the midlevel driver */
-int ibmmca_queuecommand (Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
 {
-   unsigned int ldn;
-   unsigned int scsi_cmd;
-   struct im_scb *scb;
-   struct Scsi_Host *shpnt;
-   int current_ldn;
-   int id,lun;
-   int target;
-   int host_index;
-   int max_pun;
-   int i;
-   struct scatterlist *sl;
-
-   shpnt = cmd->host;
-   /* search for the right hostadapter */
-   for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
-
-   if (!hosts[host_index]) { /* invalid hostadapter descriptor address */
-      cmd->result = DID_NO_CONNECT << 16;
-      if (done) done (cmd);
-      return 0;
-   }
-   max_pun = subsystem_maxid(host_index);
-   if (ibm_ansi_order) {
-      target = max_pun - 1 - cmd->target;
-      if ((target <= subsystem_pun(host_index))&&(cmd->target <= subsystem_pun(host_index)))
-	target--;
-      else if ((target >= subsystem_pun(host_index))&&(cmd->target >= subsystem_pun(host_index)))
-	target++;
-   } else
-     target = cmd->target;
-
-   /* if (target,lun) is NO LUN or not existing at all, return error */
-   if ((get_scsi(host_index)[target][cmd->lun] == TYPE_NO_LUN)||
-       (get_scsi(host_index)[target][cmd->lun] == TYPE_NO_DEVICE)) {
-      cmd->result = DID_NO_CONNECT << 16;
-      if (done) done (cmd);
-      return 0;
-   }
-
-   /*if (target,lun) unassigned, do further checks... */
-   ldn = get_ldn(host_index)[target][cmd->lun];
-   if (ldn >= MAX_LOG_DEV) { /* on invalid ldn do special stuff */
-      if (ldn > MAX_LOG_DEV) { /* dynamical remapping if ldn unassigned */
-	 current_ldn = next_ldn(host_index); /* stop-value for one circle */
-	 while (ld(host_index)[next_ldn(host_index)].cmd) { /* search for a occupied, but not in */
-	    /* command-processing ldn. */
-	    next_ldn(host_index)++;
-	    if (next_ldn(host_index)>=MAX_LOG_DEV)
-	      next_ldn(host_index) = 7;
-	    if (current_ldn == next_ldn(host_index)) { /* One circle done ? */
-	       /* no non-processing ldn found */
-	       printk("IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n" \
-		      "              On ldn 7-14 SCSI-commands everywhere in progress.\n" \
-		      "              Reporting DID_NO_CONNECT for device (%d,%d).\n",
-		      target, cmd->lun);
-	       cmd->result = DID_NO_CONNECT << 16;/* return no connect*/
-	       if (done) done (cmd);
-	       return 0;
-	    }
-	 }
-
-	 /* unmap non-processing ldn */
-	 for (id=0; id<max_pun; id ++)
-	   for (lun=0; lun<8; lun++) {
-	      if (get_ldn(host_index)[id][lun] == next_ldn(host_index)) {
-		 get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE;
-		 get_scsi(host_index)[id][lun] = TYPE_NO_DEVICE;
-		 /* unmap entry */
-	      }
-	   }
-	 /* set reduced interrupt_handler-mode for checking */
-	 local_checking_phase_flag(host_index) = 1;
-	 /* map found ldn to pun,lun */
-	 get_ldn(host_index)[target][cmd->lun] = next_ldn(host_index);
-	 /* change ldn to the right value, that is now next_ldn */
-	 ldn = next_ldn(host_index);
-	 /* unassign all ldns (pun,lun,ldn does not matter for remove) */
-	 immediate_assign(host_index,0,0,0,REMOVE_LDN);
-	 /* set only LDN for remapped device */
-	 immediate_assign(host_index,target,cmd->lun,ldn,SET_LDN);
-	 /* get device information for ld[ldn] */
-	 if (device_exists (host_index, ldn,
-			    &ld(host_index)[ldn].block_length,
-			    &ld(host_index)[ldn].device_type)) {
-	    ld(host_index)[ldn].cmd = NULL; /* To prevent panic set 0, because
-					       devices that were not assigned,
-					       should have nothing in progress. */
-	    get_scsi(host_index)[target][cmd->lun] = ld(host_index)[ldn].device_type;
-	    /* increase assignment counters for statistics in /proc */
-	    IBM_DS(host_index).dynamical_assignments++;
-	    IBM_DS(host_index).ldn_assignments[ldn]++;
-	 } else
-	   /* panic here, because a device, found at boottime has
-	      vanished */
-	   panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n",
-		 ldn, target, cmd->lun);
-	 /* unassign again all ldns (pun,lun,ldn does not matter for remove) */
-	 immediate_assign(host_index,0,0,0,REMOVE_LDN);
-	 /* remap all ldns, as written in the pun/lun table */
-	 lun=0;
+	unsigned int ldn;
+	unsigned int scsi_cmd;
+	struct im_scb *scb;
+	struct Scsi_Host *shpnt;
+	int current_ldn;
+	int id, lun;
+	int target;
+	int host_index;
+	int max_pun;
+	int i;
+	struct scatterlist *sl;
+
+	shpnt = cmd->host;
+	/* search for the right hostadapter */
+	for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
+
+	if (!hosts[host_index]) {	/* invalid hostadapter descriptor address */
+		cmd->result = DID_NO_CONNECT << 16;
+		if (done)
+			done(cmd);
+		return 0;
+	}
+	max_pun = subsystem_maxid(host_index);
+	if (ibm_ansi_order) {
+		target = max_pun - 1 - cmd->target;
+		if ((target <= subsystem_pun(host_index)) && (cmd->target <= subsystem_pun(host_index)))
+			target--;
+		else if ((target >= subsystem_pun(host_index)) && (cmd->target >= subsystem_pun(host_index)))
+			target++;
+	} else
+		target = cmd->target;
+
+	/* if (target,lun) is NO LUN or not existing at all, return error */
+	if ((get_scsi(host_index)[target][cmd->lun] == TYPE_NO_LUN) || (get_scsi(host_index)[target][cmd->lun] == TYPE_NO_DEVICE)) {
+		cmd->result = DID_NO_CONNECT << 16;
+		if (done)
+			done(cmd);
+		return 0;
+	}
+
+	/*if (target,lun) unassigned, do further checks... */
+	ldn = get_ldn(host_index)[target][cmd->lun];
+	if (ldn >= MAX_LOG_DEV) {	/* on invalid ldn do special stuff */
+		if (ldn > MAX_LOG_DEV) {	/* dynamical remapping if ldn unassigned */
+			current_ldn = next_ldn(host_index);	/* stop-value for one circle */
+			while (ld(host_index)[next_ldn(host_index)].cmd) {	/* search for a occupied, but not in */
+				/* command-processing ldn. */
+				next_ldn(host_index)++;
+				if (next_ldn(host_index) >= MAX_LOG_DEV)
+					next_ldn(host_index) = 7;
+				if (current_ldn == next_ldn(host_index)) {	/* One circle done ? */
+					/* no non-processing ldn found */
+					printk("IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n" "              On ldn 7-14 SCSI-commands everywhere in progress.\n" "              Reporting DID_NO_CONNECT for device (%d,%d).\n", target, cmd->lun);
+					cmd->result = DID_NO_CONNECT << 16;	/* return no connect */
+					if (done)
+						done(cmd);
+					return 0;
+				}
+			}
+
+			/* unmap non-processing ldn */
+			for (id = 0; id < max_pun; id++)
+				for (lun = 0; lun < 8; lun++) {
+					if (get_ldn(host_index)[id][lun] == next_ldn(host_index)) {
+						get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE;
+						get_scsi(host_index)[id][lun] = TYPE_NO_DEVICE;
+						/* unmap entry */
+					}
+				}
+			/* set reduced interrupt_handler-mode for checking */
+			local_checking_phase_flag(host_index) = 1;
+			/* map found ldn to pun,lun */
+			get_ldn(host_index)[target][cmd->lun] = next_ldn(host_index);
+			/* change ldn to the right value, that is now next_ldn */
+			ldn = next_ldn(host_index);
+			/* unassign all ldns (pun,lun,ldn does not matter for remove) */
+			immediate_assign(host_index, 0, 0, 0, REMOVE_LDN);
+			/* set only LDN for remapped device */
+			immediate_assign(host_index, target, cmd->lun, ldn, SET_LDN);
+			/* get device information for ld[ldn] */
+			if (device_exists(host_index, ldn, &ld(host_index)[ldn].block_length, &ld(host_index)[ldn].device_type)) {
+				ld(host_index)[ldn].cmd = NULL;	/* To prevent panic set 0, because
+								   devices that were not assigned,
+								   should have nothing in progress. */
+				get_scsi(host_index)[target][cmd->lun] = ld(host_index)[ldn].device_type;
+				/* increase assignment counters for statistics in /proc */
+				IBM_DS(host_index).dynamical_assignments++;
+				IBM_DS(host_index).ldn_assignments[ldn]++;
+			} else
+				/* panic here, because a device, found at boottime has
+				   vanished */
+				panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n", ldn, target, cmd->lun);
+			/* unassign again all ldns (pun,lun,ldn does not matter for remove) */
+			immediate_assign(host_index, 0, 0, 0, REMOVE_LDN);
+			/* remap all ldns, as written in the pun/lun table */
+			lun = 0;
 #ifdef CONFIG_SCSI_MULTI_LUN
-	 for (lun=0; lun<8; lun++)
+			for (lun = 0; lun < 8; lun++)
 #endif
-	   for (id=0; id<max_pun; id ++) {
-	      if (get_ldn(host_index)[id][lun] <= MAX_LOG_DEV)
-		immediate_assign(host_index,id,lun,
-				 get_ldn(host_index)[id][lun],SET_LDN);
-	   }
-	 /* set back to normal interrupt_handling */
-	 local_checking_phase_flag(host_index) = 0;
+				for (id = 0; id < max_pun; id++) {
+					if (get_ldn(host_index)[id][lun] <= MAX_LOG_DEV)
+						immediate_assign(host_index, id, lun, get_ldn(host_index)[id][lun], SET_LDN);
+				}
+			/* set back to normal interrupt_handling */
+			local_checking_phase_flag(host_index) = 0;
 #ifdef IM_DEBUG_PROBE
-	 /* Information on syslog terminal */
-	 printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n",
-		ldn, target, cmd->lun);
-#endif
-	 /* increase next_ldn for next dynamical assignment */
-	 next_ldn(host_index)++;
-	 if (next_ldn(host_index)>=MAX_LOG_DEV)
-	   next_ldn(host_index) = 7;
-      } else {  /* wall against Linux accesses to the subsystem adapter */
-	 cmd->result = DID_BAD_TARGET << 16;
-	 if (done) done (cmd);
-	 return 0;
-      }
-   }
-
-   /*verify there is no command already in progress for this log dev */
-   if (ld(host_index)[ldn].cmd)
-     panic ("IBM MCA SCSI: cmd already in progress for this ldn.\n");
-
-   /*save done in cmd, and save cmd for the interrupt handler */
-   cmd->scsi_done = done;
-   ld(host_index)[ldn].cmd = cmd;
-
-   /*fill scb information independent of the scsi command */
-   scb = &(ld(host_index)[ldn].scb);
-   ld(host_index)[ldn].tsb.dev_status = 0;
-   scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE;
-   scb->tsb_adr = isa_virt_to_bus(&(ld(host_index)[ldn].tsb));
-   scsi_cmd = cmd->cmnd[0];
-
-   if (cmd->use_sg) {
-      i = cmd->use_sg;
-      sl = (struct scatterlist *)(cmd->request_buffer);
-      if (i > 16)
-	panic ("IBM MCA SCSI: scatter-gather list too long.\n");
-      while (--i >= 0) {
-	 ld(host_index)[ldn].sge[i].address = (void *)(isa_page_to_bus(sl[i].page) + sl[i].offset);
-	 ld(host_index)[ldn].sge[i].byte_length = sl[i].length;
-      }
-      scb->enable |= IM_POINTER_TO_LIST;
-      scb->sys_buf_adr = isa_virt_to_bus(&(ld(host_index)[ldn].sge[0]));
-      scb->sys_buf_length = cmd->use_sg * sizeof (struct im_sge);
-   } else {
-      scb->sys_buf_adr = isa_virt_to_bus(cmd->request_buffer);
-      /* recent Linux midlevel SCSI places 1024 byte for inquiry
-       * command. Far too much for old PS/2 hardware. */
-      switch (scsi_cmd) {
-	 /* avoid command errors by setting bufferlengths to
-	  * ANSI-standard. Beware of forcing it to 255,
-	  * this could SEGV the kernel!!! */
-       case INQUIRY:
-       case REQUEST_SENSE:
-       case MODE_SENSE:
-       case MODE_SELECT:
-	 if (cmd->request_bufflen > 255) scb->sys_buf_length = 255;
-	 else scb->sys_buf_length = cmd->request_bufflen;
-	 break;
-       case TEST_UNIT_READY:
-	 scb->sys_buf_length = 0;
-	 break;
-       default:
-	 scb->sys_buf_length = cmd->request_bufflen;
-	 break;
-      }
-   }
-   /*fill scb information dependent on scsi command */
+			/* Information on syslog terminal */
+			printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n", ldn, target, cmd->lun);
+#endif
+			/* increase next_ldn for next dynamical assignment */
+			next_ldn(host_index)++;
+			if (next_ldn(host_index) >= MAX_LOG_DEV)
+				next_ldn(host_index) = 7;
+		} else {	/* wall against Linux accesses to the subsystem adapter */
+			cmd->result = DID_BAD_TARGET << 16;
+			if (done)
+				done(cmd);
+			return 0;
+		}
+	}
+
+	/*verify there is no command already in progress for this log dev */
+	if (ld(host_index)[ldn].cmd)
+		panic("IBM MCA SCSI: cmd already in progress for this ldn.\n");
+
+	/*save done in cmd, and save cmd for the interrupt handler */
+	cmd->scsi_done = done;
+	ld(host_index)[ldn].cmd = cmd;
+
+	/*fill scb information independent of the scsi command */
+	scb = &(ld(host_index)[ldn].scb);
+	ld(host_index)[ldn].tsb.dev_status = 0;
+	scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE;
+	scb->tsb_adr = isa_virt_to_bus(&(ld(host_index)[ldn].tsb));
+	scsi_cmd = cmd->cmnd[0];
+
+	if (cmd->use_sg) {
+		i = cmd->use_sg;
+		sl = (struct scatterlist *) (cmd->request_buffer);
+		if (i > 16)
+			panic("IBM MCA SCSI: scatter-gather list too long.\n");
+		while (--i >= 0) {
+			ld(host_index)[ldn].sge[i].address = (void *) (isa_page_to_bus(sl[i].page) + sl[i].offset);
+			ld(host_index)[ldn].sge[i].byte_length = sl[i].length;
+		}
+		scb->enable |= IM_POINTER_TO_LIST;
+		scb->sys_buf_adr = isa_virt_to_bus(&(ld(host_index)[ldn].sge[0]));
+		scb->sys_buf_length = cmd->use_sg * sizeof(struct im_sge);
+	} else {
+		scb->sys_buf_adr = isa_virt_to_bus(cmd->request_buffer);
+		/* recent Linux midlevel SCSI places 1024 byte for inquiry
+		 * command. Far too much for old PS/2 hardware. */
+		switch (scsi_cmd) {
+			/* avoid command errors by setting bufferlengths to
+			 * ANSI-standard. Beware of forcing it to 255,
+			 * this could SEGV the kernel!!! */
+		case INQUIRY:
+		case REQUEST_SENSE:
+		case MODE_SENSE:
+		case MODE_SELECT:
+			if (cmd->request_bufflen > 255)
+				scb->sys_buf_length = 255;
+			else
+				scb->sys_buf_length = cmd->request_bufflen;
+			break;
+		case TEST_UNIT_READY:
+			scb->sys_buf_length = 0;
+			break;
+		default:
+			scb->sys_buf_length = cmd->request_bufflen;
+			break;
+		}
+	}
+	/*fill scb information dependent on scsi command */
 
 #ifdef IM_DEBUG_CMD
-   printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn);
+	printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn);
 #endif
 
-   /* for specific device-type debugging: */
+	/* for specific device-type debugging: */
 #ifdef IM_DEBUG_CMD_SPEC_DEV
-   if (ld(host_index)[ldn].device_type==IM_DEBUG_CMD_DEVICE)
-     printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n",
-	    ld(host_index)[ldn].device_type, scsi_cmd, ldn);
-#endif
-
-   /* for possible panics store current command */
-   last_scsi_command(host_index)[ldn] = scsi_cmd;
-   last_scsi_type(host_index)[ldn] = IM_SCB;
-   /* update statistical info */
-   IBM_DS(host_index).total_accesses++;
-   IBM_DS(host_index).ldn_access[ldn]++;
-
-   switch (scsi_cmd) {
-    case READ_6:
-    case WRITE_6:
-    case READ_10:
-    case WRITE_10:
-    case READ_12:
-    case WRITE_12:
-      /* Distinguish between disk and other devices. Only disks (that are the
-	 most frequently accessed devices) should be supported by the
-       IBM-SCSI-Subsystem commands. */
-      switch (ld(host_index)[ldn].device_type) {
-       case TYPE_DISK: /* for harddisks enter here ... */
-       case TYPE_MOD:  /* ... try it also for MO-drives (send flames as */
-	 /*     you like, if this won't work.) */
-	 if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12) {
-	    /* read command preparations */
-	    scb->enable |= IM_READ_CONTROL;
-	    IBM_DS(host_index).ldn_read_access[ldn]++; /* increase READ-access on ldn stat. */
-	    scb->command = IM_READ_DATA_CMD | IM_NO_DISCONNECT;
-	 } else { /* write command preparations */
-	    IBM_DS(host_index).ldn_write_access[ldn]++; /* increase write-count on ldn stat.*/
-	    scb->command = IM_WRITE_DATA_CMD | IM_NO_DISCONNECT;
-	 }
-	 if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6) {
-	    scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) |
-	      (((unsigned) cmd->cmnd[2]) << 8) |
-	      ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16);
-	    scb->u2.blk.count = (unsigned) cmd->cmnd[4];
-	 } else {
-	    scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) |
-	      (((unsigned) cmd->cmnd[4]) << 8) |
-	      (((unsigned) cmd->cmnd[3]) << 16) |
-	      (((unsigned) cmd->cmnd[2]) << 24);
-	    scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) |
-	      (((unsigned) cmd->cmnd[7]) << 8);
-	 }
-	 last_scsi_logical_block(host_index)[ldn] = scb->u1.log_blk_adr;
-	 last_scsi_blockcount(host_index)[ldn] = scb->u2.blk.count;
-	 scb->u2.blk.length = ld(host_index)[ldn].block_length;
-	 break;
-	 /* for other devices, enter here. Other types are not known by
-	    Linux! TYPE_NO_LUN is forbidden as valid device. */
-       case TYPE_ROM:
-       case TYPE_TAPE:
-       case TYPE_PROCESSOR:
-       case TYPE_WORM:
-       case TYPE_SCANNER:
-       case TYPE_MEDIUM_CHANGER:
-	 /* If there is a sequential-device, IBM recommends to use
-	  IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE.
-	  This includes CD-ROM devices, too, due to the partial sequential
-	  read capabilities. */
-	 scb->command = IM_OTHER_SCSI_CMD_CMD;
-	 if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12)
-	   /* enable READ */
-	   scb->enable |= IM_READ_CONTROL;
-	 scb->enable |= IM_BYPASS_BUFFER;
-	 scb->u1.scsi_cmd_length = cmd->cmd_len;
-	 memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
-	 last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
-	 /* Read/write on this non-disk devices is also displayworthy,
-	    so flash-up the LED/display. */
-	 break;
-      }
-      break;
-    case INQUIRY:
-      IBM_DS(host_index).ldn_inquiry_access[ldn]++;
-      scb->command = IM_DEVICE_INQUIRY_CMD;
-      scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
-      scb->u1.log_blk_adr = 0;
-      break;
-    case TEST_UNIT_READY:
-      scb->command = IM_OTHER_SCSI_CMD_CMD;
-      scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
-      scb->u1.log_blk_adr = 0;
-      scb->u1.scsi_cmd_length = 6;
-      memcpy (scb->u2.scsi_command, cmd->cmnd, 6);
-      last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
-      break;
-    case READ_CAPACITY:
-      /* the length of system memory buffer must be exactly 8 bytes */
-      scb->command = IM_READ_CAPACITY_CMD;
-      scb->enable |= IM_READ_CONTROL | IM_BYPASS_BUFFER;
-      if (scb->sys_buf_length > 8) scb->sys_buf_length = 8;
-      break;
-      /* Commands that need read-only-mode (system <- device): */
-    case REQUEST_SENSE:
-      scb->command = IM_REQUEST_SENSE_CMD;
-      scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
-      break;
-      /* Commands that need write-only-mode (system -> device): */
-    case MODE_SELECT:
-    case MODE_SELECT_10:
-      IBM_DS(host_index).ldn_modeselect_access[ldn]++;
-      scb->command = IM_OTHER_SCSI_CMD_CMD;
-      scb->enable |= IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER; /*Select needs WRITE-enabled*/
-      scb->u1.scsi_cmd_length = cmd->cmd_len;
-      memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
-      last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
-      break;
-      /* For other commands, read-only is useful. Most other commands are
-       running without an input-data-block. */
-    default:
-      scb->command = IM_OTHER_SCSI_CMD_CMD;
-      scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
-      scb->u1.scsi_cmd_length = cmd->cmd_len;
-      memcpy (scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
-      last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
-      break;
-   }
-   /*issue scb command, and return */
-   if (++disk_rw_in_progress == 1)
-     PS2_DISK_LED_ON (shpnt->host_no, target);
-
-   if (last_scsi_type(host_index)[ldn] == IM_LONG_SCB) {
-      issue_cmd (host_index, isa_virt_to_bus(scb), IM_LONG_SCB | ldn);
-      IBM_DS(host_index).long_scbs++;
-   } else {
-      issue_cmd (host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
-      IBM_DS(host_index).scbs++;
-   }
-   return 0;
-}
-
-int ibmmca_abort (Scsi_Cmnd * cmd)
-{
-   /* Abort does not work, as the adapter never generates an interrupt on
-    * whatever situation is simulated, even when really pending commands
-    * are running on the adapters' hardware ! */
-
-   struct Scsi_Host *shpnt;
-   unsigned int ldn;
-   void (*saved_done) (Scsi_Cmnd *);
-   int target;
-   int host_index;
-   int max_pun;
-   static unsigned long flags;
-   unsigned long imm_command;
+	if (ld(host_index)[ldn].device_type == IM_DEBUG_CMD_DEVICE)
+		printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", ld(host_index)[ldn].device_type, scsi_cmd, ldn);
+#endif
+
+	/* for possible panics store current command */
+	last_scsi_command(host_index)[ldn] = scsi_cmd;
+	last_scsi_type(host_index)[ldn] = IM_SCB;
+	/* update statistical info */
+	IBM_DS(host_index).total_accesses++;
+	IBM_DS(host_index).ldn_access[ldn]++;
+
+	switch (scsi_cmd) {
+	case READ_6:
+	case WRITE_6:
+	case READ_10:
+	case WRITE_10:
+	case READ_12:
+	case WRITE_12:
+		/* Distinguish between disk and other devices. Only disks (that are the
+		   most frequently accessed devices) should be supported by the
+		   IBM-SCSI-Subsystem commands. */
+		switch (ld(host_index)[ldn].device_type) {
+		case TYPE_DISK:	/* for harddisks enter here ... */
+		case TYPE_MOD:	/* ... try it also for MO-drives (send flames as */
+			/*     you like, if this won't work.) */
+			if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12) {
+				/* read command preparations */
+				scb->enable |= IM_READ_CONTROL;
+				IBM_DS(host_index).ldn_read_access[ldn]++;	/* increase READ-access on ldn stat. */
+				scb->command = IM_READ_DATA_CMD | IM_NO_DISCONNECT;
+			} else {	/* write command preparations */
+				IBM_DS(host_index).ldn_write_access[ldn]++;	/* increase write-count on ldn stat. */
+				scb->command = IM_WRITE_DATA_CMD | IM_NO_DISCONNECT;
+			}
+			if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6) {
+				scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) | (((unsigned) cmd->cmnd[2]) << 8) | ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16);
+				scb->u2.blk.count = (unsigned) cmd->cmnd[4];
+			} else {
+				scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) | (((unsigned) cmd->cmnd[4]) << 8) | (((unsigned) cmd->cmnd[3]) << 16) | (((unsigned) cmd->cmnd[2]) << 24);
+				scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) | (((unsigned) cmd->cmnd[7]) << 8);
+			}
+			last_scsi_logical_block(host_index)[ldn] = scb->u1.log_blk_adr;
+			last_scsi_blockcount(host_index)[ldn] = scb->u2.blk.count;
+			scb->u2.blk.length = ld(host_index)[ldn].block_length;
+			break;
+			/* for other devices, enter here. Other types are not known by
+			   Linux! TYPE_NO_LUN is forbidden as valid device. */
+		case TYPE_ROM:
+		case TYPE_TAPE:
+		case TYPE_PROCESSOR:
+		case TYPE_WORM:
+		case TYPE_SCANNER:
+		case TYPE_MEDIUM_CHANGER:
+			/* If there is a sequential-device, IBM recommends to use
+			   IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE.
+			   This includes CD-ROM devices, too, due to the partial sequential
+			   read capabilities. */
+			scb->command = IM_OTHER_SCSI_CMD_CMD;
+			if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12)
+				/* enable READ */
+				scb->enable |= IM_READ_CONTROL;
+			scb->enable |= IM_BYPASS_BUFFER;
+			scb->u1.scsi_cmd_length = cmd->cmd_len;
+			memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+			last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+			/* Read/write on this non-disk devices is also displayworthy,
+			   so flash-up the LED/display. */
+			break;
+		}
+		break;
+	case INQUIRY:
+		IBM_DS(host_index).ldn_inquiry_access[ldn]++;
+		scb->command = IM_DEVICE_INQUIRY_CMD;
+		scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
+		scb->u1.log_blk_adr = 0;
+		break;
+	case TEST_UNIT_READY:
+		scb->command = IM_OTHER_SCSI_CMD_CMD;
+		scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
+		scb->u1.log_blk_adr = 0;
+		scb->u1.scsi_cmd_length = 6;
+		memcpy(scb->u2.scsi_command, cmd->cmnd, 6);
+		last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+		break;
+	case READ_CAPACITY:
+		/* the length of system memory buffer must be exactly 8 bytes */
+		scb->command = IM_READ_CAPACITY_CMD;
+		scb->enable |= IM_READ_CONTROL | IM_BYPASS_BUFFER;
+		if (scb->sys_buf_length > 8)
+			scb->sys_buf_length = 8;
+		break;
+		/* Commands that need read-only-mode (system <- device): */
+	case REQUEST_SENSE:
+		scb->command = IM_REQUEST_SENSE_CMD;
+		scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
+		break;
+		/* Commands that need write-only-mode (system -> device): */
+	case MODE_SELECT:
+	case MODE_SELECT_10:
+		IBM_DS(host_index).ldn_modeselect_access[ldn]++;
+		scb->command = IM_OTHER_SCSI_CMD_CMD;
+		scb->enable |= IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;	/*Select needs WRITE-enabled */
+		scb->u1.scsi_cmd_length = cmd->cmd_len;
+		memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+		last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+		break;
+		/* For other commands, read-only is useful. Most other commands are
+		   running without an input-data-block. */
+	default:
+		scb->command = IM_OTHER_SCSI_CMD_CMD;
+		scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
+		scb->u1.scsi_cmd_length = cmd->cmd_len;
+		memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+		last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+		break;
+	}
+	/*issue scb command, and return */
+	if (++disk_rw_in_progress == 1)
+		PS2_DISK_LED_ON(shpnt->host_no, target);
+
+	if (last_scsi_type(host_index)[ldn] == IM_LONG_SCB) {
+		issue_cmd(host_index, isa_virt_to_bus(scb), IM_LONG_SCB | ldn);
+		IBM_DS(host_index).long_scbs++;
+	} else {
+		issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
+		IBM_DS(host_index).scbs++;
+	}
+	return 0;
+}
+
+static int ibmmca_abort(Scsi_Cmnd * cmd)
+{
+	/* Abort does not work, as the adapter never generates an interrupt on
+	 * whatever situation is simulated, even when really pending commands
+	 * are running on the adapters' hardware ! */
+
+	struct Scsi_Host *shpnt;
+	unsigned int ldn;
+	void (*saved_done) (Scsi_Cmnd *);
+	int target;
+	int host_index;
+	int max_pun;
+	unsigned long imm_command;
 
 #ifdef IM_DEBUG_PROBE
-   printk("IBM MCA SCSI: Abort subroutine called...\n");
+	printk("IBM MCA SCSI: Abort subroutine called...\n");
 #endif
-   IBMLOCK(cmd->host)
-   shpnt = cmd->host;
-   /* search for the right hostadapter */
-   for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
-
-   if (!hosts[host_index]) { /* invalid hostadapter descriptor address */
-      cmd->result = DID_NO_CONNECT << 16;
-      if (cmd->scsi_done) (cmd->scsi_done) (cmd);
-      shpnt = cmd->host;
-      IBMUNLOCK(shpnt)
+
+	shpnt = cmd->host;
+	/* search for the right hostadapter */
+	for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
+
+	if (!hosts[host_index]) {	/* invalid hostadapter descriptor address */
+		cmd->result = DID_NO_CONNECT << 16;
+		if (cmd->scsi_done)
+			(cmd->scsi_done) (cmd);
+		shpnt = cmd->host;
 #ifdef IM_DEBUG_PROBE
-      printk("IBM MCA SCSI: Abort adapter selection failed!\n");
+		printk(KERN_DEBUG "IBM MCA SCSI: Abort adapter selection failed!\n");
 #endif
-      return SCSI_ABORT_SNOOZE;
-   }
-   max_pun = subsystem_maxid(host_index);
-   if (ibm_ansi_order) {
-      target = max_pun - 1 - cmd->target;
-      if ((target <= subsystem_pun(host_index))&&(cmd->target <= subsystem_pun(host_index)))
-	target--;
-      else if ((target >= subsystem_pun(host_index))&&(cmd->target >= subsystem_pun(host_index)))
-	target++;
-   } else
-     target = cmd->target;
-
-   /* get logical device number, and disable system interrupts */
-   printk ("IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n",
-	   target, cmd->lun);
-   ldn = get_ldn(host_index)[target][cmd->lun];
-
-   /*if cmd for this ldn has already finished, no need to abort */
-   if (!ld(host_index)[ldn].cmd) {
-      IBMUNLOCK(shpnt)
-      return SCSI_ABORT_NOT_RUNNING;
-   }
-
-   /* Clear ld.cmd, save done function, install internal done,
-    * send abort immediate command (this enables sys. interrupts),
-    * and wait until the interrupt arrives.
-    */
-   saved_done = cmd->scsi_done;
-   cmd->scsi_done = internal_done;
-   cmd->SCp.Status = 0;
-   last_scsi_command(host_index)[ldn] = IM_ABORT_IMM_CMD;
-   last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
-   imm_command = inl(IM_CMD_REG(host_index));
-   imm_command &= (unsigned long)(0xffff0000); /* mask reserved stuff */
-   imm_command |= (unsigned long)(IM_ABORT_IMM_CMD);
-   /* must wait for attention reg not busy */
-   while (1) {
-      if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
-	break;
-      IBMUNLOCK(shpnt)
-      IBMLOCK(shpnt)
-   }
-   /* write registers and enable system interrupts */
-   outl (imm_command, IM_CMD_REG(host_index));
-   outb (IM_IMM_CMD | ldn, IM_ATTN_REG(host_index));
-   IBMUNLOCK(shpnt)
+		return SUCCESS;
+	}
+	max_pun = subsystem_maxid(host_index);
+	if (ibm_ansi_order) {
+		target = max_pun - 1 - cmd->target;
+		if ((target <= subsystem_pun(host_index)) && (cmd->target <= subsystem_pun(host_index)))
+			target--;
+		else if ((target >= subsystem_pun(host_index)) && (cmd->target >= subsystem_pun(host_index)))
+			target++;
+	} else
+		target = cmd->target;
+
+	/* get logical device number, and disable system interrupts */
+	printk(KERN_WARNING "IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n", target, cmd->lun);
+	ldn = get_ldn(host_index)[target][cmd->lun];
+
+	/*if cmd for this ldn has already finished, no need to abort */
+	if (!ld(host_index)[ldn].cmd) {
+		    return SUCCESS;
+	}
+
+	/* Clear ld.cmd, save done function, install internal done,
+	 * send abort immediate command (this enables sys. interrupts),
+	 * and wait until the interrupt arrives.
+	 */
+	saved_done = cmd->scsi_done;
+	cmd->scsi_done = internal_done;
+	cmd->SCp.Status = 0;
+	last_scsi_command(host_index)[ldn] = IM_ABORT_IMM_CMD;
+	last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
+	imm_command = inl(IM_CMD_REG(host_index));
+	imm_command &= (unsigned long) (0xffff0000);	/* mask reserved stuff */
+	imm_command |= (unsigned long) (IM_ABORT_IMM_CMD);
+	/* must wait for attention reg not busy */
+	/* FIXME - timeout, politeness */
+	while (1) {
+		if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+			break;
+	}
+	/* write registers and enable system interrupts */
+	outl(imm_command, IM_CMD_REG(host_index));
+	outb(IM_IMM_CMD | ldn, IM_ATTN_REG(host_index));
 #ifdef IM_DEBUG_PROBE
-   printk("IBM MCA SCSI: Abort queued to adapter...\n");
+	printk("IBM MCA SCSI: Abort queued to adapter...\n");
 #endif
-   while (!cmd->SCp.Status) barrier ();
-   cmd->scsi_done = saved_done;
+	spin_unlock_irq(shpnt->host_lock);
+	while (!cmd->SCp.Status)
+		yield();
+	spin_lock_irq(shpnt->host_lock);
+	cmd->scsi_done = saved_done;
 #ifdef IM_DEBUG_PROBE
-   printk("IBM MCA SCSI: Abort returned with adapter response...\n");
+	printk("IBM MCA SCSI: Abort returned with adapter response...\n");
 #endif
 
-   /*if abort went well, call saved done, then return success or error */
-   if (cmd->result == (DID_ABORT << 16)) {
-      IBMLOCK(shpnt)
-      cmd->result |= DID_ABORT << 16;
-      if (cmd->scsi_done) (cmd->scsi_done) (cmd);
-      ld(host_index)[ldn].cmd = NULL;
-      IBMUNLOCK(shpnt)
+	/*if abort went well, call saved done, then return success or error */
+	if (cmd->result == (DID_ABORT << 16)) 
+	{
+		cmd->result |= DID_ABORT << 16;
+		if (cmd->scsi_done)
+			(cmd->scsi_done) (cmd);
+		ld(host_index)[ldn].cmd = NULL;
 #ifdef IM_DEBUG_PROBE
-      printk("IBM MCA SCSI: Abort finished with success.\n");
+		printk("IBM MCA SCSI: Abort finished with success.\n");
 #endif
-      return SCSI_ABORT_SUCCESS;
-   } else {
-      IBMLOCK(shpnt)
-      cmd->result |= DID_NO_CONNECT << 16;
-      if (cmd->scsi_done) (cmd->scsi_done) (cmd);
-      ld(host_index)[ldn].cmd = NULL;
-      IBMUNLOCK(shpnt)
+		return SUCCESS;
+	} else {
+		cmd->result |= DID_NO_CONNECT << 16;
+		if (cmd->scsi_done)
+			(cmd->scsi_done) (cmd);
+		ld(host_index)[ldn].cmd = NULL;
 #ifdef IM_DEBUG_PROBE
-      printk("IBM MCA SCSI: Abort failed.\n");
+		printk("IBM MCA SCSI: Abort failed.\n");
 #endif
-      return SCSI_ABORT_ERROR;
-   }
+		return FAILED;
+	}
+}
+
+static int ibmmca_host_reset(Scsi_Cmnd * cmd)
+{
+	struct Scsi_Host *shpnt;
+	Scsi_Cmnd *cmd_aid;
+	int ticks, i;
+	int host_index;
+	unsigned long imm_command;
+
+	if (cmd == NULL)
+		BUG();
+
+	ticks = IM_RESET_DELAY * HZ;
+	shpnt = cmd->host;
+	/* search for the right hostadapter */
+	for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
+
+	if (!hosts[host_index])	/* invalid hostadapter descriptor address */
+		return FAILED;
+
+	if (local_checking_phase_flag(host_index)) {
+		printk(KERN_WARNING "IBM MCA SCSI: unable to reset while checking devices.\n");
+		return FAILED;
+	}
+
+	/* issue reset immediate command to subsystem, and wait for interrupt */
+	printk("IBM MCA SCSI: resetting all devices.\n");
+	reset_status(host_index) = IM_RESET_IN_PROGRESS;
+	last_scsi_command(host_index)[0xf] = IM_RESET_IMM_CMD;
+	last_scsi_type(host_index)[0xf] = IM_IMM_CMD;
+	imm_command = inl(IM_CMD_REG(host_index));
+	imm_command &= (unsigned long) (0xffff0000);	/* mask reserved stuff */
+	imm_command |= (unsigned long) (IM_RESET_IMM_CMD);
+	/* must wait for attention reg not busy */
+	while (1) {
+		if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+			break;
+		spin_unlock_irq(shpnt->host_lock);
+		yield();
+		spin_lock_irq(shpnt->host_lock);
+	}
+	/*write registers and enable system interrupts */
+	outl(imm_command, IM_CMD_REG(host_index));
+	outb(IM_IMM_CMD | 0xf, IM_ATTN_REG(host_index));
+	/* wait for interrupt finished or intr_stat register to be set, as the
+	 * interrupt will not be executed, while we are in here! */
+	 
+	/* FIXME: This is really really icky we so want a sleeping version of this ! */
+	while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks && ((inb(IM_INTR_REG(host_index)) & 0x8f) != 0x8f)) {
+		udelay((1 + 999 / HZ) * 1000);
+		barrier();
+	}
+	/* if reset did not complete, just return an error */
+	if (!ticks) {
+		printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY);
+		reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+		return FAILED;
+	}
+
+	if ((inb(IM_INTR_REG(host_index)) & 0x8f) == 0x8f) {
+		/* analysis done by this routine and not by the intr-routine */
+		if (inb(IM_INTR_REG(host_index)) == 0xaf)
+			reset_status(host_index) = IM_RESET_FINISHED_OK_NO_INT;
+		else if (inb(IM_INTR_REG(host_index)) == 0xcf)
+			reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+		else		/* failed, 4get it */
+			reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS_NO_INT;
+		outb(IM_EOI | 0xf, IM_ATTN_REG(host_index));
+	}
+
+	/* if reset failed, just return an error */
+	if (reset_status(host_index) == IM_RESET_FINISHED_FAIL) {
+		printk(KERN_ERR "IBM MCA SCSI: reset failed.\n");
+		return FAILED;
+	}
+
+	/* so reset finished ok - call outstanding done's, and return success */
+	printk(KERN_INFO "IBM MCA SCSI: Reset successfully completed.\n");
+	for (i = 0; i < MAX_LOG_DEV; i++) {
+		cmd_aid = ld(host_index)[i].cmd;
+		if (cmd_aid && cmd_aid->scsi_done) {
+			ld(host_index)[i].cmd = NULL;
+			cmd_aid->result = DID_RESET << 16;
+		}
+	}
+	return SUCCESS;
 }
 
-int ibmmca_reset (Scsi_Cmnd * cmd, unsigned int reset_flags)
+static int ibmmca_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *info)
 {
-   struct Scsi_Host *shpnt;
-   Scsi_Cmnd *cmd_aid;
-   int ticks,i;
-   int host_index;
-   static unsigned long flags;
-   unsigned long imm_command;
-
-   if (cmd == NULL) {
-      printk("IBM MCA SCSI: Reset called with NULL-command!\n");
-      return(SCSI_RESET_SNOOZE);
-   }
-   IBMLOCK(cmd->host)
-   ticks = IM_RESET_DELAY*HZ;
-   shpnt = cmd->host;
-   /* search for the right hostadapter */
-   for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
-
-   if (!hosts[host_index]) /* invalid hostadapter descriptor address */
-     return SCSI_ABORT_SNOOZE;
-
-   if (local_checking_phase_flag(host_index)) {
-      printk("IBM MCA SCSI: unable to reset while checking devices.\n");
-      IBMUNLOCK(shpnt)
-      return SCSI_RESET_SNOOZE;
-   }
-
-   /* issue reset immediate command to subsystem, and wait for interrupt */
-   printk("IBM MCA SCSI: resetting all devices.\n");
-   reset_status(host_index) = IM_RESET_IN_PROGRESS;
-   last_scsi_command(host_index)[0xf] = IM_RESET_IMM_CMD;
-   last_scsi_type(host_index)[0xf] = IM_IMM_CMD;
-   imm_command = inl(IM_CMD_REG(host_index));
-   imm_command &= (unsigned long)(0xffff0000); /* mask reserved stuff */
-   imm_command |= (unsigned long)(IM_RESET_IMM_CMD);
-   /* must wait for attention reg not busy */
-   while (1) {
-      if (!(inb (IM_STAT_REG(host_index)) & IM_BUSY))
-	break;
-      IBMUNLOCK(shpnt)
-      IBMLOCK(shpnt)
-   }
-   /*write registers and enable system interrupts */
-   outl (imm_command, IM_CMD_REG(host_index));
-   outb (IM_IMM_CMD | 0xf, IM_ATTN_REG(host_index));
-   /* wait for interrupt finished or intr_stat register to be set, as the
-    * interrupt will not be executed, while we are in here! */
-   while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks
-	  && ((inb(IM_INTR_REG(host_index)) & 0x8f)!=0x8f)) {
-      udelay((1+999/HZ)*1000);
-      barrier();
-   }
-   /* if reset did not complete, just return an error*/
-   if (!ticks) {
-      printk("IBM MCA SCSI: reset did not complete within %d seconds.\n",
-	     IM_RESET_DELAY);
-      reset_status(host_index) = IM_RESET_FINISHED_FAIL;
-      IBMUNLOCK(shpnt)
-      return SCSI_RESET_ERROR;
-   }
-
-   if ((inb(IM_INTR_REG(host_index)) & 0x8f)==0x8f) {
-      /* analysis done by this routine and not by the intr-routine */
-      if (inb(IM_INTR_REG(host_index))==0xaf)
-	reset_status(host_index) = IM_RESET_FINISHED_OK_NO_INT;
-      else if (inb(IM_INTR_REG(host_index))==0xcf)
-	reset_status(host_index) = IM_RESET_FINISHED_FAIL;
-      else /* failed, 4get it */
-	reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS_NO_INT;
-      outb (IM_EOI | 0xf, IM_ATTN_REG(host_index));
-   }
-
-   /* if reset failed, just return an error */
-   if (reset_status(host_index) == IM_RESET_FINISHED_FAIL) {
-      printk("IBM MCA SCSI: reset failed.\n");
-      IBMUNLOCK(shpnt)
-      return SCSI_RESET_ERROR;
-   }
-
-   /* so reset finished ok - call outstanding done's, and return success */
-   printk ("IBM MCA SCSI: Reset successfully completed.\n");
-   IBMUNLOCK(shpnt)
-   for (i = 0; i < MAX_LOG_DEV; i++) {
-      cmd_aid = ld(host_index)[i].cmd;
-      if (cmd_aid && cmd_aid->scsi_done) {
-	 ld(host_index)[i].cmd = NULL;
-	 cmd_aid->result = DID_RESET << 16;
-      }
-   }
-   if (reset_flags & SCSI_RESET_SUGGEST_HOST_RESET)
-     return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET);
-   else if (reset_flags & SCSI_RESET_SUGGEST_BUS_RESET)
-     return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);
-   else
-     return SCSI_RESET_SUCCESS;
-}
-
-int ibmmca_biosparam (struct scsi_device *sdev, struct block_device *bdev,
-		sector_t capacity, int *info)
-{
-   int size = capacity;
-   info[0] = 64;
-   info[1] = 32;
-   info[2] = size / (info[0] * info[1]);
-   if (info[2] >= 1024) {
-      info[0] = 128;
-      info[1] = 63;
-      info[2] = size / (info[0] * info[1]);
-      if (info[2] >= 1024) {
-	 info[0] = 255;
-	 info[1] = 63;
-	 info[2] = size / (info[0] * info[1]);
-	 if (info[2] >= 1024)
-	   info[2] = 1023;
-      }
-   }
-   return 0;
+	int size = capacity;
+	info[0] = 64;
+	info[1] = 32;
+	info[2] = size / (info[0] * info[1]);
+	if (info[2] >= 1024) {
+		info[0] = 128;
+		info[1] = 63;
+		info[2] = size / (info[0] * info[1]);
+		if (info[2] >= 1024) {
+			info[0] = 255;
+			info[1] = 63;
+			info[2] = size / (info[0] * info[1]);
+			if (info[2] >= 1024)
+				info[2] = 1023;
+		}
+	}
+	return 0;
 }
 
 /* calculate percentage of total accesses on a ldn */
 static int ldn_access_load(int host_index, int ldn)
 {
-   if (IBM_DS(host_index).total_accesses == 0) return (0);
-   if (IBM_DS(host_index).ldn_access[ldn] == 0) return (0);
-   return (IBM_DS(host_index).ldn_access[ldn] * 100) / IBM_DS(host_index).total_accesses;
+	if (IBM_DS(host_index).total_accesses == 0)
+		return (0);
+	if (IBM_DS(host_index).ldn_access[ldn] == 0)
+		return (0);
+	return (IBM_DS(host_index).ldn_access[ldn] * 100) / IBM_DS(host_index).total_accesses;
 }
 
 /* calculate total amount of r/w-accesses */
 static int ldn_access_total_read_write(int host_index)
 {
-   int a;
-   int i;
+	int a;
+	int i;
 
-   a = 0;
-   for (i=0; i<=MAX_LOG_DEV; i++)
-     a+=IBM_DS(host_index).ldn_read_access[i]+IBM_DS(host_index).ldn_write_access[i];
-   return(a);
+	a = 0;
+	for (i = 0; i <= MAX_LOG_DEV; i++)
+		a += IBM_DS(host_index).ldn_read_access[i] + IBM_DS(host_index).ldn_write_access[i];
+	return (a);
 }
 
 static int ldn_access_total_inquiry(int host_index)
 {
-   int a;
-   int i;
+	int a;
+	int i;
 
-   a = 0;
-   for (i=0; i<=MAX_LOG_DEV; i++)
-     a+=IBM_DS(host_index).ldn_inquiry_access[i];
-   return(a);
+	a = 0;
+	for (i = 0; i <= MAX_LOG_DEV; i++)
+		a += IBM_DS(host_index).ldn_inquiry_access[i];
+	return (a);
 }
 
 static int ldn_access_total_modeselect(int host_index)
 {
-   int a;
-   int i;
+	int a;
+	int i;
 
-   a = 0;
-   for (i=0; i<=MAX_LOG_DEV; i++)
-     a+=IBM_DS(host_index).ldn_modeselect_access[i];
-   return(a);
+	a = 0;
+	for (i = 0; i <= MAX_LOG_DEV; i++)
+		a += IBM_DS(host_index).ldn_modeselect_access[i];
+	return (a);
 }
 
 /* routine to display info in the proc-fs-structure (a deluxe feature) */
-int ibmmca_proc_info (char *buffer, char **start, off_t offset, int length,
-		      int hostno, int inout)
+static int ibmmca_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
 {
-   int len=0;
-   int i,id,lun,host_index;
-   struct Scsi_Host *shpnt;
-   unsigned long flags;
-   int max_pun;
-
-   for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++);
-   IBMLOCK(hosts[i]) /* Check it */
-   shpnt = hosts[i];
-   host_index = i;
-   if (!shpnt) {
-      len += sprintf(buffer+len, "\nIBM MCA SCSI: Can't find adapter for host number %d\n", hostno);
-      return len;
-   }
-   max_pun = subsystem_maxid(host_index);
-
-   len += sprintf(buffer+len, "\n             IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n",
-		  IBMMCA_SCSI_DRIVER_VERSION);
-   len += sprintf(buffer+len, " SCSI Access-Statistics:\n");
-   len += sprintf(buffer+len, "               Device Scanning Order....: %s\n",
-		  (ibm_ansi_order) ? "IBM/ANSI" : "New Industry Standard");
+	int len = 0;
+	int i, id, lun, host_index;
+	struct Scsi_Host *shpnt;
+	unsigned long flags;
+	int max_pun;
+
+	for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++);
+	
+	spin_lock_irqsave(hosts[i]->host_lock, flags);	/* Check it */
+	shpnt = hosts[i];
+	host_index = i;
+	if (!shpnt) {
+		len += sprintf(buffer + len, "\nIBM MCA SCSI: Can't find adapter for host number %d\n", hostno);
+		return len;
+	}
+	max_pun = subsystem_maxid(host_index);
+
+	len += sprintf(buffer + len, "\n             IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n", IBMMCA_SCSI_DRIVER_VERSION);
+	len += sprintf(buffer + len, " SCSI Access-Statistics:\n");
+	len += sprintf(buffer + len, "               Device Scanning Order....: %s\n", (ibm_ansi_order) ? "IBM/ANSI" : "New Industry Standard");
 #ifdef CONFIG_SCSI_MULTI_LUN
-   len += sprintf(buffer+len, "               Multiple LUN probing.....: Yes\n");
+	len += sprintf(buffer + len, "               Multiple LUN probing.....: Yes\n");
 #else
-   len += sprintf(buffer+len, "               Multiple LUN probing.....: No\n");
+	len += sprintf(buffer + len, "               Multiple LUN probing.....: No\n");
 #endif
-   len += sprintf(buffer+len, "               This Hostnumber..........: %d\n",
-		  hostno);
-   len += sprintf(buffer+len, "               Base I/O-Port............: 0x%x\n",
-		  (unsigned int)(IM_CMD_REG(host_index)));
-   len += sprintf(buffer+len, "               (Shared) IRQ.............: %d\n",
-		  IM_IRQ);
-   len += sprintf(buffer+len, "               Total Interrupts.........: %d\n",
-		  IBM_DS(host_index).total_interrupts);
-   len += sprintf(buffer+len, "               Total SCSI Accesses......: %d\n",
-		  IBM_DS(host_index).total_accesses);
-   len += sprintf(buffer+len, "               Total short SCBs.........: %d\n",
-		  IBM_DS(host_index).scbs);
-   len += sprintf(buffer+len, "               Total long SCBs..........: %d\n",
-		  IBM_DS(host_index).long_scbs);
-   len += sprintf(buffer+len, "                 Total SCSI READ/WRITE..: %d\n",
-		  ldn_access_total_read_write(host_index));
-   len += sprintf(buffer+len, "                 Total SCSI Inquiries...: %d\n",
-		  ldn_access_total_inquiry(host_index));
-   len += sprintf(buffer+len, "                 Total SCSI Modeselects.: %d\n",
-		  ldn_access_total_modeselect(host_index));
-   len += sprintf(buffer+len, "                 Total SCSI other cmds..: %d\n",
-		  IBM_DS(host_index).total_accesses - ldn_access_total_read_write(host_index)
-		  - ldn_access_total_modeselect(host_index)
-		  - ldn_access_total_inquiry(host_index));
-   len += sprintf(buffer+len, "               Total SCSI command fails.: %d\n\n",
-		  IBM_DS(host_index).total_errors);
-   len += sprintf(buffer+len, " Logical-Device-Number (LDN) Access-Statistics:\n");
-   len += sprintf(buffer+len, "         LDN | Accesses [%%] |   READ    |   WRITE   | ASSIGNMENTS\n");
-   len += sprintf(buffer+len, "        -----|--------------|-----------|-----------|--------------\n");
-   for (i=0; i<=MAX_LOG_DEV; i++)
-     len += sprintf(buffer+len, "         %2X  |    %3d       |  %8d |  %8d | %8d\n",
-		    i, ldn_access_load(host_index, i), IBM_DS(host_index).ldn_read_access[i],
-		    IBM_DS(host_index).ldn_write_access[i], IBM_DS(host_index).ldn_assignments[i]);
-   len += sprintf(buffer+len, "        -----------------------------------------------------------\n\n");
-   len += sprintf(buffer+len, " Dynamical-LDN-Assignment-Statistics:\n");
-   len += sprintf(buffer+len, "               Number of physical SCSI-devices..: %d (+ Adapter)\n",
-		  IBM_DS(host_index).total_scsi_devices);
-   len += sprintf(buffer+len, "               Dynamical Assignment necessary...: %s\n",
-		  IBM_DS(host_index).dyn_flag ? "Yes" : "No ");
-   len += sprintf(buffer+len, "               Next LDN to be assigned..........: 0x%x\n",
-		  next_ldn(host_index));
-   len += sprintf(buffer+len, "               Dynamical assignments done yet...: %d\n",
-		  IBM_DS(host_index).dynamical_assignments);
-   len += sprintf(buffer+len, "\n Current SCSI-Device-Mapping:\n");
-   len += sprintf(buffer+len, "        Physical SCSI-Device Map               Logical SCSI-Device Map\n");
-   len += sprintf(buffer+len, "    ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
-   for (id=0; id<max_pun; id++) {
-      len += sprintf(buffer+len, "    %2d     ",id);
-      for (lun=0; lun<8; lun++)
-	len += sprintf(buffer+len,"%2s ",ti_p(get_scsi(host_index)[id][lun]));
-      len += sprintf(buffer+len, "      %2d     ",id);
-      for (lun=0; lun<8; lun++)
-	len += sprintf(buffer+len,"%2s ",ti_l(get_ldn(host_index)[id][lun]));
-      len += sprintf(buffer+len,"\n");
-   }
-
-   len += sprintf(buffer+len, "(A = IBM-Subsystem, D = Harddisk, T = Tapedrive, P = Processor, W = WORM,\n");
-   len += sprintf(buffer+len, " R = CD-ROM, S = Scanner, M = MO-Drive, C = Medium-Changer, + = unprovided LUN,\n");
-   len += sprintf(buffer+len, " - = nothing found, nothing assigned or unprobed LUN)\n\n");
-
-   *start = buffer + offset;
-   len -= offset;
-   if (len > length) len = length;
-   IBMUNLOCK(shpnt)
-   return len;
+	len += sprintf(buffer + len, "               This Hostnumber..........: %d\n", hostno);
+	len += sprintf(buffer + len, "               Base I/O-Port............: 0x%x\n", (unsigned int) (IM_CMD_REG(host_index)));
+	len += sprintf(buffer + len, "               (Shared) IRQ.............: %d\n", IM_IRQ);
+	len += sprintf(buffer + len, "               Total Interrupts.........: %d\n", IBM_DS(host_index).total_interrupts);
+	len += sprintf(buffer + len, "               Total SCSI Accesses......: %d\n", IBM_DS(host_index).total_accesses);
+	len += sprintf(buffer + len, "               Total short SCBs.........: %d\n", IBM_DS(host_index).scbs);
+	len += sprintf(buffer + len, "               Total long SCBs..........: %d\n", IBM_DS(host_index).long_scbs);
+	len += sprintf(buffer + len, "                 Total SCSI READ/WRITE..: %d\n", ldn_access_total_read_write(host_index));
+	len += sprintf(buffer + len, "                 Total SCSI Inquiries...: %d\n", ldn_access_total_inquiry(host_index));
+	len += sprintf(buffer + len, "                 Total SCSI Modeselects.: %d\n", ldn_access_total_modeselect(host_index));
+	len += sprintf(buffer + len, "                 Total SCSI other cmds..: %d\n", IBM_DS(host_index).total_accesses - ldn_access_total_read_write(host_index)
+		       - ldn_access_total_modeselect(host_index)
+		       - ldn_access_total_inquiry(host_index));
+	len += sprintf(buffer + len, "               Total SCSI command fails.: %d\n\n", IBM_DS(host_index).total_errors);
+	len += sprintf(buffer + len, " Logical-Device-Number (LDN) Access-Statistics:\n");
+	len += sprintf(buffer + len, "         LDN | Accesses [%%] |   READ    |   WRITE   | ASSIGNMENTS\n");
+	len += sprintf(buffer + len, "        -----|--------------|-----------|-----------|--------------\n");
+	for (i = 0; i <= MAX_LOG_DEV; i++)
+		len += sprintf(buffer + len, "         %2X  |    %3d       |  %8d |  %8d | %8d\n", i, ldn_access_load(host_index, i), IBM_DS(host_index).ldn_read_access[i], IBM_DS(host_index).ldn_write_access[i], IBM_DS(host_index).ldn_assignments[i]);
+	len += sprintf(buffer + len, "        -----------------------------------------------------------\n\n");
+	len += sprintf(buffer + len, " Dynamical-LDN-Assignment-Statistics:\n");
+	len += sprintf(buffer + len, "               Number of physical SCSI-devices..: %d (+ Adapter)\n", IBM_DS(host_index).total_scsi_devices);
+	len += sprintf(buffer + len, "               Dynamical Assignment necessary...: %s\n", IBM_DS(host_index).dyn_flag ? "Yes" : "No ");
+	len += sprintf(buffer + len, "               Next LDN to be assigned..........: 0x%x\n", next_ldn(host_index));
+	len += sprintf(buffer + len, "               Dynamical assignments done yet...: %d\n", IBM_DS(host_index).dynamical_assignments);
+	len += sprintf(buffer + len, "\n Current SCSI-Device-Mapping:\n");
+	len += sprintf(buffer + len, "        Physical SCSI-Device Map               Logical SCSI-Device Map\n");
+	len += sprintf(buffer + len, "    ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
+	for (id = 0; id < max_pun; id++) {
+		len += sprintf(buffer + len, "    %2d     ", id);
+		for (lun = 0; lun < 8; lun++)
+			len += sprintf(buffer + len, "%2s ", ti_p(get_scsi(host_index)[id][lun]));
+		len += sprintf(buffer + len, "      %2d     ", id);
+		for (lun = 0; lun < 8; lun++)
+			len += sprintf(buffer + len, "%2s ", ti_l(get_ldn(host_index)[id][lun]));
+		len += sprintf(buffer + len, "\n");
+	}
+
+	len += sprintf(buffer + len, "(A = IBM-Subsystem, D = Harddisk, T = Tapedrive, P = Processor, W = WORM,\n");
+	len += sprintf(buffer + len, " R = CD-ROM, S = Scanner, M = MO-Drive, C = Medium-Changer, + = unprovided LUN,\n");
+	len += sprintf(buffer + len, " - = nothing found, nothing assigned or unprobed LUN)\n\n");
+
+	*start = buffer + offset;
+	len -= offset;
+	if (len > length)
+		len = length;
+	spin_unlock_irqrestore(shpnt->host_lock, flags);
+	return len;
 }
 
-void ibmmca_scsi_setup (char *str, int *ints)
+static void ibmmca_scsi_setup(char *str, int *ints)
 {
-   internal_ibmmca_scsi_setup (str, ints);
+	internal_ibmmca_scsi_setup(str, ints);
 }
 
 static int option_setup(char *str)
 {
-   int ints[IM_MAX_HOSTS];
-   char *cur = str;
-   int i = 1;
-
-   while (cur && isdigit(*cur) && i <= IM_MAX_HOSTS) {
-      ints[i++] = simple_strtoul(cur, NULL, 0);
-      if ((cur = strchr(cur,',')) != NULL) cur++;
-   }
-   ints[0] = i - 1;
-   internal_ibmmca_scsi_setup(cur, ints);
-   return 0;
+	int ints[IM_MAX_HOSTS];
+	char *cur = str;
+	int i = 1;
+
+	while (cur && isdigit(*cur) && i <= IM_MAX_HOSTS) {
+		ints[i++] = simple_strtoul(cur, NULL, 0);
+		if ((cur = strchr(cur, ',')) != NULL)
+			cur++;
+	}
+	ints[0] = i - 1;
+	internal_ibmmca_scsi_setup(cur, ints);
+	return 0;
 }
 
 __setup("ibmmcascsi=", option_setup);
diff -Nru a/drivers/scsi/ibmmca.h b/drivers/scsi/ibmmca.h
--- a/drivers/scsi/ibmmca.h	Sun Nov 10 19:28:40 2002
+++ b/drivers/scsi/ibmmca.h	Sun Nov 10 19:28:40 2002
@@ -10,18 +10,14 @@
 /* Common forward declarations for all Linux-versions: */
 
 /* Interfaces to the midlevel Linux SCSI driver */
-extern int ibmmca_proc_info (char *, char **, off_t, int, int, int);
-extern int ibmmca_detect (Scsi_Host_Template *);
-extern int ibmmca_release (struct Scsi_Host *);
-extern int ibmmca_command (Scsi_Cmnd *);
-extern int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-extern int ibmmca_abort (Scsi_Cmnd *);
-extern int ibmmca_reset (Scsi_Cmnd *, unsigned int);
-extern int ibmmca_biosparam (struct scsi_device *, struct block_device *,
-		sector_t, int *);
-
-/*structure for /proc filesystem */
-extern struct proc_dir_entry proc_scsi_ibmmca;
+static int ibmmca_proc_info (char *, char **, off_t, int, int, int);
+static int ibmmca_detect (Scsi_Host_Template *);
+static int ibmmca_release (struct Scsi_Host *);
+static int ibmmca_command (Scsi_Cmnd *);
+static int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+static int ibmmca_abort (Scsi_Cmnd *);
+static int ibmmca_host_reset (Scsi_Cmnd *);
+static int ibmmca_biosparam (struct scsi_device *, struct block_device *, sector_t, int *);
 
 /*
  * 2/8/98
@@ -37,8 +33,8 @@
           release:        ibmmca_release,       /*release fn*/        \
           command:        ibmmca_command,       /*command fn*/        \
           queuecommand:   ibmmca_queuecommand,  /*queuecommand fn*/   \
-          abort:          ibmmca_abort,         /*abort fn*/          \
-          reset:          ibmmca_reset,         /*reset fn*/          \
+	  eh_abort_handler:ibmmca_abort,         /*abort fn*/          \
+	  eh_host_reset_handler:ibmmca_host_reset,         /*reset fn*/          \
           bios_param:     ibmmca_biosparam,     /*bios fn*/           \
           can_queue:      16,                   /*can_queue*/         \
           this_id:        7,                    /*set by detect*/     \
diff -Nru a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
--- a/drivers/scsi/in2000.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/scsi/in2000.c	Sun Nov 10 19:28:40 2002
@@ -16,6 +16,11 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
  *
  * Drew Eckhardt's excellent 'Generic NCR5380' sources provided
  * much of the inspiration and some of the code for this driver.
@@ -102,6 +107,10 @@
  * this thing into as good a shape as possible, and I'm positive
  * there are lots of lurking bugs and "Stupid Places".
  *
+ * Updated for Linux 2.5 by Alan Cox <alan@redhat.com>
+ *	- Using new_eh handler
+ *	- Hopefully got all the locking right again
+ *	See "FIXME" notes for items that could do with more work
  */
 
 #include <linux/module.h>
@@ -121,8 +130,8 @@
 #include "scsi.h"
 #include "hosts.h"
 
-#define IN2000_VERSION    "1.33"
-#define IN2000_DATE       "26/August/1998"
+#define IN2000_VERSION    "1.33-2.5"
+#define IN2000_DATE       "2002/11/03"
 
 #include "in2000.h"
 
@@ -174,8 +183,7 @@
  */
 
 /* Normally, no defaults are specified... */
-static char *setup_args[] =
-      {"","","","","","","","",""};
+static char *setup_args[] = { "", "", "", "", "", "", "", "", "" };
 
 /* filled in by 'insmod' */
 static char *setup_strings = 0;
@@ -184,15 +192,10 @@
 MODULE_PARM(setup_strings, "s");
 #endif
 
-
-static struct Scsi_Host *instance_list = 0;
-
-
-
 static inline uchar read_3393(struct IN2000_hostdata *hostdata, uchar reg_num)
 {
-   write1_io(reg_num,IO_WD_ADDR);
-   return read1_io(IO_WD_DATA);
+	write1_io(reg_num, IO_WD_ADDR);
+	return read1_io(IO_WD_DATA);
 }
 
 
@@ -201,8 +204,8 @@
 
 static inline void write_3393(struct IN2000_hostdata *hostdata, uchar reg_num, uchar value)
 {
-   write1_io(reg_num,IO_WD_ADDR);
-   write1_io(value,IO_WD_DATA);
+	write1_io(reg_num, IO_WD_ADDR);
+	write1_io(value, IO_WD_DATA);
 }
 
 
@@ -210,44 +213,44 @@
 {
 /*   while (READ_AUX_STAT() & ASR_CIP)
       printk("|");*/
-   write1_io(WD_COMMAND,IO_WD_ADDR);
-   write1_io(cmd,IO_WD_DATA);
+	write1_io(WD_COMMAND, IO_WD_ADDR);
+	write1_io(cmd, IO_WD_DATA);
 }
 
 
 static uchar read_1_byte(struct IN2000_hostdata *hostdata)
 {
-uchar asr, x = 0;
+	uchar asr, x = 0;
 
-   write_3393(hostdata,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
-   write_3393_cmd(hostdata,WD_CMD_TRANS_INFO|0x80);
-   do {
-      asr = READ_AUX_STAT();
-      if (asr & ASR_DBR)
-         x = read_3393(hostdata,WD_DATA);
-      } while (!(asr & ASR_INT));
-   return x;
+	write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+	write_3393_cmd(hostdata, WD_CMD_TRANS_INFO | 0x80);
+	do {
+		asr = READ_AUX_STAT();
+		if (asr & ASR_DBR)
+			x = read_3393(hostdata, WD_DATA);
+	} while (!(asr & ASR_INT));
+	return x;
 }
 
 
 static void write_3393_count(struct IN2000_hostdata *hostdata, unsigned long value)
 {
-   write1_io(WD_TRANSFER_COUNT_MSB,IO_WD_ADDR);
-   write1_io((value >> 16),IO_WD_DATA);
-   write1_io((value >> 8),IO_WD_DATA);
-   write1_io(value,IO_WD_DATA);
+	write1_io(WD_TRANSFER_COUNT_MSB, IO_WD_ADDR);
+	write1_io((value >> 16), IO_WD_DATA);
+	write1_io((value >> 8), IO_WD_DATA);
+	write1_io(value, IO_WD_DATA);
 }
 
 
 static unsigned long read_3393_count(struct IN2000_hostdata *hostdata)
 {
-unsigned long value;
+	unsigned long value;
 
-   write1_io(WD_TRANSFER_COUNT_MSB,IO_WD_ADDR);
-   value = read1_io(IO_WD_DATA) << 16;
-   value |= read1_io(IO_WD_DATA) << 8;
-   value |= read1_io(IO_WD_DATA);
-   return value;
+	write1_io(WD_TRANSFER_COUNT_MSB, IO_WD_ADDR);
+	value = read1_io(IO_WD_DATA) << 16;
+	value |= read1_io(IO_WD_DATA) << 8;
+	value |= read1_io(IO_WD_DATA);
+	return value;
 }
 
 
@@ -256,87 +259,104 @@
  * will be a DATA_OUT phase with this command, false otherwise.
  * (Thanks to Joerg Dorchain for the research and suggestion.)
  */
-static int is_dir_out(Scsi_Cmnd *cmd)
+static int is_dir_out(Scsi_Cmnd * cmd)
 {
-   switch (cmd->cmnd[0]) {
-      case WRITE_6:           case WRITE_10:          case WRITE_12:
-      case WRITE_LONG:        case WRITE_SAME:        case WRITE_BUFFER:
-      case WRITE_VERIFY:      case WRITE_VERIFY_12:      
-      case COMPARE:           case COPY:              case COPY_VERIFY:
-      case SEARCH_EQUAL:      case SEARCH_HIGH:       case SEARCH_LOW:
-      case SEARCH_EQUAL_12:   case SEARCH_HIGH_12:    case SEARCH_LOW_12:      
-      case FORMAT_UNIT:       case REASSIGN_BLOCKS:   case RESERVE:
-      case MODE_SELECT:       case MODE_SELECT_10:    case LOG_SELECT:
-      case SEND_DIAGNOSTIC:   case CHANGE_DEFINITION: case UPDATE_BLOCK:
-      case SET_WINDOW:        case MEDIUM_SCAN:       case SEND_VOLUME_TAG:
-      case 0xea:
-         return 1;
-      default:
-         return 0;
-      }
+	switch (cmd->cmnd[0]) {
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_12:
+	case WRITE_LONG:
+	case WRITE_SAME:
+	case WRITE_BUFFER:
+	case WRITE_VERIFY:
+	case WRITE_VERIFY_12:
+	case COMPARE:
+	case COPY:
+	case COPY_VERIFY:
+	case SEARCH_EQUAL:
+	case SEARCH_HIGH:
+	case SEARCH_LOW:
+	case SEARCH_EQUAL_12:
+	case SEARCH_HIGH_12:
+	case SEARCH_LOW_12:
+	case FORMAT_UNIT:
+	case REASSIGN_BLOCKS:
+	case RESERVE:
+	case MODE_SELECT:
+	case MODE_SELECT_10:
+	case LOG_SELECT:
+	case SEND_DIAGNOSTIC:
+	case CHANGE_DEFINITION:
+	case UPDATE_BLOCK:
+	case SET_WINDOW:
+	case MEDIUM_SCAN:
+	case SEND_VOLUME_TAG:
+	case 0xea:
+		return 1;
+	default:
+		return 0;
+	}
 }
 
 
 
 static struct sx_period sx_table[] = {
-   {  1, 0x20},
-   {252, 0x20},
-   {376, 0x30},
-   {500, 0x40},
-   {624, 0x50},
-   {752, 0x60},
-   {876, 0x70},
-   {1000,0x00},
-   {0,   0} };
+	{1, 0x20},
+	{252, 0x20},
+	{376, 0x30},
+	{500, 0x40},
+	{624, 0x50},
+	{752, 0x60},
+	{876, 0x70},
+	{1000, 0x00},
+	{0, 0}
+};
 
 static int round_period(unsigned int period)
 {
-int x;
+	int x;
 
-   for (x=1; sx_table[x].period_ns; x++) {
-      if ((period <= sx_table[x-0].period_ns) &&
-          (period >  sx_table[x-1].period_ns)) {
-         return x;
-         }
-      }
-   return 7;
+	for (x = 1; sx_table[x].period_ns; x++) {
+		if ((period <= sx_table[x - 0].period_ns) && (period > sx_table[x - 1].period_ns)) {
+			return x;
+		}
+	}
+	return 7;
 }
 
 static uchar calc_sync_xfer(unsigned int period, unsigned int offset)
 {
-uchar result;
+	uchar result;
 
-   period *= 4;   /* convert SDTR code to ns */
-   result = sx_table[round_period(period)].reg_value;
-   result |= (offset < OPTIMUM_SX_OFF)?offset:OPTIMUM_SX_OFF;
-   return result;
+	period *= 4;		/* convert SDTR code to ns */
+	result = sx_table[round_period(period)].reg_value;
+	result |= (offset < OPTIMUM_SX_OFF) ? offset : OPTIMUM_SX_OFF;
+	return result;
 }
 
 
 
 static void in2000_execute(struct Scsi_Host *instance);
 
-static int in2000_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
 {
-struct Scsi_Host *instance;
-struct IN2000_hostdata *hostdata;
-Scsi_Cmnd *tmp;
-unsigned long flags;
+	struct Scsi_Host *instance;
+	struct IN2000_hostdata *hostdata;
+	Scsi_Cmnd *tmp;
 
-   instance = cmd->host;
-   hostdata = (struct IN2000_hostdata *)instance->hostdata;
+	instance = cmd->host;
+	hostdata = (struct IN2000_hostdata *) instance->hostdata;
 
-DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld(",cmd->target,cmd->cmnd[0],cmd->pid))
+	DB(DB_QUEUE_COMMAND, printk("Q-%d-%02x-%ld(", cmd->target, cmd->cmnd[0], cmd->pid))
 
 /* Set up a few fields in the Scsi_Cmnd structure for our own use:
  *  - host_scribble is the pointer to the next cmd in the input queue
  *  - scsi_done points to the routine we call when a cmd is finished
  *  - result is what you'd expect
  */
-
-   cmd->host_scribble = NULL;
-   cmd->scsi_done = done;
-   cmd->result = 0;
+	    cmd->host_scribble = NULL;
+	cmd->scsi_done = done;
+	cmd->result = 0;
 
 /* We use the Scsi_Pointer structure that's included with each command
  * as a scratchpad (as it's intended to be used!). The handy thing about
@@ -353,19 +373,18 @@
  *  - SCp.phase records this command's SRCID_ER bit setting
  */
 
-   if (cmd->use_sg) {
-      cmd->SCp.buffer = (struct scatterlist *)cmd->buffer;
-      cmd->SCp.buffers_residual = cmd->use_sg - 1;
-      cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+cmd->SCp.buffer->offset;
-      cmd->SCp.this_residual = cmd->SCp.buffer->length;
-      }
-   else {
-      cmd->SCp.buffer = NULL;
-      cmd->SCp.buffers_residual = 0;
-      cmd->SCp.ptr = (char *)cmd->request_buffer;
-      cmd->SCp.this_residual = cmd->request_bufflen;
-      }
-   cmd->SCp.have_data_in = 0;
+	if (cmd->use_sg) {
+		cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+		cmd->SCp.buffers_residual = cmd->use_sg - 1;
+		cmd->SCp.ptr = (char *) page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
+		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+	} else {
+		cmd->SCp.buffer = NULL;
+		cmd->SCp.buffers_residual = 0;
+		cmd->SCp.ptr = (char *) cmd->request_buffer;
+		cmd->SCp.this_residual = cmd->request_bufflen;
+	}
+	cmd->SCp.have_data_in = 0;
 
 /* We don't set SCp.phase here - that's done in in2000_execute() */
 
@@ -386,39 +405,34 @@
  * status byte is stored.
  */
 
-   cmd->SCp.Status = ILLEGAL_STATUS_BYTE;
+	cmd->SCp.Status = ILLEGAL_STATUS_BYTE;
 
 /* We need to disable interrupts before messing with the input
  * queue and calling in2000_execute().
  */
 
-   spin_lock_irqsave(instance->host_lock, flags);
-   /*
-    * Add the cmd to the end of 'input_Q'. Note that REQUEST_SENSE
-    * commands are added to the head of the queue so that the desired
-    * sense data is not lost before REQUEST_SENSE executes.
-    */
-
-   if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
-      cmd->host_scribble = (uchar *)hostdata->input_Q;
-      hostdata->input_Q = cmd;
-      }
-   else {   /* find the end of the queue */
-      for (tmp=(Scsi_Cmnd *)hostdata->input_Q; tmp->host_scribble;
-            tmp=(Scsi_Cmnd *)tmp->host_scribble)
-         ;
-      tmp->host_scribble = (uchar *)cmd;
-      }
+	/*
+	 * Add the cmd to the end of 'input_Q'. Note that REQUEST_SENSE
+	 * commands are added to the head of the queue so that the desired
+	 * sense data is not lost before REQUEST_SENSE executes.
+	 */
+
+	if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+		cmd->host_scribble = (uchar *) hostdata->input_Q;
+		hostdata->input_Q = cmd;
+	} else {		/* find the end of the queue */
+		for (tmp = (Scsi_Cmnd *) hostdata->input_Q; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble);
+		tmp->host_scribble = (uchar *) cmd;
+	}
 
 /* We know that there's at least one command in 'input_Q' now.
  * Go see if any of them are runnable!
  */
 
-   in2000_execute(cmd->host);
+	in2000_execute(cmd->host);
 
-DB(DB_QUEUE_COMMAND,printk(")Q-%ld ",cmd->pid))
-   spin_unlock_irqrestore(instance->host_lock, flags);
-   return 0;
+	DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->pid))
+	    return 0;
 }
 
 
@@ -431,69 +445,69 @@
  * Note that this function is always called with interrupts already
  * disabled (either from in2000_queuecommand() or in2000_intr()).
  */
-static void in2000_execute (struct Scsi_Host *instance)
+static void in2000_execute(struct Scsi_Host *instance)
 {
-struct IN2000_hostdata *hostdata;
-Scsi_Cmnd *cmd, *prev;
-int i;
-unsigned short *sp;
-unsigned short f;
-unsigned short flushbuf[16];
+	struct IN2000_hostdata *hostdata;
+	Scsi_Cmnd *cmd, *prev;
+	int i;
+	unsigned short *sp;
+	unsigned short f;
+	unsigned short flushbuf[16];
 
 
-   hostdata = (struct IN2000_hostdata *)instance->hostdata;
+	hostdata = (struct IN2000_hostdata *) instance->hostdata;
 
-DB(DB_EXECUTE,printk("EX("))
+	DB(DB_EXECUTE, printk("EX("))
 
-   if (hostdata->selecting || hostdata->connected) {
+	    if (hostdata->selecting || hostdata->connected) {
 
-DB(DB_EXECUTE,printk(")EX-0 "))
+		DB(DB_EXECUTE, printk(")EX-0 "))
 
-      return;
-      }
+		    return;
+	}
 
-    /*
-     * Search through the input_Q for a command destined
-     * for an idle target/lun.
-     */
+	/*
+	 * Search through the input_Q for a command destined
+	 * for an idle target/lun.
+	 */
 
-   cmd = (Scsi_Cmnd *)hostdata->input_Q;
-   prev = 0;
-   while (cmd) {
-      if (!(hostdata->busy[cmd->target] & (1 << cmd->lun)))
-         break;
-      prev = cmd;
-      cmd = (Scsi_Cmnd *)cmd->host_scribble;
-      }
+	cmd = (Scsi_Cmnd *) hostdata->input_Q;
+	prev = 0;
+	while (cmd) {
+		if (!(hostdata->busy[cmd->target] & (1 << cmd->lun)))
+			break;
+		prev = cmd;
+		cmd = (Scsi_Cmnd *) cmd->host_scribble;
+	}
 
-   /* quit if queue empty or all possible targets are busy */
+	/* quit if queue empty or all possible targets are busy */
 
-   if (!cmd) {
+	if (!cmd) {
 
-DB(DB_EXECUTE,printk(")EX-1 "))
+		DB(DB_EXECUTE, printk(")EX-1 "))
 
-      return;
-      }
+		    return;
+	}
 
-   /*  remove command from queue */
-   
-   if (prev)
-      prev->host_scribble = cmd->host_scribble;
-   else
-      hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble;
+	/*  remove command from queue */
+
+	if (prev)
+		prev->host_scribble = cmd->host_scribble;
+	else
+		hostdata->input_Q = (Scsi_Cmnd *) cmd->host_scribble;
 
 #ifdef PROC_STATISTICS
-   hostdata->cmd_cnt[cmd->target]++;
+	hostdata->cmd_cnt[cmd->target]++;
 #endif
 
 /*
  * Start the selection process
  */
 
-   if (is_dir_out(cmd))
-      write_3393(hostdata,WD_DESTINATION_ID, cmd->target);
-   else
-      write_3393(hostdata,WD_DESTINATION_ID, cmd->target | DSTID_DPD);
+	if (is_dir_out(cmd))
+		write_3393(hostdata, WD_DESTINATION_ID, cmd->target);
+	else
+		write_3393(hostdata, WD_DESTINATION_ID, cmd->target | DSTID_DPD);
 
 /* Now we need to figure out whether or not this command is a good
  * candidate for disconnect/reselect. We guess to the best of our
@@ -518,54 +532,51 @@
  * to change around and experiment with for now.
  */
 
-   cmd->SCp.phase = 0;  /* assume no disconnect */
-   if (hostdata->disconnect == DIS_NEVER)
-      goto no;
-   if (hostdata->disconnect == DIS_ALWAYS)
-      goto yes;
-   if (cmd->device->type == 1)   /* tape drive? */
-      goto yes;
-   if (hostdata->disconnected_Q) /* other commands disconnected? */
-      goto yes;
-   if (!(hostdata->input_Q))     /* input_Q empty? */
-      goto no;
-   for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev;
-         prev=(Scsi_Cmnd *)prev->host_scribble) {
-      if ((prev->target != cmd->target) || (prev->lun != cmd->lun)) {
-         for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev;
-               prev=(Scsi_Cmnd *)prev->host_scribble)
-            prev->SCp.phase = 1;
-         goto yes;
-         }
-      }
-   goto no;
+	cmd->SCp.phase = 0;	/* assume no disconnect */
+	if (hostdata->disconnect == DIS_NEVER)
+		goto no;
+	if (hostdata->disconnect == DIS_ALWAYS)
+		goto yes;
+	if (cmd->device->type == 1)	/* tape drive? */
+		goto yes;
+	if (hostdata->disconnected_Q)	/* other commands disconnected? */
+		goto yes;
+	if (!(hostdata->input_Q))	/* input_Q empty? */
+		goto no;
+	for (prev = (Scsi_Cmnd *) hostdata->input_Q; prev; prev = (Scsi_Cmnd *) prev->host_scribble) {
+		if ((prev->target != cmd->target) || (prev->lun != cmd->lun)) {
+			for (prev = (Scsi_Cmnd *) hostdata->input_Q; prev; prev = (Scsi_Cmnd *) prev->host_scribble)
+				prev->SCp.phase = 1;
+			goto yes;
+		}
+	}
+	goto no;
 
-yes:
-   cmd->SCp.phase = 1;
+      yes:
+	cmd->SCp.phase = 1;
 
 #ifdef PROC_STATISTICS
-   hostdata->disc_allowed_cnt[cmd->target]++;
+	hostdata->disc_allowed_cnt[cmd->target]++;
 #endif
 
-no:
-   write_3393(hostdata,WD_SOURCE_ID,((cmd->SCp.phase)?SRCID_ER:0));
+      no:
+	write_3393(hostdata, WD_SOURCE_ID, ((cmd->SCp.phase) ? SRCID_ER : 0));
 
-   write_3393(hostdata,WD_TARGET_LUN, cmd->lun);
-   write_3393(hostdata,WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]);
-   hostdata->busy[cmd->target] |= (1 << cmd->lun);
-
-   if ((hostdata->level2 <= L2_NONE) ||
-       (hostdata->sync_stat[cmd->target] == SS_UNSET)) {
-
-         /*
-          * Do a 'Select-With-ATN' command. This will end with
-          * one of the following interrupts:
-          *    CSR_RESEL_AM:  failure - can try again later.
-          *    CSR_TIMEOUT:   failure - give up.
-          *    CSR_SELECT:    success - proceed.
-          */
+	write_3393(hostdata, WD_TARGET_LUN, cmd->lun);
+	write_3393(hostdata, WD_SYNCHRONOUS_TRANSFER, hostdata->sync_xfer[cmd->target]);
+	hostdata->busy[cmd->target] |= (1 << cmd->lun);
+
+	if ((hostdata->level2 <= L2_NONE) || (hostdata->sync_stat[cmd->target] == SS_UNSET)) {
+
+		/*
+		 * Do a 'Select-With-ATN' command. This will end with
+		 * one of the following interrupts:
+		 *    CSR_RESEL_AM:  failure - can try again later.
+		 *    CSR_TIMEOUT:   failure - give up.
+		 *    CSR_SELECT:    success - proceed.
+		 */
 
-      hostdata->selecting = cmd;
+		hostdata->selecting = cmd;
 
 /* Every target has its own synchronous transfer setting, kept in
  * the sync_xfer array, and a corresponding status byte in sync_stat[].
@@ -577,176 +588,173 @@
  * unless we don't want to even _try_ synchronous transfers: In this
  * case we set SS_SET to make the defaults final.
  */
-      if (hostdata->sync_stat[cmd->target] == SS_UNSET) {
-         if (hostdata->sync_off & (1 << cmd->target))
-            hostdata->sync_stat[cmd->target] = SS_SET;
-         else
-            hostdata->sync_stat[cmd->target] = SS_FIRST;
-         }
-      hostdata->state = S_SELECTING;
-      write_3393_count(hostdata,0); /* this guarantees a DATA_PHASE interrupt */
-      write_3393_cmd(hostdata,WD_CMD_SEL_ATN);
-      }
-
-   else {
-
-         /*
-          * Do a 'Select-With-ATN-Xfer' command. This will end with
-          * one of the following interrupts:
-          *    CSR_RESEL_AM:  failure - can try again later.
-          *    CSR_TIMEOUT:   failure - give up.
-          *    anything else: success - proceed.
-          */
-
-      hostdata->connected = cmd;
-      write_3393(hostdata,WD_COMMAND_PHASE, 0);
-
-   /* copy command_descriptor_block into WD chip
-    * (take advantage of auto-incrementing)
-    */
-
-      write1_io(WD_CDB_1, IO_WD_ADDR);
-      for (i=0; i<cmd->cmd_len; i++)
-         write1_io(cmd->cmnd[i], IO_WD_DATA);
-
-   /* The wd33c93 only knows about Group 0, 1, and 5 commands when
-    * it's doing a 'select-and-transfer'. To be safe, we write the
-    * size of the CDB into the OWN_ID register for every case. This
-    * way there won't be problems with vendor-unique, audio, etc.
-    */
-
-      write_3393(hostdata, WD_OWN_ID, cmd->cmd_len);
-
-   /* When doing a non-disconnect command, we can save ourselves a DATA
-    * phase interrupt later by setting everything up now. With writes we
-    * need to pre-fill the fifo; if there's room for the 32 flush bytes,
-    * put them in there too - that'll avoid a fifo interrupt. Reads are
-    * somewhat simpler.
-    * KLUDGE NOTE: It seems that you can't completely fill the fifo here:
-    * This results in the IO_FIFO_COUNT register rolling over to zero,
-    * and apparently the gate array logic sees this as empty, not full,
-    * so the 3393 chip is never signalled to start reading from the
-    * fifo. Or maybe it's seen as a permanent fifo interrupt condition.
-    * Regardless, we fix this by temporarily pretending that the fifo
-    * is 16 bytes smaller. (I see now that the old driver has a comment
-    * about "don't fill completely" in an analogous place - must be the
-    * same deal.) This results in CDROM, swap partitions, and tape drives
-    * needing an extra interrupt per write command - I think we can live
-    * with that!
-    */
-
-      if (!(cmd->SCp.phase)) {
-         write_3393_count(hostdata, cmd->SCp.this_residual);
-         write_3393(hostdata,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_BUS);
-         write1_io(0, IO_FIFO_WRITE);  /* clear fifo counter, write mode */
-
-         if (is_dir_out(cmd)) {
-            hostdata->fifo = FI_FIFO_WRITING;
-            if ((i = cmd->SCp.this_residual) > (IN2000_FIFO_SIZE - 16) )
-               i = IN2000_FIFO_SIZE - 16;
-            cmd->SCp.have_data_in = i;    /* this much data in fifo */
-            i >>= 1;                      /* Gulp. Assuming modulo 2. */
-            sp = (unsigned short *)cmd->SCp.ptr;
-            f = hostdata->io_base + IO_FIFO;
+		if (hostdata->sync_stat[cmd->target] == SS_UNSET) {
+			if (hostdata->sync_off & (1 << cmd->target))
+				hostdata->sync_stat[cmd->target] = SS_SET;
+			else
+				hostdata->sync_stat[cmd->target] = SS_FIRST;
+		}
+		hostdata->state = S_SELECTING;
+		write_3393_count(hostdata, 0);	/* this guarantees a DATA_PHASE interrupt */
+		write_3393_cmd(hostdata, WD_CMD_SEL_ATN);
+	}
+
+	else {
+
+		/*
+		 * Do a 'Select-With-ATN-Xfer' command. This will end with
+		 * one of the following interrupts:
+		 *    CSR_RESEL_AM:  failure - can try again later.
+		 *    CSR_TIMEOUT:   failure - give up.
+		 *    anything else: success - proceed.
+		 */
+
+		hostdata->connected = cmd;
+		write_3393(hostdata, WD_COMMAND_PHASE, 0);
+
+		/* copy command_descriptor_block into WD chip
+		 * (take advantage of auto-incrementing)
+		 */
+
+		write1_io(WD_CDB_1, IO_WD_ADDR);
+		for (i = 0; i < cmd->cmd_len; i++)
+			write1_io(cmd->cmnd[i], IO_WD_DATA);
+
+		/* The wd33c93 only knows about Group 0, 1, and 5 commands when
+		 * it's doing a 'select-and-transfer'. To be safe, we write the
+		 * size of the CDB into the OWN_ID register for every case. This
+		 * way there won't be problems with vendor-unique, audio, etc.
+		 */
+
+		write_3393(hostdata, WD_OWN_ID, cmd->cmd_len);
+
+		/* When doing a non-disconnect command, we can save ourselves a DATA
+		 * phase interrupt later by setting everything up now. With writes we
+		 * need to pre-fill the fifo; if there's room for the 32 flush bytes,
+		 * put them in there too - that'll avoid a fifo interrupt. Reads are
+		 * somewhat simpler.
+		 * KLUDGE NOTE: It seems that you can't completely fill the fifo here:
+		 * This results in the IO_FIFO_COUNT register rolling over to zero,
+		 * and apparently the gate array logic sees this as empty, not full,
+		 * so the 3393 chip is never signalled to start reading from the
+		 * fifo. Or maybe it's seen as a permanent fifo interrupt condition.
+		 * Regardless, we fix this by temporarily pretending that the fifo
+		 * is 16 bytes smaller. (I see now that the old driver has a comment
+		 * about "don't fill completely" in an analogous place - must be the
+		 * same deal.) This results in CDROM, swap partitions, and tape drives
+		 * needing an extra interrupt per write command - I think we can live
+		 * with that!
+		 */
+
+		if (!(cmd->SCp.phase)) {
+			write_3393_count(hostdata, cmd->SCp.this_residual);
+			write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_BUS);
+			write1_io(0, IO_FIFO_WRITE);	/* clear fifo counter, write mode */
+
+			if (is_dir_out(cmd)) {
+				hostdata->fifo = FI_FIFO_WRITING;
+				if ((i = cmd->SCp.this_residual) > (IN2000_FIFO_SIZE - 16))
+					i = IN2000_FIFO_SIZE - 16;
+				cmd->SCp.have_data_in = i;	/* this much data in fifo */
+				i >>= 1;	/* Gulp. Assuming modulo 2. */
+				sp = (unsigned short *) cmd->SCp.ptr;
+				f = hostdata->io_base + IO_FIFO;
 
 #ifdef FAST_WRITE_IO
 
-            FAST_WRITE2_IO();
+				FAST_WRITE2_IO();
 #else
-            while (i--)
-               write2_io(*sp++,IO_FIFO);
+				while (i--)
+					write2_io(*sp++, IO_FIFO);
 
 #endif
 
-      /* Is there room for the flush bytes? */
+				/* Is there room for the flush bytes? */
 
-            if (cmd->SCp.have_data_in <= ((IN2000_FIFO_SIZE - 16) - 32)) {
-               sp = flushbuf;
-               i = 16;
+				if (cmd->SCp.have_data_in <= ((IN2000_FIFO_SIZE - 16) - 32)) {
+					sp = flushbuf;
+					i = 16;
 
 #ifdef FAST_WRITE_IO
 
-               FAST_WRITE2_IO();
+					FAST_WRITE2_IO();
 #else
-               while (i--)
-                  write2_io(0,IO_FIFO);
+					while (i--)
+						write2_io(0, IO_FIFO);
 
 #endif
 
-               }
-            }
+				}
+			}
+
+			else {
+				write1_io(0, IO_FIFO_READ);	/* put fifo in read mode */
+				hostdata->fifo = FI_FIFO_READING;
+				cmd->SCp.have_data_in = 0;	/* nothing transferred yet */
+			}
 
-         else {
-            write1_io(0, IO_FIFO_READ);   /* put fifo in read mode */
-            hostdata->fifo = FI_FIFO_READING;
-            cmd->SCp.have_data_in = 0;    /* nothing transferred yet */
-            }
+		} else {
+			write_3393_count(hostdata, 0);	/* this guarantees a DATA_PHASE interrupt */
+		}
+		hostdata->state = S_RUNNING_LEVEL2;
+		write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+	}
 
-         }
-      else {
-         write_3393_count(hostdata,0); /* this guarantees a DATA_PHASE interrupt */
-         }
-      hostdata->state = S_RUNNING_LEVEL2;
-      write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER);
-      }
+	/*
+	 * Since the SCSI bus can handle only 1 connection at a time,
+	 * we get out of here now. If the selection fails, or when
+	 * the command disconnects, we'll come back to this routine
+	 * to search the input_Q again...
+	 */
 
-   /*
-    * Since the SCSI bus can handle only 1 connection at a time,
-    * we get out of here now. If the selection fails, or when
-    * the command disconnects, we'll come back to this routine
-    * to search the input_Q again...
-    */
-      
-DB(DB_EXECUTE,printk("%s%ld)EX-2 ",(cmd->SCp.phase)?"d:":"",cmd->pid))
+	DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->pid))
 
 }
 
 
 
-static void transfer_pio(uchar *buf, int cnt,
-                  int data_in_dir, struct IN2000_hostdata *hostdata)
+static void transfer_pio(uchar * buf, int cnt, int data_in_dir, struct IN2000_hostdata *hostdata)
 {
-uchar asr;
+	uchar asr;
 
-DB(DB_TRANSFER,printk("(%p,%d,%s)",buf,cnt,data_in_dir?"in":"out"))
+	DB(DB_TRANSFER, printk("(%p,%d,%s)", buf, cnt, data_in_dir ? "in" : "out"))
 
-   write_3393(hostdata,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
-   write_3393_count(hostdata,cnt);
-   write_3393_cmd(hostdata,WD_CMD_TRANS_INFO);
-   if (data_in_dir) {
-      do {
-         asr = READ_AUX_STAT();
-         if (asr & ASR_DBR)
-            *buf++ = read_3393(hostdata,WD_DATA);
-         } while (!(asr & ASR_INT));
-      }
-   else {
-      do {
-         asr = READ_AUX_STAT();
-         if (asr & ASR_DBR)
-            write_3393(hostdata,WD_DATA, *buf++);
-         } while (!(asr & ASR_INT));
-      }
+	    write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+	write_3393_count(hostdata, cnt);
+	write_3393_cmd(hostdata, WD_CMD_TRANS_INFO);
+	if (data_in_dir) {
+		do {
+			asr = READ_AUX_STAT();
+			if (asr & ASR_DBR)
+				*buf++ = read_3393(hostdata, WD_DATA);
+		} while (!(asr & ASR_INT));
+	} else {
+		do {
+			asr = READ_AUX_STAT();
+			if (asr & ASR_DBR)
+				write_3393(hostdata, WD_DATA, *buf++);
+		} while (!(asr & ASR_INT));
+	}
 
-   /* Note: we are returning with the interrupt UN-cleared.
-   * Since (presumably) an entire I/O operation has
-   * completed, the bus phase is probably different, and
-   * the interrupt routine will discover this when it
-   * responds to the uncleared int.
-   */
+	/* Note: we are returning with the interrupt UN-cleared.
+	 * Since (presumably) an entire I/O operation has
+	 * completed, the bus phase is probably different, and
+	 * the interrupt routine will discover this when it
+	 * responds to the uncleared int.
+	 */
 
 }
 
 
 
-static void transfer_bytes(Scsi_Cmnd *cmd, int data_in_dir)
+static void transfer_bytes(Scsi_Cmnd * cmd, int data_in_dir)
 {
-struct IN2000_hostdata *hostdata;
-unsigned short *sp;
-unsigned short f;
-int i;
+	struct IN2000_hostdata *hostdata;
+	unsigned short *sp;
+	unsigned short f;
+	int i;
 
-   hostdata = (struct IN2000_hostdata *)cmd->host->hostdata;
+	hostdata = (struct IN2000_hostdata *) cmd->host->hostdata;
 
 /* Normally, you'd expect 'this_residual' to be non-zero here.
  * In a series of scatter-gather transfers, however, this
@@ -756,67 +764,63 @@
  * now we need to setup the next scatter-gather buffer as the
  * source or destination for THIS transfer.
  */
-   if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
-      ++cmd->SCp.buffer;
-      --cmd->SCp.buffers_residual;
-      cmd->SCp.this_residual = cmd->SCp.buffer->length;
-      cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
-      }
+	if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+		++cmd->SCp.buffer;
+		--cmd->SCp.buffers_residual;
+		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+		cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
+	}
 
 /* Set up hardware registers */
 
-   write_3393(hostdata,WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]);
-   write_3393_count(hostdata,cmd->SCp.this_residual);
-   write_3393(hostdata,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_BUS);
-   write1_io(0,IO_FIFO_WRITE); /* zero counter, assume write */
+	write_3393(hostdata, WD_SYNCHRONOUS_TRANSFER, hostdata->sync_xfer[cmd->target]);
+	write_3393_count(hostdata, cmd->SCp.this_residual);
+	write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_BUS);
+	write1_io(0, IO_FIFO_WRITE);	/* zero counter, assume write */
 
 /* Reading is easy. Just issue the command and return - we'll
  * get an interrupt later when we have actual data to worry about.
  */
 
-   if (data_in_dir) {
-      write1_io(0,IO_FIFO_READ);
-      if ((hostdata->level2 >= L2_DATA) ||
-          (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) {
-         write_3393(hostdata,WD_COMMAND_PHASE,0x45);
-         write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER);
-         hostdata->state = S_RUNNING_LEVEL2;
-         }
-      else
-         write_3393_cmd(hostdata,WD_CMD_TRANS_INFO);
-      hostdata->fifo = FI_FIFO_READING;
-      cmd->SCp.have_data_in = 0;
-      return;
-      }
+	if (data_in_dir) {
+		write1_io(0, IO_FIFO_READ);
+		if ((hostdata->level2 >= L2_DATA) || (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) {
+			write_3393(hostdata, WD_COMMAND_PHASE, 0x45);
+			write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+			hostdata->state = S_RUNNING_LEVEL2;
+		} else
+			write_3393_cmd(hostdata, WD_CMD_TRANS_INFO);
+		hostdata->fifo = FI_FIFO_READING;
+		cmd->SCp.have_data_in = 0;
+		return;
+	}
 
 /* Writing is more involved - we'll start the WD chip and write as
  * much data to the fifo as we can right now. Later interrupts will
  * write any bytes that don't make it at this stage.
  */
 
-      if ((hostdata->level2 >= L2_DATA) ||
-          (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) {
-      write_3393(hostdata,WD_COMMAND_PHASE,0x45);
-      write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER);
-      hostdata->state = S_RUNNING_LEVEL2;
-      }
-   else
-      write_3393_cmd(hostdata,WD_CMD_TRANS_INFO);
-   hostdata->fifo = FI_FIFO_WRITING;
-   sp = (unsigned short *)cmd->SCp.ptr;
-
-   if ((i = cmd->SCp.this_residual) > IN2000_FIFO_SIZE)
-      i = IN2000_FIFO_SIZE;
-   cmd->SCp.have_data_in = i;
-   i >>= 1;    /* Gulp. We assume this_residual is modulo 2 */
-   f = hostdata->io_base + IO_FIFO;
+	if ((hostdata->level2 >= L2_DATA) || (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) {
+		write_3393(hostdata, WD_COMMAND_PHASE, 0x45);
+		write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+		hostdata->state = S_RUNNING_LEVEL2;
+	} else
+		write_3393_cmd(hostdata, WD_CMD_TRANS_INFO);
+	hostdata->fifo = FI_FIFO_WRITING;
+	sp = (unsigned short *) cmd->SCp.ptr;
+
+	if ((i = cmd->SCp.this_residual) > IN2000_FIFO_SIZE)
+		i = IN2000_FIFO_SIZE;
+	cmd->SCp.have_data_in = i;
+	i >>= 1;		/* Gulp. We assume this_residual is modulo 2 */
+	f = hostdata->io_base + IO_FIFO;
 
 #ifdef FAST_WRITE_IO
 
-   FAST_WRITE2_IO();
+	FAST_WRITE2_IO();
 #else
-   while (i--)
-      write2_io(*sp++,IO_FIFO);
+	while (i--)
+		write2_io(*sp++, IO_FIFO);
 
 #endif
 
@@ -829,26 +833,26 @@
  * but it _does_ need to be able to compile and run in an SMP kernel.)
  */
 
-static void in2000_intr (int irqnum, void * dev_id, struct pt_regs *ptregs)
+static void in2000_intr(int irqnum, void *dev_id, struct pt_regs *ptregs)
 {
-struct Scsi_Host *instance = dev_id;
-struct IN2000_hostdata *hostdata;
-Scsi_Cmnd *patch, *cmd;
-uchar asr, sr, phs, id, lun, *ucp, msg;
-int i,j;
-unsigned long length;
-unsigned short *sp;
-unsigned short f;
-unsigned long flags;
+	struct Scsi_Host *instance = dev_id;
+	struct IN2000_hostdata *hostdata;
+	Scsi_Cmnd *patch, *cmd;
+	uchar asr, sr, phs, id, lun, *ucp, msg;
+	int i, j;
+	unsigned long length;
+	unsigned short *sp;
+	unsigned short f;
+	unsigned long flags;
 
-   hostdata = (struct IN2000_hostdata *)instance->hostdata;
+	hostdata = (struct IN2000_hostdata *) instance->hostdata;
 
 /* Get the spin_lock and disable further ints, for SMP */
 
-   spin_lock_irqsave(instance->host_lock, flags);
+	spin_lock_irqsave(instance->host_lock, flags);
 
 #ifdef PROC_STATISTICS
-   hostdata->int_cnt++;
+	hostdata->int_cnt++;
 #endif
 
 /* The IN2000 card has 2 interrupt sources OR'ed onto its IRQ line - the
@@ -886,9 +890,9 @@
  *          state. Who'd a thought?
  */
 
-   write1_io(0, IO_LED_ON);
-   asr = READ_AUX_STAT();
-   if (!(asr & ASR_INT)) {    /* no WD33c93 interrupt? */
+	write1_io(0, IO_LED_ON);
+	asr = READ_AUX_STAT();
+	if (!(asr & ASR_INT)) {	/* no WD33c93 interrupt? */
 
 /* Ok. This is definitely a FIFO-only interrupt.
  *
@@ -909,35 +913,35 @@
  *    (Big thanks to Bill Earnest for getting me out of the mud in here.)
  */
 
-      cmd = (Scsi_Cmnd *)hostdata->connected;   /* assume we're connected */
-CHECK_NULL(cmd,"fifo_int")
+		cmd = (Scsi_Cmnd *) hostdata->connected;	/* assume we're connected */
+		CHECK_NULL(cmd, "fifo_int")
 
-      if (hostdata->fifo == FI_FIFO_READING) {
+		    if (hostdata->fifo == FI_FIFO_READING) {
 
-DB(DB_FIFO,printk("{R:%02x} ",read1_io(IO_FIFO_COUNT)))
+			DB(DB_FIFO, printk("{R:%02x} ", read1_io(IO_FIFO_COUNT)))
 
-         sp = (unsigned short *)(cmd->SCp.ptr + cmd->SCp.have_data_in);
-         i = read1_io(IO_FIFO_COUNT) & 0xfe;
-         i <<= 2;    /* # of words waiting in the fifo */
-         f = hostdata->io_base + IO_FIFO;
+			    sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
+			i = read1_io(IO_FIFO_COUNT) & 0xfe;
+			i <<= 2;	/* # of words waiting in the fifo */
+			f = hostdata->io_base + IO_FIFO;
 
 #ifdef FAST_READ_IO
 
-         FAST_READ2_IO();
+			FAST_READ2_IO();
 #else
-         while (i--)
-            *sp++ = read2_io(IO_FIFO);
+			while (i--)
+				*sp++ = read2_io(IO_FIFO);
 
 #endif
 
-         i = sp - (unsigned short *)(cmd->SCp.ptr + cmd->SCp.have_data_in);
-         i <<= 1;
-         cmd->SCp.have_data_in += i;
-         }
+			i = sp - (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
+			i <<= 1;
+			cmd->SCp.have_data_in += i;
+		}
 
-      else if (hostdata->fifo == FI_FIFO_WRITING) {
+		else if (hostdata->fifo == FI_FIFO_WRITING) {
 
-DB(DB_FIFO,printk("{W:%02x} ",read1_io(IO_FIFO_COUNT)))
+			DB(DB_FIFO, printk("{W:%02x} ", read1_io(IO_FIFO_COUNT)))
 
 /* If all bytes have been written to the fifo, flush out the stragglers.
  * Note that while writing 16 dummy words seems arbitrary, we don't
@@ -949,63 +953,62 @@
  *  UPDATE: Bill says this is exactly what Always does, so there.
  *          More thanks due him for help in this section.
  */
-
-         if (cmd->SCp.this_residual == cmd->SCp.have_data_in) {
-            i = 16;
-            while (i--)          /* write 32 dummy bytes */
-               write2_io(0,IO_FIFO);
-            }
+			    if (cmd->SCp.this_residual == cmd->SCp.have_data_in) {
+				i = 16;
+				while (i--)	/* write 32 dummy bytes */
+					write2_io(0, IO_FIFO);
+			}
 
 /* If there are still bytes left in the SCSI buffer, write as many as we
  * can out to the fifo.
  */
 
-         else {
-            sp = (unsigned short *)(cmd->SCp.ptr + cmd->SCp.have_data_in);
-            i = cmd->SCp.this_residual - cmd->SCp.have_data_in;   /* bytes yet to go */
-            j = read1_io(IO_FIFO_COUNT) & 0xfe;
-            j <<= 2;    /* how many words the fifo has room for */
-            if ((j << 1) > i)
-               j = (i >> 1);
-            while (j--)
-               write2_io(*sp++,IO_FIFO);
-
-            i = sp - (unsigned short *)(cmd->SCp.ptr + cmd->SCp.have_data_in);
-            i <<= 1;
-            cmd->SCp.have_data_in += i;
-            }
-         }
-
-      else {
-            printk("*** Spurious FIFO interrupt ***");
-            }
+			else {
+				sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
+				i = cmd->SCp.this_residual - cmd->SCp.have_data_in;	/* bytes yet to go */
+				j = read1_io(IO_FIFO_COUNT) & 0xfe;
+				j <<= 2;	/* how many words the fifo has room for */
+				if ((j << 1) > i)
+					j = (i >> 1);
+				while (j--)
+					write2_io(*sp++, IO_FIFO);
+
+				i = sp - (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
+				i <<= 1;
+				cmd->SCp.have_data_in += i;
+			}
+		}
+
+		else {
+			printk("*** Spurious FIFO interrupt ***");
+		}
 
-      write1_io(0, IO_LED_OFF);
+		write1_io(0, IO_LED_OFF);
 
 /* release the SMP spin_lock and restore irq state */
-      spin_unlock_irqrestore(instance->host_lock, flags);
-      return;
-      }
+		spin_unlock_irqrestore(instance->host_lock, flags);
+		return;
+	}
 
 /* This interrupt was triggered by the WD33c93 chip. The fifo interrupt
  * may also be asserted, but we don't bother to check it: we get more
  * detailed info from FIFO_READING and FIFO_WRITING (see below).
  */
 
-   cmd = (Scsi_Cmnd *)hostdata->connected;   /* assume we're connected */
-   sr = read_3393(hostdata,WD_SCSI_STATUS);  /* clear the interrupt */
-   phs = read_3393(hostdata,WD_COMMAND_PHASE);
-
-   if (!cmd && (sr != CSR_RESEL_AM && sr != CSR_TIMEOUT && sr != CSR_SELECT)) {
-      printk("\nNR:wd-intr-1\n");
-      write1_io(0, IO_LED_OFF);
+	cmd = (Scsi_Cmnd *) hostdata->connected;	/* assume we're connected */
+	sr = read_3393(hostdata, WD_SCSI_STATUS);	/* clear the interrupt */
+	phs = read_3393(hostdata, WD_COMMAND_PHASE);
+
+	if (!cmd && (sr != CSR_RESEL_AM && sr != CSR_TIMEOUT && sr != CSR_SELECT)) {
+		printk("\nNR:wd-intr-1\n");
+		write1_io(0, IO_LED_OFF);
 
 /* release the SMP spin_lock and restore irq state */
-      spin_unlock_irqrestore(instance->host_lock, flags);
-      return;
-      }
+		spin_unlock_irqrestore(instance->host_lock, flags);
+		return;
+	}
 
-DB(DB_INTR,printk("{%02x:%02x-",asr,sr))
+	DB(DB_INTR, printk("{%02x:%02x-", asr, sr))
 
 /* After starting a FIFO-based transfer, the next _WD3393_ interrupt is
  * guaranteed to be in response to the completion of the transfer.
@@ -1019,239 +1022,234 @@
  * After doing whatever is necessary with the fifo, we go on and
  * service the WD3393 interrupt normally.
  */
-
-   if (hostdata->fifo == FI_FIFO_READING) {
+	    if (hostdata->fifo == FI_FIFO_READING) {
 
 /* buffer index = start-of-buffer + #-of-bytes-already-read */
 
-      sp = (unsigned short *)(cmd->SCp.ptr + cmd->SCp.have_data_in);
+		sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
 
 /* bytes remaining in fifo = (total-wanted - #-not-got) - #-already-read */
 
-      i = (cmd->SCp.this_residual - read_3393_count(hostdata)) - cmd->SCp.have_data_in;
-      i >>= 1;    /* Gulp. We assume this will always be modulo 2 */
-      f = hostdata->io_base + IO_FIFO;
+		i = (cmd->SCp.this_residual - read_3393_count(hostdata)) - cmd->SCp.have_data_in;
+		i >>= 1;	/* Gulp. We assume this will always be modulo 2 */
+		f = hostdata->io_base + IO_FIFO;
 
 #ifdef FAST_READ_IO
 
-      FAST_READ2_IO();
+		FAST_READ2_IO();
 #else
-      while (i--)
-         *sp++ = read2_io(IO_FIFO);
+		while (i--)
+			*sp++ = read2_io(IO_FIFO);
 
 #endif
 
-      hostdata->fifo = FI_FIFO_UNUSED;
-      length = cmd->SCp.this_residual;
-      cmd->SCp.this_residual = read_3393_count(hostdata);
-      cmd->SCp.ptr += (length - cmd->SCp.this_residual);
+		hostdata->fifo = FI_FIFO_UNUSED;
+		length = cmd->SCp.this_residual;
+		cmd->SCp.this_residual = read_3393_count(hostdata);
+		cmd->SCp.ptr += (length - cmd->SCp.this_residual);
 
-DB(DB_TRANSFER,printk("(%p,%d)",cmd->SCp.ptr,cmd->SCp.this_residual))
+		DB(DB_TRANSFER, printk("(%p,%d)", cmd->SCp.ptr, cmd->SCp.this_residual))
 
-      }
+	}
 
-   else if (hostdata->fifo == FI_FIFO_WRITING) {
-      hostdata->fifo = FI_FIFO_UNUSED;
-      length = cmd->SCp.this_residual;
-      cmd->SCp.this_residual = read_3393_count(hostdata);
-      cmd->SCp.ptr += (length - cmd->SCp.this_residual);
+	else if (hostdata->fifo == FI_FIFO_WRITING) {
+		hostdata->fifo = FI_FIFO_UNUSED;
+		length = cmd->SCp.this_residual;
+		cmd->SCp.this_residual = read_3393_count(hostdata);
+		cmd->SCp.ptr += (length - cmd->SCp.this_residual);
 
-DB(DB_TRANSFER,printk("(%p,%d)",cmd->SCp.ptr,cmd->SCp.this_residual))
+		DB(DB_TRANSFER, printk("(%p,%d)", cmd->SCp.ptr, cmd->SCp.this_residual))
 
-      }
+	}
 
 /* Respond to the specific WD3393 interrupt - there are quite a few! */
 
-   switch (sr) {
+	switch (sr) {
 
-      case CSR_TIMEOUT:
-DB(DB_INTR,printk("TIMEOUT"))
+	case CSR_TIMEOUT:
+		DB(DB_INTR, printk("TIMEOUT"))
 
-         if (hostdata->state == S_RUNNING_LEVEL2)
-            hostdata->connected = NULL;
-         else {
-            cmd = (Scsi_Cmnd *)hostdata->selecting;   /* get a valid cmd */
-CHECK_NULL(cmd,"csr_timeout")
-            hostdata->selecting = NULL;
-            }
-
-         cmd->result = DID_NO_CONNECT << 16;
-         hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
-         hostdata->state = S_UNCONNECTED;
-         cmd->scsi_done(cmd);
+		    if (hostdata->state == S_RUNNING_LEVEL2)
+			hostdata->connected = NULL;
+		else {
+			cmd = (Scsi_Cmnd *) hostdata->selecting;	/* get a valid cmd */
+			CHECK_NULL(cmd, "csr_timeout")
+			    hostdata->selecting = NULL;
+		}
+
+		cmd->result = DID_NO_CONNECT << 16;
+		hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+		hostdata->state = S_UNCONNECTED;
+		cmd->scsi_done(cmd);
 
 /* We are not connected to a target - check to see if there
  * are commands waiting to be executed.
  */
 
-         in2000_execute(instance);
-         break;
+		in2000_execute(instance);
+		break;
 
 
 /* Note: this interrupt should not occur in a LEVEL2 command */
 
-      case CSR_SELECT:
-DB(DB_INTR,printk("SELECT"))
-         hostdata->connected = cmd = (Scsi_Cmnd *)hostdata->selecting;
-CHECK_NULL(cmd,"csr_select")
-         hostdata->selecting = NULL;
-
-      /* construct an IDENTIFY message with correct disconnect bit */
-
-         hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->lun);
-         if (cmd->SCp.phase)
-            hostdata->outgoing_msg[0] |= 0x40;
+	case CSR_SELECT:
+		DB(DB_INTR, printk("SELECT"))
+		    hostdata->connected = cmd = (Scsi_Cmnd *) hostdata->selecting;
+		CHECK_NULL(cmd, "csr_select")
+		    hostdata->selecting = NULL;
+
+		/* construct an IDENTIFY message with correct disconnect bit */
+
+		hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->lun);
+		if (cmd->SCp.phase)
+			hostdata->outgoing_msg[0] |= 0x40;
 
-         if (hostdata->sync_stat[cmd->target] == SS_FIRST) {
+		if (hostdata->sync_stat[cmd->target] == SS_FIRST) {
 #ifdef SYNC_DEBUG
-printk(" sending SDTR ");
+			printk(" sending SDTR ");
 #endif
 
-            hostdata->sync_stat[cmd->target] = SS_WAITING;
+			hostdata->sync_stat[cmd->target] = SS_WAITING;
 
-      /* tack on a 2nd message to ask about synchronous transfers */
+			/* tack on a 2nd message to ask about synchronous transfers */
 
-            hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;
-            hostdata->outgoing_msg[2] = 3;
-            hostdata->outgoing_msg[3] = EXTENDED_SDTR;
-            hostdata->outgoing_msg[4] = OPTIMUM_SX_PER/4;
-            hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
-            hostdata->outgoing_len = 6;
-            }
-         else
-            hostdata->outgoing_len = 1;
-
-         hostdata->state = S_CONNECTED;
-         break;
-
-
-      case CSR_XFER_DONE|PHS_DATA_IN:
-      case CSR_UNEXP    |PHS_DATA_IN:
-      case CSR_SRV_REQ  |PHS_DATA_IN:
-DB(DB_INTR,printk("IN-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual))
-         transfer_bytes(cmd, DATA_IN_DIR);
-         if (hostdata->state != S_RUNNING_LEVEL2)
-            hostdata->state = S_CONNECTED;
-         break;
-
-
-      case CSR_XFER_DONE|PHS_DATA_OUT:
-      case CSR_UNEXP    |PHS_DATA_OUT:
-      case CSR_SRV_REQ  |PHS_DATA_OUT:
-DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual))
-         transfer_bytes(cmd, DATA_OUT_DIR);
-         if (hostdata->state != S_RUNNING_LEVEL2)
-            hostdata->state = S_CONNECTED;
-         break;
+			hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;
+			hostdata->outgoing_msg[2] = 3;
+			hostdata->outgoing_msg[3] = EXTENDED_SDTR;
+			hostdata->outgoing_msg[4] = OPTIMUM_SX_PER / 4;
+			hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
+			hostdata->outgoing_len = 6;
+		} else
+			hostdata->outgoing_len = 1;
+
+		hostdata->state = S_CONNECTED;
+		break;
+
+
+	case CSR_XFER_DONE | PHS_DATA_IN:
+	case CSR_UNEXP | PHS_DATA_IN:
+	case CSR_SRV_REQ | PHS_DATA_IN:
+		DB(DB_INTR, printk("IN-%d.%d", cmd->SCp.this_residual, cmd->SCp.buffers_residual))
+		    transfer_bytes(cmd, DATA_IN_DIR);
+		if (hostdata->state != S_RUNNING_LEVEL2)
+			hostdata->state = S_CONNECTED;
+		break;
+
+
+	case CSR_XFER_DONE | PHS_DATA_OUT:
+	case CSR_UNEXP | PHS_DATA_OUT:
+	case CSR_SRV_REQ | PHS_DATA_OUT:
+		DB(DB_INTR, printk("OUT-%d.%d", cmd->SCp.this_residual, cmd->SCp.buffers_residual))
+		    transfer_bytes(cmd, DATA_OUT_DIR);
+		if (hostdata->state != S_RUNNING_LEVEL2)
+			hostdata->state = S_CONNECTED;
+		break;
 
 
 /* Note: this interrupt should not occur in a LEVEL2 command */
 
-      case CSR_XFER_DONE|PHS_COMMAND:
-      case CSR_UNEXP    |PHS_COMMAND:
-      case CSR_SRV_REQ  |PHS_COMMAND:
-DB(DB_INTR,printk("CMND-%02x,%ld",cmd->cmnd[0],cmd->pid))
-         transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata);
-         hostdata->state = S_CONNECTED;
-         break;
-
-
-      case CSR_XFER_DONE|PHS_STATUS:
-      case CSR_UNEXP    |PHS_STATUS:
-      case CSR_SRV_REQ  |PHS_STATUS:
-DB(DB_INTR,printk("STATUS="))
-
-         cmd->SCp.Status = read_1_byte(hostdata);
-DB(DB_INTR,printk("%02x",cmd->SCp.Status))
-         if (hostdata->level2 >= L2_BASIC) {
-            sr = read_3393(hostdata,WD_SCSI_STATUS);  /* clear interrupt */
-            hostdata->state = S_RUNNING_LEVEL2;
-            write_3393(hostdata,WD_COMMAND_PHASE, 0x50);
-            write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER);
-            }
-         else {
-            hostdata->state = S_CONNECTED;
-            }
-         break;
-
-
-      case CSR_XFER_DONE|PHS_MESS_IN:
-      case CSR_UNEXP    |PHS_MESS_IN:
-      case CSR_SRV_REQ  |PHS_MESS_IN:
-DB(DB_INTR,printk("MSG_IN="))
-
-         msg = read_1_byte(hostdata);
-         sr = read_3393(hostdata,WD_SCSI_STATUS);  /* clear interrupt */
-
-         hostdata->incoming_msg[hostdata->incoming_ptr] = msg;
-         if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE)
-            msg = EXTENDED_MESSAGE;
-         else
-            hostdata->incoming_ptr = 0;
-
-         cmd->SCp.Message = msg;
-         switch (msg) {
-
-            case COMMAND_COMPLETE:
-DB(DB_INTR,printk("CCMP-%ld",cmd->pid))
-               write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK);
-               hostdata->state = S_PRE_CMP_DISC;
-               break;
-
-            case SAVE_POINTERS:
-DB(DB_INTR,printk("SDP"))
-               write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK);
-               hostdata->state = S_CONNECTED;
-               break;
-
-            case RESTORE_POINTERS:
-DB(DB_INTR,printk("RDP"))
-               if (hostdata->level2 >= L2_BASIC) {
-                  write_3393(hostdata,WD_COMMAND_PHASE, 0x45);
-                  write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER);
-                  hostdata->state = S_RUNNING_LEVEL2;
-                  }
-               else {
-                  write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK);
-                  hostdata->state = S_CONNECTED;
-                  }
-               break;
-
-            case DISCONNECT:
-DB(DB_INTR,printk("DIS"))
-               cmd->device->disconnect = 1;
-               write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK);
-               hostdata->state = S_PRE_TMP_DISC;
-               break;
+	case CSR_XFER_DONE | PHS_COMMAND:
+	case CSR_UNEXP | PHS_COMMAND:
+	case CSR_SRV_REQ | PHS_COMMAND:
+		DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid))
+		    transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata);
+		hostdata->state = S_CONNECTED;
+		break;
+
+
+	case CSR_XFER_DONE | PHS_STATUS:
+	case CSR_UNEXP | PHS_STATUS:
+	case CSR_SRV_REQ | PHS_STATUS:
+		DB(DB_INTR, printk("STATUS="))
+
+		    cmd->SCp.Status = read_1_byte(hostdata);
+		DB(DB_INTR, printk("%02x", cmd->SCp.Status))
+		    if (hostdata->level2 >= L2_BASIC) {
+			sr = read_3393(hostdata, WD_SCSI_STATUS);	/* clear interrupt */
+			hostdata->state = S_RUNNING_LEVEL2;
+			write_3393(hostdata, WD_COMMAND_PHASE, 0x50);
+			write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+		} else {
+			hostdata->state = S_CONNECTED;
+		}
+		break;
+
+
+	case CSR_XFER_DONE | PHS_MESS_IN:
+	case CSR_UNEXP | PHS_MESS_IN:
+	case CSR_SRV_REQ | PHS_MESS_IN:
+		DB(DB_INTR, printk("MSG_IN="))
+
+		    msg = read_1_byte(hostdata);
+		sr = read_3393(hostdata, WD_SCSI_STATUS);	/* clear interrupt */
+
+		hostdata->incoming_msg[hostdata->incoming_ptr] = msg;
+		if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE)
+			msg = EXTENDED_MESSAGE;
+		else
+			hostdata->incoming_ptr = 0;
+
+		cmd->SCp.Message = msg;
+		switch (msg) {
+
+		case COMMAND_COMPLETE:
+			DB(DB_INTR, printk("CCMP-%ld", cmd->pid))
+			    write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_PRE_CMP_DISC;
+			break;
+
+		case SAVE_POINTERS:
+			DB(DB_INTR, printk("SDP"))
+			    write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_CONNECTED;
+			break;
+
+		case RESTORE_POINTERS:
+			DB(DB_INTR, printk("RDP"))
+			    if (hostdata->level2 >= L2_BASIC) {
+				write_3393(hostdata, WD_COMMAND_PHASE, 0x45);
+				write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+				hostdata->state = S_RUNNING_LEVEL2;
+			} else {
+				write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+				hostdata->state = S_CONNECTED;
+			}
+			break;
+
+		case DISCONNECT:
+			DB(DB_INTR, printk("DIS"))
+			    cmd->device->disconnect = 1;
+			write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_PRE_TMP_DISC;
+			break;
 
-            case MESSAGE_REJECT:
-DB(DB_INTR,printk("REJ"))
+		case MESSAGE_REJECT:
+			DB(DB_INTR, printk("REJ"))
 #ifdef SYNC_DEBUG
-printk("-REJ-");
+			    printk("-REJ-");
 #endif
-               if (hostdata->sync_stat[cmd->target] == SS_WAITING)
-                  hostdata->sync_stat[cmd->target] = SS_SET;
-               write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK);
-               hostdata->state = S_CONNECTED;
-               break;
+			if (hostdata->sync_stat[cmd->target] == SS_WAITING)
+				hostdata->sync_stat[cmd->target] = SS_SET;
+			write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_CONNECTED;
+			break;
 
-            case EXTENDED_MESSAGE:
-DB(DB_INTR,printk("EXT"))
+		case EXTENDED_MESSAGE:
+			DB(DB_INTR, printk("EXT"))
 
-               ucp = hostdata->incoming_msg;
+			    ucp = hostdata->incoming_msg;
 
 #ifdef SYNC_DEBUG
-printk("%02x",ucp[hostdata->incoming_ptr]);
+			printk("%02x", ucp[hostdata->incoming_ptr]);
 #endif
-         /* Is this the last byte of the extended message? */
+			/* Is this the last byte of the extended message? */
 
-               if ((hostdata->incoming_ptr >= 2) &&
-                   (hostdata->incoming_ptr == (ucp[1] + 1))) {
+			if ((hostdata->incoming_ptr >= 2) && (hostdata->incoming_ptr == (ucp[1] + 1))) {
 
-                  switch (ucp[2]) {   /* what's the EXTENDED code? */
-                     case EXTENDED_SDTR:
-                        id = calc_sync_xfer(ucp[3],ucp[4]);
-                        if (hostdata->sync_stat[cmd->target] != SS_WAITING) {
+				switch (ucp[2]) {	/* what's the EXTENDED code? */
+				case EXTENDED_SDTR:
+					id = calc_sync_xfer(ucp[3], ucp[4]);
+					if (hostdata->sync_stat[cmd->target] != SS_WAITING) {
 
 /* A device has sent an unsolicited SDTR message; rather than go
  * through the effort of decoding it and then figuring out what
@@ -1262,120 +1260,117 @@
  * specifically ask for sync transfers, we won't do any.
  */
 
-                           write_3393_cmd(hostdata,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
-                           hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
-                           hostdata->outgoing_msg[1] = 3;
-                           hostdata->outgoing_msg[2] = EXTENDED_SDTR;
-                           hostdata->outgoing_msg[3] = hostdata->default_sx_per/4;
-                           hostdata->outgoing_msg[4] = 0;
-                           hostdata->outgoing_len = 5;
-                           hostdata->sync_xfer[cmd->target] =
-                                       calc_sync_xfer(hostdata->default_sx_per/4,0);
-                           }
-                        else {
-                           hostdata->sync_xfer[cmd->target] = id;
-                           }
+						write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
+						hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
+						hostdata->outgoing_msg[1] = 3;
+						hostdata->outgoing_msg[2] = EXTENDED_SDTR;
+						hostdata->outgoing_msg[3] = hostdata->default_sx_per / 4;
+						hostdata->outgoing_msg[4] = 0;
+						hostdata->outgoing_len = 5;
+						hostdata->sync_xfer[cmd->target] = calc_sync_xfer(hostdata->default_sx_per / 4, 0);
+					} else {
+						hostdata->sync_xfer[cmd->target] = id;
+					}
 #ifdef SYNC_DEBUG
-printk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]);
+					printk("sync_xfer=%02x", hostdata->sync_xfer[cmd->target]);
 #endif
-                        hostdata->sync_stat[cmd->target] = SS_SET;
-                        write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK);
-                        hostdata->state = S_CONNECTED;
-                        break;
-                     case EXTENDED_WDTR:
-                        write_3393_cmd(hostdata,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
-                        printk("sending WDTR ");
-                        hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
-                        hostdata->outgoing_msg[1] = 2;
-                        hostdata->outgoing_msg[2] = EXTENDED_WDTR;
-                        hostdata->outgoing_msg[3] = 0;   /* 8 bit transfer width */
-                        hostdata->outgoing_len = 4;
-                        write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK);
-                        hostdata->state = S_CONNECTED;
-                        break;
-                     default:
-                        write_3393_cmd(hostdata,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
-                        printk("Rejecting Unknown Extended Message(%02x). ",ucp[2]);
-                        hostdata->outgoing_msg[0] = MESSAGE_REJECT;
-                        hostdata->outgoing_len = 1;
-                        write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK);
-                        hostdata->state = S_CONNECTED;
-                        break;
-                     }
-                  hostdata->incoming_ptr = 0;
-                  }
-
-         /* We need to read more MESS_IN bytes for the extended message */
-
-               else {
-                  hostdata->incoming_ptr++;
-                  write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK);
-                  hostdata->state = S_CONNECTED;
-                  }
-               break;
-
-            default:
-               printk("Rejecting Unknown Message(%02x) ",msg);
-               write_3393_cmd(hostdata,WD_CMD_ASSERT_ATN); /* want MESS_OUT */
-               hostdata->outgoing_msg[0] = MESSAGE_REJECT;
-               hostdata->outgoing_len = 1;
-               write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK);
-               hostdata->state = S_CONNECTED;
-            }
-         break;
+					hostdata->sync_stat[cmd->target] = SS_SET;
+					write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+					hostdata->state = S_CONNECTED;
+					break;
+				case EXTENDED_WDTR:
+					write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
+					printk("sending WDTR ");
+					hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
+					hostdata->outgoing_msg[1] = 2;
+					hostdata->outgoing_msg[2] = EXTENDED_WDTR;
+					hostdata->outgoing_msg[3] = 0;	/* 8 bit transfer width */
+					hostdata->outgoing_len = 4;
+					write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+					hostdata->state = S_CONNECTED;
+					break;
+				default:
+					write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
+					printk("Rejecting Unknown Extended Message(%02x). ", ucp[2]);
+					hostdata->outgoing_msg[0] = MESSAGE_REJECT;
+					hostdata->outgoing_len = 1;
+					write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+					hostdata->state = S_CONNECTED;
+					break;
+				}
+				hostdata->incoming_ptr = 0;
+			}
+
+			/* We need to read more MESS_IN bytes for the extended message */
+
+			else {
+				hostdata->incoming_ptr++;
+				write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+				hostdata->state = S_CONNECTED;
+			}
+			break;
+
+		default:
+			printk("Rejecting Unknown Message(%02x) ", msg);
+			write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
+			hostdata->outgoing_msg[0] = MESSAGE_REJECT;
+			hostdata->outgoing_len = 1;
+			write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_CONNECTED;
+		}
+		break;
 
 
 /* Note: this interrupt will occur only after a LEVEL2 command */
 
-      case CSR_SEL_XFER_DONE:
+	case CSR_SEL_XFER_DONE:
 
 /* Make sure that reselection is enabled at this point - it may
  * have been turned off for the command that just completed.
  */
 
-         write_3393(hostdata,WD_SOURCE_ID, SRCID_ER);
-         if (phs == 0x60) {
-DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid))
-            cmd->SCp.Message = COMMAND_COMPLETE;
-            lun = read_3393(hostdata,WD_TARGET_LUN);
-DB(DB_INTR,printk(":%d.%d",cmd->SCp.Status,lun))
-            hostdata->connected = NULL;
-            hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
-            hostdata->state = S_UNCONNECTED;
-            if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE)
-               cmd->SCp.Status = lun;
-            if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
-               cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-            else
-               cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-            cmd->scsi_done(cmd);
+		write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
+		if (phs == 0x60) {
+			DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid))
+			    cmd->SCp.Message = COMMAND_COMPLETE;
+			lun = read_3393(hostdata, WD_TARGET_LUN);
+			DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))
+			    hostdata->connected = NULL;
+			hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+			hostdata->state = S_UNCONNECTED;
+			if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE)
+				cmd->SCp.Status = lun;
+			if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
+				cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+			else
+				cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+			cmd->scsi_done(cmd);
 
 /* We are no longer connected to a target - check to see if
  * there are commands waiting to be executed.
  */
 
-            in2000_execute(instance);
-            }
-         else {
-            printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",asr,sr,phs,cmd->pid);
-            }
-         break;
+			in2000_execute(instance);
+		} else {
+			printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs, cmd->pid);
+		}
+		break;
 
 
 /* Note: this interrupt will occur only after a LEVEL2 command */
 
-      case CSR_SDP:
-DB(DB_INTR,printk("SDP"))
-            hostdata->state = S_RUNNING_LEVEL2;
-            write_3393(hostdata,WD_COMMAND_PHASE, 0x41);
-            write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER);
-         break;
+	case CSR_SDP:
+		DB(DB_INTR, printk("SDP"))
+		    hostdata->state = S_RUNNING_LEVEL2;
+		write_3393(hostdata, WD_COMMAND_PHASE, 0x41);
+		write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+		break;
 
 
-      case CSR_XFER_DONE|PHS_MESS_OUT:
-      case CSR_UNEXP    |PHS_MESS_OUT:
-      case CSR_SRV_REQ  |PHS_MESS_OUT:
-DB(DB_INTR,printk("MSG_OUT="))
+	case CSR_XFER_DONE | PHS_MESS_OUT:
+	case CSR_UNEXP | PHS_MESS_OUT:
+	case CSR_SRV_REQ | PHS_MESS_OUT:
+		DB(DB_INTR, printk("MSG_OUT="))
 
 /* To get here, we've probably requested MESSAGE_OUT and have
  * already put the correct bytes in outgoing_msg[] and filled
@@ -1389,20 +1384,18 @@
  * NOP messages in these situations results in no harm and
  * makes everyone happy.
  */
+		    if (hostdata->outgoing_len == 0) {
+			hostdata->outgoing_len = 1;
+			hostdata->outgoing_msg[0] = NOP;
+		}
+		transfer_pio(hostdata->outgoing_msg, hostdata->outgoing_len, DATA_OUT_DIR, hostdata);
+		DB(DB_INTR, printk("%02x", hostdata->outgoing_msg[0]))
+		    hostdata->outgoing_len = 0;
+		hostdata->state = S_CONNECTED;
+		break;
 
-         if (hostdata->outgoing_len == 0) {
-            hostdata->outgoing_len = 1;
-            hostdata->outgoing_msg[0] = NOP;
-            }
-         transfer_pio(hostdata->outgoing_msg, hostdata->outgoing_len,
-                      DATA_OUT_DIR, hostdata);
-DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0]))
-         hostdata->outgoing_len = 0;
-         hostdata->state = S_CONNECTED;
-         break;
 
- 
-      case CSR_UNEXP_DISC:
+	case CSR_UNEXP_DISC:
 
 /* I think I've seen this after a request-sense that was in response
  * to an error condition, but not sure. We certainly need to do
@@ -1417,189 +1410,186 @@
  * have been turned off for the command that just completed.
  */
 
-         write_3393(hostdata,WD_SOURCE_ID, SRCID_ER);
-         if (cmd == NULL) {
-            printk(" - Already disconnected! ");
-            hostdata->state = S_UNCONNECTED;
+		write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
+		if (cmd == NULL) {
+			printk(" - Already disconnected! ");
+			hostdata->state = S_UNCONNECTED;
 
 /* release the SMP spin_lock and restore irq state */
-            spin_unlock_irqrestore(instance->host_lock, flags);
-            return;
-            }
-DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid))
-         hostdata->connected = NULL;
-         hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
-         hostdata->state = S_UNCONNECTED;
-         if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
-            cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-         else
-            cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-         cmd->scsi_done(cmd);
+			spin_unlock_irqrestore(instance->host_lock, flags);
+			return;
+		}
+		DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid))
+		    hostdata->connected = NULL;
+		hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+		hostdata->state = S_UNCONNECTED;
+		if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
+			cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+		else
+			cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+		cmd->scsi_done(cmd);
 
 /* We are no longer connected to a target - check to see if
  * there are commands waiting to be executed.
  */
 
-         in2000_execute(instance);
-         break;
+		in2000_execute(instance);
+		break;
 
 
-      case CSR_DISC:
+	case CSR_DISC:
 
 /* Make sure that reselection is enabled at this point - it may
  * have been turned off for the command that just completed.
  */
 
-         write_3393(hostdata,WD_SOURCE_ID, SRCID_ER);
-DB(DB_INTR,printk("DISC-%ld",cmd->pid))
-         if (cmd == NULL) {
-            printk(" - Already disconnected! ");
-            hostdata->state = S_UNCONNECTED;
-            }
-         switch (hostdata->state) {
-            case S_PRE_CMP_DISC:
-               hostdata->connected = NULL;
-               hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
-               hostdata->state = S_UNCONNECTED;
-DB(DB_INTR,printk(":%d",cmd->SCp.Status))
-               if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
-                  cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-               else
-                  cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-               cmd->scsi_done(cmd);
-               break;
-            case S_PRE_TMP_DISC:
-            case S_RUNNING_LEVEL2:
-               cmd->host_scribble = (uchar *)hostdata->disconnected_Q;
-               hostdata->disconnected_Q = cmd;
-               hostdata->connected = NULL;
-               hostdata->state = S_UNCONNECTED;
+		write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
+		DB(DB_INTR, printk("DISC-%ld", cmd->pid))
+		    if (cmd == NULL) {
+			printk(" - Already disconnected! ");
+			hostdata->state = S_UNCONNECTED;
+		}
+		switch (hostdata->state) {
+		case S_PRE_CMP_DISC:
+			hostdata->connected = NULL;
+			hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+			hostdata->state = S_UNCONNECTED;
+			DB(DB_INTR, printk(":%d", cmd->SCp.Status))
+			    if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
+				cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+			else
+				cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+			cmd->scsi_done(cmd);
+			break;
+		case S_PRE_TMP_DISC:
+		case S_RUNNING_LEVEL2:
+			cmd->host_scribble = (uchar *) hostdata->disconnected_Q;
+			hostdata->disconnected_Q = cmd;
+			hostdata->connected = NULL;
+			hostdata->state = S_UNCONNECTED;
 
 #ifdef PROC_STATISTICS
-               hostdata->disc_done_cnt[cmd->target]++;
+			hostdata->disc_done_cnt[cmd->target]++;
 #endif
 
-               break;
-            default:
-               printk("*** Unexpected DISCONNECT interrupt! ***");
-               hostdata->state = S_UNCONNECTED;
-            }
+			break;
+		default:
+			printk("*** Unexpected DISCONNECT interrupt! ***");
+			hostdata->state = S_UNCONNECTED;
+		}
 
 /* We are no longer connected to a target - check to see if
  * there are commands waiting to be executed.
  */
 
-         in2000_execute(instance);
-         break;
+		in2000_execute(instance);
+		break;
 
 
-      case CSR_RESEL_AM:
-DB(DB_INTR,printk("RESEL"))
+	case CSR_RESEL_AM:
+		DB(DB_INTR, printk("RESEL"))
 
-   /* First we have to make sure this reselection didn't */
-   /* happen during Arbitration/Selection of some other device. */
-   /* If yes, put losing command back on top of input_Q. */
-
-         if (hostdata->level2 <= L2_NONE) {
-
-            if (hostdata->selecting) {
-               cmd = (Scsi_Cmnd *)hostdata->selecting;
-               hostdata->selecting = NULL;
-               hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
-               cmd->host_scribble = (uchar *)hostdata->input_Q;
-               hostdata->input_Q = cmd;
-               }
-            }
-
-         else {
-
-            if (cmd) {
-               if (phs == 0x00) {
-                  hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
-                  cmd->host_scribble = (uchar *)hostdata->input_Q;
-                  hostdata->input_Q = cmd;
-                  }
-               else {
-                  printk("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---",asr,sr,phs);
-                  while (1)
-                     printk("\r");
-                  }
-               }
-
-            }
-
-   /* OK - find out which device reselected us. */
-
-         id = read_3393(hostdata,WD_SOURCE_ID);
-         id &= SRCID_MASK;
-
-   /* and extract the lun from the ID message. (Note that we don't
-    * bother to check for a valid message here - I guess this is
-    * not the right way to go, but....)
-    */
-
-         lun = read_3393(hostdata,WD_DATA);
-         if (hostdata->level2 < L2_RESELECT)
-            write_3393_cmd(hostdata,WD_CMD_NEGATE_ACK);
-         lun &= 7;
-
-   /* Now we look for the command that's reconnecting. */
-
-         cmd = (Scsi_Cmnd *)hostdata->disconnected_Q;
-         patch = NULL;
-         while (cmd) {
-            if (id == cmd->target && lun == cmd->lun)
-               break;
-            patch = cmd;
-            cmd = (Scsi_Cmnd *)cmd->host_scribble;
-            }
-
-   /* Hmm. Couldn't find a valid command.... What to do? */
-
-         if (!cmd) {
-            printk("---TROUBLE: target %d.%d not in disconnect queue---",id,lun);
-            break;
-            }
-
-   /* Ok, found the command - now start it up again. */
-
-         if (patch)
-            patch->host_scribble = cmd->host_scribble;
-         else
-            hostdata->disconnected_Q = (Scsi_Cmnd *)cmd->host_scribble;
-         hostdata->connected = cmd;
-
-   /* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]'
-    * because these things are preserved over a disconnect.
-    * But we DO need to fix the DPD bit so it's correct for this command.
-    */
-
-         if (is_dir_out(cmd))
-            write_3393(hostdata,WD_DESTINATION_ID,cmd->target);
-         else
-            write_3393(hostdata,WD_DESTINATION_ID,cmd->target | DSTID_DPD);
-         if (hostdata->level2 >= L2_RESELECT) {
-            write_3393_count(hostdata,0); /* we want a DATA_PHASE interrupt */
-            write_3393(hostdata,WD_COMMAND_PHASE, 0x45);
-            write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER);
-            hostdata->state = S_RUNNING_LEVEL2;
-            }
-         else
-            hostdata->state = S_CONNECTED;
-
-DB(DB_INTR,printk("-%ld",cmd->pid))
-         break;
-
-      default:
-         printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--",asr,sr,phs);
-      }
+		    /* First we have to make sure this reselection didn't */
+		    /* happen during Arbitration/Selection of some other device. */
+		    /* If yes, put losing command back on top of input_Q. */
+		    if (hostdata->level2 <= L2_NONE) {
+
+			if (hostdata->selecting) {
+				cmd = (Scsi_Cmnd *) hostdata->selecting;
+				hostdata->selecting = NULL;
+				hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+				cmd->host_scribble = (uchar *) hostdata->input_Q;
+				hostdata->input_Q = cmd;
+			}
+		}
+
+		else {
+
+			if (cmd) {
+				if (phs == 0x00) {
+					hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+					cmd->host_scribble = (uchar *) hostdata->input_Q;
+					hostdata->input_Q = cmd;
+				} else {
+					printk("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---", asr, sr, phs);
+					while (1)
+						printk("\r");
+				}
+			}
+
+		}
+
+		/* OK - find out which device reselected us. */
+
+		id = read_3393(hostdata, WD_SOURCE_ID);
+		id &= SRCID_MASK;
+
+		/* and extract the lun from the ID message. (Note that we don't
+		 * bother to check for a valid message here - I guess this is
+		 * not the right way to go, but....)
+		 */
+
+		lun = read_3393(hostdata, WD_DATA);
+		if (hostdata->level2 < L2_RESELECT)
+			write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+		lun &= 7;
+
+		/* Now we look for the command that's reconnecting. */
+
+		cmd = (Scsi_Cmnd *) hostdata->disconnected_Q;
+		patch = NULL;
+		while (cmd) {
+			if (id == cmd->target && lun == cmd->lun)
+				break;
+			patch = cmd;
+			cmd = (Scsi_Cmnd *) cmd->host_scribble;
+		}
+
+		/* Hmm. Couldn't find a valid command.... What to do? */
+
+		if (!cmd) {
+			printk("---TROUBLE: target %d.%d not in disconnect queue---", id, lun);
+			break;
+		}
+
+		/* Ok, found the command - now start it up again. */
+
+		if (patch)
+			patch->host_scribble = cmd->host_scribble;
+		else
+			hostdata->disconnected_Q = (Scsi_Cmnd *) cmd->host_scribble;
+		hostdata->connected = cmd;
+
+		/* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]'
+		 * because these things are preserved over a disconnect.
+		 * But we DO need to fix the DPD bit so it's correct for this command.
+		 */
+
+		if (is_dir_out(cmd))
+			write_3393(hostdata, WD_DESTINATION_ID, cmd->target);
+		else
+			write_3393(hostdata, WD_DESTINATION_ID, cmd->target | DSTID_DPD);
+		if (hostdata->level2 >= L2_RESELECT) {
+			write_3393_count(hostdata, 0);	/* we want a DATA_PHASE interrupt */
+			write_3393(hostdata, WD_COMMAND_PHASE, 0x45);
+			write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+			hostdata->state = S_RUNNING_LEVEL2;
+		} else
+			hostdata->state = S_CONNECTED;
+
+		DB(DB_INTR, printk("-%ld", cmd->pid))
+		    break;
+
+	default:
+		printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--", asr, sr, phs);
+	}
 
-   write1_io(0, IO_LED_OFF);
+	write1_io(0, IO_LED_OFF);
 
-DB(DB_INTR,printk("} "))
+	DB(DB_INTR, printk("} "))
 
 /* release the SMP spin_lock and restore irq state */
-   spin_unlock_irqrestore(instance->host_lock, flags);
+	    spin_unlock_irqrestore(instance->host_lock, flags);
 
 }
 
@@ -1612,135 +1602,124 @@
 /*
  *	Caller must hold instance lock!
  */
- 
+
 static int reset_hardware(struct Scsi_Host *instance, int type)
 {
-struct IN2000_hostdata *hostdata;
-int qt,x;
+	struct IN2000_hostdata *hostdata;
+	int qt, x;
 
-   hostdata = (struct IN2000_hostdata *)instance->hostdata;
+	hostdata = (struct IN2000_hostdata *) instance->hostdata;
 
-   write1_io(0, IO_LED_ON);
-   if (type == RESET_CARD_AND_BUS) {
-      write1_io(0,IO_CARD_RESET);
-      x = read1_io(IO_HARDWARE);
-      }
-   x = read_3393(hostdata,WD_SCSI_STATUS);   /* clear any WD intrpt */
-   write_3393(hostdata,WD_OWN_ID, instance->this_id |
-                           OWNID_EAF | OWNID_RAF | OWNID_FS_8);
-   write_3393(hostdata,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
-   write_3393(hostdata,WD_SYNCHRONOUS_TRANSFER,
-              calc_sync_xfer(hostdata->default_sx_per/4,DEFAULT_SX_OFF));
-
-   write1_io(0,IO_FIFO_WRITE);            /* clear fifo counter */
-   write1_io(0,IO_FIFO_READ);             /* start fifo out in read mode */
-   write_3393(hostdata,WD_COMMAND, WD_CMD_RESET);
-   /* FIXME: timeout ?? */
-   while (!(READ_AUX_STAT() & ASR_INT))
-      cpu_relax();                           /* wait for RESET to complete */
-
-   x = read_3393(hostdata,WD_SCSI_STATUS);   /* clear interrupt */
-
-   write_3393(hostdata,WD_QUEUE_TAG,0xa5);   /* any random number */
-   qt = read_3393(hostdata,WD_QUEUE_TAG);
-   if (qt == 0xa5) {
-      x |= B_FLAG;
-      write_3393(hostdata,WD_QUEUE_TAG,0);
-      }
-   write_3393(hostdata,WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE);
-   write_3393(hostdata,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
-   write1_io(0, IO_LED_OFF);
-   return x;
-}
-
-
-
-static int in2000_bus_reset(Scsi_Cmnd *cmd)
-{
-unsigned long flags;
-struct Scsi_Host *instance;
-struct IN2000_hostdata *hostdata;
-int x;
-
-   instance = cmd->host;
-   hostdata = (struct IN2000_hostdata *)instance->hostdata;
-
-   printk(KERN_WARNING "scsi%d: Reset. ", instance->host_no);
-
-   spin_lock_irqsave(instance->host_lock, flags);
-   /* do scsi-reset here */
-
-   reset_hardware(instance, RESET_CARD_AND_BUS);
-   for (x = 0; x < 8; x++) {
-      hostdata->busy[x] = 0;
-      hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF);
-      hostdata->sync_stat[x] = SS_UNSET;  /* using default sync values */
-      }
-   hostdata->input_Q = NULL;
-   hostdata->selecting = NULL;
-   hostdata->connected = NULL;
-   hostdata->disconnected_Q = NULL;
-   hostdata->state = S_UNCONNECTED;
-   hostdata->fifo = FI_FIFO_UNUSED;
-   hostdata->incoming_ptr = 0;
-   hostdata->outgoing_len = 0;
-
-   cmd->result = DID_RESET << 16;
-   spin_unlock_irqrestore(instance->host_lock, flags);
-   return SUCCESS;
+	write1_io(0, IO_LED_ON);
+	if (type == RESET_CARD_AND_BUS) {
+		write1_io(0, IO_CARD_RESET);
+		x = read1_io(IO_HARDWARE);
+	}
+	x = read_3393(hostdata, WD_SCSI_STATUS);	/* clear any WD intrpt */
+	write_3393(hostdata, WD_OWN_ID, instance->this_id | OWNID_EAF | OWNID_RAF | OWNID_FS_8);
+	write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+	write_3393(hostdata, WD_SYNCHRONOUS_TRANSFER, calc_sync_xfer(hostdata->default_sx_per / 4, DEFAULT_SX_OFF));
+
+	write1_io(0, IO_FIFO_WRITE);	/* clear fifo counter */
+	write1_io(0, IO_FIFO_READ);	/* start fifo out in read mode */
+	write_3393(hostdata, WD_COMMAND, WD_CMD_RESET);
+	/* FIXME: timeout ?? */
+	while (!(READ_AUX_STAT() & ASR_INT))
+		cpu_relax();	/* wait for RESET to complete */
+
+	x = read_3393(hostdata, WD_SCSI_STATUS);	/* clear interrupt */
+
+	write_3393(hostdata, WD_QUEUE_TAG, 0xa5);	/* any random number */
+	qt = read_3393(hostdata, WD_QUEUE_TAG);
+	if (qt == 0xa5) {
+		x |= B_FLAG;
+		write_3393(hostdata, WD_QUEUE_TAG, 0);
+	}
+	write_3393(hostdata, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE);
+	write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+	write1_io(0, IO_LED_OFF);
+	return x;
+}
+
+
+
+static int in2000_bus_reset(Scsi_Cmnd * cmd)
+{
+	struct Scsi_Host *instance;
+	struct IN2000_hostdata *hostdata;
+	int x;
+
+	instance = cmd->host;
+	hostdata = (struct IN2000_hostdata *) instance->hostdata;
+
+	printk(KERN_WARNING "scsi%d: Reset. ", instance->host_no);
+
+	/* do scsi-reset here */
+
+	reset_hardware(instance, RESET_CARD_AND_BUS);
+	for (x = 0; x < 8; x++) {
+		hostdata->busy[x] = 0;
+		hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);
+		hostdata->sync_stat[x] = SS_UNSET;	/* using default sync values */
+	}
+	hostdata->input_Q = NULL;
+	hostdata->selecting = NULL;
+	hostdata->connected = NULL;
+	hostdata->disconnected_Q = NULL;
+	hostdata->state = S_UNCONNECTED;
+	hostdata->fifo = FI_FIFO_UNUSED;
+	hostdata->incoming_ptr = 0;
+	hostdata->outgoing_len = 0;
+
+	cmd->result = DID_RESET << 16;
+	return SUCCESS;
 }
 
-static int in2000_host_reset(Scsi_Cmnd *cmd)
+static int in2000_host_reset(Scsi_Cmnd * cmd)
 {
 	return FAILED;
 }
 
-static int in2000_device_reset(Scsi_Cmnd *cmd)
+static int in2000_device_reset(Scsi_Cmnd * cmd)
 {
 	return FAILED;
 }
 
 
-static int in2000_abort (Scsi_Cmnd *cmd)
+static int in2000_abort(Scsi_Cmnd * cmd)
 {
-struct Scsi_Host *instance;
-struct IN2000_hostdata *hostdata;
-Scsi_Cmnd *tmp, *prev;
-unsigned long flags;
-uchar sr, asr;
-unsigned long timeout;
-
-   instance = cmd->host;
-   hostdata = (struct IN2000_hostdata *)instance->hostdata;
-
-   printk(KERN_DEBUG "scsi%d: Abort-", instance->host_no);
-   printk("(asr=%02x,count=%ld,resid=%d,buf_resid=%d,have_data=%d,FC=%02x)- ",
-            READ_AUX_STAT(),read_3393_count(hostdata),cmd->SCp.this_residual,cmd->SCp.buffers_residual,
-            cmd->SCp.have_data_in,read1_io(IO_FIFO_COUNT));
+	struct Scsi_Host *instance;
+	struct IN2000_hostdata *hostdata;
+	Scsi_Cmnd *tmp, *prev;
+	uchar sr, asr;
+	unsigned long timeout;
+
+	instance = cmd->host;
+	hostdata = (struct IN2000_hostdata *) instance->hostdata;
+
+	printk(KERN_DEBUG "scsi%d: Abort-", instance->host_no);
+	printk("(asr=%02x,count=%ld,resid=%d,buf_resid=%d,have_data=%d,FC=%02x)- ", READ_AUX_STAT(), read_3393_count(hostdata), cmd->SCp.this_residual, cmd->SCp.buffers_residual, cmd->SCp.have_data_in, read1_io(IO_FIFO_COUNT));
 
 /*
  * Case 1 : If the command hasn't been issued yet, we simply remove it
  *     from the inout_Q.
  */
 
-   spin_lock_irqsave(instance->host_lock, flags);
-   tmp = (Scsi_Cmnd *)hostdata->input_Q;
-   prev = 0;
-   while (tmp) {
-      if (tmp == cmd) {
-         if (prev)
-            prev->host_scribble = cmd->host_scribble;
-         cmd->host_scribble = NULL;
-         cmd->result = DID_ABORT << 16;
-         printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ",
-           instance->host_no, cmd->pid);
-         cmd->scsi_done(cmd);
-         spin_unlock_irqrestore(instance->host_lock, flags);
-         return SUCCESS;
-         }
-      prev = tmp;
-      tmp = (Scsi_Cmnd *)tmp->host_scribble;
-      }
+	tmp = (Scsi_Cmnd *) hostdata->input_Q;
+	prev = 0;
+	while (tmp) {
+		if (tmp == cmd) {
+			if (prev)
+				prev->host_scribble = cmd->host_scribble;
+			cmd->host_scribble = NULL;
+			cmd->result = DID_ABORT << 16;
+			printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->pid);
+			cmd->scsi_done(cmd);
+			return SUCCESS;
+		}
+		prev = tmp;
+		tmp = (Scsi_Cmnd *) tmp->host_scribble;
+	}
 
 /*
  * Case 2 : If the command is connected, we're going to fail the abort
@@ -1753,54 +1732,52 @@
  *     we fail.
  */
 
-   if (hostdata->connected == cmd) {
+	if (hostdata->connected == cmd) {
 
-      printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ",
-              instance->host_no, cmd->pid);
+		printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->pid);
 
-      printk("sending wd33c93 ABORT command - ");
-      write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
-      write_3393_cmd(hostdata, WD_CMD_ABORT);
+		printk("sending wd33c93 ABORT command - ");
+		write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+		write_3393_cmd(hostdata, WD_CMD_ABORT);
 
 /* Now we have to attempt to flush out the FIFO... */
 
-      printk("flushing fifo - ");
-      timeout = 1000000;
-      do {
-         asr = READ_AUX_STAT();
-         if (asr & ASR_DBR)
-            read_3393(hostdata, WD_DATA);
-         } while (!(asr & ASR_INT) && timeout-- > 0);
-      sr = read_3393(hostdata, WD_SCSI_STATUS);
-      printk("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ",
-             asr, sr, read_3393_count(hostdata), timeout);
-
-   /*
-    * Abort command processed.
-    * Still connected.
-    * We must disconnect.
-    */
-
-      printk("sending wd33c93 DISCONNECT command - ");
-      write_3393_cmd(hostdata, WD_CMD_DISCONNECT);
-
-      timeout = 1000000;
-      asr = READ_AUX_STAT();
-      while ((asr & ASR_CIP) && timeout-- > 0)
-         asr = READ_AUX_STAT();
-      sr = read_3393(hostdata, WD_SCSI_STATUS);
-      printk("asr=%02x, sr=%02x.",asr,sr);
-
-      hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
-      hostdata->connected = NULL;
-      hostdata->state = S_UNCONNECTED;
-      cmd->result = DID_ABORT << 16;
-      cmd->scsi_done(cmd);
+		printk("flushing fifo - ");
+		timeout = 1000000;
+		do {
+			asr = READ_AUX_STAT();
+			if (asr & ASR_DBR)
+				read_3393(hostdata, WD_DATA);
+		} while (!(asr & ASR_INT) && timeout-- > 0);
+		sr = read_3393(hostdata, WD_SCSI_STATUS);
+		printk("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ", asr, sr, read_3393_count(hostdata), timeout);
+
+		/*
+		 * Abort command processed.
+		 * Still connected.
+		 * We must disconnect.
+		 */
+
+		printk("sending wd33c93 DISCONNECT command - ");
+		write_3393_cmd(hostdata, WD_CMD_DISCONNECT);
+
+		timeout = 1000000;
+		asr = READ_AUX_STAT();
+		while ((asr & ASR_CIP) && timeout-- > 0)
+			asr = READ_AUX_STAT();
+		sr = read_3393(hostdata, WD_SCSI_STATUS);
+		printk("asr=%02x, sr=%02x.", asr, sr);
+
+		hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+		hostdata->connected = NULL;
+		hostdata->state = S_UNCONNECTED;
+		cmd->result = DID_ABORT << 16;
+		cmd->scsi_done(cmd);
 
-      in2000_execute (instance);
+		in2000_execute(instance);
 
-      return SCSI_ABORT_SUCCESS;
-      }
+		return SUCCESS;
+	}
 
 /*
  * Case 3: If the command is currently disconnected from the bus,
@@ -1808,13 +1785,11 @@
  * an ABORT_SNOOZE and hope for the best...
  */
 
-   for (tmp=(Scsi_Cmnd *)hostdata->disconnected_Q; tmp;
-         tmp=(Scsi_Cmnd *)tmp->host_scribble)
-      if (cmd == tmp) {
-	 spin_unlock_irqrestore(instance->host_lock, flags);
-	 printk(KERN_DEBUG "scsi%d: unable to abort disconnected command.\n", instance->host_no);
-         return FAILED;
-         }
+	for (tmp = (Scsi_Cmnd *) hostdata->disconnected_Q; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble)
+		if (cmd == tmp) {
+			printk(KERN_DEBUG "scsi%d: unable to abort disconnected command.\n", instance->host_no);
+			return FAILED;
+		}
 
 /*
  * Case 4 : If we reached this point, the command was not found in any of
@@ -1826,12 +1801,10 @@
  * broke.
  */
 
-   in2000_execute (instance);
+	in2000_execute(instance);
 
-   spin_unlock_irqrestore(instance->host_lock, flags);
-   printk("scsi%d: warning : SCSI command probably completed successfully"
-      "         before abortion. ", instance->host_no);
-   return SUCCESS;
+	printk("scsi%d: warning : SCSI command probably completed successfully" "         before abortion. ", instance->host_no);
+	return SUCCESS;
 }
 
 
@@ -1843,32 +1816,31 @@
 static char setup_used[MAX_SETUP_ARGS];
 static int done_setup = 0;
 
-static void __init in2000_setup (char *str, int *ints)
+static void __init in2000_setup(char *str, int *ints)
 {
-int i;
-char *p1,*p2;
+	int i;
+	char *p1, *p2;
 
-   strncpy(setup_buffer,str,SETUP_BUFFER_SIZE);
-   setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
-   p1 = setup_buffer;
-   i = 0;
-   while (*p1 && (i < MAX_SETUP_ARGS)) {
-      p2 = strchr(p1, ',');
-      if (p2) {
-         *p2 = '\0';
-         if (p1 != p2)
-            setup_args[i] = p1;
-         p1 = p2 + 1;
-         i++;
-         }
-      else {
-         setup_args[i] = p1;
-         break;
-         }
-      }
-   for (i=0; i<MAX_SETUP_ARGS; i++)
-      setup_used[i] = 0;
-   done_setup = 1;
+	strncpy(setup_buffer, str, SETUP_BUFFER_SIZE);
+	setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
+	p1 = setup_buffer;
+	i = 0;
+	while (*p1 && (i < MAX_SETUP_ARGS)) {
+		p2 = strchr(p1, ',');
+		if (p2) {
+			*p2 = '\0';
+			if (p1 != p2)
+				setup_args[i] = p1;
+			p1 = p2 + 1;
+			i++;
+		} else {
+			setup_args[i] = p1;
+			break;
+		}
+	}
+	for (i = 0; i < MAX_SETUP_ARGS; i++)
+		setup_used[i] = 0;
+	done_setup = 1;
 }
 
 
@@ -1877,27 +1849,27 @@
 
 static int __init check_setup_args(char *key, int *flags, int *val, char *buf)
 {
-int x;
-char *cp;
+	int x;
+	char *cp;
 
-   for  (x=0; x<MAX_SETUP_ARGS; x++) {
-      if (setup_used[x])
-         continue;
-      if (!strncmp(setup_args[x], key, strlen(key)))
-         break;
-      }
-   if (x == MAX_SETUP_ARGS)
-      return 0;
-   setup_used[x] = 1;
-   cp = setup_args[x] + strlen(key);
-   *val = -1;
-   if (*cp != ':')
-      return ++x;
-   cp++;
-   if ((*cp >= '0') && (*cp <= '9')) {
-      *val = simple_strtoul(cp,NULL,0);
-      }
-   return ++x;
+	for (x = 0; x < MAX_SETUP_ARGS; x++) {
+		if (setup_used[x])
+			continue;
+		if (!strncmp(setup_args[x], key, strlen(key)))
+			break;
+	}
+	if (x == MAX_SETUP_ARGS)
+		return 0;
+	setup_used[x] = 1;
+	cp = setup_args[x] + strlen(key);
+	*val = -1;
+	if (*cp != ':')
+		return ++x;
+	cp++;
+	if ((*cp >= '0') && (*cp <= '9')) {
+		*val = simple_strtoul(cp, NULL, 0);
+	}
+	return ++x;
 }
 
 
@@ -1908,40 +1880,40 @@
  * when reading from the card's BIOS area in in2000_detect().
  */
 static u32 bios_tab[] in2000__INITDATA = {
-   0xc8000,
-   0xd0000,
-   0xd8000,
-   0
-   };
+	0xc8000,
+	0xd0000,
+	0xd8000,
+	0
+};
 
 static const unsigned short base_tab[] in2000__INITDATA = {
-   0x220,
-   0x200,
-   0x110,
-   0x100,
-   };
+	0x220,
+	0x200,
+	0x110,
+	0x100,
+};
 
 static const int int_tab[] in2000__INITDATA = {
-   15,
-   14,
-   11,
-   10
-   };
+	15,
+	14,
+	11,
+	10
+};
 
 
 static int __init in2000_detect(Scsi_Host_Template * tpnt)
 {
-struct Scsi_Host *instance;
-struct IN2000_hostdata *hostdata;
-int detect_count;
-int bios;
-int x;
-unsigned short base;
-uchar switches;
-uchar hrev;
-int flags;
-int val;
-char buf[32];
+	struct Scsi_Host *instance;
+	struct IN2000_hostdata *hostdata;
+	int detect_count;
+	int bios;
+	int x;
+	unsigned short base;
+	uchar switches;
+	uchar hrev;
+	int flags;
+	int val;
+	char buf[32];
 
 /* Thanks to help from Bill Earnest, probing for IN2000 cards is a
  * pretty straightforward and fool-proof operation. There are 3
@@ -1955,203 +1927,187 @@
  * or disabled.
  */
 
-   if (!done_setup && setup_strings)
-      in2000_setup(setup_strings,0);
+	if (!done_setup && setup_strings)
+		in2000_setup(setup_strings, 0);
 
-   detect_count = 0;
-   for (bios = 0; bios_tab[bios]; bios++) {
-      if (check_setup_args("ioport",&flags,&val,buf)) {
-         base = val;
-         switches = ~inb(base + IO_SWITCHES) & 0xff;
-         printk("Forcing IN2000 detection at IOport 0x%x ",base);
-         bios = 2;
-         }
+	detect_count = 0;
+	for (bios = 0; bios_tab[bios]; bios++) {
+		if (check_setup_args("ioport", &flags, &val, buf)) {
+			base = val;
+			switches = ~inb(base + IO_SWITCHES) & 0xff;
+			printk("Forcing IN2000 detection at IOport 0x%x ", base);
+			bios = 2;
+		}
 /*
  * There have been a couple of BIOS versions with different layouts
  * for the obvious ID strings. We look for the 2 most common ones and
  * hope that they cover all the cases...
  */
-      else if (isa_readl(bios_tab[bios]+0x10) == 0x41564f4e ||
-               isa_readl(bios_tab[bios]+0x30) == 0x61776c41) {
-         printk("Found IN2000 BIOS at 0x%x ",(unsigned int)bios_tab[bios]);
+		else if (isa_readl(bios_tab[bios] + 0x10) == 0x41564f4e || isa_readl(bios_tab[bios] + 0x30) == 0x61776c41) {
+			printk("Found IN2000 BIOS at 0x%x ", (unsigned int) bios_tab[bios]);
 
 /* Read the switch image that's mapped into EPROM space */
 
-         switches = ~((isa_readb(bios_tab[bios]+0x20) & 0xff));
+			switches = ~((isa_readb(bios_tab[bios] + 0x20) & 0xff));
 
 /* Find out where the IO space is */
 
-         x = switches & (SW_ADDR0 | SW_ADDR1);
-         base = base_tab[x];
+			x = switches & (SW_ADDR0 | SW_ADDR1);
+			base = base_tab[x];
 
 /* Check for the IN2000 signature in IO space. */
 
-         x = ~inb(base + IO_SWITCHES) & 0xff;
-         if (x != switches) {
-            printk("Bad IO signature: %02x vs %02x.\n",x,switches);
-            continue;
-            }
-         }
-      else
-         continue;
+			x = ~inb(base + IO_SWITCHES) & 0xff;
+			if (x != switches) {
+				printk("Bad IO signature: %02x vs %02x.\n", x, switches);
+				continue;
+			}
+		} else
+			continue;
 
 /* OK. We have a base address for the IO ports - run a few safety checks */
 
-      if (!(switches & SW_BIT7)) {        /* I _think_ all cards do this */
-         printk("There is no IN-2000 SCSI card at IOport 0x%03x!\n",base);
-         continue;
-         }
+		if (!(switches & SW_BIT7)) {	/* I _think_ all cards do this */
+			printk("There is no IN-2000 SCSI card at IOport 0x%03x!\n", base);
+			continue;
+		}
 
 /* Let's assume any hardware version will work, although the driver
  * has only been tested on 0x21, 0x22, 0x25, 0x26, and 0x27. We'll
  * print out the rev number for reference later, but accept them all.
  */
 
-      hrev = inb(base + IO_HARDWARE);
+		hrev = inb(base + IO_HARDWARE);
 
-  /* Bit 2 tells us if interrupts are disabled */
-      if (switches & SW_DISINT) {
-         printk("The IN-2000 SCSI card at IOport 0x%03x ",base);
-         printk("is not configured for interrupt operation!\n");
-         printk("This driver requires an interrupt: cancelling detection.\n");
-         continue;
-         }
+		/* Bit 2 tells us if interrupts are disabled */
+		if (switches & SW_DISINT) {
+			printk("The IN-2000 SCSI card at IOport 0x%03x ", base);
+			printk("is not configured for interrupt operation!\n");
+			printk("This driver requires an interrupt: cancelling detection.\n");
+			continue;
+		}
 
 /* Ok. We accept that there's an IN2000 at ioaddr 'base'. Now
  * initialize it.
  */
 
-      tpnt->proc_name = "in2000";
-      instance  = scsi_register(tpnt, sizeof(struct IN2000_hostdata));
-      if(instance == NULL)
-      	continue;
-      detect_count++;
-      if (!instance_list)
-         instance_list = instance;
-      hostdata = (struct IN2000_hostdata *)instance->hostdata;
-      instance->io_port = hostdata->io_base = base;
-      hostdata->dip_switch = switches;
-      hostdata->hrev = hrev;
-
-      write1_io(0,IO_FIFO_WRITE);            /* clear fifo counter */
-      write1_io(0,IO_FIFO_READ);             /* start fifo out in read mode */
-      write1_io(0,IO_INTR_MASK);    /* allow all ints */
-      x = int_tab[(switches & (SW_INT0 | SW_INT1)) >> SW_INT_SHIFT];
-      if (request_irq(x, in2000_intr, SA_INTERRUPT, "in2000", instance)) {
-         printk("in2000_detect: Unable to allocate IRQ.\n");
-         detect_count--;
-         continue;
-         }
-      instance->irq = x;
-      instance->n_io_port = 13;
-      request_region(base, 13, "in2000"); /* lock in this IO space for our use */
-
-      for (x = 0; x < 8; x++) {
-         hostdata->busy[x] = 0;
-         hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF);
-         hostdata->sync_stat[x] = SS_UNSET;  /* using default sync values */
+		tpnt->proc_name = "in2000";
+		instance = scsi_register(tpnt, sizeof(struct IN2000_hostdata));
+		if (instance == NULL)
+			continue;
+		detect_count++;
+		hostdata = (struct IN2000_hostdata *) instance->hostdata;
+		instance->io_port = hostdata->io_base = base;
+		hostdata->dip_switch = switches;
+		hostdata->hrev = hrev;
+
+		write1_io(0, IO_FIFO_WRITE);	/* clear fifo counter */
+		write1_io(0, IO_FIFO_READ);	/* start fifo out in read mode */
+		write1_io(0, IO_INTR_MASK);	/* allow all ints */
+		x = int_tab[(switches & (SW_INT0 | SW_INT1)) >> SW_INT_SHIFT];
+		if (request_irq(x, in2000_intr, SA_INTERRUPT, "in2000", instance)) {
+			printk("in2000_detect: Unable to allocate IRQ.\n");
+			detect_count--;
+			continue;
+		}
+		instance->irq = x;
+		instance->n_io_port = 13;
+		request_region(base, 13, "in2000");	/* lock in this IO space for our use */
+
+		for (x = 0; x < 8; x++) {
+			hostdata->busy[x] = 0;
+			hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);
+			hostdata->sync_stat[x] = SS_UNSET;	/* using default sync values */
 #ifdef PROC_STATISTICS
-         hostdata->cmd_cnt[x] = 0;
-         hostdata->disc_allowed_cnt[x] = 0;
-         hostdata->disc_done_cnt[x] = 0;
+			hostdata->cmd_cnt[x] = 0;
+			hostdata->disc_allowed_cnt[x] = 0;
+			hostdata->disc_done_cnt[x] = 0;
 #endif
-         }
-      hostdata->input_Q = NULL;
-      hostdata->selecting = NULL;
-      hostdata->connected = NULL;
-      hostdata->disconnected_Q = NULL;
-      hostdata->state = S_UNCONNECTED;
-      hostdata->fifo = FI_FIFO_UNUSED;
-      hostdata->level2 = L2_BASIC;
-      hostdata->disconnect = DIS_ADAPTIVE;
-      hostdata->args = DEBUG_DEFAULTS;
-      hostdata->incoming_ptr = 0;
-      hostdata->outgoing_len = 0;
-      hostdata->default_sx_per = DEFAULT_SX_PER;
+		}
+		hostdata->input_Q = NULL;
+		hostdata->selecting = NULL;
+		hostdata->connected = NULL;
+		hostdata->disconnected_Q = NULL;
+		hostdata->state = S_UNCONNECTED;
+		hostdata->fifo = FI_FIFO_UNUSED;
+		hostdata->level2 = L2_BASIC;
+		hostdata->disconnect = DIS_ADAPTIVE;
+		hostdata->args = DEBUG_DEFAULTS;
+		hostdata->incoming_ptr = 0;
+		hostdata->outgoing_len = 0;
+		hostdata->default_sx_per = DEFAULT_SX_PER;
 
 /* Older BIOS's had a 'sync on/off' switch - use its setting */
 
-      if (isa_readl(bios_tab[bios]+0x10) == 0x41564f4e && (switches & SW_SYNC_DOS5))
-         hostdata->sync_off = 0x00;    /* sync defaults to on */
-      else
-         hostdata->sync_off = 0xff;    /* sync defaults to off */
+		if (isa_readl(bios_tab[bios] + 0x10) == 0x41564f4e && (switches & SW_SYNC_DOS5))
+			hostdata->sync_off = 0x00;	/* sync defaults to on */
+		else
+			hostdata->sync_off = 0xff;	/* sync defaults to off */
 
 #ifdef PROC_INTERFACE
-      hostdata->proc = PR_VERSION|PR_INFO|PR_STATISTICS|
-                       PR_CONNECTED|PR_INPUTQ|PR_DISCQ|
-                       PR_STOP;
+		hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS | PR_CONNECTED | PR_INPUTQ | PR_DISCQ | PR_STOP;
 #ifdef PROC_STATISTICS
-      hostdata->int_cnt = 0;
+		hostdata->int_cnt = 0;
 #endif
 #endif
 
-      if (check_setup_args("nosync",&flags,&val,buf))
-         hostdata->sync_off = val;
+		if (check_setup_args("nosync", &flags, &val, buf))
+			hostdata->sync_off = val;
 
-      if (check_setup_args("period",&flags,&val,buf))
-         hostdata->default_sx_per = sx_table[round_period((unsigned int)val)].period_ns;
+		if (check_setup_args("period", &flags, &val, buf))
+			hostdata->default_sx_per = sx_table[round_period((unsigned int) val)].period_ns;
 
-      if (check_setup_args("disconnect",&flags,&val,buf)) {
-         if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS))
-            hostdata->disconnect = val;
-         else
-            hostdata->disconnect = DIS_ADAPTIVE;
-         }
+		if (check_setup_args("disconnect", &flags, &val, buf)) {
+			if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS))
+				hostdata->disconnect = val;
+			else
+				hostdata->disconnect = DIS_ADAPTIVE;
+		}
 
-      if (check_setup_args("noreset",&flags,&val,buf))
-         hostdata->args ^= A_NO_SCSI_RESET;
+		if (check_setup_args("noreset", &flags, &val, buf))
+			hostdata->args ^= A_NO_SCSI_RESET;
 
-      if (check_setup_args("level2",&flags,&val,buf))
-         hostdata->level2 = val;
+		if (check_setup_args("level2", &flags, &val, buf))
+			hostdata->level2 = val;
 
-      if (check_setup_args("debug",&flags,&val,buf))
-         hostdata->args = (val & DB_MASK);
+		if (check_setup_args("debug", &flags, &val, buf))
+			hostdata->args = (val & DB_MASK);
 
 #ifdef PROC_INTERFACE
-      if (check_setup_args("proc",&flags,&val,buf))
-         hostdata->proc = val;
+		if (check_setup_args("proc", &flags, &val, buf))
+			hostdata->proc = val;
 #endif
 
 
-      /* FIXME: not strictly needed I think but the called code expects
-         to be locked */
-      spin_lock_irqsave(instance->host_lock, flags);
-      x = reset_hardware(instance,(hostdata->args & A_NO_SCSI_RESET)?RESET_CARD:RESET_CARD_AND_BUS);
-      spin_unlock_irqrestore(instance->host_lock, flags);
-
-      hostdata->microcode = read_3393(hostdata,WD_CDB_1);
-      if (x & 0x01) {
-         if (x & B_FLAG)
-            hostdata->chip = C_WD33C93B;
-         else
-            hostdata->chip = C_WD33C93A;
-         }
-      else
-         hostdata->chip = C_WD33C93;
-
-      printk("dip_switch=%02x irq=%d ioport=%02x floppy=%s sync/DOS5=%s ",
-                  (switches & 0x7f),
-                  instance->irq,hostdata->io_base,
-                  (switches & SW_FLOPPY)?"Yes":"No",
-                  (switches & SW_SYNC_DOS5)?"Yes":"No");
-      printk("hardware_ver=%02x chip=%s microcode=%02x\n",
-                  hrev,
-                  (hostdata->chip==C_WD33C93)?"WD33c93":
-                  (hostdata->chip==C_WD33C93A)?"WD33c93A":
-                  (hostdata->chip==C_WD33C93B)?"WD33c93B":"unknown",
-                  hostdata->microcode);
+		/* FIXME: not strictly needed I think but the called code expects
+		   to be locked */
+		spin_lock_irqsave(instance->host_lock, flags);
+		x = reset_hardware(instance, (hostdata->args & A_NO_SCSI_RESET) ? RESET_CARD : RESET_CARD_AND_BUS);
+		spin_unlock_irqrestore(instance->host_lock, flags);
+
+		hostdata->microcode = read_3393(hostdata, WD_CDB_1);
+		if (x & 0x01) {
+			if (x & B_FLAG)
+				hostdata->chip = C_WD33C93B;
+			else
+				hostdata->chip = C_WD33C93A;
+		} else
+			hostdata->chip = C_WD33C93;
+
+		printk("dip_switch=%02x irq=%d ioport=%02x floppy=%s sync/DOS5=%s ", (switches & 0x7f), instance->irq, hostdata->io_base, (switches & SW_FLOPPY) ? "Yes" : "No", (switches & SW_SYNC_DOS5) ? "Yes" : "No");
+		printk("hardware_ver=%02x chip=%s microcode=%02x\n", hrev, (hostdata->chip == C_WD33C93) ? "WD33c93" : (hostdata->chip == C_WD33C93A) ? "WD33c93A" : (hostdata->chip == C_WD33C93B) ? "WD33c93B" : "unknown", hostdata->microcode);
 #ifdef DEBUGGING_ON
-      printk("setup_args = ");
-      for (x=0; x<MAX_SETUP_ARGS; x++)
-         printk("%s,",setup_args[x]);
-      printk("\n");
+		printk("setup_args = ");
+		for (x = 0; x < MAX_SETUP_ARGS; x++)
+			printk("%s,", setup_args[x]);
+		printk("\n");
 #endif
-      if (hostdata->sync_off == 0xff)
-         printk("Sync-transfer DISABLED on all devices: ENABLE from command-line\n");
-      printk("IN2000 driver version %s - %s\n",IN2000_VERSION,IN2000_DATE);
-      }
+		if (hostdata->sync_off == 0xff)
+			printk("Sync-transfer DISABLED on all devices: ENABLE from command-line\n");
+		printk("IN2000 driver version %s - %s\n", IN2000_VERSION, IN2000_DATE);
+	}
 
-   return detect_count;
+	return detect_count;
 }
 
 static int in2000_release(struct Scsi_Host *shost)
@@ -2163,43 +2119,40 @@
 	return 0;
 }
 
-
 /* NOTE: I lifted this function straight out of the old driver,
  *       and have not tested it. Presumably it does what it's
  *       supposed to do...
  */
 
-static int in2000_biosparam(struct scsi_device *sdev,
-		struct block_device *bdev,
-		sector_t capacity, int *iinfo)
-{
-int size;
-
-   size  = capacity;
-   iinfo[0] = 64;
-   iinfo[1] = 32;
-   iinfo[2] = size >> 11;
+static int in2000_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *iinfo)
+{
+	int size;
+
+	size = capacity;
+	iinfo[0] = 64;
+	iinfo[1] = 32;
+	iinfo[2] = size >> 11;
 
 /* This should approximate the large drive handling that the DOS ASPI manager
    uses.  Drives very near the boundaries may not be handled correctly (i.e.
    near 2.0 Gb and 4.0 Gb) */
 
-   if (iinfo[2] > 1024) {
-      iinfo[0] = 64;
-      iinfo[1] = 63;
-      iinfo[2] = (unsigned long)capacity / (iinfo[0] * iinfo[1]);
-      }
-   if (iinfo[2] > 1024) {
-      iinfo[0] = 128;
-      iinfo[1] = 63;
-      iinfo[2] = (unsigned long)capacity / (iinfo[0] * iinfo[1]);
-      }
-   if (iinfo[2] > 1024) {
-      iinfo[0] = 255;
-      iinfo[1] = 63;
-      iinfo[2] = (unsigned long)capacity / (iinfo[0] * iinfo[1]);
-      }
-    return 0;
+	if (iinfo[2] > 1024) {
+		iinfo[0] = 64;
+		iinfo[1] = 63;
+		iinfo[2] = (unsigned long) capacity / (iinfo[0] * iinfo[1]);
+	}
+	if (iinfo[2] > 1024) {
+		iinfo[0] = 128;
+		iinfo[1] = 63;
+		iinfo[2] = (unsigned long) capacity / (iinfo[0] * iinfo[1]);
+	}
+	if (iinfo[2] > 1024) {
+		iinfo[0] = 255;
+		iinfo[1] = 63;
+		iinfo[2] = (unsigned long) capacity / (iinfo[0] * iinfo[1]);
+	}
+	return 0;
 }
 
 
@@ -2208,21 +2161,21 @@
 
 #ifdef PROC_INTERFACE
 
-char *bp;
-char tbuf[128];
-unsigned long flags;
-struct Scsi_Host *instance;
-struct IN2000_hostdata *hd;
-Scsi_Cmnd *cmd;
-int x,i;
-static int stop = 0;
-
-   instance = scsi_host_hn_get(hn);  
-   if (!instance) {
-      printk("*** Hmm... Can't find host #%d!\n",hn);
-      return (-ESRCH);
-      }
-   hd = (struct IN2000_hostdata *)instance->hostdata;
+	char *bp;
+	char tbuf[128];
+	unsigned long flags;
+	struct Scsi_Host *instance;
+	struct IN2000_hostdata *hd;
+	Scsi_Cmnd *cmd;
+	int x, i;
+	static int stop = 0;
+
+	instance = scsi_host_hn_get(hn);
+	if (!instance) {
+		printk("*** Hmm... Can't find host #%d!\n", hn);
+		return (-ESRCH);
+	}
+	hd = (struct IN2000_hostdata *) instance->hostdata;
 
 /* If 'in' is TRUE we need to _read_ the proc file. We accept the following
  * keywords (same format as command-line, but only ONE per read):
@@ -2233,139 +2186,127 @@
  *    proc
  */
 
-   if (in) {
-      buf[len] = '\0';
-      bp = buf;
-      if (!strncmp(bp,"debug:",6)) {
-         bp += 6;
-         hd->args = simple_strtoul(bp,NULL,0) & DB_MASK;
-         }
-      else if (!strncmp(bp,"disconnect:",11)) {
-         bp += 11;
-         x = simple_strtoul(bp,NULL,0);
-         if (x < DIS_NEVER || x > DIS_ALWAYS)
-            x = DIS_ADAPTIVE;
-         hd->disconnect = x;
-         }
-      else if (!strncmp(bp,"period:",7)) {
-         bp += 7;
-         x = simple_strtoul(bp,NULL,0);
-         hd->default_sx_per = sx_table[round_period((unsigned int)x)].period_ns;
-         }
-      else if (!strncmp(bp,"resync:",7)) {
-         bp += 7;
-         x = simple_strtoul(bp,NULL,0);
-         for (i=0; i<7; i++)
-            if (x & (1<<i))
-               hd->sync_stat[i] = SS_UNSET;
-         }
-      else if (!strncmp(bp,"proc:",5)) {
-         bp += 5;
-         hd->proc = simple_strtoul(bp,NULL,0);
-         }
-      else if (!strncmp(bp,"level2:",7)) {
-         bp += 7;
-         hd->level2 = simple_strtoul(bp,NULL,0);
-         }
-      return len;
-      }
-
-   spin_lock_irqsave(instance->host_lock, flags);
-   bp = buf;
-   *bp = '\0';
-   if (hd->proc & PR_VERSION) {
-      sprintf(tbuf,"\nVersion %s - %s. Compiled %s %s",
-            IN2000_VERSION,IN2000_DATE,__DATE__,__TIME__);
-      strcat(bp,tbuf);
-      }
-   if (hd->proc & PR_INFO) {
-      sprintf(tbuf,"\ndip_switch=%02x: irq=%d io=%02x floppy=%s sync/DOS5=%s",
-                  (hd->dip_switch & 0x7f), instance->irq, hd->io_base,
-                  (hd->dip_switch & 0x40)?"Yes":"No",
-                  (hd->dip_switch & 0x20)?"Yes":"No");
-      strcat(bp,tbuf);
-      strcat(bp,"\nsync_xfer[] =       ");
-      for (x=0; x<7; x++) {
-         sprintf(tbuf,"\t%02x",hd->sync_xfer[x]);
-         strcat(bp,tbuf);
-         }
-      strcat(bp,"\nsync_stat[] =       ");
-      for (x=0; x<7; x++) {
-         sprintf(tbuf,"\t%02x",hd->sync_stat[x]);
-         strcat(bp,tbuf);
-         }
-      }
+	if (in) {
+		buf[len] = '\0';
+		bp = buf;
+		if (!strncmp(bp, "debug:", 6)) {
+			bp += 6;
+			hd->args = simple_strtoul(bp, NULL, 0) & DB_MASK;
+		} else if (!strncmp(bp, "disconnect:", 11)) {
+			bp += 11;
+			x = simple_strtoul(bp, NULL, 0);
+			if (x < DIS_NEVER || x > DIS_ALWAYS)
+				x = DIS_ADAPTIVE;
+			hd->disconnect = x;
+		} else if (!strncmp(bp, "period:", 7)) {
+			bp += 7;
+			x = simple_strtoul(bp, NULL, 0);
+			hd->default_sx_per = sx_table[round_period((unsigned int) x)].period_ns;
+		} else if (!strncmp(bp, "resync:", 7)) {
+			bp += 7;
+			x = simple_strtoul(bp, NULL, 0);
+			for (i = 0; i < 7; i++)
+				if (x & (1 << i))
+					hd->sync_stat[i] = SS_UNSET;
+		} else if (!strncmp(bp, "proc:", 5)) {
+			bp += 5;
+			hd->proc = simple_strtoul(bp, NULL, 0);
+		} else if (!strncmp(bp, "level2:", 7)) {
+			bp += 7;
+			hd->level2 = simple_strtoul(bp, NULL, 0);
+		}
+		return len;
+	}
+
+	spin_lock_irqsave(instance->host_lock, flags);
+	bp = buf;
+	*bp = '\0';
+	if (hd->proc & PR_VERSION) {
+		sprintf(tbuf, "\nVersion %s - %s. Compiled %s %s", IN2000_VERSION, IN2000_DATE, __DATE__, __TIME__);
+		strcat(bp, tbuf);
+	}
+	if (hd->proc & PR_INFO) {
+		sprintf(tbuf, "\ndip_switch=%02x: irq=%d io=%02x floppy=%s sync/DOS5=%s", (hd->dip_switch & 0x7f), instance->irq, hd->io_base, (hd->dip_switch & 0x40) ? "Yes" : "No", (hd->dip_switch & 0x20) ? "Yes" : "No");
+		strcat(bp, tbuf);
+		strcat(bp, "\nsync_xfer[] =       ");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%02x", hd->sync_xfer[x]);
+			strcat(bp, tbuf);
+		}
+		strcat(bp, "\nsync_stat[] =       ");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%02x", hd->sync_stat[x]);
+			strcat(bp, tbuf);
+		}
+	}
 #ifdef PROC_STATISTICS
-   if (hd->proc & PR_STATISTICS) {
-      strcat(bp,"\ncommands issued:    ");
-      for (x=0; x<7; x++) {
-         sprintf(tbuf,"\t%ld",hd->cmd_cnt[x]);
-         strcat(bp,tbuf);
-         }
-      strcat(bp,"\ndisconnects allowed:");
-      for (x=0; x<7; x++) {
-         sprintf(tbuf,"\t%ld",hd->disc_allowed_cnt[x]);
-         strcat(bp,tbuf);
-         }
-      strcat(bp,"\ndisconnects done:   ");
-      for (x=0; x<7; x++) {
-         sprintf(tbuf,"\t%ld",hd->disc_done_cnt[x]);
-         strcat(bp,tbuf);
-         }
-      sprintf(tbuf,"\ninterrupts:      \t%ld",hd->int_cnt);
-      strcat(bp,tbuf);
-      }
+	if (hd->proc & PR_STATISTICS) {
+		strcat(bp, "\ncommands issued:    ");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%ld", hd->cmd_cnt[x]);
+			strcat(bp, tbuf);
+		}
+		strcat(bp, "\ndisconnects allowed:");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%ld", hd->disc_allowed_cnt[x]);
+			strcat(bp, tbuf);
+		}
+		strcat(bp, "\ndisconnects done:   ");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%ld", hd->disc_done_cnt[x]);
+			strcat(bp, tbuf);
+		}
+		sprintf(tbuf, "\ninterrupts:      \t%ld", hd->int_cnt);
+		strcat(bp, tbuf);
+	}
 #endif
-   if (hd->proc & PR_CONNECTED) {
-      strcat(bp,"\nconnected:     ");
-      if (hd->connected) {
-         cmd = (Scsi_Cmnd *)hd->connected;
-         sprintf(tbuf," %ld-%d:%d(%02x)",
-               cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
-         strcat(bp,tbuf);
-         }
-      }
-   if (hd->proc & PR_INPUTQ) {
-      strcat(bp,"\ninput_Q:       ");
-      cmd = (Scsi_Cmnd *)hd->input_Q;
-      while (cmd) {
-         sprintf(tbuf," %ld-%d:%d(%02x)",
-               cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
-         strcat(bp,tbuf);
-         cmd = (Scsi_Cmnd *)cmd->host_scribble;
-         }
-      }
-   if (hd->proc & PR_DISCQ) {
-      strcat(bp,"\ndisconnected_Q:");
-      cmd = (Scsi_Cmnd *)hd->disconnected_Q;
-      while (cmd) {
-         sprintf(tbuf," %ld-%d:%d(%02x)",
-               cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
-         strcat(bp,tbuf);
-         cmd = (Scsi_Cmnd *)cmd->host_scribble;
-         }
-      }
-   if (hd->proc & PR_TEST) {
-      ;  /* insert your own custom function here */
-      }
-   strcat(bp,"\n");
-   spin_unlock_irqrestore(instance->host_lock, flags);
-   *start = buf;
-   if (stop) {
-      stop = 0;
-      return 0;         /* return 0 to signal end-of-file */
-      }
-   if (off > 0x40000)   /* ALWAYS stop after 256k bytes have been read */
-      stop = 1;;
-   if (hd->proc & PR_STOP)    /* stop every other time */
-      stop = 1;
-   return strlen(bp);
+	if (hd->proc & PR_CONNECTED) {
+		strcat(bp, "\nconnected:     ");
+		if (hd->connected) {
+			cmd = (Scsi_Cmnd *) hd->connected;
+			sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
+			strcat(bp, tbuf);
+		}
+	}
+	if (hd->proc & PR_INPUTQ) {
+		strcat(bp, "\ninput_Q:       ");
+		cmd = (Scsi_Cmnd *) hd->input_Q;
+		while (cmd) {
+			sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
+			strcat(bp, tbuf);
+			cmd = (Scsi_Cmnd *) cmd->host_scribble;
+		}
+	}
+	if (hd->proc & PR_DISCQ) {
+		strcat(bp, "\ndisconnected_Q:");
+		cmd = (Scsi_Cmnd *) hd->disconnected_Q;
+		while (cmd) {
+			sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]);
+			strcat(bp, tbuf);
+			cmd = (Scsi_Cmnd *) cmd->host_scribble;
+		}
+	}
+	if (hd->proc & PR_TEST) {
+		;		/* insert your own custom function here */
+	}
+	strcat(bp, "\n");
+	spin_unlock_irqrestore(instance->host_lock, flags);
+	*start = buf;
+	if (stop) {
+		stop = 0;
+		return 0;	/* return 0 to signal end-of-file */
+	}
+	if (off > 0x40000)	/* ALWAYS stop after 256k bytes have been read */
+		stop = 1;;
+	if (hd->proc & PR_STOP)	/* stop every other time */
+		stop = 1;
+	return strlen(bp);
 
-#else    /* PROC_INTERFACE */
+#else				/* PROC_INTERFACE */
 
-   return 0;
+	return 0;
 
-#endif   /* PROC_INTERFACE */
+#endif				/* PROC_INTERFACE */
 
 }
 
@@ -2374,4 +2315,3 @@
 
 static Scsi_Host_Template driver_template = IN2000;
 #include "scsi_module.c"
-
diff -Nru a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
--- a/drivers/scsi/megaraid.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/scsi/megaraid.c	Sun Nov 10 19:28:36 2002
@@ -2865,16 +2865,14 @@
 		pciDevFun = pdev->devfn;
 #endif
 		if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
-			pcibios_read_config_word (pciBus, pciDevFun,
-						  PCI_CONF_AMISIG, &magic);
+			pci_read_config_word (pdev, PCI_CONF_AMISIG, &magic);
 			if ((magic != AMI_SIGNATURE)
 			    && (magic != AMI_SIGNATURE_471)) {
 				pciIdx++;
 				continue;	/* not an AMI board */
 			}
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-			pcibios_read_config_dword (pciBus, pciDevFun,
-						   PCI_CONF_AMISIG64, &magic64);
+			pci_read_config_dword (pdev, PCI_CONF_AMISIG64, &magic64);
 
 			if (magic64 == AMI_64BIT_SIGNATURE)
 				flag |= BOARD_64BIT;
@@ -3215,7 +3213,6 @@
 	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
 				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
 
-	mega_reorder_hosts ();
 
 #ifdef CONFIG_PROC_FS
 	if (count) {
@@ -3481,173 +3478,6 @@
 }
 
 
-static void mega_reorder_hosts (void)
-{
-	struct Scsi_Host *shpnt;
-	struct Scsi_Host *shone;
-	struct Scsi_Host *shtwo;
-	mega_host_config *boot_host;
-	int i;
-
-	/*
-	 * Find the (first) host which has it's BIOS enabled
-	 */
-	boot_host = NULL;
-	for (i = 0; i < MAX_CONTROLLERS; i++) {
-		if (mega_hbas[i].is_bios_enabled) {
-			boot_host = mega_hbas[i].hostdata_addr;
-			break;
-		}
-	}
-
-	if (boot_host == NULL) {
-		printk (KERN_WARNING "megaraid: no BIOS enabled.\n");
-		return;
-	}
-
-	/*
-	 * Traverse through the list of SCSI hosts for our HBA locations
-	 */
-	shone = shtwo = NULL;
-	for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
-		/* Is it one of ours? */
-		for (i = 0; i < MAX_CONTROLLERS; i++) {
-			if ((mega_host_config *) shpnt->hostdata ==
-			    mega_hbas[i].hostdata_addr) {
-				/* Does this one has BIOS enabled */
-				if (mega_hbas[i].hostdata_addr == boot_host) {
-
-					/* Are we first */
-					if (shtwo == NULL)	/* Yes! */
-						return;
-					else {	/* :-( */
-						shone = shpnt;
-					}
-				} else {
-					if (!shtwo) {
-						/* were we here before? xchng first */
-						shtwo = shpnt;
-					}
-				}
-				break;
-			}
-		}
-		/*
-		 * Have we got the boot host and one which does not have the bios
-		 * enabled.
-		 */
-		if (shone && shtwo)
-			break;
-	}
-	if (shone && shtwo) {
-		mega_swap_hosts (shone, shtwo);
-	}
-
-	return;
-}
-
-static void mega_swap_hosts (struct Scsi_Host *shone, struct Scsi_Host *shtwo)
-{
-	struct Scsi_Host *prevtoshtwo;
-	struct Scsi_Host *prevtoshone;
-	struct Scsi_Host *save = NULL;;
-
-	/* Are these two nodes adjacent */
-	if (shtwo->next == shone) {
-
-		if (shtwo == scsi_hostlist && shone->next == NULL) {
-
-			/* just two nodes */
-			scsi_hostlist = shone;
-			shone->next = shtwo;
-			shtwo->next = NULL;
-		} else if (shtwo == scsi_hostlist) {
-			/* first two nodes of the list */
-
-			scsi_hostlist = shone;
-			shtwo->next = shone->next;
-			scsi_hostlist->next = shtwo;
-		} else if (shone->next == NULL) {
-			/* last two nodes of the list */
-
-			prevtoshtwo = scsi_hostlist;
-
-			while (prevtoshtwo->next != shtwo)
-				prevtoshtwo = prevtoshtwo->next;
-
-			prevtoshtwo->next = shone;
-			shone->next = shtwo;
-			shtwo->next = NULL;
-		} else {
-			prevtoshtwo = scsi_hostlist;
-
-			while (prevtoshtwo->next != shtwo)
-				prevtoshtwo = prevtoshtwo->next;
-
-			prevtoshtwo->next = shone;
-			shtwo->next = shone->next;
-			shone->next = shtwo;
-		}
-
-	} else if (shtwo == scsi_hostlist && shone->next == NULL) {
-		/* shtwo at head, shone at tail, not adjacent */
-
-		prevtoshone = scsi_hostlist;
-
-		while (prevtoshone->next != shone)
-			prevtoshone = prevtoshone->next;
-
-		scsi_hostlist = shone;
-		shone->next = shtwo->next;
-		prevtoshone->next = shtwo;
-		shtwo->next = NULL;
-	} else if (shtwo == scsi_hostlist && shone->next != NULL) {
-		/* shtwo at head, shone is not at tail */
-
-		prevtoshone = scsi_hostlist;
-		while (prevtoshone->next != shone)
-			prevtoshone = prevtoshone->next;
-
-		scsi_hostlist = shone;
-		prevtoshone->next = shtwo;
-		save = shtwo->next;
-		shtwo->next = shone->next;
-		shone->next = save;
-	} else if (shone->next == NULL) {
-		/* shtwo not at head, shone at tail */
-
-		prevtoshtwo = scsi_hostlist;
-		prevtoshone = scsi_hostlist;
-
-		while (prevtoshtwo->next != shtwo)
-			prevtoshtwo = prevtoshtwo->next;
-		while (prevtoshone->next != shone)
-			prevtoshone = prevtoshone->next;
-
-		prevtoshtwo->next = shone;
-		shone->next = shtwo->next;
-		prevtoshone->next = shtwo;
-		shtwo->next = NULL;
-
-	} else {
-		prevtoshtwo = scsi_hostlist;
-		prevtoshone = scsi_hostlist;
-		save = NULL;;
-
-		while (prevtoshtwo->next != shtwo)
-			prevtoshtwo = prevtoshtwo->next;
-		while (prevtoshone->next != shone)
-			prevtoshone = prevtoshone->next;
-
-		prevtoshtwo->next = shone;
-		save = shone->next;
-		shone->next = shtwo->next;
-		prevtoshone->next = shtwo;
-		shtwo->next = save;
-	}
-	return;
-}
-
 static inline void mega_freeSgList (mega_host_config * megaCfg)
 {
 	int i;
@@ -4235,7 +4065,7 @@
 			/* Default heads (64) & sectors (32) */
 			heads = 64;
 			sectors = 32;
-			cylinders = (unsigned long)capacity / (heads * sectors);
+			cylinders = (unsigned long)capacity >> 11;
 
 			/* Handle extended translation size for logical drives > 1Gb */
 			if (capacity >= 0x200000) {
@@ -4293,7 +4123,6 @@
 	struct partition *p, *largest = NULL;
 	int i, largest_cyl;
 	int heads, cyls, sectors;
-	int capacity = capacity;
 	unsigned char *buf;
 
 	if (!(buf = scsi_bios_ptable(bdev)))
@@ -4324,7 +4153,7 @@
 			return -1;
 		}
 
-		cyls = capacity/(heads * sectors);
+		cyls = (unsigned long)capacity/(heads * sectors);
 
 		geom[0] = heads;
 		geom[1] = sectors;
@@ -4683,12 +4512,7 @@
 		/*
 		 * Find this host
 		 */
-		for( shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next ) {
-			if( shpnt->hostdata == (unsigned long *)megaCtlrs[adapno] ) {
-				megacfg = (mega_host_config *)shpnt->hostdata;
-				break;
-			}
-		}
+		shpnt = megaCtlrs[adapno]->host;
 		if(shpnt == NULL)  return -ENODEV;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
@@ -4803,12 +4627,7 @@
 		/*
 		 * Find this host
 		 */
-		for( shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next ) {
-			if( shpnt->hostdata == (unsigned long *)megaCtlrs[adapno] ) {
-				megacfg = (mega_host_config *)shpnt->hostdata;
-				break;
-			}
-		}
+		shpnt = megaCtlrs[adapno]->host;
 		if(shpnt == NULL)  return -ENODEV;
 
 		/*
diff -Nru a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
--- a/drivers/scsi/megaraid.h	Sun Nov 10 19:28:40 2002
+++ b/drivers/scsi/megaraid.h	Sun Nov 10 19:28:40 2002
@@ -214,8 +214,6 @@
     info:	     	megaraid_info,	   	/* Driver Info Function		*/\
     command:	  	megaraid_command,	/* Command Function		*/\
     queuecommand:  	megaraid_queue,		/* Queue Command Function	*/\
-    abort:	    	megaraid_abort,	  	/* Abort Command Function	*/\
-    reset:	    	megaraid_reset,	  	/* Reset Command Function	*/\
     bios_param:     	megaraid_biosparam, 	/* Disk BIOS Parameters		*/\
     can_queue:		MAX_COMMANDS,	    	/* Can Queue			*/\
     this_id:	  	7,		       	/* HBA Target ID		*/\
@@ -989,8 +987,6 @@
 			      int lock, int intr);
 
 static int mega_is_bios_enabled (mega_host_config *);
-static void mega_reorder_hosts (void);
-static void mega_swap_hosts (struct Scsi_Host *, struct Scsi_Host *);
 
 static void mega_create_proc_entry (int index, struct proc_dir_entry *);
 static int mega_support_ext_cdb(mega_host_config *);
diff -Nru a/drivers/scsi/osst.c b/drivers/scsi/osst.c
--- a/drivers/scsi/osst.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/scsi/osst.c	Sun Nov 10 19:28:39 2002
@@ -156,6 +156,10 @@
 static int osst_detect(Scsi_Device *);
 static void osst_detach(Scsi_Device *);
 
+static int osst_dev_noticed;
+static int osst_nr_dev;
+static int osst_dev_max;
+
 struct Scsi_Device_Template osst_template =
 {
        module:		THIS_MODULE,
@@ -163,7 +167,6 @@
        tag:		"osst",
        scsi_type:	TYPE_TAPE,
        detect:		osst_detect,
-       init:		osst_init,
        attach:		osst_attach,
        detach:		osst_detach
 };
@@ -4155,7 +4158,7 @@
 	char *name;
 	int mode = TAPE_MODE(inode->i_rdev);
 
-	if (dev >= osst_template.dev_max || (STp = os_scsi_tapes[dev]) == NULL || !STp->device)
+	if (dev >= osst_dev_max || (STp = os_scsi_tapes[dev]) == NULL || !STp->device)
 		return (-ENXIO);
 
 	filp->private_data = STp;
@@ -4980,7 +4983,7 @@
 	int i, priority, b_size, order, got = 0, segs = 0;
 	OSST_buffer *tb;
 
-	if (osst_nbr_buffers >= osst_template.dev_max)
+	if (osst_nbr_buffers >= osst_dev_max)
 		return NULL;  /* Should never happen */
 
 	if (from_initialization)
@@ -5411,26 +5414,31 @@
 	if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
 		 return 1;
 
+	osst_init();
+
 	disk = alloc_disk(1);
 	if (!disk)
 		return 1;
 
-	if (osst_template.nr_dev >= osst_template.dev_max) {
-		 SDp->attached--;
+	if (osst_nr_dev >= osst_dev_max) {
 		 put_disk(disk);
 		 return 1;
 	}
+
+	if (scsi_slave_attach(SDp))
+		return 1;
 	
 	/* find a free minor number */
-	for (i=0; os_scsi_tapes[i] && i<osst_template.dev_max; i++);
-	if(i >= osst_template.dev_max) panic ("Scsi_devices corrupt (osst)");
+	for (i=0; os_scsi_tapes[i] && i<osst_dev_max; i++);
+	if(i >= osst_dev_max) panic ("Scsi_devices corrupt (osst)");
 
 	/* allocate a OS_Scsi_Tape for this device */
 	tpnt = (OS_Scsi_Tape *)kmalloc(sizeof(OS_Scsi_Tape), GFP_ATOMIC);
 	if (tpnt == NULL) {
-		 SDp->attached--;
 		 printk(KERN_WARNING "osst :W: Can't allocate device descriptor.\n");
 		 put_disk(disk);
+
+		 scsi_slave_detach(SDp);
 		 return 1;
 	}
 	memset(tpnt, 0, sizeof(OS_Scsi_Tape));
@@ -5547,7 +5555,7 @@
 	tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE;
 	init_MUTEX(&tpnt->lock);
 
-	osst_template.nr_dev++;
+	osst_nr_dev++;
 
 	printk(KERN_INFO
 		"osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as %s\n",
@@ -5561,7 +5569,7 @@
 	if (SDp->type != TYPE_TAPE) return 0;
 	if ( ! osst_supports(SDp) ) return 0;
 	
-	osst_template.dev_noticed++;
+	osst_dev_noticed++;
 	return 1;
 }
 
@@ -5572,7 +5580,7 @@
 {
 	int i;
 
-	if (osst_template.dev_noticed == 0)
+	if (osst_dev_noticed == 0)
 		return 0;
 
 	if (!osst_registered) {
@@ -5585,10 +5593,10 @@
 
 	if (os_scsi_tapes)
 		return 0;
-	osst_template.dev_max = OSST_MAX_TAPES;
-	if (osst_template.dev_max > 128 / ST_NBR_MODES)
+	osst_dev_max = OSST_MAX_TAPES;
+	if (osst_dev_max > 128 / ST_NBR_MODES)
 		printk(KERN_INFO "osst :I: Only %d tapes accessible.\n", 128 / ST_NBR_MODES);
-	os_scsi_tapes = kmalloc(osst_template.dev_max * sizeof(OS_Scsi_Tape *),
+	os_scsi_tapes = kmalloc(osst_dev_max * sizeof(OS_Scsi_Tape *),
 								GFP_ATOMIC);
 	if (!os_scsi_tapes) {
 		printk(KERN_ERR "osst :W: Unable to allocate array for OnStream SCSI tapes.\n");
@@ -5596,11 +5604,11 @@
 		return 1;
 	}
 
-	for (i=0; i < osst_template.dev_max; ++i)
+	for (i=0; i < osst_dev_max; ++i)
 		os_scsi_tapes[i] = NULL;
 
 	/* Allocate the buffer pointers */
-	osst_buffers = kmalloc(osst_template.dev_max * sizeof(OSST_buffer *),
+	osst_buffers = kmalloc(osst_dev_max * sizeof(OSST_buffer *),
 								GFP_ATOMIC);
 	if (!osst_buffers) {
 		printk(KERN_ERR "osst :W: Unable to allocate tape buffer pointers.\n");
@@ -5628,7 +5636,7 @@
   int mode;
 #endif
 
-  for(i=0; i<osst_template.dev_max; i++) {
+  for(i=0; i<osst_dev_max; i++) {
 	tpnt = os_scsi_tapes[i];
 	if(tpnt != NULL && tpnt->device == SDp) {
 		tpnt->device = NULL;
@@ -5643,9 +5651,9 @@
 		put_disk(tpnt->disk);
 		kfree(tpnt);
 		os_scsi_tapes[i] = NULL;
-		SDp->attached--;
-		osst_template.nr_dev--;
-		osst_template.dev_noticed--;
+		scsi_slave_detach(SDp);
+		osst_nr_dev--;
+		osst_dev_noticed--;
 		return;
 	}
   }
@@ -5667,7 +5675,7 @@
 	unregister_chrdev(MAJOR_NR, "osst");
 	osst_registered--;
 	if (os_scsi_tapes) {
-		for (i=0; i < osst_template.dev_max; ++i) {
+		for (i=0; i < osst_dev_max; ++i) {
 			STp = os_scsi_tapes[i];
 			if (!STp)
 				continue;
@@ -5689,7 +5697,7 @@
 			kfree(osst_buffers);
 		}
 	}
-	osst_template.dev_max = 0;
+	osst_dev_max = 0;
 	printk(KERN_INFO "osst :I: Unloaded.\n");
 }
 
diff -Nru a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
--- a/drivers/scsi/pcmcia/nsp_cs.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/scsi/pcmcia/nsp_cs.c	Sun Nov 10 19:28:41 2002
@@ -25,7 +25,7 @@
 
 ***********************************************************************/
 
-/* $Id: nsp_cs.c,v 1.4 2002/10/15 15:57:01 elca Exp $ */
+/* $Id: nsp_cs.c,v 1.5 2002/11/05 12:06:29 elca Exp $ */
 
 #ifdef NSP_KERNEL_2_2
 #include <pcmcia/config.h>
@@ -67,7 +67,7 @@
 #include "nsp_cs.h"
 
 MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
-MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module $Revision: 1.4 $");
+MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module $Revision: 1.5 $");
 MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
 #ifdef MODULE_LICENSE
 MODULE_LICENSE("GPL");
@@ -77,7 +77,7 @@
 static int pc_debug = PCMCIA_DEBUG;
 MODULE_PARM(pc_debug, "i");
 MODULE_PARM_DESC(pc_debug, "set debug level");
-static char *version = "$Id: nsp_cs.c,v 1.4 2002/10/15 15:57:01 elca Exp $";
+static char *version = "$Id: nsp_cs.c,v 1.5 2002/11/05 12:06:29 elca Exp $";
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
 #else
 #define DEBUG(n, args...) /* */
@@ -129,39 +129,30 @@
 
 /* /usr/src/linux/drivers/scsi/hosts.h */
 static Scsi_Host_Template driver_template = {
-/*	.next			 = NULL,*/
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0))
 	.proc_name	         = "nsp_cs",      /* kernel 2.4 */
 #else
 	.proc_dir	         = &proc_scsi_nsp, /* kernel 2.2 */
 #endif
 	.proc_info		 = nsp_proc_info,
-	.name			 = "WorkBit NinjaSCSI-3/32Bi",
+	.name			 = "WorkBit NinjaSCSI-3/32Bi(16bit)",
 	.detect			 = nsp_detect,
 	.release		 = nsp_release,
 	.info			 = nsp_info,
-/*	.command		 = NULL,*/
 	.queuecommand		 = nsp_queuecommand,
 /*	.eh_strategy_handler	 = nsp_eh_strategy,*/
 /*	.eh_abort_handler	 = nsp_eh_abort,*/
 /*	.eh_device_reset_handler = nsp_eh_device_reset,*/
 	.eh_bus_reset_handler	 = nsp_eh_bus_reset,
 	.eh_host_reset_handler	 = nsp_eh_host_reset,
-	.abort			 = nsp_abort,
-	.reset			 = nsp_reset,
-/*	.slave_attach		 = NULL,*/
-/*	.bios_param		 = NULL,*/
 	.can_queue		 = 1,
 	.this_id		 = NSP_INITIATOR_ID,
 	.sg_tablesize		 = SG_ALL,
 	.cmd_per_lun		 = 1,
-/*	.present		 = 0,*/
-/*	.unchecked_isa_dma	 = 0,*/
 	.use_clustering		 = DISABLE_CLUSTERING,
 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
 	.use_new_eh_code	 = 1,
 #endif
-/*	.emulated		 = 0,*/
 };
 
 static dev_link_t *dev_list = NULL;
@@ -180,12 +171,12 @@
 #endif
 	nsp_hw_data *data = &nsp_data;
 
-	DEBUG(0, "%s() SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d\n",
-	      __FUNCTION__,  SCpnt, target, SCpnt->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
+	DEBUG(0, "%s: SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d\n",
+	      __FUNCTION__, SCpnt, target, SCpnt->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
 	//DEBUG(0, " before CurrentSC=0x%p\n", data->CurrentSC);
 
 	if(data->CurrentSC != NULL) {
-		printk(KERN_DEBUG " %s() CurrentSC!=NULL cannot happen!\n", __FUNCTION__);
+		printk(KERN_DEBUG " %s: CurrentSC!=NULL this can't be happen\n", __FUNCTION__);
 		data->CurrentSC = NULL;
 		SCpnt->result   = DID_BAD_TARGET << 16;
 		done(SCpnt);
@@ -231,7 +222,7 @@
 	}
 
 
-	//DEBUG(0, __func__ "() out\n");
+	//DEBUG(0, "%s: out\n", __FUNCTION__);
 	return 0;
 }
 
@@ -243,7 +234,7 @@
 	unsigned int  base = data->BaseAddress;
 	unsigned char transfer_mode_reg;
 
-	//DEBUG(0, __func__ "() enabled=%d\n", enabled);
+	//DEBUG(0, "%s: enabled=%d\n", __FUNCTION__, enabled);
 
 	if (enabled != FALSE) {
 		transfer_mode_reg = TRANSFER_GO | BRAIND;
@@ -265,7 +256,7 @@
 	int i;
 
 	/* setup sync data */
-	for ( i = 0; i < N_TARGET; i++ ) {
+	for ( i = 0; i < NUMBER(data->Sync); i++ ) {
 		data->Sync[i] = tmp_sync;
 	}
 }
@@ -277,7 +268,7 @@
 {
 	unsigned int base     = data->BaseAddress;
 
-	DEBUG(0, "%s() in base=0x%x\n", __FUNCTION__, base);
+	DEBUG(0, "%s: in base=0x%x\n", __FUNCTION__, base);
 
 	data->ScsiClockDiv = CLOCK_40M | FAST_20;
 	data->CurrentSC    = NULL;
@@ -340,7 +331,7 @@
 	int	      time_out;
 	unsigned char phase, arbit;
 
-	//DEBUG(0, __func__ "()in\n");
+	//DEBUG(0, "%s:in\n", __FUNCTION__);
 
 	phase = nsp_index_read(base, SCSIBUSMON);
 	if(phase != BUSMON_BUS_FREE) {
@@ -422,7 +413,7 @@
 	int		       i;
 
 
-	DEBUG(0, "%s()\n", __FUNCTION__);
+	DEBUG(0, "%s:\n", __FUNCTION__);
 
 	period = sync->SyncPeriod;
 	offset = sync->SyncOffset;
@@ -473,7 +464,7 @@
 {
 	unsigned int base = SCpnt->host->io_port;
 
-	//DEBUG(0, __func__ "() in SCpnt=0x%p, time=%d\n", SCpnt, time);
+	//DEBUG(0, "%s: in SCpnt=0x%p, time=%d\n", __FUNCTION__, SCpnt, time);
 	data->TimerCount = time;
 	nsp_index_write(base, TIMERCOUNT, time);
 }
@@ -487,7 +478,7 @@
 	unsigned char reg;
 	int	      time_out;
 
-	//DEBUG(0, __func__ "()\n");
+	//DEBUG(0, "%s:\n", __FUNCTION__);
 
 	time_out = 100;
 
@@ -499,7 +490,7 @@
 	} while ((time_out-- != 0) && (reg & mask) != 0);
 
 	if (time_out == 0) {
-		printk(KERN_DEBUG "%s: %s signal off timeut\n", __FUNCTION__, str);
+		printk(KERN_DEBUG "%s:: %s signal off timeut\n", __FUNCTION__, str);
 	}
 
 	return 0;
@@ -516,7 +507,7 @@
 	int	      time_out;
 	unsigned char phase, i_src;
 
-	//DEBUG(0, __func__ "() current_phase=0x%x, mask=0x%x\n", current_phase, mask);
+	//DEBUG(0, "%s: current_phase=0x%x, mask=0x%x\n", __FUNCTION__, current_phase, mask);
 
 	time_out = 100;
 	do {
@@ -536,7 +527,7 @@
 		}
 	} while(time_out-- != 0);
 
-	//DEBUG(0, __func__ " : " __func__ " timeout\n");
+	//DEBUG(0, "%s: timeout\n", __FUNCTION__);
 	return -1;
 }
 
@@ -551,7 +542,7 @@
 	int	      ptr;
 	int	      ret;
 
-	//DEBUG(0, __func__ "()\n");
+	//DEBUG(0, "%s:\n", __FUNCTION__);
 	for (ptr = 0; len > 0; len --, ptr ++) {
 
 		ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
@@ -586,7 +577,7 @@
 {
 	unsigned int count;
 
-	//DEBUG(0, __func__ "()\n");
+	//DEBUG(0, "%s:\n", __FUNCTION__);
 
 	if (SCpnt->SCp.have_data_in != IO_IN) {
 		return 0;
@@ -618,7 +609,7 @@
 	unsigned int  base = SCpnt->host->io_port;
 	unsigned char reg;
 
-	//DEBUG(0, __func__ "()\n");
+	//DEBUG(0, "%s:\n", __FUNCTION__);
 
 	nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
 
@@ -648,7 +639,7 @@
 
 	count = (h << 16) | (m << 8) | (l << 0);
 
-	//DEBUG(0, __func__ "() =0x%x\n", count);
+	//DEBUG(0, "%s: =0x%x\n", __FUNCTION__, count);
 
 	return count;
 }
@@ -670,8 +661,8 @@
 
 	ocount = data->FifoCount;
 
-	DEBUG(0, "%s() in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d\n", 
-		__FUNCTION__, SCpnt, RESID, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
+	DEBUG(0, "%s: in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d\n",
+	      __FUNCTION__, SCpnt, RESID, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
 
 	time_out = 1000;
 
@@ -744,8 +735,8 @@
 	data->FifoCount = ocount;
 
 	if (time_out == 0) {
-		printk(KERN_DEBUG "%s() pio read timeout resid=%d this_residual=%d buffers_residual=%d\n", 
-			__FUNCTION__, RESID, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
+		printk(KERN_DEBUG "%s: pio read timeout resid=%d this_residual=%d buffers_residual=%d\n",
+		       __FUNCTION__, RESID, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
 	}
 	DEBUG(0, " read ocount=0x%x\n", ocount);
 }
@@ -763,7 +754,8 @@
 
 	ocount	 = data->FifoCount;
 
-	DEBUG(0,  "%s() in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n", __FUNCTION__, data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, RESID);
+	DEBUG(0, "%s: in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x\n",
+	      __FUNCTION__, data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, RESID);
 
 	time_out = 1000;
 
@@ -833,7 +825,7 @@
 	data->FifoCount = ocount;
 
 	if (time_out == 0) {
-		printk(KERN_DEBUG "%s() pio write timeout resid=0x%x\n", __FUNCTION__, RESID);
+		printk(KERN_DEBUG "%s: pio write timeout resid=0x%x\n", __FUNCTION__, RESID);
 	}
 	DEBUG(0, " write ocount=0x%x\n", ocount);
 }
@@ -851,7 +843,7 @@
 //	unsigned char  lun    = SCpnt->lun;
 	sync_data     *sync   = &(data->Sync[target]);
 
-	//DEBUG(0, __func__ "() in SCpnt=0x%p\n", SCpnt);
+	//DEBUG(0, "%s: in SCpnt=0x%p\n", __FUNCTION__, SCpnt);
 
 	/* setup synch transfer registers */
 	nsp_index_write(base, SYNCREG,	sync->SyncRegister);
@@ -948,7 +940,7 @@
 	nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
 
 	if (data->CurrentSC == NULL) {
-		printk(KERN_DEBUG "%s: CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x cannot happen\n", __FUNCTION__, i_src, phase, irq_phase);
+		printk(KERN_DEBUG "%s: CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen\n", __FUNCTION__, i_src, phase, irq_phase);
 		return;
 	} else {
 		tmpSC    = data->CurrentSC;
@@ -962,7 +954,7 @@
 	 */
 	if ((i_src & IRQSTATUS_SCSI) != 0) {
 		if ((irq_phase & SCSI_RESET_IRQ) != 0) {
-			printk(KERN_DEBUG " %s() bus reset (power off?)\n", __FUNCTION__);
+			printk(KERN_DEBUG " %s: bus reset (power off?)\n", __FUNCTION__);
 			*sync_neg          = SYNC_NOT_YET;
 			data->CurrentSC    = NULL;
 			tmpSC->result	   = (DID_RESET                   << 16) |
@@ -1064,7 +1056,7 @@
 
 	/* check unexpected bus free state */
 	if (phase == 0) {
-		printk(KERN_DEBUG "%s: unexpected bus free. i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", __FUNCTION__, i_src, phase, irq_phase);
+		printk(KERN_DEBUG " %s: unexpected bus free. i_src=0x%x, phase=0x%x, irq_phase=0x%x\n", __FUNCTION__, i_src, phase, irq_phase);
 
 		*sync_neg       = SYNC_NOT_YET;
 		data->CurrentSC = NULL;
@@ -1208,7 +1200,7 @@
 		break;
 	}
 
-	//DEBUG(0, __func__ "() out\n");
+	//DEBUG(0, "%s: out\n", __FUNCTION__);
 	return;	
 
 timer_out:
@@ -1246,7 +1238,7 @@
 
 	snprintf(data->nspinfo,
 		 sizeof(data->nspinfo),
-		 "NinjaSCSI-3/32Bi Driver $Revision: 1.4 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d",
+		 "NinjaSCSI-3/32Bi Driver $Revision: 1.5 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d",
 		 host->io_port, host->io_port + host->n_io_port - 1,
 		 host->base,
 		 host->irq);
@@ -1303,16 +1295,28 @@
 	int speed;
 	unsigned long flags;
 	nsp_hw_data *data = &nsp_data;
-	struct Scsi_Host *host;
+	struct Scsi_Host *host = NULL;
 
 	if (inout) {
 		return -EINVAL;
 	}
 
+	/* search this HBA host */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45))
 	host = scsi_host_hn_get(hostno);
+#else
+	for (host=scsi_hostlist; host; host=host->next) {
+                if (host->host_no == hostno) {
+                        break;
+                }
+        }
+#endif
+	if (host == NULL) {
+		return -ESRCH;
+	}
 
 	SPRINTF("NinjaSCSI status\n\n");
-	SPRINTF("Driver version:        $Revision: 1.4 $\n");
+	SPRINTF("Driver version:        $Revision: 1.5 $\n");
 	SPRINTF("SCSI host No.:         %d\n",          hostno);
 	SPRINTF("IRQ:                   %d\n",          host->irq);
 	SPRINTF("IO:                    0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
@@ -1393,45 +1397,6 @@
 }
 #undef SPRINTF
 
-/*---------------------------------------------------------------*/
-/* error handler                                                 */
-/*---------------------------------------------------------------*/
-static int nsp_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
-{
-	nsp_hw_data *data = &nsp_data;
-	int ret = 0;
-
-	DEBUG(0, "%s: SCpnt=0x%p why=%d\n", __FUNCTION__, SCpnt, reset_flags);
-
-	if (reset_flags & SCSI_RESET_SUGGEST_BUS_RESET) {
-		nsp_eh_bus_reset(SCpnt);
-
-		ret |= SCSI_RESET_BUS_RESET;
-	}
-
-	if (reset_flags & SCSI_RESET_SUGGEST_HOST_RESET) {
-		nsp_eh_host_reset(SCpnt);
-
-		ret |= SCSI_RESET_HOST_RESET;
-	}
-
-	if (ret != 0) {
-		return SCSI_RESET_SUCCESS | ret;
-	} else {
-		nsphw_init_sync(data);
-		return SCSI_RESET_PUNT;
-	}
-}
-
-static int nsp_abort(Scsi_Cmnd *SCpnt)
-{
-	DEBUG(0, "%s: SCpnt=0x%p\n", __FUNCTION__, SCpnt);
-
-	nsp_eh_host_reset(SCpnt);
-	nsp_eh_bus_reset(SCpnt);
-
-	return SCSI_ABORT_SUCCESS;
-}
 
 /*static int nsp_eh_strategy(struct Scsi_Host *Shost)
 {
@@ -1460,7 +1425,7 @@
 	unsigned int base = SCpnt->host->io_port;
 	int	     i;
 
-	DEBUG(0, "%s() SCpnt=0x%p base=0x%x\n", __FUNCTION__, SCpnt, base);
+	DEBUG(0, "%s: SCpnt=0x%p base=0x%x\n", __FUNCTION__, SCpnt, base);
 
 	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
 
@@ -1482,7 +1447,7 @@
 {
 	nsp_hw_data *data = &nsp_data;
 
-	DEBUG(0, "%s\n", __FUNCTION__);
+	DEBUG(0, "%s:\n", __FUNCTION__);
 
 	nsphw_init(data);
 
@@ -1517,7 +1482,7 @@
 	dev_link_t   *link;
 	int	      ret, i;
 
-	DEBUG(0, "%s()\n", __FUNCTION__);
+	DEBUG(0, "%s:\n", __FUNCTION__);
 
 	/* Create new SCSI device */
 	info = kmalloc(sizeof(*info), GFP_KERNEL);
@@ -1607,7 +1572,7 @@
 		return;
 	}
 
-	del_timer_sync(&link->release);
+	del_timer(&link->release);
 	if (link->state & DEV_CONFIG) {
 		nsp_cs_release((u_long)link);
 		if (link->state & DEV_STALE_CONFIG) {
@@ -1659,7 +1624,7 @@
 	nsp_hw_data      *data = &nsp_data;
 
 
-	DEBUG(0, "%s() in\n", __FUNCTION__);
+	DEBUG(0, "%s: in\n", __FUNCTION__);
 
 	tuple.DesiredTuple    = CISTPL_CONFIG;
 	tuple.Attributes      = 0;
@@ -1764,7 +1729,7 @@
 		break;
 
 	next_entry:
-		DEBUG(0, "%s next\n", __FUNCTION__);
+		DEBUG(0, "%s: next\n", __FUNCTION__);
 
 		if (link->io.NumPorts1)
 			CardServices(ReleaseIO, link->handle, &link->io);
@@ -1787,9 +1752,8 @@
 	data->NumAddress             = link->io.NumPorts1;
 	data->IrqNumber              = link->irq.AssignedIRQ;
 
-	DEBUG(0, "%s I/O[0x%x+0x%x] IRQ %d\n",
-		__FUNCTION__,
-	      data->BaseAddress, data->NumAddress, data->IrqNumber);
+	DEBUG(0, "%s: I/O[0x%x+0x%x] IRQ %d\n",
+	      __FUNCTION__, data->BaseAddress, data->NumAddress, data->IrqNumber);
 
 	if(nsphw_init(data) == FALSE) {
 		goto cs_failed;
@@ -1804,8 +1768,13 @@
 	DEBUG(0, "GET_SCSI_INFO\n");
 	tail = &link->dev;
 	info->ndev = 0;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45))
 	for (host = scsi_host_get_next(NULL); host;
 	     host = scsi_host_get_next(host)) {
+#else
+	for (host = scsi_hostlist; host != NULL; host = host->next) {
+#endif
 		if (host->hostt == &driver_template) {
 			for (dev = host->host_queue; dev != NULL; dev = dev->next) {
 				u_long arg[2], id;
@@ -1998,7 +1967,7 @@
 		DEBUG(0, " event: unknown\n");
 		break;
 	}
-	DEBUG(0, "%s end\n", __FUNCTION__);
+	DEBUG(0, "%s: end\n", __FUNCTION__);
 	return 0;
 } /* nsp_cs_event */
 
@@ -2009,7 +1978,7 @@
 {
 	servinfo_t serv;
 
-	DEBUG(0, "%s() in\n", __FUNCTION__);
+	DEBUG(0, "%s: in\n", __FUNCTION__);
 	DEBUG(0, "%s\n", version);
 	CardServices(GetCardServicesInfo, &serv);
 	if (serv.Revision != CS_RELEASE_CODE) {
@@ -2019,14 +1988,14 @@
 	}
 	register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach);
 
-	DEBUG(0, "%s() out\n", __FUNCTION__);
+	DEBUG(0, "%s: out\n", __FUNCTION__);
 	return 0;
 }
 
 
 static void __exit nsp_cs_cleanup(void)
 {
-	DEBUG(0, "%s() unloading\n", __FUNCTION__);
+	DEBUG(0, "%s: unloading\n", __FUNCTION__);
 	unregister_pcmcia_driver(&dev_info);
 	while (dev_list != NULL) {
 		if (dev_list->state & DEV_CONFIG) {
diff -Nru a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
--- a/drivers/scsi/pcmcia/nsp_cs.h	Sun Nov 10 19:28:39 2002
+++ b/drivers/scsi/pcmcia/nsp_cs.h	Sun Nov 10 19:28:39 2002
@@ -10,7 +10,7 @@
 
 =========================================================*/
 
-/* $Id: nsp_cs.h,v 1.3 2002/10/10 11:07:52 elca Exp $ */
+/* $Id: nsp_cs.h,v 1.4 2002/11/05 12:06:29 elca Exp $ */
 
 #ifndef  __nsp_cs__
 #define  __nsp_cs__
@@ -26,7 +26,7 @@
 /************************************
  * Some useful macros...
  */
-#define Number(arr) ((int) (sizeof(arr) / sizeof(arr[0])))
+#define NUMBER(arr) ((int) (sizeof(arr) / sizeof(arr[0]))) /* from XtNumber() in /usr/X11R6/include/X11/Intrinsic.h */
 #define BIT(x)      (1L << (x))
 #define MIN(a,b)    ((a) > (b) ? (b) : (a))
 
@@ -270,10 +270,10 @@
 
 
 
-static void nsp_cs_release(u_long arg);
-static int nsp_cs_event(event_t event, int priority, event_callback_args_t *args);
+static void        nsp_cs_release(u_long arg);
+static int         nsp_cs_event(event_t event, int priority, event_callback_args_t *args);
 static dev_link_t *nsp_cs_attach(void);
-static void nsp_cs_detach(dev_link_t *);
+static void        nsp_cs_detach(dev_link_t *);
 
 static unsigned int nsphw_start_selection(Scsi_Cmnd *SCpnt, nsp_hw_data *data);
 static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time);
@@ -284,9 +284,6 @@
 static int nsp_proc_info(char *buffer, char **start, off_t offset,
 			 int length, int hostno, int inout);
 static int nsp_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
-
-static int nsp_abort(Scsi_Cmnd *);
-static int nsp_reset(Scsi_Cmnd *, unsigned int);
 
 /*static int nsp_eh_abort(Scsi_Cmnd * SCpnt);*/
 /*static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt);*/
diff -Nru a/drivers/scsi/pcmcia/nsp_message.c b/drivers/scsi/pcmcia/nsp_message.c
--- a/drivers/scsi/pcmcia/nsp_message.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/scsi/pcmcia/nsp_message.c	Sun Nov 10 19:28:38 2002
@@ -64,7 +64,7 @@
 	DEBUG(0, " msgout loop\n");
 	do {
 		if (nsp_xfer(SCpnt, data, BUSPHASE_MESSAGE_OUT)) {
-			printk(KERN_DEBUG " %s msgout: xfer short\n", __FUNCTION__);
+			printk(KERN_DEBUG " %s: msgout: xfer short\n", __FUNCTION__);
 		}
 
 		/* catch a next signal */
diff -Nru a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
--- a/drivers/scsi/pluto.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/scsi/pluto.c	Sun Nov 10 19:28:38 2002
@@ -95,7 +95,8 @@
 	int i, retry, nplutos;
 	fc_channel *fc;
 	Scsi_Device dev;
-	struct timer_list fc_timer = { function: pluto_detect_timeout };
+	struct timer_list fc_timer =
+		TIMER_INITIALIZER(pluto_detect_timeout, 0, 0);
 
 	tpnt->proc_name = "pluto";
 	fcscount = 0;
diff -Nru a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
--- a/drivers/scsi/qlogicfas.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/scsi/qlogicfas.c	Sun Nov 10 19:28:41 2002
@@ -613,7 +613,7 @@
 #ifdef PCMCIA
 
 /*
- *	Allow PCMCIA code to preset the port */
+ *	Allow PCMCIA code to preset the port
  *	port should be 0 and irq to -1 respectively for autoprobing 
  */
 
diff -Nru a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
--- a/drivers/scsi/qlogicpti.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/scsi/qlogicpti.c	Sun Nov 10 19:28:40 2002
@@ -807,7 +807,7 @@
 }
 
 /* Detect all PTI Qlogic ISP's in the machine. */
-int __init qlogicpti_detect(Scsi_Host_Template *tpnt)
+static int __init qlogicpti_detect(Scsi_Host_Template *tpnt)
 {
 	struct qlogicpti *qpti;
 	struct Scsi_Host *qpti_host;
@@ -946,7 +946,7 @@
 	return nqptis;
 }
 
-int qlogicpti_release(struct Scsi_Host *host)
+static int qlogicpti_release(struct Scsi_Host *host)
 {
 	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
 
@@ -1164,7 +1164,10 @@
 	done(Cmnd);
 }
 
-int qlogicpti_queuecommand_slow(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
+static int qlogicpti_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *));
+
+static int qlogicpti_queuecommand_slow(Scsi_Cmnd *Cmnd,
+				       void (*done)(Scsi_Cmnd *))
 {
 	struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->host->hostdata;
 	unsigned long flags;
@@ -1240,7 +1243,7 @@
  *
  * "This code must fly." -davem
  */
-int qlogicpti_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
+static int qlogicpti_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
 {
 	struct Scsi_Host *host = Cmnd->host;
 	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
@@ -1461,7 +1464,7 @@
 	local_irq_restore(flags);
 }
 
-int qlogicpti_abort(Scsi_Cmnd *Cmnd)
+static int qlogicpti_abort(Scsi_Cmnd *Cmnd)
 {
 	u_short param[6];
 	struct Scsi_Host *host = Cmnd->host;
@@ -1503,7 +1506,7 @@
 	return return_status;
 }
 
-int qlogicpti_reset(Scsi_Cmnd *Cmnd)
+static int qlogicpti_reset(Scsi_Cmnd *Cmnd)
 {
 	u_short param[6];
 	struct Scsi_Host *host = Cmnd->host;
@@ -1532,6 +1535,23 @@
 	return return_status;
 }
 
-static Scsi_Host_Template driver_template = QLOGICPTI;
+static Scsi_Host_Template driver_template = {
+	.detect			= qlogicpti_detect,
+	.release		= qlogicpti_release,
+	.info			= qlogicpti_info,
+	.queuecommand		= qlogicpti_queuecommand_slow,
+	.eh_abort_handler	= qlogicpti_abort,
+	.eh_bus_reset_handler	= qlogicpti_reset,
+	.can_queue		= QLOGICPTI_REQ_QUEUE_LEN,
+	.this_id		= 7,
+	.sg_tablesize		= QLOGICPTI_MAX_SG(QLOGICPTI_REQ_QUEUE_LEN),
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+/* Sparc32's iommu code cannot handle highmem pages yet. */
+#ifdef CONFIG_SPARC64
+	.highmem_io		= 1,
+#endif
+};
+
 
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h
--- a/drivers/scsi/qlogicpti.h	Sun Nov 10 19:28:37 2002
+++ b/drivers/scsi/qlogicpti.h	Sun Nov 10 19:28:37 2002
@@ -47,18 +47,6 @@
 #define QLOGICPTI_REQ_QUEUE_LEN	255	/* must be power of two - 1 */
 #define QLOGICPTI_MAX_SG(ql)	(4 + ((ql) > 0) ? 7*((ql) - 1) : 0)
 
-#ifndef NULL
-#define NULL (0)
-#endif
-
-int qlogicpti_detect(Scsi_Host_Template *);
-int qlogicpti_release(struct Scsi_Host *);
-const char * qlogicpti_info(struct Scsi_Host *);
-int qlogicpti_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
-int qlogicpti_queuecommand_slow(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
-int qlogicpti_abort(Scsi_Cmnd *);
-int qlogicpti_reset(Scsi_Cmnd *);
-
 /* mailbox command complete status codes */
 #define MBOX_COMMAND_COMPLETE		0x4000
 #define INVALID_COMMAND			0x4001
@@ -513,28 +501,6 @@
 #define HCCTRL_EBENAB           0x0010      /* External breakpoint enable       */
 #define HCCTRL_B1ENAB           0x0008      /* Breakpoint 1 enable              */
 #define HCCTRL_B0ENAB           0x0004      /* Breakpoint 0 enable              */
-
-#ifdef CONFIG_SPARC64
-#define QLOGICPTI_HIGHMEM_IO 1
-#else
-/* Sparc32's iommu code cannot handle highmem pages yet. */
-#define QLOGICPTI_HIGHMEM_IO 0
-#endif
-
-#define QLOGICPTI {						\
-	.detect		=	qlogicpti_detect,		\
-	.release	=	qlogicpti_release,		\
-	.info		=	qlogicpti_info,			\
-	.queuecommand	=	qlogicpti_queuecommand_slow,	\
-	.eh_abort_handler	=	qlogicpti_abort,	\
-	.eh_bus_reset_handler	=	qlogicpti_reset,	\
-	.can_queue	=	QLOGICPTI_REQ_QUEUE_LEN,	\
-	.this_id	=	7,				\
-	.sg_tablesize	=	QLOGICPTI_MAX_SG(QLOGICPTI_REQ_QUEUE_LEN), \
-	.cmd_per_lun	=	1,				\
-	.use_clustering	=	ENABLE_CLUSTERING,		\
-	.highmem_io	=	QLOGICPTI_HIGHMEM_IO,		\
-}
 
 /* For our interrupt engine. */
 #define for_each_qlogicpti(qp) \
diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/scsi/scsi.c	Sun Nov 10 19:28:40 2002
@@ -133,6 +133,12 @@
 static struct softscsi_data softscsi_data[NR_CPUS] __cacheline_aligned;
 
 /*
+ * List of all highlevel drivers.
+ */
+static struct Scsi_Device_Template *scsi_devicelist;
+static DECLARE_RWSEM(scsi_devicelist_mutex);
+
+/*
  * Note - the initial logging level can be set here to log events at boot time.
  * After the system is up, you may enable logging via the /proc interface.
  */
@@ -603,6 +609,7 @@
 				 GFP_DMA : 0));
 		if(newSCpnt) {
 			memset(newSCpnt, 0, sizeof(Scsi_Cmnd));
+			init_timer(&newSCpnt->eh_timeout);
 			newSCpnt->host = SDpnt->host;
 			newSCpnt->device = SDpnt;
 			newSCpnt->target = SDpnt->id;
@@ -1551,6 +1558,7 @@
 	}
 
 	memset(SCpnt, 0, sizeof(Scsi_Cmnd));
+	init_timer(&SCpnt->eh_timeout);
 	SCpnt->host = SDpnt->host;
 	SCpnt->device = SDpnt;
 	SCpnt->target = SDpnt->id;
@@ -1658,10 +1666,6 @@
 			break;
 	}
 	spin_unlock_irqrestore(&device_request_lock, flags);
-	if(SDpnt->current_queue_depth == 0)
-	{
-		scsi_build_commandblocks(SDpnt);
-	}
 }
 
 #ifdef CONFIG_PROC_FS
@@ -1718,7 +1722,6 @@
 static int proc_scsi_gen_write(struct file * file, const char * buf,
                               unsigned long length, void *data)
 {
-	struct Scsi_Device_Template *SDTpnt;
 	Scsi_Device *scd;
 	struct Scsi_Host *HBA_ptr;
 	char *p;
@@ -1924,24 +1927,10 @@
 		if (scd->access_count)
 			goto out;
 
-		SDTpnt = scsi_devicelist;
-		while (SDTpnt != NULL) {
-			if (SDTpnt->detach)
-				(*SDTpnt->detach) (scd);
-			SDTpnt = SDTpnt->next;
-		}
+		scsi_detach_device(scd);
 
 		if (scd->attached == 0) {
-			/*
-			 * Nobody is using this device any more.
-			 * Free all of the command structures.
-			 */
-                        if (HBA_ptr->hostt->revoke)
-                                HBA_ptr->hostt->revoke(scd);
-			if (HBA_ptr->hostt->slave_detach)
-				(*HBA_ptr->hostt->slave_detach) (scd);
 			devfs_unregister (scd->de);
-			scsi_release_commandblocks(scd);
 
 			/* Now we can remove the device structure */
 			if (scd->next != NULL)
@@ -1969,6 +1958,109 @@
 }
 #endif
 
+void scsi_detect_device(struct scsi_device *sdev)
+{
+	struct Scsi_Device_Template *sdt;
+
+	down_read(&scsi_devicelist_mutex);
+	for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
+		if (sdt->detect)
+			(*sdt->detect)(sdev);
+	up_read(&scsi_devicelist_mutex);
+}
+
+int scsi_attach_device(struct scsi_device *sdev)
+{
+	struct Scsi_Device_Template *sdt;
+
+	down_read(&scsi_devicelist_mutex);
+	for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
+		if (sdt->attach)
+			/*
+			 * XXX check result when the upper level attach
+			 * return values are fixed, and on failure goto
+			 * fail.
+			 */
+			(*sdt->attach) (sdev);
+	up_read(&scsi_devicelist_mutex);
+	return 0;
+
+fail:
+	printk(KERN_ERR "%s: Allocation failure during SCSI scanning, "
+			"some SCSI devices might not be configured\n",
+			__FUNCTION__);
+	return -ENOMEM;
+}
+
+void scsi_detach_device(struct scsi_device *sdev)
+{
+	struct Scsi_Device_Template *sdt;
+
+	down_read(&scsi_devicelist_mutex);
+	for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
+		if (sdt->detach)
+			(*sdt->detach)(sdev);
+	up_read(&scsi_devicelist_mutex);
+}
+
+/*
+ * Function:	scsi_slave_attach()
+ *
+ * Purpose:	Called from the upper level driver attach to handle common
+ * 		attach code.
+ *
+ * Arguments:	sdev - scsi_device to attach
+ *
+ * Returns:	1 on error, 0 on succes
+ *
+ * Lock Status:	Protected via scsi_devicelist_mutex.
+ */
+int scsi_slave_attach(struct scsi_device *sdev)
+{
+	if (sdev->attached++ == 0) {
+		/*
+		 * No one was attached.
+		 */
+		scsi_build_commandblocks(sdev);
+		if (sdev->current_queue_depth == 0) {
+			printk(KERN_ERR "scsi: Allocation failure during"
+			       " attach, some SCSI devices might not be"
+			       " configured\n");
+			return 1;
+		}
+		if (sdev->host->hostt->slave_attach != NULL) {
+			if (sdev->host->hostt->slave_attach(sdev) != 0) {
+				printk(KERN_INFO "scsi: failed low level driver"
+				       " attach, some SCSI device might not be"
+				       " configured\n");
+				scsi_release_commandblocks(sdev);
+				return 1;
+			}
+		} else if (sdev->host->cmd_per_lun != 0)
+			scsi_adjust_queue_depth(sdev, 0,
+						sdev->host->cmd_per_lun);
+	}
+	return 0;
+}
+
+/*
+ * Function:	scsi_slave_detach()
+ *
+ * Purpose:	Called from the upper level driver attach to handle common
+ * 		detach code.
+ *
+ * Arguments:	sdev - struct scsi_device to detach
+ *
+ * Lock Status:	Protected via scsi_devicelist_mutex.
+ */
+void scsi_slave_detach(struct scsi_device *sdev)
+{
+	if (--sdev->attached == 0) {
+		if (sdev->host->hostt->slave_detach != NULL)
+			sdev->host->hostt->slave_detach(sdev);
+		scsi_release_commandblocks(sdev);
+	}
+}
 /*
  * This entry point should be called by a loadable module if it is trying
  * add a high level scsi driver to the system.
@@ -1987,8 +2079,10 @@
 	if (tpnt->next)
 		return 1;
 
+	down_write(&scsi_devicelist_mutex);
 	tpnt->next = scsi_devicelist;
 	scsi_devicelist = tpnt;
+	up_write(&scsi_devicelist_mutex);
 
 	tpnt->scsi_driverfs_driver.name = (char *)tpnt->tag;
 	tpnt->scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
@@ -2004,41 +2098,25 @@
 		for (SDpnt = shpnt->host_queue; SDpnt;
 		     SDpnt = SDpnt->next) {
 			if (tpnt->detect)
-				SDpnt->attached += (*tpnt->detect) (SDpnt);
+				(*tpnt->detect) (SDpnt);
 		}
 	}
 
 	/*
-	 * If any of the devices would match this driver, then perform the
-	 * init function.
-	 */
-	if (tpnt->init && tpnt->dev_noticed)
-		if ((*tpnt->init) ())
-			return 1;
-
-	/*
 	 * Now actually connect the devices to the new driver.
 	 */
 	for (shpnt = scsi_host_get_next(NULL); shpnt;
 	     shpnt = scsi_host_get_next(shpnt)) {
 		for (SDpnt = shpnt->host_queue; SDpnt;
 		     SDpnt = SDpnt->next) {
-			scsi_build_commandblocks(SDpnt);
-			if (SDpnt->current_queue_depth == 0) {
-				out_of_space = 1;
-				continue;
-			}
 			if (tpnt->attach)
+				/*
+				 * XXX check result when the upper level
+				 * attach return values are fixed, and
+				 * stop attaching on failure.
+				 */
 				(*tpnt->attach) (SDpnt);
 
-			/*
-			 * If this driver attached to the device, and don't have any
-			 * command blocks for this device, allocate some.
-			 */
-			if (SDpnt->attached)
-				SDpnt->online = TRUE;
-			else
-				scsi_release_commandblocks(SDpnt);
 		}
 	}
 
@@ -2078,22 +2156,12 @@
 		     SDpnt = SDpnt->next) {
 			if (tpnt->detach)
 				(*tpnt->detach) (SDpnt);
-			if (SDpnt->attached == 0) {
-				SDpnt->online = FALSE;
-
-				/*
-				 * Nobody is using this device any more.  Free all of the
-				 * command structures.
-				 */
-				if (shpnt->hostt->slave_detach)
-					(*shpnt->hostt->slave_detach) (SDpnt);
-				scsi_release_commandblocks(SDpnt);
-			}
 		}
 	}
 	/*
 	 * Extract the template from the linked list.
 	 */
+	down_write(&scsi_devicelist_mutex);
 	spnt = scsi_devicelist;
 	prev_spnt = NULL;
 	while (spnt != tpnt) {
@@ -2104,6 +2172,7 @@
 		scsi_devicelist = tpnt->next;
 	else
 		prev_spnt->next = spnt->next;
+	up_write(&scsi_devicelist_mutex);
 
 	MOD_DEC_USE_COUNT;
 	unlock_kernel();
diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
--- a/drivers/scsi/scsi.h	Sun Nov 10 19:28:38 2002
+++ b/drivers/scsi/scsi.h	Sun Nov 10 19:28:38 2002
@@ -466,6 +466,8 @@
 extern void scsi_release_commandblocks(Scsi_Device * SDpnt);
 extern void scsi_build_commandblocks(Scsi_Device * SDpnt);
 extern void scsi_adjust_queue_depth(Scsi_Device *, int, int);
+extern int scsi_slave_attach(struct scsi_device *sdev);
+extern void scsi_slave_detach(struct scsi_device *sdev);
 extern void scsi_done(Scsi_Cmnd * SCpnt);
 extern void scsi_finish_command(Scsi_Cmnd *);
 extern int scsi_retry_command(Scsi_Cmnd *);
@@ -478,6 +480,9 @@
 			int timeout, int retries);
 extern int scsi_dev_init(void);
 extern int scsi_mlqueue_insert(struct scsi_cmnd *, int);
+extern void scsi_detect_device(struct scsi_device *);
+extern int scsi_attach_device(struct scsi_device *);
+extern void scsi_detach_device(struct scsi_device *);
 
 /*
  * Newer request-based interfaces.
@@ -910,8 +915,8 @@
 
         if(!blk_rq_tagged(req))
                 return 0;
-    
-        if(req->flags & REQ_BARRIER)
+
+	if (req->flags & REQ_HARDBARRIER)
                 *msg++ = MSG_ORDERED_TAG;
         else
                 *msg++ = MSG_SIMPLE_TAG;
diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
--- a/drivers/scsi/scsi_debug.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/scsi/scsi_debug.c	Sun Nov 10 19:28:40 2002
@@ -17,6 +17,7 @@
  *        forked for lk 2.5 series [20011216, 20020101]
  *        use vmalloc() more inquiry+mode_sense [20020302]
  *        add timers for delayed responses [20020721]
+ *   Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
  */
 
 #include <linux/config.h>
@@ -49,7 +50,7 @@
 
 #include "scsi_debug.h"
 
-static const char * scsi_debug_version_str = "Version: 1.62 (20020812)";
+static const char * scsi_debug_version_str = "Version: 1.63 (20021103)";
 
 #define DRIVERFS_SUPPORT 1	/* comment out whole line to disable */
 
@@ -60,9 +61,8 @@
 #ifndef SCSI_CMD_WRITE_16
 #define SCSI_CMD_WRITE_16 0x8a
 #endif
-#ifndef REPORT_LUNS
-#define REPORT_LUNS 0xa0
-#endif
+
+#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
 
 /* A few options that we want selected */
 #define DEF_NR_FAKE_DEVS   1
@@ -70,6 +70,8 @@
 #define DEF_FAKE_BLK0   0
 #define DEF_EVERY_NTH   100
 #define DEF_DELAY   1
+#define DEF_MAX_LUNS   2
+#define DEF_SCSI_LEVEL   3
 
 #define DEF_OPTS   0
 #define SCSI_DEBUG_OPT_NOISE   1
@@ -83,8 +85,11 @@
 static int scsi_debug_every_nth = DEF_EVERY_NTH;
 static int scsi_debug_cmnd_count = 0;
 static int scsi_debug_delay = DEF_DELAY;
+static int scsi_debug_max_luns = DEF_MAX_LUNS;
+static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
 
 #define NR_HOSTS_PRESENT (((scsi_debug_num_devs - 1) / 7) + 1)
+	/* This assumes one lun used per allocated target id */
 #define N_HEAD          8
 #define N_SECTOR        32
 #define DEV_READONLY(TGT)      (0)
@@ -118,7 +123,7 @@
 };
 static struct sdebug_dev_info * devInfop;
 
-typedef void (* done_funct_t) (Scsi_Cmnd *);
+typedef void (* done_funct_t) (struct scsi_cmnd *);
 
 struct sdebug_queued_cmd {
 	int in_use;
@@ -131,7 +136,7 @@
 
 static unsigned char * fake_storep;	/* ramdisk storage */
 
-static unsigned char broken_buff[SDEBUG_SENSE_LEN];
+static unsigned char spare_buff[SDEBUG_SENSE_LEN];
 
 static int num_aborts = 0;
 static int num_dev_resets = 0;
@@ -151,17 +156,18 @@
 static int resp_mode_sense(unsigned char * cmd, int target,
 			   unsigned char * buff, int bufflen,
 			   struct sdebug_dev_info * devip);
-static int resp_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, 
+static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, 
 		     int num, struct sdebug_dev_info * devip);
-static int resp_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num,
-		      struct sdebug_dev_info * devip);
+static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
+		      int num, struct sdebug_dev_info * devip);
 static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
 			    int bufflen, struct sdebug_dev_info * devip);
 static void timer_intr_handler(unsigned long);
-static struct sdebug_dev_info * devInfoReg(Scsi_Cmnd *scmd);
+static struct sdebug_dev_info * devInfoReg(struct scsi_cmnd *scmd);
 static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 
 			    int asc, int asq, int inbandLen);
-static int check_reset(Scsi_Cmnd * SCpnt, struct sdebug_dev_info * devip);
+static int check_reset(struct scsi_cmnd * SCpnt, 
+		       struct sdebug_dev_info * devip);
 static int schedule_resp(struct scsi_cmnd * cmnd, 
 			 struct sdebug_dev_info * devip, 
 			 done_funct_t done, int scsi_result, int delta_jiff);
@@ -188,7 +194,7 @@
 }
 
 static
-int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, done_funct_t done)
+int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
 {
 	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
 	int block;
@@ -215,8 +221,7 @@
 	else 
 		buff = (unsigned char *) SCpnt->request_buffer;
 	if (NULL == buff) {
-		printk(KERN_WARNING "scsi_debug:qc: buff was NULL??\n");
-		buff = broken_buff;	/* just point at dummy */
+		buff = spare_buff;	/* assume cmd moves no data */
 		bufflen = SDEBUG_SENSE_LEN;
 	}
 
@@ -226,11 +231,11 @@
 		return schedule_resp(SCpnt, NULL, done, 0, 0);
         }
 
-	if (SCpnt->lun != 0)
+	if (SCpnt->lun >= scsi_debug_max_luns)
 		return schedule_resp(SCpnt, NULL, done, 
 				     DID_NO_CONNECT << 16, 0);
 #if 0
-	printk(KERN_INFO "sdebug:qc: host_no=%d, id=%d, sdp=%p, cmd=0x%x\n",
+	printk(KERN_INFO "sdebug:qc: host_no=%u, id=%u, sdp=%p, cmd=0x%x\n",
 	       (int)SCpnt->device->host->host_no, (int)SCpnt->device->id,
 	       SCpnt->device, (int)*cmd);
 #endif
@@ -248,9 +253,6 @@
 
 	switch (*cmd) {
 	case INQUIRY:     /* mandatory */
-		/* assume INQUIRY called first so setup max_cmd_len */
-		if (SCpnt->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
-			SCpnt->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
 		errsts = resp_inquiry(cmd, target, buff, bufflen, devip);
 		break;
 	case REQUEST_SENSE:	/* mandatory */
@@ -380,6 +382,9 @@
 	case MODE_SENSE_10:
 		errsts = resp_mode_sense(cmd, target, buff, bufflen, devip);
 		break;
+	case SYNCHRONIZE_CACHE:
+		memset(buff, 0, bufflen);
+		break;
 	default:
 #if 0
 		printk(KERN_INFO "scsi_debug: Unsupported command, "
@@ -394,7 +399,7 @@
 	return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay);
 }
 
-static int scsi_debug_ioctl(Scsi_Device *dev, int cmd, void *arg)
+static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void *arg)
 {
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
 		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
@@ -403,7 +408,7 @@
 	/* return -ENOTTY; // correct return but upsets fdisk */
 }
 
-static int check_reset(Scsi_Cmnd * SCpnt, struct sdebug_dev_info * devip)
+static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip)
 {
 	if (devip->reset) {
 		devip->reset = 0;
@@ -474,8 +479,8 @@
 		int dev_id_num, len;
 		char dev_id_str[6];
 		
-		dev_id_num = ((devip->host->host_no + 1) * 1000) + 
-			      devip->target;
+		dev_id_num = ((devip->host->host_no + 1) * 2000) +
+			     (devip->target * 1000) + devip->lun;
 		len = snprintf(dev_id_str, 6, "%d", dev_id_num);
 		len = (len > 6) ? 6 : len;
 		if (0 == cmd[2]) { /* supported vital product data pages */
@@ -501,7 +506,7 @@
 	}
 	/* drops through here for a standard inquiry */
 	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
-	arr[2] = 3;	/* claim SCSI 3 */
+	arr[2] = scsi_debug_scsi_level;
 	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
 	arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */
 	memcpy(&arr[8], vendor_id, 8);
@@ -643,6 +648,7 @@
 	case 0x3f:	/* Read all Mode pages */
 		len = resp_err_recov_pg(ap, pcontrol, target);
 		len += resp_disconnect_pg(ap + len, pcontrol, target);
+		len += resp_format_pg(ap + len, pcontrol, target);
 		len += resp_caching_pg(ap + len, pcontrol, target);
 		len += resp_ctrl_m_pg(ap + len, pcontrol, target);
 		offset += len;
@@ -662,8 +668,8 @@
 	return 0;
 }
 
-static int resp_read(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, 
-		     struct sdebug_dev_info * devip)
+static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, 
+		     int num, struct sdebug_dev_info * devip)
 {
         unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
         int nbytes, sgcount;
@@ -711,8 +717,8 @@
 	return 0;
 }
 
-static int resp_write(Scsi_Cmnd * SCpnt, int upper_blk, int block, int num, 
-		      struct sdebug_dev_info * devip)
+static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
+		      int num, struct sdebug_dev_info * devip)
 {
         unsigned char *buff = (unsigned char *) SCpnt->request_buffer;
         int nbytes, sgcount;
@@ -756,8 +762,9 @@
 static int resp_report_luns(unsigned char * cmd, unsigned char * buff,
 			    int bufflen, struct sdebug_dev_info * devip)
 {
-	unsigned int alloc_len;
+	unsigned int alloc_len, lun_cnt, i;
 	int select_report = (int)cmd[2];
+	ScsiLun *one_lun;
 
 	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
 	if ((alloc_len < 16) || (select_report > 2)) {
@@ -765,8 +772,13 @@
 		return (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
 	}
 	if (bufflen > 3) {
+		lun_cnt = min((int)(bufflen / sizeof(ScsiLun)),
+			      (int)scsi_debug_max_luns);
 		memset(buff, 0, bufflen);
-		buff[3] = 8;
+		buff[3] = 8 * lun_cnt;
+		one_lun = (ScsiLun*) &buff[0];
+		for (i = 0; i < lun_cnt; i++)
+			one_lun[i].scsi_lun[1] = i;
 	}
 	return 0;
 }
@@ -798,12 +810,13 @@
 }
 
 static int initialized = 0;
-static int num_present = 0;
+static int num_hosts_present = 0;
 static const char * sdebug_proc_name = "scsi_debug";
 
-static int scsi_debug_detect(Scsi_Host_Template * tpnt)
+static int scsi_debug_detect(struct SHT * tpnt)
 {
 	int k, sz;
+	struct Scsi_Host * hpnt;
 
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
 		printk(KERN_INFO "scsi_debug: detect\n");
@@ -813,7 +826,7 @@
 		devInfop = vmalloc(sz);
 		if (NULL == devInfop) {
 			printk(KERN_ERR "scsi_debug_detect: out of "
-			       "memory, 0.5\n");
+			       "memory\n");
 			return 0;
 		}
 		memset(devInfop, 0, sz);
@@ -821,28 +834,31 @@
 		fake_storep = vmalloc(sz);
 		if (NULL == fake_storep) {
 			printk(KERN_ERR "scsi_debug_detect: out of memory"
-			       ", 0\n");
+			       ", 1\n");
 			return 0;
 		}
 		memset(fake_storep, 0, sz);
 		init_all_queued();
+#ifdef DRIVERFS_SUPPORT
+		sdebug_driverfs_driver.name = (char *)sdebug_proc_name;
+		sdebug_driverfs_driver.bus = &scsi_driverfs_bus_type;
+		driver_register(&sdebug_driverfs_driver);
+		do_create_driverfs_files();
+#endif
 		tpnt->proc_name = (char *)sdebug_proc_name;
-		for (num_present = 0, k = 0; k < NR_HOSTS_PRESENT; k++) {
-			if (NULL == scsi_register(tpnt, 0))
+		for (num_hosts_present = 0, k = 0; k < NR_HOSTS_PRESENT; k++) {
+			if ((hpnt = scsi_register(tpnt, 0)) == NULL)
 				printk(KERN_ERR "scsi_debug_detect: "
 					"scsi_register failed k=%d\n", k);
-			else
-				++num_present;
-		}
-#ifdef DRIVERFS_SUPPORT
-		if (num_present) {
-			sdebug_driverfs_driver.name = (char *)sdebug_proc_name;
-			sdebug_driverfs_driver.bus = &scsi_driverfs_bus_type;
-			driver_register(&sdebug_driverfs_driver);
-			do_create_driverfs_files();
+			else {
+				hpnt->max_lun = scsi_debug_max_luns;
+				++num_hosts_present;
+			}
 		}
-#endif
-		return num_present;
+		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+			printk(KERN_INFO "scsi_debug: ... built %d host(s)\n",
+			       num_hosts_present);
+		return num_hosts_present;
 	} else {
 		printk(KERN_WARNING "scsi_debug_detect: called again\n");
 		return 0;
@@ -854,11 +870,15 @@
 
 static int scsi_debug_release(struct Scsi_Host * hpnt)
 {
-	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
-		printk(KERN_INFO "scsi_debug: release\n");
-	stop_all_queued();
-	scsi_unregister(hpnt);
-	if (++num_releases == num_present) {
+	int host_no = hpnt->host_no;
+
+	if (++num_releases == num_hosts_present) {
+		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+			printk(KERN_INFO "scsi_debug: [last] release, "
+			       "host_no=%u\n", host_no);
+		num_releases = 0;
+		initialized = 0;
+		stop_all_queued();
 #ifdef DRIVERFS_SUPPORT
 		do_remove_driverfs_files();
 		driver_unregister(&sdebug_driverfs_driver);
@@ -866,14 +886,65 @@
 		vfree(fake_storep);
 		vfree(devInfop);
 	}
+	else {
+		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+			printk(KERN_INFO "scsi_debug: release, host_no=%u\n",
+			       host_no);
+	}
+	scsi_unregister(hpnt);
+	return 0;
+}
+
+static int scsi_debug_slave_attach(struct scsi_device * sdp)
+{
+	int k;
+	struct sdebug_dev_info * devip; 
+
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: slave_attach <%u %u %u %u>\n",
+		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
+	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
+		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+	for (k = 0; k < scsi_debug_num_devs; ++k) {
+		devip = &devInfop[k];
+		if ((devip->channel == sdp->channel) &&
+		    (devip->target == sdp->id) &&
+		    (devip->lun == sdp->lun) &&
+		    (devip->host == sdp->host)) {
+			sdp->hostdata = devip;
+			break;
+		}
+	}
+	if (sdp->host->cmd_per_lun)
+		scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, 
+					sdp->host->cmd_per_lun);
 	return 0;
 }
 
-static struct sdebug_dev_info * devInfoReg(Scsi_Cmnd *scmd)
+static void scsi_debug_slave_detach(struct scsi_device * sdp)
+{
+	struct sdebug_dev_info * devip = 
+				(struct sdebug_dev_info *)sdp->hostdata;
+
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: slave_detach <%u %u %u %u>\n",
+		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
+	if (devip) {
+		/* make this slot avaliable for re-use */
+		memset(devip, 0, sizeof(struct sdebug_dev_info));
+		sdp->hostdata = NULL;
+	}
+}
+
+static struct sdebug_dev_info * devInfoReg(struct scsi_cmnd *scmd)
 {
 	int k;
-	struct sdebug_dev_info * devip;
+	struct scsi_device * sdp = scmd->device;
+	struct sdebug_dev_info * devip =
+			(struct sdebug_dev_info *)sdp->hostdata;
 
+	if (devip)
+		return devip;
 	for (k = 0; k < scsi_debug_num_devs; ++k) {
 		devip = &devInfop[k];
 		if ((devip->channel == scmd->channel) &&
@@ -915,7 +986,7 @@
 	sbuff[13] = asq;
 }
 
-static int scsi_debug_abort(Scsi_Cmnd * SCpnt)
+static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
 {
 	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
 		printk(KERN_INFO "scsi_debug: abort\n");
@@ -938,7 +1009,7 @@
 	return 0;
 }
 
-static int scsi_debug_device_reset(Scsi_Cmnd * SCpnt)
+static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
 {
 	struct sdebug_dev_info * devip;
 
@@ -953,9 +1024,9 @@
 	return SUCCESS;
 }
 
-static int scsi_debug_bus_reset(Scsi_Cmnd * SCpnt)
+static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
 {
-	Scsi_Device * sdp;
+	struct scsi_device * sdp;
 	struct Scsi_Host * hp;
 	int k;
 
@@ -971,7 +1042,7 @@
 	return SUCCESS;
 }
 
-static int scsi_debug_host_reset(Scsi_Cmnd * SCpnt)
+static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
 {
 	int k;
 
@@ -1048,11 +1119,18 @@
 {
 	int k, num; 
 
-	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
+	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
 		printk(KERN_INFO "scsi_debug: cmd ");
 		for (k = 0, num = cmnd->cmd_len; k < num; ++k)
 	            printk("%02x ", (int)cmnd->cmnd[k]);
-		printk("result=0x%x\n", scsi_result);
+		printk("\n");
+		if (scsi_result) {
+			struct scsi_device * sdp = cmnd->device;
+
+			printk(KERN_INFO "scsi_debug: ... <%u %u %u %u> "
+			       "non-zero result=0x%x\n", sdp->host->host_no,
+			       sdp->channel, sdp->id, sdp->lun, scsi_result);
+		}
 	}
 	if (cmnd && devip) {
 		/* simulate autosense by this driver */
@@ -1113,6 +1191,38 @@
 }
 __setup("scsi_debug_num_devs=", num_devs_setup);
 
+static int __init max_luns_setup(char *str)
+{   
+    int tmp; 
+    
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_max_luns = tmp;
+        return 1;
+    } else {
+        printk(KERN_INFO "scsi_debug_max_luns: usage scsi_debug_max_luns=<n> "
+               "(<n> is a postive integer (def=2))\n");
+        return 0;
+    }
+}
+__setup("scsi_debug_max_luns=", max_luns_setup);
+
+static int __init scsi_level_setup(char *str)
+{   
+    int tmp; 
+    
+    if (get_option(&str, &tmp) == 1) {
+        if (tmp > 0)
+            scsi_debug_scsi_level = tmp;
+        return 1;
+    } else {
+        printk(KERN_INFO "scsi_debug_scsi_level: usage "
+	"scsi_debug_scsi_level=<n> (<n> is 1..4 (def=3))\n");
+        return 0;
+    }
+}
+__setup("scsi_debug_scsi_level=", scsi_level_setup);
+
 static int __init dev_size_mb_setup(char *str)
 {   
     int tmp; 
@@ -1186,6 +1296,10 @@
 MODULE_DESCRIPTION("SCSI debug adapter driver");
 MODULE_PARM(scsi_debug_num_devs, "i");
 MODULE_PARM_DESC(scsi_debug_num_devs, "number of SCSI devices to simulate");
+MODULE_PARM(scsi_debug_max_luns, "i");
+MODULE_PARM_DESC(scsi_debug_max_luns, "number of SCSI LUNs per target to simulate");
+MODULE_PARM(scsi_debug_scsi_level, "i");
+MODULE_PARM_DESC(scsi_debug_scsi_level, "SCSI level to simulate");
 MODULE_PARM(scsi_debug_dev_size_mb, "i");
 MODULE_PARM_DESC(scsi_debug_dev_size_mb, "size in MB of ram shared by devs");
 MODULE_PARM(scsi_debug_opts, "i");
@@ -1237,13 +1351,15 @@
 	pos = len = sprintf(buffer, "scsi_debug adapter driver, %s\n"
 	    "num_devs=%d, shared (ram) size=%d MB, opts=0x%x, "
 	    "every_nth=%d(curr:%d)\n"
-	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d, "
-	    "delay=%d\nnumber of aborts=%d, device_reset=%d, bus_resets=%d, " 
+	    "delay=%d, max_luns=%d, scsi_level=%d\n"
+	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
+	    "number of aborts=%d, device_reset=%d, bus_resets=%d, " 
 	    "host_resets=%d\n",
 	    scsi_debug_version_str, scsi_debug_num_devs, 
 	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
-	    scsi_debug_cmnd_count,
-	    SECT_SIZE, N_CYLINDER, N_HEAD, N_SECTOR, scsi_debug_delay,
+	    scsi_debug_cmnd_count, scsi_debug_delay,
+	    scsi_debug_max_luns, scsi_debug_scsi_level,
+	    SECT_SIZE, N_CYLINDER, N_HEAD, N_SECTOR,
 	    num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
 	if (pos < offset) {
 		len = 0;
@@ -1253,8 +1369,7 @@
 	len -= (offset - begin);
 	if (len > length)
 		len = length;
-
-	return (len);
+	return len;
 }
 
 #ifdef DRIVERFS_SUPPORT
@@ -1280,7 +1395,6 @@
 	}
 	return -EINVAL;
 }
-
 DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_read, 
 	    sdebug_delay_write)
 
@@ -1312,7 +1426,6 @@
 	scsi_debug_opts = opts;
 	return count;
 }
-
 DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_read, 
 	    sdebug_opts_write)
 
@@ -1321,18 +1434,53 @@
 {
         return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_num_devs);
 }
-
 DRIVER_ATTR(num_devs, S_IRUGO, sdebug_num_devs_read, NULL) 
 
+static ssize_t sdebug_dev_size_mb_read(struct device_driver * ddp, char * buf, 
+				       size_t count, loff_t off)
+{
+        return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_dev_size_mb);
+}
+DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_read, NULL) 
+
+static ssize_t sdebug_every_nth_read(struct device_driver * ddp, char * buf, 
+				     size_t count, loff_t off)
+{
+        return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_every_nth);
+}
+DRIVER_ATTR(every_nth, S_IRUGO, sdebug_every_nth_read, NULL) 
+
+static ssize_t sdebug_max_luns_read(struct device_driver * ddp, char * buf, 
+				    size_t count, loff_t off)
+{
+        return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_max_luns);
+}
+DRIVER_ATTR(max_luns, S_IRUGO, sdebug_max_luns_read, NULL) 
+
+static ssize_t sdebug_scsi_level_read(struct device_driver * ddp, char * buf, 
+				      size_t count, loff_t off)
+{
+        return off ? 0 : snprintf(buf, count, "%d\n", scsi_debug_scsi_level);
+}
+DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_read, NULL) 
+
 static void do_create_driverfs_files()
 {
 	driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
 	driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
 	driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_devs);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
 }
 
 static void do_remove_driverfs_files()
 {
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_devs);
 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
 	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
diff -Nru a/drivers/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h
--- a/drivers/scsi/scsi_debug.h	Sun Nov 10 19:28:39 2002
+++ b/drivers/scsi/scsi_debug.h	Sun Nov 10 19:28:39 2002
@@ -3,17 +3,20 @@
 #include <linux/types.h>
 #include <linux/kdev_t.h>
 
-static int scsi_debug_detect(Scsi_Host_Template *);
+static int scsi_debug_detect(struct SHT *);
+static int scsi_debug_slave_attach(struct scsi_device *);
+static void scsi_debug_slave_detach(struct scsi_device *);
 static int scsi_debug_release(struct Scsi_Host *);
-/* static int scsi_debug_command(Scsi_Cmnd *); */
-static int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
-static int scsi_debug_ioctl(Scsi_Device *, int, void *);
+/* static int scsi_debug_command(struct scsi_cmnd *); */
+static int scsi_debug_queuecommand(struct scsi_cmnd *, 
+				   void (*done) (struct scsi_cmnd *));
+static int scsi_debug_ioctl(struct scsi_device *, int, void *);
 static int scsi_debug_biosparam(struct scsi_device *, struct block_device *,
 		sector_t, int[]);
-static int scsi_debug_abort(Scsi_Cmnd *);
-static int scsi_debug_bus_reset(Scsi_Cmnd *);
-static int scsi_debug_device_reset(Scsi_Cmnd *);
-static int scsi_debug_host_reset(Scsi_Cmnd *);
+static int scsi_debug_abort(struct scsi_cmnd *);
+static int scsi_debug_bus_reset(struct scsi_cmnd *);
+static int scsi_debug_device_reset(struct scsi_cmnd *);
+static int scsi_debug_host_reset(struct scsi_cmnd *);
 static int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
 static const char * scsi_debug_info(struct Scsi_Host *);
 
@@ -33,6 +36,8 @@
 	.name =			"SCSI DEBUG",
 	.info =			scsi_debug_info,
 	.detect =		scsi_debug_detect,
+	.slave_attach =		scsi_debug_slave_attach,
+	.slave_detach =		scsi_debug_slave_detach,
 	.release =		scsi_debug_release,
 	.ioctl =		scsi_debug_ioctl,
 	.queuecommand =		scsi_debug_queuecommand,
diff -Nru a/drivers/scsi/scsi_mid_low_api.txt b/drivers/scsi/scsi_mid_low_api.txt
--- a/drivers/scsi/scsi_mid_low_api.txt	Sun Nov 10 19:28:40 2002
+++ b/drivers/scsi/scsi_mid_low_api.txt	Sun Nov 10 19:28:40 2002
@@ -352,33 +352,11 @@
  *      Locks: lock_kernel() active on entry and expected to be active
  *      on return.
  *
- *      Notes: Invoked from mid level's scsi_unregister_host(). When a
- *      host is being unregistered the mid level does not bother to
- *      call revoke() on the devices it controls.
+ *      Notes: Invoked from mid level's scsi_unregister_host().
  *      This function should call scsi_unregister(shp) [found in hosts.c]
  *      prior to returning.
  **/
     int release(struct Scsi_Host * shp);
-
-
-/**
- *      revoke - indicate disinterest in a scsi device
- *      @sdp: host template for this driver.
- *
- *      Return value ignored.
- *
- *      Required: no
- *
- *      Locks: none held
- *
- *      Notes: Called when "scsi remove-single-device <h> <b> <t> <l>"
- *      is written to /proc/scsi/scsi to indicate the device is no longer 
- *      required. It is called after the upper level drivers have detached 
- *      this device and before the device name  (e.g. /dev/sdc) is 
- *      unregistered and the resources associated with it are freed.
- **/
-    int revoke(Scsi_device * sdp);
-
 
 /**
  *      select_queue_depths - calculate allowable number of scsi commands
diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/scsi/scsi_scan.c	Sun Nov 10 19:28:40 2002
@@ -1322,7 +1322,6 @@
 			Scsi_Request *sreq, char *inq_result, int *bflags)
 {
 	Scsi_Device *sdev;
-	struct Scsi_Device_Template *sdt;
 	char devname[64];
 	extern devfs_handle_t scsi_devfs_handle;
 
@@ -1479,18 +1478,7 @@
 	 * function */
 	sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED;
 
-	for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
-		if (sdt->detect)
-			sdev->attached += (*sdt->detect) (sdev);
-
-	if (sdev->host->hostt->slave_attach != NULL) {
-		if (sdev->host->hostt->slave_attach(sdev) != 0) {
-			printk(KERN_INFO "%s: scsi_add_lun: failed low level driver attach, setting device offline", devname);
-			sdev->online = FALSE;
-		}
-	} else if(sdev->host->cmd_per_lun) {
-		scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
-	}
+	scsi_detect_device(sdev);
 
 	if (sdevnew != NULL)
 		*sdevnew = sdev;
@@ -2010,7 +1998,6 @@
 				   uint id, uint lun)
 {
 	Scsi_Device *sdevscan, *sdev = NULL;
-	struct Scsi_Device_Template *sdt;
 	int res;
 
 	if ((channel > shost->max_channel) || (id >= shost->max_id) ||
@@ -2028,24 +2015,7 @@
 	if (res != SCSI_SCAN_LUN_PRESENT) 
 		return;
 
-	BUG_ON(sdev == NULL);
-
-	scsi_build_commandblocks(sdev);
-	if (sdev->current_queue_depth == 0) {
-		printk(ALLOC_FAILURE_MSG, __FUNCTION__);
-		return;
-	}
-
-	for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
-		if (sdt->init && sdt->dev_noticed)
-			(*sdt->init) ();
-
-	for (sdt = scsi_devicelist; sdt; sdt = sdt->next)
-		if (sdt->attach)
-			(*sdt->attach) (sdev);
-
-	if (!sdev->attached)
-		scsi_release_commandblocks(sdev);
+	scsi_attach_device(sdev);
 }
 
 /**
diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
--- a/drivers/scsi/scsi_syms.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/scsi/scsi_syms.c	Sun Nov 10 19:28:39 2002
@@ -32,6 +32,8 @@
 EXPORT_SYMBOL(scsi_unregister_device);
 EXPORT_SYMBOL(scsi_register_host);
 EXPORT_SYMBOL(scsi_unregister_host);
+EXPORT_SYMBOL(scsi_add_host);
+EXPORT_SYMBOL(scsi_remove_host);
 EXPORT_SYMBOL(scsi_register);
 EXPORT_SYMBOL(scsi_unregister);
 EXPORT_SYMBOL(scsicam_bios_param);
@@ -80,6 +82,8 @@
 
 EXPORT_SYMBOL(scsi_register_blocked_host);
 EXPORT_SYMBOL(scsi_deregister_blocked_host);
+EXPORT_SYMBOL(scsi_slave_attach);
+EXPORT_SYMBOL(scsi_slave_detach);
 
 /*
  * This symbol is for the highlevel drivers (e.g. sg) only.
@@ -92,7 +96,6 @@
 EXPORT_SYMBOL(scsi_host_get_next);
 EXPORT_SYMBOL(scsi_host_hn_get);
 EXPORT_SYMBOL(scsi_host_put);
-EXPORT_SYMBOL(scsi_devicelist);
 EXPORT_SYMBOL(scsi_device_types);
 
 /*
diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/scsi/sd.c	Sun Nov 10 19:28:40 2002
@@ -83,6 +83,7 @@
 	unsigned	RCD : 1;	/* state of disk RCD bit */
 };
 
+static int sd_nr_dev;	/* XXX(hch) bad hack, we want a bitmap instead */
 static LIST_HEAD(sd_devlist);
 static spinlock_t sd_devlist_lock = SPIN_LOCK_UNLOCKED;
 
@@ -106,7 +107,6 @@
 	.name		= "disk",
 	.tag		= "sd",
 	.scsi_type	= TYPE_DISK,
-	.blk		= 1,
 	.detect		= sd_detect,
 	.attach		= sd_attach,
 	.detach		= sd_detach,
@@ -1179,7 +1179,6 @@
 	SCSI_LOG_HLQUEUE(3, printk("sd_detect: type=%d\n", sdp->type));
 	if (sdp->type != TYPE_DISK && sdp->type != TYPE_MOD)
 		return 0;
-	sd_template.dev_noticed++;
 	return 1;
 }
 
@@ -1213,9 +1212,12 @@
 	SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n", 
 			 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun));
 
+	if (scsi_slave_attach(sdp))
+		goto out;
+
 	sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL);
 	if (!sdkp)
-		goto out;
+		goto out_detach;
 
 	gd = alloc_disk(16);
 	if (!gd)
@@ -1228,7 +1230,7 @@
 	 * XXX  use find_first_zero_bit on it.  This will happen at the
 	 * XXX  same time template->nr_* goes away.		--hch
 	 */
-	dsk_nr = sd_template.nr_dev++;
+	dsk_nr = sd_nr_dev++;
 
 	sdkp->device = sdp;
 	sdkp->driver = &sd_template;
@@ -1264,8 +1266,9 @@
 
 out_free:
 	kfree(sdkp);
+out_detach:
+	scsi_slave_detach(sdp);
 out:
-	sdp->attached--;
 	return 1;
 }
 
@@ -1313,9 +1316,8 @@
 
 	sd_devlist_remove(sdkp);
 	del_gendisk(sdkp->disk);
-	sdp->attached--;
-	sd_template.dev_noticed--;
-	sd_template.nr_dev--;
+	scsi_slave_detach(sdp);
+	sd_nr_dev--;
 	put_disk(sdkp->disk);
 	kfree(sdkp);
 }
diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c
--- a/drivers/scsi/sg.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/scsi/sg.c	Sun Nov 10 19:28:39 2002
@@ -110,7 +110,6 @@
 
 #define SG_DEV_ARR_LUMP 6	/* amount to over allocate sg_dev_arr by */
 
-static int sg_init(void);
 static int sg_attach(Scsi_Device *);
 static int sg_detect(Scsi_Device *);
 static void sg_detach(Scsi_Device *);
@@ -126,7 +125,6 @@
 	.tag = "sg",
 	.scsi_type = 0xff,
 	.detect = sg_detect,
-	.init = sg_init,
 	.attach = sg_attach,
 	.detach = sg_detach
 };
@@ -235,6 +233,9 @@
 #endif
 
 static Sg_device **sg_dev_arr = NULL;
+static int sg_dev_noticed;
+static int sg_dev_max;
+static int sg_nr_dev;
 
 #define SZ_SG_HEADER sizeof(struct sg_header)
 #define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
@@ -1340,59 +1341,10 @@
 static int
 sg_detect(Scsi_Device * scsidp)
 {
-	sg_template.dev_noticed++;
+	sg_dev_noticed++;
 	return 1;
 }
 
-/* Driver initialization */
-static int
-sg_init()
-{
-	static int sg_registered = 0;
-	unsigned long iflags;
-	int tmp_dev_max;
-	Sg_device **tmp_da;
-
-	if ((sg_template.dev_noticed == 0) || sg_dev_arr)
-		return 0;
-
-	SCSI_LOG_TIMEOUT(3, printk("sg_init\n"));
-
-	write_lock_irqsave(&sg_dev_arr_lock, iflags);
-	tmp_dev_max = sg_template.dev_noticed + SG_DEV_ARR_LUMP;
-	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-
-	tmp_da = (Sg_device **)vmalloc(
-				tmp_dev_max * sizeof(Sg_device *));
-	if (NULL == tmp_da) {
-		printk(KERN_ERR "sg_init: no space for sg_dev_arr\n");
-		return 1;
-	}
-	write_lock_irqsave(&sg_dev_arr_lock, iflags);
-
-	if (!sg_registered) {
-		if (register_chrdev(SCSI_GENERIC_MAJOR, "sg", &sg_fops)) {
-			printk(KERN_ERR
-			       "Unable to get major %d for generic SCSI device\n",
-			       SCSI_GENERIC_MAJOR);
-			write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-			vfree((char *) tmp_da);
-			return 1;
-		}
-		sg_registered++;
-	}
-
-	memset(tmp_da, 0, tmp_dev_max * sizeof (Sg_device *));
-	sg_template.dev_max = tmp_dev_max;
-	sg_dev_arr = tmp_da;
-
-	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
-#ifdef CONFIG_PROC_FS
-	sg_proc_init();
-#endif				/* CONFIG_PROC_FS */
-	return 0;
-}
-
 #ifndef MODULE
 static int __init
 sg_def_reserved_size_setup(char *str)
@@ -1444,36 +1396,37 @@
 
 	if (!disk)
 		return 1;
+	if (scsi_slave_attach(scsidp))
+		return 1;
 	write_lock_irqsave(&sg_dev_arr_lock, iflags);
-	if (sg_template.nr_dev >= sg_template.dev_max) {	/* try to resize */
+	if (sg_nr_dev >= sg_dev_max) {	/* try to resize */
 		Sg_device **tmp_da;
-		int tmp_dev_max = sg_template.nr_dev + SG_DEV_ARR_LUMP;
+		int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP;
 
 		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 		tmp_da = (Sg_device **)vmalloc(
 				tmp_dev_max * sizeof(Sg_device *));
 		if (NULL == tmp_da) {
-			scsidp->attached--;
 			printk(KERN_ERR
 			       "sg_attach: device array cannot be resized\n");
 			put_disk(disk);
+			scsi_slave_detach(scsidp);
 			return 1;
 		}
 		write_lock_irqsave(&sg_dev_arr_lock, iflags);
 		memset(tmp_da, 0, tmp_dev_max * sizeof (Sg_device *));
 		memcpy(tmp_da, sg_dev_arr,
-		       sg_template.dev_max * sizeof (Sg_device *));
+		       sg_dev_max * sizeof (Sg_device *));
 		vfree((char *) sg_dev_arr);
 		sg_dev_arr = tmp_da;
-		sg_template.dev_max = tmp_dev_max;
+		sg_dev_max = tmp_dev_max;
 	}
 
 find_empty_slot:
-	for (k = 0; k < sg_template.dev_max; k++)
+	for (k = 0; k < sg_dev_max; k++)
 		if (!sg_dev_arr[k])
 			break;
 	if (k > SG_MAX_DEVS_MASK) {
-		scsidp->attached--;
 		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 		printk(KERN_WARNING
 		       "Unable to attach sg device <%d, %d, %d, %d>"
@@ -1483,9 +1436,10 @@
 		if (NULL != sdp)
 			vfree((char *) sdp);
 		put_disk(disk);
+		scsi_slave_detach(scsidp);
 		return 1;
 	}
-	if (k < sg_template.dev_max) {
+	if (k < sg_dev_max) {
 		if (NULL == sdp) {
 			write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 			sdp = (Sg_device *)vmalloc(sizeof(Sg_device));
@@ -1496,10 +1450,10 @@
 	} else
 		sdp = NULL;
 	if (NULL == sdp) {
-		scsidp->attached--;
 		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 		printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n");
 		put_disk(disk);
+		scsi_slave_detach(scsidp);
 		return 1;
 	}
 
@@ -1527,7 +1481,7 @@
 	sdp->sg_driverfs_dev.parent = &scsidp->sdev_driverfs_dev;
 	sdp->sg_driverfs_dev.bus = &scsi_driverfs_bus_type;
 
-	sg_template.nr_dev++;
+	sg_nr_dev++;
 	sg_dev_arr[k] = sdp;
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 
@@ -1570,7 +1524,7 @@
 		return;
 	delay = 0;
 	write_lock_irqsave(&sg_dev_arr_lock, iflags);
-	for (k = 0; k < sg_template.dev_max; k++) {
+	for (k = 0; k < sg_dev_max; k++) {
 		sdp = sg_dev_arr[k];
 		if ((NULL == sdp) || (sdp->device != scsidp))
 			continue;	/* dirty but lowers nesting */
@@ -1607,9 +1561,9 @@
 			SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
 			sg_dev_arr[k] = NULL;
 		}
-		scsidp->attached--;
-		sg_template.nr_dev--;
-		sg_template.dev_noticed--;	/* from <dan@lectra.fr> */
+		scsi_slave_detach(scsidp);
+		sg_nr_dev--;
+		sg_dev_noticed--;	/* from <dan@lectra.fr> */
 		break;
 	}
 	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
@@ -1643,9 +1597,21 @@
 static int __init
 init_sg(void)
 {
+	int rc;
+
 	if (def_reserved_size >= 0)
 		sg_big_buff = def_reserved_size;
-	return scsi_register_device(&sg_template);
+
+	rc = register_chrdev(SCSI_GENERIC_MAJOR, "sg", &sg_fops);
+	if (rc)
+		return rc;
+	rc = scsi_register_device(&sg_template);
+	if (rc)
+		return rc;
+#ifdef CONFIG_PROC_FS
+	sg_proc_init();
+#endif				/* CONFIG_PROC_FS */
+	return 0;
 }
 
 static void __exit
@@ -1660,7 +1626,7 @@
 		vfree((char *) sg_dev_arr);
 		sg_dev_arr = NULL;
 	}
-	sg_template.dev_max = 0;
+	sg_dev_max = 0;
 }
 
 static int
@@ -2552,7 +2518,7 @@
 		if (sdp->detached && (NULL == sdp->headfp)) {
 			int k, maxd;
 
-			maxd = sg_template.dev_max;
+			maxd = sg_dev_max;
 			for (k = 0; k < maxd; ++k) {
 				if (sdp == sg_dev_arr[k])
 					break;
@@ -2684,7 +2650,7 @@
 	unsigned long iflags;
 
 	read_lock_irqsave(&sg_dev_arr_lock, iflags);
-	for (k = sg_template.dev_max - 1; k >= 0; --k)
+	for (k = sg_dev_max - 1; k >= 0; --k)
 		if (sg_dev_arr[k] && sg_dev_arr[k]->device)
 			break;
 	read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
@@ -2700,7 +2666,7 @@
 
 	if (sg_dev_arr && (dev >= 0)) {
 		read_lock_irqsave(&sg_dev_arr_lock, iflags);
-		if (dev < sg_template.dev_max)
+		if (dev < sg_dev_max)
 			sdp = sg_dev_arr[dev];
 		read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 	}
@@ -2982,7 +2948,7 @@
 	}
 	max_dev = sg_last_dev();
 	PRINT_PROC("dev_max(currently)=%d max_active_device=%d (origin 1)\n",
-		   sg_template.dev_max, max_dev);
+		   sg_dev_max, max_dev);
 	PRINT_PROC(" def_reserved_size=%d\n", sg_big_buff);
 	for (j = 0; j < max_dev; ++j) {
 		if ((sdp = sg_get_dev(j))) {
diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/scsi/sr.c	Sun Nov 10 19:28:38 2002
@@ -65,11 +65,9 @@
 	 CDC_PLAY_AUDIO|CDC_RESET|CDC_IOCTLS|CDC_DRIVE_STATUS| \
 	 CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_GENERIC_PACKET)
 
-static int sr_init(void);
 static int sr_attach(struct scsi_device *);
 static int sr_detect(struct scsi_device *);
 static void sr_detach(struct scsi_device *);
-
 static int sr_init_command(struct scsi_cmnd *);
 
 static struct Scsi_Device_Template sr_template = {
@@ -77,24 +75,54 @@
 	.name		= "cdrom",
 	.tag		= "sr",
 	.scsi_type	= TYPE_ROM,
-	.blk		= 1,
 	.detect		= sr_detect,
-	.init		= sr_init,
 	.attach		= sr_attach,
 	.detach		= sr_detach,
 	.init_command	= sr_init_command
 };
 
-static struct scsi_cd *scsi_CDs;
+static int sr_nr_dev;	/* XXX(hch) bad hack, we want a bitmap instead */
+static LIST_HEAD(sr_devlist);
+static spinlock_t sr_devlist_lock = SPIN_LOCK_UNLOCKED;
 
 static int sr_open(struct cdrom_device_info *, int);
 static void get_sectorsize(struct scsi_cd *);
 static void get_capabilities(struct scsi_cd *);
-static int sr_init_one(struct scsi_cd *, int);
 
 static int sr_media_change(struct cdrom_device_info *, int);
 static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *);
 
+static Scsi_CD *sr_find_by_sdev(Scsi_Device *sd)
+{
+	struct list_head *p;
+	Scsi_CD *cd;
+
+	spin_lock(&sr_devlist_lock);
+	list_for_each(p, &sr_devlist) {
+		cd = list_entry(p, Scsi_CD, list);
+		if (cd->device == sd) {
+			spin_unlock(&sr_devlist_lock);
+			return cd;
+		}
+	}
+	spin_unlock(&sr_devlist_lock);
+	return NULL;
+}
+
+static inline void sr_devlist_insert(Scsi_CD *cd)
+{
+	spin_lock(&sr_devlist_lock);
+	list_add(&cd->list, &sr_devlist);
+	spin_unlock(&sr_devlist_lock);
+}
+
+static inline void sr_devlist_remove(Scsi_CD *cd)
+{
+	spin_lock(&sr_devlist_lock);
+	list_del(&cd->list);
+	spin_unlock(&sr_devlist_lock);
+}
+
 static void sr_release(struct cdrom_device_info *cdi)
 {
 	struct scsi_cd *cd = cdi->handle;
@@ -466,44 +494,90 @@
 
 	if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM)
 		return 0;
-	sr_template.dev_noticed++;
 	return 1;
 }
 
-static int sr_attach(struct scsi_device * SDp)
+static int sr_attach(struct scsi_device *sdev)
 {
-	struct scsi_cd *cpnt;
-	int i;
+	struct gendisk *disk;
+	struct scsi_cd *cd;
+	int minor;
 
-	if (SDp->type != TYPE_ROM && SDp->type != TYPE_WORM)
+	if (sdev->type != TYPE_ROM && sdev->type != TYPE_WORM)
+		return 1;
+
+	if (scsi_slave_attach(sdev))
 		return 1;
 
-	if (sr_template.nr_dev >= sr_template.dev_max)
+	cd = kmalloc(sizeof(*cd), GFP_KERNEL);
+	if (!cd)
 		goto fail;
+	memset(cd, 0, sizeof(*cd));
 
-	for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++)
-		if (!cpnt->device)
-			break;
+	disk = alloc_disk(1);
+	if (!disk)
+		goto fail_free;
 
-	if (i >= sr_template.dev_max)
-		panic("scsi_devices corrupt (sr)");
+	/*
+	 * XXX  This doesn't make us better than the previous code in the
+	 * XXX  end (not worse either, though..).
+	 * XXX  To properly support hotplugging we should have a bitmap and
+	 * XXX  use find_first_zero_bit on it.  This will happen at the
+	 * XXX  same time template->nr_* goes away.		--hch
+	 */
+	minor = sr_nr_dev++;
 
-	scsi_CDs[i].device = SDp;
+	disk->major = MAJOR_NR;
+	disk->first_minor = minor;
+	sprintf(disk->disk_name, "sr%d", minor);
+	disk->fops = &sr_bdops;
+	disk->flags = GENHD_FL_CD;
 
-	if (sr_init_one(cpnt, i))
-		goto fail;
+	cd->device = sdev;
+	cd->disk = disk;
+	cd->driver = &sr_template;
+	cd->disk = disk;
+	cd->capacity = 0x1fffff;
+	cd->needs_sector_size = 1;
+	cd->device->changed = 1;	/* force recheck CD type */
+	cd->use = 1;
+	cd->readcd_known = 0;
+	cd->readcd_cdda = 0;
+
+	cd->cdi.ops = &sr_dops;
+	cd->cdi.handle = cd;
+	cd->cdi.mask = 0;
+	cd->cdi.capacity = 1;
+	sprintf(cd->cdi.name, "sr%d", minor);
+
+	sdev->sector_size = 2048;	/* A guess, just in case */
+	sdev->ten = 1;
+	sdev->remap = 1;
+
+	/* FIXME: need to handle a get_capabilities failure properly ?? */
+	get_capabilities(cd);
+	sr_vendor_init(cd);
+
+	disk->de = sdev->de;
+	disk->driverfs_dev = &sdev->sdev_driverfs_dev;
+	register_cdrom(&cd->cdi);
+	set_capacity(disk, cd->capacity);
+	disk->private_data = &cd->driver;
+	disk->queue = &sdev->request_queue;
+
+	add_disk(disk);
+	sr_devlist_insert(cd);
 
-	sr_template.nr_dev++;
-	if (sr_template.nr_dev > sr_template.dev_max)
-		panic("scsi_devices corrupt (sr)");
-
-	printk("Attached scsi CD-ROM %s at scsi%d, channel %d, id %d, lun %d\n",
-	       scsi_CDs[i].cdi.name, SDp->host->host_no, SDp->channel,
-	       SDp->id, SDp->lun);
+	printk(KERN_DEBUG
+	    "Attached scsi CD-ROM %s at scsi%d, channel %d, id %d, lun %d\n",
+	    cd->cdi.name, sdev->host->host_no, sdev->channel,
+	    sdev->id, sdev->lun);
 	return 0;
 
+fail_free:
+	kfree(cd);
 fail:
-	SDp->attached--;
+	scsi_slave_detach(sdev);
 	return 1;
 }
 
@@ -723,126 +797,32 @@
 	return cgc->stat;
 }
 
-static int sr_registered;
-
-static int sr_init()
-{
-	int i;
-	if (sr_template.dev_noticed == 0)
-		return 0;
-
-	if (!sr_registered) {
-		if (register_blkdev(MAJOR_NR, "sr", &sr_bdops)) {
-			printk("Unable to get major %d for SCSI-CD\n",
-					MAJOR_NR);
-			return 1;
-		}
-		sr_registered++;
-	}
-	if (scsi_CDs)
-		return 0;
-
-	sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS;
-	scsi_CDs = kmalloc(sr_template.dev_max * sizeof(struct scsi_cd), GFP_ATOMIC);
-	if (!scsi_CDs)
-		goto cleanup_dev;
-	memset(scsi_CDs, 0, sr_template.dev_max * sizeof(struct scsi_cd));
-	for (i = 0; i < sr_template.dev_max; i++)
-		sprintf(scsi_CDs[i].cdi.name, "sr%d", i);
-	return 0;
-
-cleanup_dev:
-	unregister_blkdev(MAJOR_NR, "sr");
-	sr_registered--;
-	return 1;
-}
-
-static int sr_init_one(struct scsi_cd *cd, int first_minor)
+static void sr_detach(struct scsi_device * SDp)
 {
-	struct gendisk *disk;
-
-	disk = alloc_disk(1);
-	if (!disk)
-		return -ENOMEM;
-
-	disk->major = MAJOR_NR;
-	disk->first_minor = first_minor;
-	strcpy(disk->disk_name, cd->cdi.name);
-	disk->fops = &sr_bdops;
-	disk->flags = GENHD_FL_CD;
-	cd->driver = &sr_template;
-	cd->disk = disk;
-	cd->capacity = 0x1fffff;
-	cd->device->sector_size = 2048;/* A guess, just in case */
-	cd->needs_sector_size = 1;
-	cd->device->changed = 1;	/* force recheck CD type */
-#if 0
-	/* seems better to leave this for later */
-	get_sectorsize(cd);
-	printk("Scd sectorsize = %d bytes.\n", cd->sector_size);
-#endif
-	cd->use = 1;
-
-	cd->device->ten = 1;
-	cd->device->remap = 1;
-	cd->readcd_known = 0;
-	cd->readcd_cdda = 0;
+	struct scsi_cd *cd;
 
-	cd->cdi.ops = &sr_dops;
-	cd->cdi.handle = cd;
-	cd->cdi.mask = 0;
-	cd->cdi.capacity = 1;
-
-	/*
-	 *	FIXME: someone needs to handle a get_capabilities
-	 *	failure properly ??
-	 */
-	get_capabilities(cd);
-	sr_vendor_init(cd);
-	disk->de = cd->device->de;
-	disk->driverfs_dev = &cd->device->sdev_driverfs_dev;
-	register_cdrom(&cd->cdi);
-	set_capacity(disk, cd->capacity);
-	disk->private_data = &cd->driver;
-	disk->queue = &cd->device->request_queue;
-	add_disk(disk);
-
-	return 0;
-}
+	cd = sr_find_by_sdev(SDp);
+	if (!cd)
+		return;
 
-static void sr_detach(struct scsi_device * SDp)
-{
-	struct scsi_cd *cpnt;
-	int i;
+	sr_devlist_remove(cd);
+	del_gendisk(cd->disk);
+	put_disk(cd->disk);
+	unregister_cdrom(&cd->cdi);
 
-	for (cpnt = scsi_CDs, i = 0; i < sr_template.dev_max; i++, cpnt++) {
-		if (cpnt->device == SDp) {
-			/*
-			 * Since the cdrom is read-only, no need to sync
-			 * the device.
-			 * We should be kind to our buffer cache, however.
-			 */
-			del_gendisk(cpnt->disk);
-			put_disk(cpnt->disk);
-			cpnt->disk = NULL;
+	scsi_slave_detach(SDp);
+	sr_nr_dev--;
 
-			/*
-			 * Reset things back to a sane state so that one can
-			 * re-load a new driver (perhaps the same one).
-			 */
-			unregister_cdrom(&(cpnt->cdi));
-			cpnt->device = NULL;
-			cpnt->capacity = 0;
-			SDp->attached--;
-			sr_template.nr_dev--;
-			sr_template.dev_noticed--;
-			return;
-		}
-	}
+	kfree(cd);
 }
 
 static int __init init_sr(void)
 {
+	int rc;
+
+	rc = register_blkdev(MAJOR_NR, "sr", &sr_bdops);
+	if (rc)
+		return rc;
 	return scsi_register_device(&sr_template);
 }
 
@@ -850,11 +830,6 @@
 {
 	scsi_unregister_device(&sr_template);
 	unregister_blkdev(MAJOR_NR, "sr");
-	sr_registered--;
-	if (scsi_CDs != NULL)
-		kfree(scsi_CDs);
-
-	sr_template.dev_max = 0;
 }
 
 module_init(init_sr);
diff -Nru a/drivers/scsi/sr.h b/drivers/scsi/sr.h
--- a/drivers/scsi/sr.h	Sun Nov 10 19:28:39 2002
+++ b/drivers/scsi/sr.h	Sun Nov 10 19:28:39 2002
@@ -26,6 +26,7 @@
 
 typedef struct scsi_cd {
 	struct Scsi_Device_Template *driver;
+	struct list_head list;
 	unsigned capacity;	/* size in blocks                       */
 	Scsi_Device *device;
 	unsigned int vendor;	/* vendor code, see sr_vendor.c         */
diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c
--- a/drivers/scsi/st.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/scsi/st.c	Sun Nov 10 19:28:40 2002
@@ -74,6 +74,9 @@
 static int try_rdio = TRUE;
 static int try_wdio = TRUE;
 
+static int st_dev_max;
+static int st_nr_dev;
+
 MODULE_AUTHOR("Kai Makisara");
 MODULE_DESCRIPTION("SCSI Tape Driver");
 MODULE_LICENSE("GPL");
@@ -976,7 +979,7 @@
 	char *name;
 
 	write_lock(&st_dev_arr_lock);
-	if (dev >= st_template.dev_max || scsi_tapes == NULL ||
+	if (dev >= st_dev_max || scsi_tapes == NULL ||
 	    ((STp = scsi_tapes[dev]) == NULL)) {
 		write_unlock(&st_dev_arr_lock);
 		return (-ENXIO);
@@ -3664,6 +3667,9 @@
 		return 1;
 	}
 
+	if (scsi_slave_attach(SDp))
+		return 1;
+
 	i = SDp->host->sg_tablesize;
 	if (st_max_sg_segs < i)
 		i = st_max_sg_segs;
@@ -3680,20 +3686,20 @@
 	}
 
 	write_lock(&st_dev_arr_lock);
-	if (st_template.nr_dev >= st_template.dev_max) {
+	if (st_nr_dev >= st_dev_max) {
 		Scsi_Tape **tmp_da;
 		ST_buffer **tmp_ba;
 		int tmp_dev_max;
 
-		tmp_dev_max = st_template.nr_dev + ST_DEV_ARR_LUMP;
+		tmp_dev_max = st_nr_dev + ST_DEV_ARR_LUMP;
 		if (tmp_dev_max > ST_MAX_TAPES)
 			tmp_dev_max = ST_MAX_TAPES;
-		if (tmp_dev_max <= st_template.nr_dev) {
-			SDp->attached--;
+		if (tmp_dev_max <= st_nr_dev) {
 			write_unlock(&st_dev_arr_lock);
 			printk(KERN_ERR "st: Too many tape devices (max. %d).\n",
 			       ST_MAX_TAPES);
 			put_disk(disk);
+			scsi_slave_detach(SDp);
 			return 1;
 		}
 
@@ -3704,36 +3710,36 @@
 				kfree(tmp_da);
 			if (tmp_ba != NULL)
 				kfree(tmp_ba);
-			SDp->attached--;
 			write_unlock(&st_dev_arr_lock);
 			printk(KERN_ERR "st: Can't extend device array.\n");
 			put_disk(disk);
+			scsi_slave_detach(SDp);
 			return 1;
 		}
 
 		memset(tmp_da, 0, tmp_dev_max * sizeof(Scsi_Tape *));
 		if (scsi_tapes != NULL) {
 			memcpy(tmp_da, scsi_tapes,
-			       st_template.dev_max * sizeof(Scsi_Tape *));
+			       st_dev_max * sizeof(Scsi_Tape *));
 			kfree(scsi_tapes);
 		}
 		scsi_tapes = tmp_da;
 
-		st_template.dev_max = tmp_dev_max;
+		st_dev_max = tmp_dev_max;
 	}
 
-	for (i = 0; i < st_template.dev_max; i++)
+	for (i = 0; i < st_dev_max; i++)
 		if (scsi_tapes[i] == NULL)
 			break;
-	if (i >= st_template.dev_max)
+	if (i >= st_dev_max)
 		panic("scsi_devices corrupt (st)");
 
 	tpnt = kmalloc(sizeof(Scsi_Tape), GFP_ATOMIC);
 	if (tpnt == NULL) {
-		SDp->attached--;
 		write_unlock(&st_dev_arr_lock);
 		printk(KERN_ERR "st: Can't allocate device descriptor.\n");
 		put_disk(disk);
+		scsi_slave_detach(SDp);
 		return 1;
 	}
 	memset(tpnt, 0, sizeof(Scsi_Tape));
@@ -3821,7 +3827,7 @@
 	    tpnt->blksize_changed = FALSE;
 	init_MUTEX(&tpnt->lock);
 
-	st_template.nr_dev++;
+	st_nr_dev++;
 	write_unlock(&st_dev_arr_lock);
 
 	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
@@ -3883,7 +3889,6 @@
 {
 	if (SDp->type != TYPE_TAPE || st_incompatible(SDp))
 		return 0;
-        st_template.dev_noticed++;
 	return 1;
 }
 
@@ -3893,7 +3898,7 @@
 	int i, mode;
 
 	write_lock(&st_dev_arr_lock);
-	for (i = 0; i < st_template.dev_max; i++) {
+	for (i = 0; i < st_dev_max; i++) {
 		tpnt = scsi_tapes[i];
 		if (tpnt != NULL && tpnt->device == SDp) {
 			tpnt->device = NULL;
@@ -3904,9 +3909,8 @@
 				tpnt->de_n[mode] = NULL;
 			}
 			scsi_tapes[i] = 0;
-			SDp->attached--;
-			st_template.nr_dev--;
-			st_template.dev_noticed--;
+			scsi_slave_detach(SDp);
+			st_nr_dev--;
 			write_unlock(&st_dev_arr_lock);
 
 			for (mode = 0; mode < ST_NBR_MODES; ++mode) {
@@ -3962,14 +3966,13 @@
 	scsi_unregister_device(&st_template);
 	unregister_chrdev(SCSI_TAPE_MAJOR, "st");
 	if (scsi_tapes != NULL) {
-		for (i=0; i < st_template.dev_max; ++i)
+		for (i=0; i < st_dev_max; ++i)
 			if (scsi_tapes[i]) {
 				put_disk(scsi_tapes[i]->disk);
 				kfree(scsi_tapes[i]);
 			}
 		kfree(scsi_tapes);
 	}
-	st_template.dev_max = 0;
 	printk(KERN_INFO "st: Unloaded.\n");
 }
 
diff -Nru a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
--- a/drivers/scsi/u14-34f.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/scsi/u14-34f.c	Sun Nov 10 19:28:38 2002
@@ -1486,16 +1486,16 @@
    return SUCCESS;
 }
 
-static int u14_34f_bios_param(Disk *disk, struct block_device *bdev,
-                                                          int *dkinfo) {
+static int u14_34f_bios_param(struct scsi_device *disk, struct block_device *bdev,
+	sector_t capacity, int *dkinfo) {
    unsigned int j = 0;
-   int size = disk->capacity;
+   unsigned int size = capacity;
 
    dkinfo[0] = HD(j)->heads;
    dkinfo[1] = HD(j)->sectors;
    dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors);
 
-   if (ext_tran && (scsicam_bios_param(disk, bdev, dkinfo) < 0)) {
+   if (ext_tran && (scsicam_bios_param(bdev, capacity, dkinfo) < 0)) {
       dkinfo[0] = 255;
       dkinfo[1] = 63;
       dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
diff -Nru a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h
--- a/drivers/scsi/u14-34f.h	Sun Nov 10 19:28:41 2002
+++ b/drivers/scsi/u14-34f.h	Sun Nov 10 19:28:41 2002
@@ -7,7 +7,7 @@
 static int u14_34f_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
 static int u14_34f_eh_abort(Scsi_Cmnd *);
 static int u14_34f_eh_host_reset(Scsi_Cmnd *);
-static int u14_34f_bios_param(Disk *, struct block_device *, int *);
+static int u14_34f_bios_param(struct scsi_device *, struct block_device *, sector_t, int *);
 static int u14_34f_slave_attach(Scsi_Device *);
 
 #define U14_34F_VERSION "8.00.00"
@@ -17,8 +17,6 @@
                 detect:                  u14_34f_detect,                     \
                 release:                 u14_34f_release,                    \
                 queuecommand:            u14_34f_queuecommand,               \
-                abort:                   NULL,                               \
-                reset:                   NULL,                               \
                 eh_abort_handler:        u14_34f_eh_abort,                   \
                 eh_device_reset_handler: NULL,                               \
                 eh_bus_reset_handler:    NULL,                               \
diff -Nru a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
--- a/drivers/scsi/ultrastor.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/scsi/ultrastor.c	Sun Nov 10 19:28:40 2002
@@ -8,6 +8,9 @@
  *    John's work modified by Caleb Epstein (cae@jpmorgan.com) and 
  *    Eric Youngdale (ericy@cais.com).
  *	Thanks to UltraStor for providing the necessary documentation
+ *
+ *  This is an old driver, for the 14F and 34F you should be using the
+ *  u14-34f driver instead.
  */
 
 /*
@@ -164,8 +167,8 @@
    packed structure.  */
 
 typedef struct {
-  unsigned int address;
-  unsigned int num_bytes;
+  u32 address;
+  u32 num_bytes;
 } ultrastor_sg_list;
 
 
@@ -190,7 +193,7 @@
   unsigned char scsi_cdbs[12];	/* SCSI commands */
   unsigned char adapter_status;	/* non-zero indicates HA error */
   unsigned char target_status;	/* non-zero indicates target error */
-  unsigned int sense_data PACKED;
+  u32 sense_data PACKED;
   /* The following fields are for software only.  They are included in
      the MSCP structure because they are associated with SCSI requests.  */
   void (*done)(Scsi_Cmnd *);
@@ -289,17 +292,15 @@
 static inline void build_sg_list(struct mscp *, Scsi_Cmnd *SCpnt);
 
 
+/* Always called with host lock held */
+
 static inline int find_and_clear_bit_16(unsigned short *field)
 {
   int rv;
-  unsigned long flags;
 
-  save_flags(flags);
-  cli();
   if (*field == 0) panic("No free mscp");
   asm("xorl %0,%0\n0:\tbsfw %1,%w0\n\tbtr %0,%1\n\tjnc 0b"
       : "=&r" (rv), "=m" (*field) : "1" (*field));
-  restore_flags(flags);
   return rv;
 }
 
@@ -320,14 +321,12 @@
 
 #if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT)
 
-static void log_ultrastor_abort(register struct ultrastor_config *config,
+/* Always called with the host lock held */
+static void log_ultrastor_abort(struct ultrastor_config *config,
 				int command)
 {
   static char fmt[80] = "abort %d (%x); MSCP free pool: %x;";
-  register int i;
-  unsigned long flags;
-  save_flags(flags);
-  cli();
+  int i;
 
   for (i = 0; i < ULTRASTOR_MAX_CMDS; i++)
     {
@@ -340,7 +339,7 @@
   fmt[20 + ULTRASTOR_MAX_CMDS * 2] = '\n';
   fmt[21 + ULTRASTOR_MAX_CMDS * 2] = 0;
   printk(fmt, command, &config->mscp[command], config->mscp_free);
-  restore_flags(flags);
+
 }
 #endif
 
@@ -528,7 +527,7 @@
 
 static int ultrastor_24f_detect(Scsi_Host_Template * tpnt)
 {
-  register int i;
+  int i;
   struct Scsi_Host * shpnt = NULL;
 
 #if (ULTRASTOR_DEBUG & UD_DETECT)
@@ -638,13 +637,13 @@
   return FALSE;
 }
 
-int ultrastor_detect(Scsi_Host_Template * tpnt)
+static int ultrastor_detect(Scsi_Host_Template * tpnt)
 {
-    tpnt->proc_name = "ultrastor";
-  return ultrastor_14f_detect(tpnt) || ultrastor_24f_detect(tpnt);
+	tpnt->proc_name = "ultrastor";
+	return ultrastor_14f_detect(tpnt) || ultrastor_24f_detect(tpnt);
 }
 
-const char *ultrastor_info(struct Scsi_Host * shpnt)
+static const char *ultrastor_info(struct Scsi_Host * shpnt)
 {
     static char buf[64];
 
@@ -662,7 +661,7 @@
     return buf;
 }
 
-static inline void build_sg_list(register struct mscp *mscp, Scsi_Cmnd *SCpnt)
+static inline void build_sg_list(struct mscp *mscp, Scsi_Cmnd *SCpnt)
 {
 	struct scatterlist *sl;
 	long transfer_length = 0;
@@ -683,14 +682,13 @@
 	mscp->transfer_data_length = transfer_length;
 }
 
-int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
-    register struct mscp *my_mscp;
+    struct mscp *my_mscp;
 #if ULTRASTOR_MAX_CMDS > 1
     int mscp_index;
 #endif
     unsigned int status;
-    unsigned long flags;
 
     /* Next test is for debugging; "can't happen" */
     if ((config.mscp_free & ((1U << ULTRASTOR_MAX_CMDS) - 1)) == 0)
@@ -706,14 +704,8 @@
 
     my_mscp = &config.mscp[mscp_index];
 
-#if 1
-    /* This way is faster.  */
     *(unsigned char *)my_mscp = OP_SCSI | (DTD_SCSI << 3);
-#else
-    my_mscp->opcode = OP_SCSI;
-    my_mscp->xdir = DTD_SCSI;
-    my_mscp->dcn = FALSE;
-#endif
+
     /* Tape drives don't work properly if the cache is used.  The SCSI
        READ command for a tape doesn't have a block offset, and the adapter
        incorrectly assumes that all reads from the tape read the same
@@ -748,35 +740,31 @@
     SCpnt->host_scribble = (unsigned char *)my_mscp;
 
     /* Find free OGM slot.  On 24F, look for OGM status byte == 0.
-       On 14F and 34F, wait for local interrupt pending flag to clear.  */
+       On 14F and 34F, wait for local interrupt pending flag to clear. 
+       
+       FIXME: now we are using new_eh we should punt here and let the
+       midlayer sort it out */
 
-  retry:
+retry:
     if (config.slot)
-	while (inb(config.ogm_address - 1) != 0 &&
-	       config.aborted[mscp_index] == 0xff) barrier();
+	while (inb(config.ogm_address - 1) != 0 && config.aborted[mscp_index] == 0xff)
+		barrier();
 
     /* else??? */
 
-    while ((inb(LCL_DOORBELL_INTR(config.doorbell_address)) & 
-	    (config.slot ? 2 : 1)) 
-	   && config.aborted[mscp_index] == 0xff) barrier();
+    while ((inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1))  && config.aborted[mscp_index] == 0xff)
+    	barrier();
 
-    /* To avoid race conditions, make the code to write to the adapter
-       atomic.  This simplifies the abort code.  */
-
-    save_flags(flags);
-    cli();
+    /* To avoid race conditions, keep the code to write to the adapter
+       atomic.  This simplifies the abort code.  Right now the
+       scsi mid layer has the host_lock already held
+     */
 
-    if (inb(LCL_DOORBELL_INTR(config.doorbell_address)) &
-	(config.slot ? 2 : 1))
-      {
-      restore_flags(flags);
+    if (inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1))
       goto retry;
-      }
 
     status = xchgb(0, &config.aborted[mscp_index]);
     if (status != 0xff) {
-	restore_flags(flags);
 
 #if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT)
 	printk("USx4F: queuecommand: aborted\n");
@@ -811,8 +799,6 @@
 	outb(0x1, LCL_DOORBELL_INTR(config.doorbell_address));
     }
 
-    restore_flags(flags);
-
 #if (ULTRASTOR_DEBUG & UD_COMMAND)
     printk("USx4F: queuecommand: returning\n");
 #endif
@@ -835,7 +821,7 @@
 
  */
 
-int ultrastor_abort(Scsi_Cmnd *SCpnt)
+static int ultrastor_abort(Scsi_Cmnd *SCpnt)
 {
 #if ULTRASTOR_DEBUG & UD_ABORT
     char out[108];
@@ -844,14 +830,16 @@
 #endif
     unsigned int mscp_index;
     unsigned char old_aborted;
+    unsigned long flags;
     void (*done)(Scsi_Cmnd *);
+    struct Scsi_Host *host = SCpnt->host;
 
     if(config.slot) 
-      return SCSI_ABORT_SNOOZE;  /* Do not attempt an abort for the 24f */
-
+      return FAILED;  /* Do not attempt an abort for the 24f */
+      
     /* Simple consistency checking */
     if(!SCpnt->host_scribble)
-      return SCSI_ABORT_NOT_RUNNING;
+      return FAILED;
 
     mscp_index = ((struct mscp *)SCpnt->host_scribble) - config.mscp;
     if (mscp_index >= ULTRASTOR_MAX_CMDS)
@@ -863,8 +851,8 @@
 	int port0 = (config.slot << 12) | 0xc80;
 	int i;
 	unsigned long flags;
-	save_flags(flags);
-	cli();
+	
+	spin_lock_irqsave(host->host_lock, flags);
 	strcpy(out, "OGM %d:%x ICM %d:%x ports:  ");
 	for (i = 0; i < 16; i++)
 	  {
@@ -879,7 +867,7 @@
 	ogm_addr = (unsigned int)isa_bus_to_virt(inl(port0 + 23));
 	icm_status = inb(port0 + 27);
 	icm_addr = (unsigned int)isa_bus_to_virt(inl(port0 + 28));
-	restore_flags(flags);
+	spin_lock_irqsave(host->host_lock, flags);
       }
 
     /* First check to see if an interrupt is pending.  I suspect the SiS
@@ -888,14 +876,13 @@
     if (config.slot ? inb(config.icm_address - 1) == 2 :
 	(inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
       {
-	unsigned long flags;
-	save_flags(flags);
 	printk("Ux4F: abort while completed command pending\n");
-	restore_flags(flags);
-	cli();
+	
+	spin_lock_irqsave(host->host_lock, flags);
+	/* FIXME: Ewww... need to think about passing host around properly */
 	ultrastor_interrupt(0, NULL, NULL);
-	restore_flags(flags);
-	return SCSI_ABORT_SUCCESS;  /* FIXME - is this correct? -ERY */
+	spin_unlock_irqrestore(host->host_lock, flags);
+	return SUCCESS;
       }
 #endif
 
@@ -904,7 +891,7 @@
     /* aborted == 0xff is the signal that queuecommand has not yet sent
        the command.  It will notice the new abort flag and fail.  */
     if (old_aborted == 0xff)
-	return SCSI_ABORT_SUCCESS;
+	return SUCCESS;
 
     /* On 24F, send an abort MSCP request.  The adapter will interrupt
        and the interrupt handler will call done.  */
@@ -912,18 +899,18 @@
       {
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(host->host_lock, flags);
 	outl(isa_virt_to_bus(&config.mscp[mscp_index]), config.ogm_address);
-	inb(0xc80);	/* delay */
+	udelay(8);
 	outb(0x80, config.ogm_address - 1);
 	outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address));
 #if ULTRASTOR_DEBUG & UD_ABORT
 	log_ultrastor_abort(&config, mscp_index);
 	printk(out, ogm_status, ogm_addr, icm_status, icm_addr);
 #endif
-	restore_flags(flags);
-	return SCSI_ABORT_PENDING;
+	spin_unlock_irqrestore(host->host_lock, flags);
+	/* FIXME: add a wait for the abort to complete */
+	return SUCCESS;
       }
 
 #if ULTRASTOR_DEBUG & UD_ABORT
@@ -953,27 +940,30 @@
     done = config.mscp[mscp_index].done;
     config.mscp[mscp_index].done = 0;
     SCpnt->result = DID_ABORT << 16;
-    /* I worry about reentrancy in scsi.c  */
+    
+    /* Take the host lock to guard against scsi layer re-entry */
+    spin_lock_irqsave(host->host_lock, flags);
     done(SCpnt);
+    spin_unlock_irqrestore(host->host_lock, flags);
 
     /* Need to set a timeout here in case command never completes.  */
-    return SCSI_ABORT_SUCCESS;
+    return SUCCESS;
 }
 
-int ultrastor_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+static int ultrastor_host_reset(Scsi_Cmnd * SCpnt)
 {
     unsigned long flags;
-    register int i;
+    int i;
+    struct Scsi_Host *host = SCpnt->host;
+    
 #if (ULTRASTOR_DEBUG & UD_RESET)
     printk("US14F: reset: called\n");
 #endif
 
     if(config.slot)
-      return SCSI_RESET_PUNT;  /* Do not attempt a reset for the 24f */
-
-    save_flags(flags);
-    cli();
+    	return FAILED;
 
+    spin_lock_irqsave(host->host_lock, flags);
     /* Reset the adapter and SCSI bus.  The SCSI bus reset can be
        inhibited by clearing ultrastor_bus_reset before probe.  */
     outb(0xc0, LCL_DOORBELL_INTR(config.doorbell_address));
@@ -1005,7 +995,10 @@
 #endif
 
     /* FIXME - if the device implements soft resets, then the command
-       will still be running.  ERY */
+       will still be running.  ERY  
+       
+       Even bigger deal with new_eh! 
+     */
 
     memset((unsigned char *)config.aborted, 0, sizeof config.aborted);
 #if ULTRASTOR_MAX_CMDS == 1
@@ -1014,7 +1007,7 @@
     config.mscp_free = ~0;
 #endif
 
-    restore_flags(flags);
+    spin_unlock_irqrestore(host->host_lock, flags);
     return SCSI_RESET_SUCCESS;
 
 }
@@ -1041,7 +1034,7 @@
 #if ULTRASTOR_MAX_CMDS > 1
     unsigned int mscp_index;
 #endif
-    register struct mscp *mscp;
+    struct mscp *mscp;
     void (*done)(Scsi_Cmnd *);
     Scsi_Cmnd *SCtmp;
 
diff -Nru a/drivers/scsi/ultrastor.h b/drivers/scsi/ultrastor.h
--- a/drivers/scsi/ultrastor.h	Sun Nov 10 19:28:39 2002
+++ b/drivers/scsi/ultrastor.h	Sun Nov 10 19:28:39 2002
@@ -13,13 +13,12 @@
 #ifndef _ULTRASTOR_H
 #define _ULTRASTOR_H
 
-int ultrastor_detect(Scsi_Host_Template *);
-const char *ultrastor_info(struct Scsi_Host * shpnt);
-int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int ultrastor_abort(Scsi_Cmnd *);
-int ultrastor_reset(Scsi_Cmnd *, unsigned int);
-int ultrastor_biosparam(struct scsi_device *, struct block_device *,
-		sector_t, int *);
+static int ultrastor_detect(Scsi_Host_Template *);
+static const char *ultrastor_info(struct Scsi_Host * shpnt);
+static int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int ultrastor_abort(Scsi_Cmnd *);
+static int ultrastor_host_reset(Scsi_Cmnd *);
+static int ultrastor_biosparam(struct scsi_device *, struct block_device *, sector_t, int *);
 
 
 #define ULTRASTOR_14F_MAX_SG 16
@@ -35,8 +34,8 @@
 			  detect:            ultrastor_detect, 		\
 			  info:              ultrastor_info, 		\
 			  queuecommand:      ultrastor_queuecommand,	\
-			  abort:             ultrastor_abort, 		\
-			  reset:             ultrastor_reset,		\
+			  eh_abort_handler:  ultrastor_abort, 		\
+			  eh_host_reset_handler:  ultrastor_host_reset,	\
 			  bios_param:        ultrastor_biosparam, 	\
 			  can_queue:         ULTRASTOR_MAX_CMDS,	\
 			  this_id:           0, 			\
diff -Nru a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
--- a/drivers/scsi/wd7000.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/scsi/wd7000.c	Sun Nov 10 19:28:41 2002
@@ -1240,7 +1240,7 @@
 	host->control = 0;	/* this must always shadow ASC_CONTROL */
 
 	if (WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
-		printk("wd7000_init: WAIT timed out.\n");
+		printk(KERN_ERR "wd7000_init: WAIT timed out.\n");
 		return -1;	/* -1 = not ok */
 	}
 
@@ -1249,25 +1249,25 @@
 
 		switch (diag) {
 		case 2:
-			printk("RAM failure.\n");
+			printk(KERN_ERR "RAM failure.\n");
 			break;
 		case 3:
-			printk("FIFO R/W failed\n");
+			printk(KERN_ERR "FIFO R/W failed\n");
 			break;
 		case 4:
-			printk("SBIC register R/W failed\n");
+			printk(KERN_ERR "SBIC register R/W failed\n");
 			break;
 		case 5:
-			printk("Initialization D-FF failed.\n");
+			printk(KERN_ERR "Initialization D-FF failed.\n");
 			break;
 		case 6:
-			printk("Host IRQ D-FF failed.\n");
+			printk(KERN_ERR "Host IRQ D-FF failed.\n");
 			break;
 		case 7:
-			printk("ROM checksum error.\n");
+			printk(KERN_ERR "ROM checksum error.\n");
 			break;
 		default:
-			printk("diagnostic code 0x%02Xh received.\n", diag);
+			printk(KERN_ERR "diagnostic code 0x%02Xh received.\n", diag);
 		}
 		return -1;
 	}
diff -Nru a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/serial/68328serial.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,1698 @@
+/* 68328serial.c: Serial port driver for 68328 microcontroller
+ *
+ * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
+ * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
+ * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
+ * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
+ * Copyright (C) 2002       David McCullough   <davidm@snapgear.com>
+ * Copyright (C) 2002       Greg Ungerer       <gerg@snapgear.com>
+ *
+ * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
+ * Multiple UART support        Daniel Potts <danielp@cse.unsw.edu.au>
+ * Power management support     Daniel Potts <danielp@cse.unsw.edu.au>
+ * VZ Second Serial Port enable Phil Wilshire
+ * 2.4/2.5 port                 David McCullough
+ */
+
+#include <asm/dbg.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/console.h>
+#include <linux/reboot.h>
+#include <linux/keyboard.h>
+#include <linux/init.h>
+#include <linux/pm.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/delay.h>
+#include <asm/uaccess.h>
+
+/* (es) */
+/* note: perhaps we can murge these files, so that you can just
+ * 	 define 1 of them, and they can sort that out for themselves
+ */
+#if defined(CONFIG_M68EZ328)
+#include <asm/MC68EZ328.h>
+#else
+#if defined(CONFIG_M68VZ328)
+#include <asm/MC68VZ328.h>
+#else
+#include <asm/MC68328.h>
+#endif /* CONFIG_M68VZ328 */
+#endif /* CONFIG_M68EZ328 */
+
+#include "68328serial.h"
+
+/* Turn off usage of real serial interrupt code, to "support" Copilot */
+#ifdef CONFIG_XCOPILOT_BUGS
+#undef USE_INTS
+#else
+#define USE_INTS
+#endif
+
+static struct m68k_serial m68k_soft[NR_PORTS];
+struct m86k_serial *IRQ_ports[NR_IRQS];
+
+static unsigned int uart_irqs[NR_PORTS] = UART_IRQ_DEFNS;
+
+/* multiple ports are contiguous in memory */
+m68328_uart *uart_addr = USTCNT_ADDR;
+
+struct tty_struct m68k_ttys;
+struct m68k_serial *m68k_consinfo = 0;
+
+#define M68K_CLOCK (16667000) /* FIXME: 16MHz is likely wrong */
+
+#ifdef CONFIG_CONSOLE
+extern wait_queue_head_t keypress_wait; 
+#endif
+
+struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL	1
+#define SERIAL_TYPE_CALLOUT	2
+  
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* Debugging... DEBUG_INTR is bad to use when one of the zs
+ * lines is your console ;(
+ */
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define RS_ISR_PASS_LIMIT 256
+
+#define _INLINE_ inline
+
+static void change_speed(struct m68k_serial *info);
+
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+/*
+ *	Setup for console. Argument comes from the boot command line.
+ */
+
+#if defined(CONFIG_M68EZ328ADS) || defined(CONFIG_ALMA_ANS) || defined(CONFIG_DRAGONIXVZ)
+#define	CONSOLE_BAUD_RATE	115200
+#define	DEFAULT_CBAUD		B115200
+#else
+	/* (es) */
+	/* note: this is messy, but it works, again, perhaps defined somewhere else?*/
+	#ifdef CONFIG_M68VZ328
+	#define CONSOLE_BAUD_RATE	19200
+	#define DEFAULT_CBAUD		B19200
+	#endif
+	/* (/es) */
+#endif
+
+#ifndef CONSOLE_BAUD_RATE
+#define	CONSOLE_BAUD_RATE	9600
+#define	DEFAULT_CBAUD		B9600
+#endif
+
+
+static int m68328_console_initted = 0;
+static int m68328_console_baud    = CONSOLE_BAUD_RATE;
+static int m68328_console_cbaud   = DEFAULT_CBAUD;
+
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the memcpy_fromfs blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char tmp_buf[SERIAL_XMIT_SIZE]; /* This is cheating */
+DECLARE_MUTEX(tmp_buf_sem);
+
+static inline int serial_paranoia_check(struct m68k_serial *info,
+					kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for serial struct (%d, %d) in %s\n";
+	static const char *badinfo =
+		"Warning: null m68k_serial for (%d, %d) in %s\n";
+
+	if (!info) {
+		printk(badinfo, major(device), minor(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, major(device), minor(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts
+ */
+static int baud_table[] = {
+	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+	9600, 19200, 38400, 57600, 115200, 0 };
+
+#define BAUD_TABLE_SIZE (sizeof(baud_table)/sizeof(baud_table[0]))
+
+/* Sets or clears DTR/RTS on the requested line */
+static inline void m68k_rtsdtr(struct m68k_serial *ss, int set)
+{
+	if (set) {
+		/* set the RTS/CTS line */
+	} else {
+		/* clear it */
+	}
+	return;
+}
+
+/* Utility routines */
+static inline int get_baud(struct m68k_serial *ss)
+{
+	unsigned long result = 115200;
+	unsigned short int baud = uart_addr[ss->line].ubaud;
+	if (GET_FIELD(baud, UBAUD_PRESCALER) == 0x38) result = 38400;
+	result >>= GET_FIELD(baud, UBAUD_DIVIDE);
+
+	return result;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_stop(struct tty_struct *tty)
+{
+	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+	m68328_uart *uart = &uart_addr[info->line];
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_stop"))
+		return;
+	
+	save_flags(flags); cli();
+	uart->ustcnt &= ~USTCNT_TXEN;
+	restore_flags(flags);
+}
+
+static void rs_put_char(char ch)
+{
+        int flags, loops = 0;
+
+        save_flags(flags); cli();
+
+	while (!(UTX & UTX_TX_AVAIL) && (loops < 1000)) {
+        	loops++;
+        	udelay(5);
+        }
+
+	UTX_TXDATA = ch;
+        udelay(5);
+        restore_flags(flags);
+}
+
+static void rs_start(struct tty_struct *tty)
+{
+	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+	m68328_uart *uart = &uart_addr[info->line];
+	unsigned long flags;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_start"))
+		return;
+	
+	save_flags(flags); cli();
+	if (info->xmit_cnt && info->xmit_buf && !(uart->ustcnt & USTCNT_TXEN)) {
+#ifdef USE_INTS
+		uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
+#else
+		uart->ustcnt |= USTCNT_TXEN;
+#endif
+	}
+	restore_flags(flags);
+}
+
+/* Drop into either the boot monitor or kadb upon receiving a break
+ * from keyboard/console input.
+ */
+static void batten_down_hatches(void)
+{
+	/* Drop into the debugger */
+}
+
+static _INLINE_ void status_handle(struct m68k_serial *info, unsigned short status)
+{
+#if 0
+	if(status & DCD) {
+		if((info->tty->termios->c_cflag & CRTSCTS) &&
+		   ((info->curregs[3] & AUTO_ENAB)==0)) {
+			info->curregs[3] |= AUTO_ENAB;
+			info->pendregs[3] |= AUTO_ENAB;
+			write_zsreg(info->m68k_channel, 3, info->curregs[3]);
+		}
+	} else {
+		if((info->curregs[3] & AUTO_ENAB)) {
+			info->curregs[3] &= ~AUTO_ENAB;
+			info->pendregs[3] &= ~AUTO_ENAB;
+			write_zsreg(info->m68k_channel, 3, info->curregs[3]);
+		}
+	}
+#endif
+	/* If this is console input and this is a
+	 * 'break asserted' status change interrupt
+	 * see if we can drop into the debugger
+	 */
+	if((status & URX_BREAK) && info->break_abort)
+		batten_down_hatches();
+	return;
+}
+
+static _INLINE_ void receive_chars(struct m68k_serial *info, struct pt_regs *regs, unsigned short rx)
+{
+	struct tty_struct *tty = info->tty;
+	m68328_uart *uart = &uart_addr[info->line];
+	unsigned char ch;
+
+	/*
+	 * This do { } while() loop will get ALL chars out of Rx FIFO 
+         */
+#ifndef CONFIG_XCOPILOT_BUGS
+	do {
+#endif	
+		ch = GET_FIELD(rx, URX_RXDATA);
+	
+		if(info->is_cons) {
+			if(URX_BREAK & rx) { /* whee, break received */
+				status_handle(info, rx);
+				return;
+#ifdef CONFIG_MAGIC_SYSRQ
+			} else if (ch == 0x10) { /* ^P */
+				show_state();
+				show_free_areas();
+				show_buffers();
+/*				show_net_buffers(); */
+				return;
+			} else if (ch == 0x12) { /* ^R */
+				machine_restart(NULL);
+				return;
+#endif /* CONFIG_MAGIC_SYSRQ */
+			}
+			/* It is a 'keyboard interrupt' ;-) */
+#ifdef CONFIG_CONSOLE
+			wake_up(&keypress_wait);
+#endif			
+		}
+
+		if(!tty)
+			goto clear_and_exit;
+		
+		/*
+		 * Make sure that we do not overflow the buffer
+		 */
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
+			schedule_work(&tty->flip.work);
+			return;
+		}
+
+		if(rx & URX_PARITY_ERROR) {
+			*tty->flip.flag_buf_ptr++ = TTY_PARITY;
+			status_handle(info, rx);
+		} else if(rx & URX_OVRUN) {
+			*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+			status_handle(info, rx);
+		} else if(rx & URX_FRAME_ERROR) {
+			*tty->flip.flag_buf_ptr++ = TTY_FRAME;
+			status_handle(info, rx);
+		} else {
+			*tty->flip.flag_buf_ptr++ = 0; /* XXX */
+		}
+                *tty->flip.char_buf_ptr++ = ch;
+		tty->flip.count++;
+
+#ifndef CONFIG_XCOPILOT_BUGS
+	} while((rx = uart->urx.w) & URX_DATA_READY);
+#endif
+
+	schedule_work(&tty->flip.work);
+
+clear_and_exit:
+	return;
+}
+
+static _INLINE_ void transmit_chars(struct m68k_serial *info)
+{
+	m68328_uart *uart = &uart_addr[info->line];
+
+	if (info->x_char) {
+		/* Send next char */
+		uart->utx.b.txdata = info->x_char;
+		info->x_char = 0;
+		goto clear_and_return;
+	}
+
+	if((info->xmit_cnt <= 0) || info->tty->stopped) {
+		/* That's peculiar... TX ints off */
+		uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
+		goto clear_and_return;
+	}
+
+	/* Send char */
+	uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
+	info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+	info->xmit_cnt--;
+
+	if (info->xmit_cnt < WAKEUP_CHARS)
+		schedule_work(&info->tqueue);
+
+	if(info->xmit_cnt <= 0) {
+		/* All done for now... TX ints off */
+		uart->ustcnt &= ~USTCNT_TX_INTR_MASK;
+		goto clear_and_return;
+	}
+
+clear_and_return:
+	/* Clear interrupt (should be auto)*/
+	return;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct m68k_serial * info;
+	m68328_uart *uart;
+	unsigned short rx;
+	unsigned short tx;
+
+	info = IRQ_ports[irq];
+	if(!info)
+	    return;
+
+	uart = &uart_addr[info->line];
+	rx = uart->urx.w;
+
+#ifdef USE_INTS
+	tx = uart->utx.w;
+
+	if (rx & URX_DATA_READY) receive_chars(info, regs, rx);
+	if (tx & UTX_TX_AVAIL)   transmit_chars(info);
+#else
+	receive_chars(info, regs, rx);		
+#endif
+	return;
+}
+
+static void do_softint(void *private)
+{
+	struct m68k_serial	*info = (struct m68k_serial *) private;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+#if 0
+	if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+#endif   
+}
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ * 	serial interrupt routine -> (scheduler tqueue) ->
+ * 	do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * 
+ */
+static void do_serial_hangup(void *private)
+{
+	struct m68k_serial	*info = (struct m68k_serial *) private;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	tty_hangup(tty);
+}
+
+
+static int startup(struct m68k_serial * info)
+{
+	m68328_uart *uart = &uart_addr[info->line];
+	unsigned long flags;
+	
+	if (info->flags & S_INITIALIZED)
+		return 0;
+
+	if (!info->xmit_buf) {
+		info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
+		if (!info->xmit_buf)
+			return -ENOMEM;
+	}
+
+	save_flags(flags); cli();
+
+	/*
+	 * Clear the FIFO buffers and disable them
+	 * (they will be reenabled in change_speed())
+	 */
+
+	uart->ustcnt = USTCNT_UEN;
+	info->xmit_fifo_size = 1;
+	uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_TXEN;
+	(void)uart->urx.w;
+
+	/*
+	 * Finally, enable sequencing and interrupts
+	 */
+#ifdef USE_INTS
+	uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | 
+                 USTCNT_RX_INTR_MASK | USTCNT_TX_INTR_MASK;
+#else
+	uart->ustcnt = USTCNT_UEN | USTCNT_RXEN | USTCNT_RX_INTR_MASK;
+#endif
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+	/*
+	 * and set the speed of the serial port
+	 */
+
+	change_speed(info);
+
+	info->flags |= S_INITIALIZED;
+	restore_flags(flags);
+	return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct m68k_serial * info)
+{
+	m68328_uart *uart = &uart_addr[info->line];
+	unsigned long	flags;
+
+	uart->ustcnt = 0; /* All off! */
+	if (!(info->flags & S_INITIALIZED))
+		return;
+
+	save_flags(flags); cli(); /* Disable interrupts */
+	
+	if (info->xmit_buf) {
+		free_page((unsigned long) info->xmit_buf);
+		info->xmit_buf = 0;
+	}
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	
+	info->flags &= ~S_INITIALIZED;
+	restore_flags(flags);
+}
+
+struct {
+	int divisor, prescale;
+}
+#ifndef CONFIG_M68VZ328
+ hw_baud_table[18] = {
+	{0,0}, /* 0 */
+	{0,0}, /* 50 */
+	{0,0}, /* 75 */
+	{0,0}, /* 110 */
+	{0,0}, /* 134 */
+	{0,0}, /* 150 */
+	{0,0}, /* 200 */
+	{7,0x26}, /* 300 */
+	{6,0x26}, /* 600 */
+	{5,0x26}, /* 1200 */
+	{0,0}, /* 1800 */
+	{4,0x26}, /* 2400 */
+	{3,0x26}, /* 4800 */
+	{2,0x26}, /* 9600 */
+	{1,0x26}, /* 19200 */
+	{0,0x26}, /* 38400 */
+	{1,0x38}, /* 57600 */
+	{0,0x38}, /* 115200 */
+};
+#else
+ hw_baud_table[18] = {
+                 {0,0}, /* 0 */
+                 {0,0}, /* 50 */
+                 {0,0}, /* 75 */
+                 {0,0}, /* 110 */
+                 {0,0}, /* 134 */
+                 {0,0}, /* 150 */
+                 {0,0}, /* 200 */
+                 {0,0}, /* 300 */
+                 {7,0x26}, /* 600 */
+                 {6,0x26}, /* 1200 */
+                 {0,0}, /* 1800 */
+                 {5,0x26}, /* 2400 */
+                 {4,0x26}, /* 4800 */
+                 {3,0x26}, /* 9600 */
+                 {2,0x26}, /* 19200 */
+                 {1,0x26}, /* 38400 */
+                 {0,0x26}, /* 57600 */
+                 {1,0x38}, /* 115200 */
+}; 
+#endif
+/* rate = 1036800 / ((65 - prescale) * (1<<divider)) */
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(struct m68k_serial *info)
+{
+	m68328_uart *uart = &uart_addr[info->line];
+	unsigned short port;
+	unsigned short ustcnt;
+	unsigned cflag;
+	int	i;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+	if (!(port = info->port))
+		return;
+
+	ustcnt = uart->ustcnt;
+	uart->ustcnt = ustcnt & ~USTCNT_TXEN;
+
+	i = cflag & CBAUD;
+        if (i & CBAUDEX) {
+                i = (i & ~CBAUDEX) + B38400;
+        }
+
+	info->baud = baud_table[i];
+	uart->ubaud = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) | 
+		PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
+
+	ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
+	
+	if ((cflag & CSIZE) == CS8)
+		ustcnt |= USTCNT_8_7;
+		
+	if (cflag & CSTOPB)
+		ustcnt |= USTCNT_STOP;
+
+	if (cflag & PARENB)
+		ustcnt |= USTCNT_PARITYEN;
+	if (cflag & PARODD)
+		ustcnt |= USTCNT_ODD_EVEN;
+	
+#ifdef CONFIG_SERIAL_68328_RTS_CTS
+	if (cflag & CRTSCTS) {
+		uart->utx.w &= ~ UTX_NOCTS;
+	} else {
+		uart->utx.w |= UTX_NOCTS;
+	}
+#endif
+
+	ustcnt |= USTCNT_TXEN;
+	
+	uart->ustcnt = ustcnt;
+	return;
+}
+
+/*
+ * Fair output driver allows a process to speak.
+ */
+static void rs_fair_output(void)
+{
+	int left;		/* Output no more than that */
+	unsigned long flags;
+	struct m68k_serial *info = &m68k_soft[0];
+	char c;
+
+	if (info == 0) return;
+	if (info->xmit_buf == 0) return;
+
+	save_flags(flags);  cli();
+	left = info->xmit_cnt;
+	while (left != 0) {
+		c = info->xmit_buf[info->xmit_tail];
+		info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt--;
+		restore_flags(flags);
+
+		rs_put_char(c);
+
+		save_flags(flags);  cli();
+		left = min(info->xmit_cnt, left-1);
+	}
+
+	/* Last character is being transmitted now (hopefully). */
+	udelay(5);
+
+	restore_flags(flags);
+	return;
+}
+
+/*
+ * m68k_console_print is registered for printk.
+ */
+void console_print_68328(const char *p)
+{
+	char c;
+	
+	while((c=*(p++)) != 0) {
+		if(c == '\n')
+			rs_put_char('\r');
+		rs_put_char(c);
+	}
+
+	/* Comment this if you want to have a strict interrupt-driven output */
+	rs_fair_output();
+
+	return;
+}
+
+static void rs_set_ldisc(struct tty_struct *tty)
+{
+	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "rs_set_ldisc"))
+		return;
+
+	info->is_cons = (tty->termios->c_line == N_TTY);
+	
+	printk("ttyS%d console mode %s\n", info->line, info->is_cons ? "on" : "off");
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+	m68328_uart *uart = &uart_addr[info->line];
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
+		return;
+#ifndef USE_INTS
+	for(;;) {
+#endif
+
+	/* Enable transmitter */
+	save_flags(flags); cli();
+
+	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+			!info->xmit_buf) {
+		restore_flags(flags);
+		return;
+	}
+
+#ifdef USE_INTS
+	uart->ustcnt |= USTCNT_TXEN | USTCNT_TX_INTR_MASK;
+#else
+	uart->ustcnt |= USTCNT_TXEN;
+#endif
+
+#ifdef USE_INTS
+	if (uart->utx.w & UTX_TX_AVAIL) {
+#else
+	if (1) {
+#endif
+		/* Send char */
+		uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
+		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt--;
+	}
+
+#ifndef USE_INTS
+	while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
+	}
+#endif
+	restore_flags(flags);
+}
+
+extern void console_printn(const char * b, int count);
+
+static int rs_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	int	c, total = 0;
+	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+	m68328_uart *uart = &uart_addr[info->line];
+	unsigned long flags;
+
+	if (serial_paranoia_check(info, tty->device, "rs_write"))
+		return 0;
+
+	if (!tty || !info->xmit_buf)
+		return 0;
+
+	save_flags(flags);
+	while (1) {
+		cli();		
+		c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				   SERIAL_XMIT_SIZE - info->xmit_head));
+		if (c <= 0)
+			break;
+
+		if (from_user) {
+			down(&tmp_buf_sem);
+			copy_from_user(tmp_buf, buf, c);
+			c = min(c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				       SERIAL_XMIT_SIZE - info->xmit_head));
+			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
+			up(&tmp_buf_sem);
+		} else
+			memcpy(info->xmit_buf + info->xmit_head, buf, c);
+		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt += c;
+		restore_flags(flags);
+		buf += c;
+		count -= c;
+		total += c;
+	}
+
+	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped) {
+		/* Enable transmitter */
+		cli();		
+#ifndef USE_INTS
+		while(info->xmit_cnt) {
+#endif
+
+		uart->ustcnt |= USTCNT_TXEN;
+#ifdef USE_INTS
+		uart->ustcnt |= USTCNT_TX_INTR_MASK;
+#else
+		while (!(uart->utx.w & UTX_TX_AVAIL)) udelay(5);
+#endif
+		if (uart->utx.w & UTX_TX_AVAIL) {
+			uart->utx.b.txdata = info->xmit_buf[info->xmit_tail++];
+			info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+			info->xmit_cnt--;
+		}
+
+#ifndef USE_INTS
+		}
+#endif
+		restore_flags(flags);
+	}
+	restore_flags(flags);
+	return total;
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+	int	ret;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+		return 0;
+	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	return ret;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+		return 0;
+	return info->xmit_cnt;
+}
+
+static void rs_flush_buffer(struct tty_struct *tty)
+{
+	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+		return;
+	cli();
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	sti();
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_throttle(struct tty_struct * tty)
+{
+	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+		return;
+	
+	if (I_IXOFF(tty))
+		info->x_char = STOP_CHAR(tty);
+
+	/* Turn off RTS line (do this atomic) */
+}
+
+static void rs_unthrottle(struct tty_struct * tty)
+{
+	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			info->x_char = START_CHAR(tty);
+	}
+
+	/* Assert RTS line (do this atomic) */
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct m68k_serial * info,
+			   struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+  
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = info->type;
+	tmp.line = info->line;
+	tmp.port = info->port;
+	tmp.irq = info->irq;
+	tmp.flags = info->flags;
+	tmp.baud_base = info->baud_base;
+	tmp.close_delay = info->close_delay;
+	tmp.closing_wait = info->closing_wait;
+	tmp.custom_divisor = info->custom_divisor;
+	copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+	return 0;
+}
+
+static int set_serial_info(struct m68k_serial * info,
+			   struct serial_struct * new_info)
+{
+	struct serial_struct new_serial;
+	struct m68k_serial old_info;
+	int 			retval = 0;
+
+	if (!new_info)
+		return -EFAULT;
+	copy_from_user(&new_serial,new_info,sizeof(new_serial));
+	old_info = *info;
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		if ((new_serial.baud_base != info->baud_base) ||
+		    (new_serial.type != info->type) ||
+		    (new_serial.close_delay != info->close_delay) ||
+		    ((new_serial.flags & ~S_USR_MASK) !=
+		     (info->flags & ~S_USR_MASK)))
+			return -EPERM;
+		info->flags = ((info->flags & ~S_USR_MASK) |
+			       (new_serial.flags & S_USR_MASK));
+		info->custom_divisor = new_serial.custom_divisor;
+		goto check_and_exit;
+	}
+
+	if (info->count > 1)
+		return -EBUSY;
+
+	/*
+	 * OK, past this point, all the error checking has been done.
+	 * At this point, we start making changes.....
+	 */
+
+	info->baud_base = new_serial.baud_base;
+	info->flags = ((info->flags & ~S_FLAGS) |
+			(new_serial.flags & S_FLAGS));
+	info->type = new_serial.type;
+	info->close_delay = new_serial.close_delay;
+	info->closing_wait = new_serial.closing_wait;
+
+check_and_exit:
+	retval = startup(info);
+	return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * 	    is emptied.  On bus types like RS485, the transmitter must
+ * 	    release the bus after transmitting. This must be done when
+ * 	    the transmit shift register is empty, not be done when the
+ * 	    transmit holding register is empty.  This functionality
+ * 	    allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
+{
+#ifdef CONFIG_SERIAL_68328_RTS_CTS
+	m68328_uart *uart = &uart_addr[info->line];
+#endif
+	unsigned char status;
+
+	cli();
+#ifdef CONFIG_SERIAL_68328_RTS_CTS
+	status = (uart->utx.w & UTX_CTS_STAT) ? 1 : 0;
+#else
+	status = 0;
+#endif
+	sti();
+	put_user(status,value);
+	return 0;
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(	struct m68k_serial * info, int duration)
+{
+	m68328_uart *uart = &uart_addr[info->line];
+        unsigned long flags;
+        if (!info->port)
+                return;
+        current->state = TASK_INTERRUPTIBLE;
+        save_flags(flags);
+        cli();
+#ifdef USE_INTS	
+	uart->utx.w |= UTX_SEND_BREAK;
+        schedule_timeout(duration);
+	uart->utx.w &= ~UTX_SEND_BREAK;
+#endif		
+        restore_flags(flags);
+}
+
+static int rs_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int error;
+	struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+	int retval;
+
+	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+	
+	switch (cmd) {
+		case TCSBRK:	/* SVID version: non-zero arg --> no break */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (!arg)
+				send_break(info, HZ/4);	/* 1/4 second */
+			return 0;
+		case TCSBRKP:	/* support for POSIX tcsendbreak() */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			send_break(info, arg ? arg*(HZ/10) : HZ/4);
+			return 0;
+		case TIOCGSOFTCAR:
+			error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+			if (error)
+				return error;
+			put_user(C_CLOCAL(tty) ? 1 : 0,
+				    (unsigned long *) arg);
+			return 0;
+		case TIOCSSOFTCAR:
+			get_user(arg, (unsigned long *) arg);
+			tty->termios->c_cflag =
+				((tty->termios->c_cflag & ~CLOCAL) |
+				 (arg ? CLOCAL : 0));
+			return 0;
+		case TIOCGSERIAL:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+						sizeof(struct serial_struct));
+			if (error)
+				return error;
+			return get_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSSERIAL:
+			return set_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSERGETLSR: /* Get line status register */
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+				sizeof(unsigned int));
+			if (error)
+				return error;
+			else
+			    return get_lsr_info(info, (unsigned int *) arg);
+
+		case TIOCSERGSTRUCT:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+						sizeof(struct m68k_serial));
+			if (error)
+				return error;
+			copy_to_user((struct m68k_serial *) arg,
+				    info, sizeof(struct m68k_serial));
+			return 0;
+			
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	struct m68k_serial *info = (struct m68k_serial *)tty->driver_data;
+
+	if (tty->termios->c_cflag == old_termios->c_cflag)
+		return;
+
+	change_speed(info);
+
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		rs_start(tty);
+	}
+	
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * S structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+	struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+	m68328_uart *uart = &uart_addr[info->line];
+	unsigned long flags;
+
+	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+		return;
+	
+	save_flags(flags); cli();
+	
+	if (tty_hung_up_p(filp)) {
+		restore_flags(flags);
+		return;
+	}
+	
+	if ((tty->count == 1) && (info->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  Info->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("rs_close: bad serial port count; tty->count is 1, "
+		       "info->count is %d\n", info->count);
+		info->count = 1;
+	}
+	if (--info->count < 0) {
+		printk("rs_close: bad serial port count for ttyS%d: %d\n",
+		       info->line, info->count);
+		info->count = 0;
+	}
+	if (info->count) {
+		restore_flags(flags);
+		return;
+	}
+	info->flags |= S_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & S_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+	if (info->flags & S_CALLOUT_ACTIVE)
+		info->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != S_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+
+	uart->ustcnt &= ~USTCNT_RXEN;
+	uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK);
+
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (tty->ldisc.num != ldiscs[N_TTY].num) {
+		if (tty->ldisc.close)
+			(tty->ldisc.close)(tty);
+		tty->ldisc = ldiscs[N_TTY];
+		tty->termios->c_line = N_TTY;
+		if (tty->ldisc.open)
+			(tty->ldisc.open)(tty);
+	}
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(S_NORMAL_ACTIVE|S_CALLOUT_ACTIVE|
+			 S_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	restore_flags(flags);
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void rs_hangup(struct tty_struct *tty)
+{
+	struct m68k_serial * info = (struct m68k_serial *)tty->driver_data;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+		return;
+	
+	rs_flush_buffer(tty);
+	shutdown(info);
+	info->event = 0;
+	info->count = 0;
+	info->flags &= ~(S_NORMAL_ACTIVE|S_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   struct m68k_serial *info)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int		retval;
+	int		do_clocal = 0;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (info->flags & S_CLOSING) {
+		interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		if (info->flags & S_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & S_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & S_CALLOUT_ACTIVE) &&
+		    (info->flags & S_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & S_CALLOUT_ACTIVE) &&
+		    (info->flags & S_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= S_CALLOUT_ACTIVE;
+		return 0;
+	}
+	
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & S_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= S_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & S_CALLOUT_ACTIVE) {
+		if (info->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+
+	info->count--;
+	info->blocked_open++;
+	while (1) {
+		cli();
+		if (!(info->flags & S_CALLOUT_ACTIVE))
+			m68k_rtsdtr(info, 1);
+		sti();
+		current->state = TASK_INTERRUPTIBLE;
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & S_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & S_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & S_CALLOUT_ACTIVE) &&
+		    !(info->flags & S_CLOSING) && do_clocal)
+			break;
+                if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&info->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		info->count++;
+	info->blocked_open--;
+
+	if (retval)
+		return retval;
+	info->flags |= S_NORMAL_ACTIVE;
+	return 0;
+}	
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its S structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+int rs_open(struct tty_struct *tty, struct file * filp)
+{
+	struct m68k_serial	*info;
+	int 			retval, line;
+
+	line = minor(tty->device) - tty->driver.minor_start;
+	
+	if (line >= NR_PORTS || line < 0) /* we have exactly one */
+		return -ENODEV;
+
+	info = &m68k_soft[line];
+
+	if (serial_paranoia_check(info, tty->device, "rs_open"))
+		return -ENODEV;
+
+	info->count++;
+	tty->driver_data = info;
+	info->tty = tty;
+
+	/*
+	 * Start up serial port
+	 */
+	retval = startup(info);
+	if (retval)
+		return retval;
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+		return retval;
+	}
+
+	if ((info->count == 1) && (info->flags & S_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->normal_termios;
+		else 
+			*tty->termios = info->callout_termios;
+		change_speed(info);
+	}
+
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+	return 0;
+}
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void show_serial_version(void)
+{
+	printk("MC68328 serial driver version 1.00\n");
+}
+
+#ifdef CONFIG_PM
+/* Serial Power management
+ *  The console (currently fixed at line 0) is a special case for power
+ *  management because the kernel is so chatty. The console will be 
+ *  explicitly disabled my our power manager as the last minute, so we won't
+ *  mess with it here.
+ */
+static struct pm_dev *serial_pm[NR_PORTS];
+
+static int serial_pm_callback(struct pm_dev *dev, pm_request_t request, void *data)
+{
+	struct m68k_serial *info = (struct m68k_serial *)dev->data;
+
+	if(info == NULL)
+		return -1;
+
+	/* special case for line 0 - pm restores it */
+	if(info->line == 0)
+		return 0; 
+
+	switch (request) {
+	case PM_SUSPEND:
+		shutdown(info);
+		break;
+
+	case PM_RESUME:
+		startup(info);
+		break;
+	}
+	return 0;
+}
+
+void shutdown_console(void)
+{
+	struct m68k_serial *info = &m68k_soft[0];
+
+	/* HACK: wait a bit for any pending printk's to be dumped */
+	{
+		int i = 10000;
+		while(i--);
+	}
+
+	shutdown(info);
+}
+
+void startup_console(void)
+{
+	struct m68k_serial *info = &m68k_soft[0];
+	startup(info);
+}
+#endif
+
+
+/* rs_init inits the driver */
+static int __init
+rs68328_init(void)
+{
+	int flags, i;
+	struct m68k_serial *info;
+	
+	show_serial_version();
+
+	/* Initialize the tty_driver structure */
+	/* SPARC: Not all of this is exactly right for us. */
+	
+	memset(&serial_driver, 0, sizeof(struct tty_driver));
+	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.name = "ttyS";
+	serial_driver.major = TTY_MAJOR;
+	serial_driver.minor_start = 64;
+	serial_driver.num = NR_PORTS;
+	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	serial_driver.init_termios = tty_std_termios;
+	serial_driver.init_termios.c_cflag = 
+			m68328_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.refcount = &serial_refcount;
+	serial_driver.table = serial_table;
+	serial_driver.termios = serial_termios;
+	serial_driver.termios_locked = serial_termios_locked;
+
+	serial_driver.open = rs_open;
+	serial_driver.close = rs_close;
+	serial_driver.write = rs_write;
+	serial_driver.flush_chars = rs_flush_chars;
+	serial_driver.write_room = rs_write_room;
+	serial_driver.chars_in_buffer = rs_chars_in_buffer;
+	serial_driver.flush_buffer = rs_flush_buffer;
+	serial_driver.ioctl = rs_ioctl;
+	serial_driver.throttle = rs_throttle;
+	serial_driver.unthrottle = rs_unthrottle;
+	serial_driver.set_termios = rs_set_termios;
+	serial_driver.stop = rs_stop;
+	serial_driver.start = rs_start;
+	serial_driver.hangup = rs_hangup;
+	serial_driver.set_ldisc = rs_set_ldisc;
+
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	callout_driver = serial_driver;
+	callout_driver.name = "cua";
+	callout_driver.major = TTYAUX_MAJOR;
+	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+
+	if (tty_register_driver(&serial_driver))
+		panic("Couldn't register serial driver\n");
+	if (tty_register_driver(&callout_driver))
+		panic("Couldn't register callout driver\n");
+	
+	save_flags(flags); cli();
+
+	for(i=0;i<NR_PORTS;i++) {
+
+	    info = &m68k_soft[i];
+	    info->magic = SERIAL_MAGIC;
+	    info->port = (int) &uart_addr[i];
+	    info->tty = 0;
+	    info->irq = uart_irqs[i];
+	    info->custom_divisor = 16;
+	    info->close_delay = 50;
+	    info->closing_wait = 3000;
+	    info->x_char = 0;
+	    info->event = 0;
+	    info->count = 0;
+	    info->blocked_open = 0;
+	    INIT_WORK(&info->tqueue, do_softint, info);
+	    INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
+	    info->callout_termios =callout_driver.init_termios;
+	    info->normal_termios = serial_driver.init_termios;
+	    init_waitqueue_head(&info->open_wait);
+	    init_waitqueue_head(&info->close_wait);
+	    info->line = i;
+	    info->is_cons = 1; /* Means shortcuts work */
+	    
+	    printk("%s%d at 0x%08x (irq = %d)", serial_driver.name, info->line, 
+		   info->port, info->irq);
+	    printk(" is a builtin MC68328 UART\n");
+	    
+	    IRQ_ports[info->irq] = info;	/* waste of space */
+
+#ifdef CONFIG_M68VZ328
+		if (i > 0 )
+			PJSEL &= 0xCF;  /* PSW enable second port output */
+#endif
+
+	    if (request_irq(uart_irqs[i],
+			    rs_interrupt,
+			    IRQ_FLG_STD,
+			    "M68328_UART", NULL))
+                panic("Unable to attach 68328 serial interrupt\n");
+#ifdef CONFIG_PM
+	    serial_pm[i] = pm_register(PM_SYS_DEV, PM_SYS_COM, serial_pm_callback);
+	    if (serial_pm[i])
+		    serial_pm[i]->data = info;
+#endif
+	}
+	restore_flags(flags);
+	return 0;
+}
+
+
+
+/*
+ * register_serial and unregister_serial allows for serial ports to be
+ * configured at run-time, to support PCMCIA modems.
+ */
+/* SPARC: Unused at this time, just here to make things link. */
+int register_serial(struct serial_struct *req)
+{
+	return -1;
+}
+
+void unregister_serial(int line)
+{
+	return;
+}
+	
+module_init(rs68328_init);
+/* DAVIDM module_exit(rs68328_fini); */
+
+
+
+static void m68328_set_baud(void)
+{
+	unsigned short ustcnt;
+	int	i;
+
+	ustcnt = USTCNT;
+	USTCNT = ustcnt & ~USTCNT_TXEN;
+
+again:
+	for (i = 0; i < sizeof(baud_table) / sizeof(baud_table[0]); i++)
+		if (baud_table[i] == m68328_console_baud)
+			break;
+	if (i >= sizeof(baud_table) / sizeof(baud_table[0])) {
+		m68328_console_baud = 9600;
+		goto again;
+	}
+
+	UBAUD = PUT_FIELD(UBAUD_DIVIDE,    hw_baud_table[i].divisor) | 
+		PUT_FIELD(UBAUD_PRESCALER, hw_baud_table[i].prescale);
+	ustcnt &= ~(USTCNT_PARITYEN | USTCNT_ODD_EVEN | USTCNT_STOP | USTCNT_8_7);
+	ustcnt |= USTCNT_8_7;
+	ustcnt |= USTCNT_TXEN;
+	USTCNT = ustcnt;
+	m68328_console_initted = 1;
+	return;
+}
+
+
+int m68328_console_setup(struct console *cp, char *arg)
+{
+	int		i, n = CONSOLE_BAUD_RATE;
+
+	if (!cp)
+		return(-1);
+
+	if (arg)
+		n = simple_strtoul(arg,NULL,0);
+
+	for (i = 0; i < BAUD_TABLE_SIZE; i++)
+		if (baud_table[i] == n)
+			break;
+	if (i < BAUD_TABLE_SIZE) {
+		m68328_console_baud = n;
+		m68328_console_cbaud = 0;
+		if (i > 15) {
+			m68328_console_cbaud |= CBAUDEX;
+			i -= 15;
+		}
+		m68328_console_cbaud |= i;
+	}
+
+	m68328_set_baud(); /* make sure baud rate changes */
+	return(0);
+}
+
+
+static kdev_t m68328_console_device(struct console *c)
+{
+	return mk_kdev(TTY_MAJOR, 64 + c->index);
+}
+
+
+void m68328_console_write (struct console *co, const char *str,
+			   unsigned int count)
+{
+	if (!m68328_console_initted)
+		m68328_set_baud();
+    while (count--) {
+        if (*str == '\n')
+           rs_put_char('\r');
+        rs_put_char( *str++ );
+    }
+}
+
+
+static struct console m68328_driver = {
+	name:		"ttyS",
+	write:		m68328_console_write,
+	device:		m68328_console_device,
+	setup:		m68328_console_setup,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
+};
+
+
+void m68328_console_init(void)
+{
+	register_console(&m68328_driver);
+}
+
diff -Nru a/drivers/serial/68328serial.h b/drivers/serial/68328serial.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/serial/68328serial.h	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,198 @@
+/* 68328serial.h: Definitions for the mc68328 serial driver.
+ *
+ * Copyright (C) 1995       David S. Miller    <davem@caip.rutgers.edu>
+ * Copyright (C) 1998       Kenneth Albanowski <kjahds@kjahds.com>
+ * Copyright (C) 1998, 1999 D. Jeff Dionne     <jeff@uclinux.org>
+ * Copyright (C) 1999       Vladimir Gurevich  <vgurevic@cisco.com>
+ *
+ * VZ Support/Fixes             Evan Stawnyczy <e@lineo.ca>
+ */
+
+#ifndef _MC683XX_SERIAL_H
+#define _MC683XX_SERIAL_H
+
+#include <linux/config.h>
+
+struct serial_struct {
+	int	type;
+	int	line;
+	int	port;
+	int	irq;
+	int	flags;
+	int	xmit_fifo_size;
+	int	custom_divisor;
+	int	baud_base;
+	unsigned short	close_delay;
+	char	reserved_char[2];
+	int	hub6;  /* FIXME: We don't have AT&T Hub6 boards! */
+	unsigned short	closing_wait; /* time to wait before closing */
+	unsigned short	closing_wait2; /* no longer used... */
+	int	reserved[4];
+};
+
+/*
+ * For the close wait times, 0 means wait forever for serial port to
+ * flush its output.  65535 means don't wait at all.
+ */
+#define S_CLOSING_WAIT_INF	0
+#define S_CLOSING_WAIT_NONE	65535
+
+/*
+ * Definitions for S_struct (and serial_struct) flags field
+ */
+#define S_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes 
+				   on the callout port */
+#define S_FOURPORT  0x0002	/* Set OU1, OUT2 per AST Fourport settings */
+#define S_SAK	0x0004	/* Secure Attention Key (Orange book) */
+#define S_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
+
+#define S_SPD_MASK	0x0030
+#define S_SPD_HI	0x0010	/* Use 56000 instead of 38400 bps */
+
+#define S_SPD_VHI	0x0020  /* Use 115200 instead of 38400 bps */
+#define S_SPD_CUST	0x0030  /* Use user-specified divisor */
+
+#define S_SKIP_TEST	0x0040 /* Skip UART test during autoconfiguration */
+#define S_AUTO_IRQ  0x0080 /* Do automatic IRQ during autoconfiguration */
+#define S_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
+#define S_PGRP_LOCKOUT    0x0200 /* Lock out cua opens based on pgrp */
+#define S_CALLOUT_NOHUP   0x0400 /* Don't do hangups for cua device */
+
+#define S_FLAGS	0x0FFF	/* Possible legal S flags */
+#define S_USR_MASK 0x0430	/* Legal flags that non-privileged
+				 * users can set or reset */
+
+/* Internal flags used only by kernel/chr_drv/serial.c */
+#define S_INITIALIZED	0x80000000 /* Serial port was initialized */
+#define S_CALLOUT_ACTIVE	0x40000000 /* Call out device is active */
+#define S_NORMAL_ACTIVE	0x20000000 /* Normal device is active */
+#define S_BOOT_AUTOCONF	0x10000000 /* Autoconfigure port on bootup */
+#define S_CLOSING		0x08000000 /* Serial port is closing */
+#define S_CTS_FLOW		0x04000000 /* Do CTS flow control */
+#define S_CHECK_CD		0x02000000 /* i.e., CLOCAL */
+
+/* Software state per channel */
+
+#ifdef __KERNEL__
+
+/*
+ * I believe this is the optimal setting that reduces the number of interrupts.
+ * At high speeds the output might become a little "bursted" (use USTCNT_TXHE
+ * if that bothers you), but in most cases it will not, since we try to 
+ * transmit characters every time rs_interrupt is called. Thus, quite often
+ * you'll see that a receive interrupt occures before the transmit one.
+ *                                  -- Vladimir Gurevich
+ */
+#define USTCNT_TX_INTR_MASK (USTCNT_TXEE)
+
+/*
+ * 68328 and 68EZ328 UARTS are a little bit different. EZ328 has special
+ * "Old data interrupt" which occures whenever the data stay in the FIFO
+ * longer than 30 bits time. This allows us to use FIFO without compromising
+ * latency. '328 does not have this feature and without the real  328-based
+ * board I would assume that RXRE is the safest setting.
+ *
+ * For EZ328 I use RXHE (Half empty) interrupt to reduce the number of
+ * interrupts. RXFE (receive queue full) causes the system to loose data
+ * at least at 115200 baud
+ *
+ * If your board is busy doing other stuff, you might consider to use
+ * RXRE (data ready intrrupt) instead.
+ *
+ * The other option is to make these INTR masks run-time configurable, so
+ * that people can dynamically adapt them according to the current usage.
+ *                                  -- Vladimir Gurevich
+ */
+
+/* (es) */
+#if defined(CONFIG_M68EZ328) || defined(CONFIG_M68VZ328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXHE | USTCNT_ODEN)
+#elif defined(CONFIG_M68328)
+#define USTCNT_RX_INTR_MASK (USTCNT_RXRE)
+#else
+#error Please, define the Rx interrupt events for your CPU
+#endif
+/* (/es) */
+
+/*
+ * This is our internal structure for each serial port's state.
+ * 
+ * Many fields are paralleled by the structure used by the serial_struct
+ * structure.
+ *
+ * For definitions of the flags field, see tty.h
+ */
+
+struct m68k_serial {
+	char soft_carrier;  /* Use soft carrier on this channel */
+	char break_abort;   /* Is serial console in, so process brk/abrt */
+	char is_cons;       /* Is this our console. */
+
+	/* We need to know the current clock divisor
+	 * to read the bps rate the chip has currently
+	 * loaded.
+	 */
+	unsigned char clk_divisor;  /* May be 1, 16, 32, or 64 */
+	int baud;
+	int			magic;
+	int			baud_base;
+	int			port;
+	int			irq;
+	int			flags; 		/* defined in tty.h */
+	int			type; 		/* UART type */
+	struct tty_struct 	*tty;
+	int			read_status_mask;
+	int			ignore_status_mask;
+	int			timeout;
+	int			xmit_fifo_size;
+	int			custom_divisor;
+	int			x_char;	/* xon/xoff character */
+	int			close_delay;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
+	unsigned long		event;
+	unsigned long		last_active;
+	int			line;
+	int			count;	    /* # of fd on device */
+	int			blocked_open; /* # of blocked opens */
+	long			session; /* Session of opening process */
+	long			pgrp; /* pgrp of opening process */
+	unsigned char 		*xmit_buf;
+	int			xmit_head;
+	int			xmit_tail;
+	int			xmit_cnt;
+	struct workqueue	tqueue;
+	struct workqueue	tqueue_hangup;
+	struct termios		normal_termios;
+	struct termios		callout_termios;
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
+};
+
+
+#define SERIAL_MAGIC 0x5301
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE 4096
+
+/*
+ * Events are used to schedule things to happen at timer-interrupt
+ * time, instead of at rs interrupt time.
+ */
+#define RS_EVENT_WRITE_WAKEUP	0
+
+/* 
+ * Define the number of ports supported and their irqs.
+ */
+#ifndef CONFIG_68328_SERIAL_UART2
+#define NR_PORTS 1
+#define UART_IRQ_DEFNS {UART_IRQ_NUM}
+#else
+#define NR_PORTS 2
+#define UART_IRQ_DEFNS {UART1_IRQ_NUM, UART2_IRQ_NUM}
+#endif
+
+#endif /* __KERNEL__ */
+#endif /* !(_MC683XX_SERIAL_H) */
diff -Nru a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/serial/68360serial.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,3197 @@
+/*
+ *  UART driver for 68360 CPM SCC or SMC
+ *  Copyright (c) 2000 D. Jeff Dionne <jeff@uclinux.org>,
+ *  Copyright (c) 2000 Michael Leslie <mleslie@lineo.ca>
+ *  Copyright (c) 1997 Dan Malek <dmalek@jlc.net>
+ *
+ * I used the serial.c driver as the framework for this driver.
+ * Give credit to those guys.
+ * The original code was written for the MBX860 board.  I tried to make
+ * it generic, but there may be some assumptions in the structures that
+ * have to be fixed later.
+ * To save porting time, I did not bother to change any object names
+ * that are not accessed outside of this file.
+ * It still needs lots of work........When it was easy, I included code
+ * to support the SCCs, but this has never been tested, nor is it complete.
+ * Only the SCCs support modem control, so that is not complete either.
+ *
+ * This module exports the following rs232 io functions:
+ *
+ *	int rs_360_init(void);
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serialP.h> 
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/ptrace.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/irq.h>
+#include <linux/compatmac.h>
+#include <asm/m68360.h>
+#include <asm/commproc.h>
+
+ 
+#ifdef CONFIG_KGDB
+extern void breakpoint(void);
+extern void set_debug_traps(void);
+extern int  kgdb_output_string (const char* s, unsigned int count);
+#endif
+
+
+/* #ifdef CONFIG_SERIAL_CONSOLE */ /* This seems to be a post 2.0 thing - mles */
+#include <linux/console.h>
+
+/* this defines the index into rs_table for the port to use
+ */
+#ifndef CONFIG_SERIAL_CONSOLE_PORT
+#define CONFIG_SERIAL_CONSOLE_PORT	1 /* ie SMC2 - note USE_SMC2 must be defined */
+#endif
+/* #endif */
+
+#if 0
+/* SCC2 for console
+ */
+#undef CONFIG_SERIAL_CONSOLE_PORT
+#define CONFIG_SERIAL_CONSOLE_PORT	2
+#endif
+
+
+#define TX_WAKEUP	ASYNC_SHARE_IRQ
+
+static char *serial_name = "CPM UART driver";
+static char *serial_version = "0.03";
+
+static DECLARE_TASK_QUEUE(tq_serial);
+
+static struct tty_driver serial_driver, callout_driver;
+static int serial_refcount;
+int serial_console_setup(struct console *co, char *options);
+
+/*
+ * Serial driver configuration section.  Here are the various options:
+ */
+#define SERIAL_PARANOIA_CHECK
+#define CONFIG_SERIAL_NOPAUSE_IO
+#define SERIAL_DO_RESTART
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+
+#define _INLINE_ inline
+  
+#define DBG_CNT(s)
+
+/* We overload some of the items in the data structure to meet our
+ * needs.  For example, the port address is the CPM parameter ram
+ * offset for the SCC or SMC.  The maximum number of ports is 4 SCCs and
+ * 2 SMCs.  The "hub6" field is used to indicate the channel number, with
+ * a flag indicating SCC or SMC, and the number is used as an index into
+ * the CPM parameter area for this device.
+ * The "type" field is currently set to 0, for PORT_UNKNOWN.  It is
+ * not currently used.  I should probably use it to indicate the port
+ * type of SMC or SCC.
+ * The SMCs do not support any modem control signals.
+ */
+#define smc_scc_num	hub6
+#define NUM_IS_SCC	((int)0x00010000)
+#define PORT_NUM(P)	((P) & 0x0000ffff)
+
+
+#if defined (CONFIG_UCQUICC)
+
+volatile extern void *_periph_base;
+/* sipex transceiver
+ *   mode bits for       are on pins
+ *
+ *    SCC2                d16..19
+ *    SCC3                d20..23
+ *    SCC4                d24..27
+ */
+#define SIPEX_MODE(n,m) ((m & 0x0f)<<(16+4*(n-1)))
+
+static uint sipex_mode_bits = 0x00000000;
+
+#endif
+
+/* There is no `serial_state' defined back here in 2.0.
+ * Try to get by with serial_struct
+ */
+/* #define serial_state serial_struct */
+
+/* 2.4 -> 2.0 portability problem: async_icount in 2.4 has a few
+ * extras: */
+
+#if 0
+struct async_icount_24 {
+	__u32   cts, dsr, rng, dcd, tx, rx;
+	__u32   frame, parity, overrun, brk;
+	__u32   buf_overrun;
+} icount;
+#endif
+
+#if 0
+
+struct serial_state {
+        int     magic;
+        int     baud_base;
+        unsigned long   port;
+        int     irq;
+        int     flags;
+        int     hub6;
+        int     type;
+        int     line;
+        int     revision;       /* Chip revision (950) */
+        int     xmit_fifo_size;
+        int     custom_divisor;
+        int     count;
+        u8      *iomem_base;
+        u16     iomem_reg_shift;
+        unsigned short  close_delay;
+        unsigned short  closing_wait; /* time to wait before closing */
+        struct async_icount_24     icount; 
+        struct termios          normal_termios;
+        struct termios          callout_termios;
+        int     io_type;
+        struct async_struct *info;
+};
+#endif
+
+#define SSTATE_MAGIC 0x5302
+
+
+
+/* SMC2 is sometimes used for low performance TDM interfaces.  Define
+ * this as 1 if you want SMC2 as a serial port UART managed by this driver.
+ * Define this as 0 if you wish to use SMC2 for something else.
+ */
+#define USE_SMC2 1
+
+#if 0
+/* Define SCC to ttySx mapping. */
+#define SCC_NUM_BASE	(USE_SMC2 + 1)	/* SCC base tty "number" */
+
+/* Define which SCC is the first one to use for a serial port.  These
+ * are 0-based numbers, i.e. this assumes the first SCC (SCC1) is used
+ * for Ethernet, and the first available SCC for serial UART is SCC2.
+ * NOTE:  IF YOU CHANGE THIS, you have to change the PROFF_xxx and
+ * interrupt vectors in the table below to match.
+ */
+#define SCC_IDX_BASE	1	/* table index */
+#endif
+
+
+/* Processors other than the 860 only get SMCs configured by default.
+ * Either they don't have SCCs or they are allocated somewhere else.
+ * Of course, there are now 860s without some SCCs, so we will need to
+ * address that someday.
+ * The Embedded Planet Multimedia I/O cards use TDM interfaces to the
+ * stereo codec parts, and we use SMC2 to help support that.
+ */
+static struct serial_state rs_table[] = {
+/*  type   line   PORT           IRQ       FLAGS  smc_scc_num (F.K.A. hub6) */
+	{  0,     0, PRSLOT_SMC1, CPMVEC_SMC1,   0,    0 }    /* SMC1 ttyS0 */
+#if USE_SMC2
+	,{ 0,     0, PRSLOT_SMC2, CPMVEC_SMC2,   0,    1 }     /* SMC2 ttyS1 */
+#endif
+
+#if defined(CONFIG_SERIAL_68360_SCC)
+	,{ 0,     0, PRSLOT_SCC2, CPMVEC_SCC2,   0, (NUM_IS_SCC | 1) }    /* SCC2 ttyS2 */
+	,{ 0,     0, PRSLOT_SCC3, CPMVEC_SCC3,   0, (NUM_IS_SCC | 2) }    /* SCC3 ttyS3 */
+	,{ 0,     0, PRSLOT_SCC4, CPMVEC_SCC4,   0, (NUM_IS_SCC | 3) }    /* SCC4 ttyS4 */
+#endif
+};
+
+#define NR_PORTS	(sizeof(rs_table)/sizeof(struct serial_state))
+
+static struct tty_struct *serial_table[NR_PORTS];
+static struct termios *serial_termios[NR_PORTS];
+static struct termios *serial_termios_locked[NR_PORTS];
+
+/* The number of buffer descriptors and their sizes.
+ */
+#define RX_NUM_FIFO	4
+#define RX_BUF_SIZE	32
+#define TX_NUM_FIFO	4
+#define TX_BUF_SIZE	32
+
+#define CONSOLE_NUM_FIFO 2
+#define CONSOLE_BUF_SIZE 4
+
+char *console_fifos[CONSOLE_NUM_FIFO * CONSOLE_BUF_SIZE];
+
+/* The async_struct in serial.h does not really give us what we
+ * need, so define our own here.
+ */
+typedef struct serial_info {
+	int			magic;
+	int			flags;
+
+	struct serial_state		*state;
+ 	/* struct serial_struct	*state; */
+ 	/* struct async_struct	*state; */
+	
+	struct tty_struct 	*tty;
+	int			read_status_mask;
+	int			ignore_status_mask;
+	int			timeout;
+	int			line;
+	int			x_char;	/* xon/xoff character */
+	int			close_delay;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
+	unsigned long		event;
+	unsigned long		last_active;
+	int			blocked_open; /* # of blocked opens */
+	long			session; /* Session of opening process */
+	long			pgrp; /* pgrp of opening process */
+	struct tq_struct	tqueue;
+	struct tq_struct	tqueue_hangup;
+ 	wait_queue_head_t	open_wait; 
+ 	wait_queue_head_t	close_wait; 
+/*	struct wait_queue     *open_wait; */
+/*	struct wait_queue	   *close_wait;i */
+
+	
+/* CPM Buffer Descriptor pointers.
+	*/
+	QUICC_BD			*rx_bd_base;
+	QUICC_BD			*rx_cur;
+	QUICC_BD			*tx_bd_base;
+	QUICC_BD			*tx_cur;
+} ser_info_t;
+
+
+/* since kmalloc_init() does not get called until much after this initialization: */
+static ser_info_t  quicc_ser_info[NR_PORTS];
+static char rx_buf_pool[NR_PORTS * RX_NUM_FIFO * RX_BUF_SIZE];
+static char tx_buf_pool[NR_PORTS * TX_NUM_FIFO * TX_BUF_SIZE];
+
+static void change_speed(ser_info_t *info);
+static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout);
+
+static inline int serial_paranoia_check(ser_info_t *info,
+					kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"Warning: bad magic number for serial struct (%s) in %s\n";
+	static const char *badinfo =
+		"Warning: null async_struct for (%s) in %s\n";
+
+	if (!info) {
+		printk(badinfo, kdevname(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, kdevname(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts,
+ * indexed by the termio value.  The generic CPM functions are responsible
+ * for setting and assigning baud rate generators for us.
+ */
+static int baud_table[] = {
+	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+	9600, 19200, 38400, 57600, 115200, 230400, 460800, 0 };
+
+/* This sucks. There is a better way: */
+#if defined(CONFIG_CONSOLE_9600)
+  #define CONSOLE_BAUDRATE 9600
+#elif defined(CONFIG_CONSOLE_19200)
+  #define CONSOLE_BAUDRATE 19200
+#elif defined(CONFIG_CONSOLE_115200)
+  #define CONSOLE_BAUDRATE 115200
+#else
+#error "console baud rate undefined"
+#endif
+
+/*
+ * ------------------------------------------------------------
+ * rs_stop() and rs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void rs_360_stop(struct tty_struct *tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	int	idx;
+	unsigned long flags;
+ 	volatile struct scc_regs *sccp;
+ 	volatile struct smc_regs *smcp;
+
+	if (serial_paranoia_check(info, tty->device, "rs_stop"))
+		return;
+	
+	local_irq_save(flags);
+	idx = PORT_NUM(info->state->smc_scc_num);
+	if (info->state->smc_scc_num & NUM_IS_SCC) {
+		sccp = &pquicc->scc_regs[idx];
+		sccp->scc_sccm &= ~UART_SCCM_TX;
+	} else {
+		/* smcp = &cpmp->cp_smc[idx]; */
+		smcp = &pquicc->smc_regs[idx];
+		smcp->smc_smcm &= ~SMCM_TX;
+	}
+	local_irq_restore(flags);
+}
+
+
+static void rs_360_start(struct tty_struct *tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	int	idx;
+	unsigned long flags;
+	volatile struct scc_regs *sccp;
+	volatile struct smc_regs *smcp;
+
+	if (serial_paranoia_check(info, tty->device, "rs_stop"))
+		return;
+	
+	local_irq_save(flags);
+	idx = PORT_NUM(info->state->smc_scc_num);
+	if (info->state->smc_scc_num & NUM_IS_SCC) {
+		sccp = &pquicc->scc_regs[idx];
+		sccp->scc_sccm |= UART_SCCM_TX;
+	} else {
+		smcp = &pquicc->smc_regs[idx];
+		smcp->smc_smcm |= SMCM_TX;
+	}
+	local_irq_restore(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * rs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: rs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * rs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used by the interrupt handler to schedule
+ * processing in the software interrupt portion of the driver.
+ */
+static _INLINE_ void rs_sched_event(ser_info_t *info,
+				  int event)
+{
+	info->event |= 1 << event;
+	queue_task(&info->tqueue, &tq_serial);
+	mark_bh(SERIAL_BH);
+}
+
+static _INLINE_ void receive_chars(ser_info_t *info)
+{
+	struct tty_struct *tty = info->tty;
+	unsigned char ch, *cp;
+	/*int	ignored = 0;*/
+	int	i;
+	ushort	status;
+	 struct	async_icount *icount; 
+	/* struct	async_icount_24 *icount; */
+	volatile QUICC_BD	*bdp;
+
+	icount = &info->state->icount;
+
+	/* Just loop through the closed BDs and copy the characters into
+	 * the buffer.
+	 */
+	bdp = info->rx_cur;
+	for (;;) {
+		if (bdp->status & BD_SC_EMPTY)	/* If this one is empty */
+			break;			/*   we are all done */
+
+		/* The read status mask tell us what we should do with
+		 * incoming characters, especially if errors occur.
+		 * One special case is the use of BD_SC_EMPTY.  If
+		 * this is not set, we are supposed to be ignoring
+		 * inputs.  In this case, just mark the buffer empty and
+		 * continue.
+		 */
+		if (!(info->read_status_mask & BD_SC_EMPTY)) {
+			bdp->status |= BD_SC_EMPTY;
+			bdp->status &=
+				~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
+
+			if (bdp->status & BD_SC_WRAP)
+				bdp = info->rx_bd_base;
+			else
+				bdp++;
+			continue;
+		}
+
+		/* Get the number of characters and the buffer pointer.
+		*/
+		i = bdp->length;
+		/* cp = (unsigned char *)__va(bdp->buf); */
+		cp = (char *)bdp->buf;
+		status = bdp->status;
+
+		/* Check to see if there is room in the tty buffer for
+		 * the characters in our BD buffer.  If not, we exit
+		 * now, leaving the BD with the characters.  We'll pick
+		 * them up again on the next receive interrupt (which could
+		 * be a timeout).
+		 */
+		if ((tty->flip.count + i) >= TTY_FLIPBUF_SIZE)
+			break;
+
+		while (i-- > 0) {
+			ch = *cp++;
+			*tty->flip.char_buf_ptr = ch;
+			icount->rx++;
+
+#ifdef SERIAL_DEBUG_INTR
+			printk("DR%02x:%02x...", ch, status);
+#endif
+			*tty->flip.flag_buf_ptr = 0;
+			if (status & (BD_SC_BR | BD_SC_FR |
+				       BD_SC_PR | BD_SC_OV)) {
+				/*
+				 * For statistics only
+				 */
+				if (status & BD_SC_BR)
+					icount->brk++;
+				else if (status & BD_SC_PR)
+					icount->parity++;
+				else if (status & BD_SC_FR)
+					icount->frame++;
+				if (status & BD_SC_OV)
+					icount->overrun++;
+
+				/*
+				 * Now check to see if character should be
+				 * ignored, and mask off conditions which
+				 * should be ignored.
+				if (status & info->ignore_status_mask) {
+					if (++ignored > 100)
+						break;
+					continue;
+				}
+				 */
+				status &= info->read_status_mask;
+		
+				if (status & (BD_SC_BR)) {
+#ifdef SERIAL_DEBUG_INTR
+					printk("handling break....");
+#endif
+					*tty->flip.flag_buf_ptr = TTY_BREAK;
+					if (info->flags & ASYNC_SAK)
+						do_SAK(tty);
+				} else if (status & BD_SC_PR)
+					*tty->flip.flag_buf_ptr = TTY_PARITY;
+				else if (status & BD_SC_FR)
+					*tty->flip.flag_buf_ptr = TTY_FRAME;
+				if (status & BD_SC_OV) {
+					/*
+					 * Overrun is special, since it's
+					 * reported immediately, and doesn't
+					 * affect the current character
+					 */
+					if (tty->flip.count < TTY_FLIPBUF_SIZE) {
+						tty->flip.count++;
+						tty->flip.flag_buf_ptr++;
+						tty->flip.char_buf_ptr++;
+						*tty->flip.flag_buf_ptr =
+								TTY_OVERRUN;
+					}
+				}
+			}
+			if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+				break;
+
+			tty->flip.flag_buf_ptr++;
+			tty->flip.char_buf_ptr++;
+			tty->flip.count++;
+		}
+
+		/* This BD is ready to be used again.  Clear status.
+		 * Get next BD.
+		 */
+		bdp->status |= BD_SC_EMPTY;
+		bdp->status &= ~(BD_SC_BR | BD_SC_FR | BD_SC_PR | BD_SC_OV);
+
+		if (bdp->status & BD_SC_WRAP)
+			bdp = info->rx_bd_base;
+		else
+			bdp++;
+	}
+
+	info->rx_cur = (QUICC_BD *)bdp;
+
+	queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+static _INLINE_ void receive_break(ser_info_t *info)
+{
+	struct tty_struct *tty = info->tty;
+
+	info->state->icount.brk++;
+	/* Check to see if there is room in the tty buffer for
+	 * the break.  If not, we exit now, losing the break.  FIXME
+	 */
+	if ((tty->flip.count + 1) >= TTY_FLIPBUF_SIZE)
+		return;
+	*(tty->flip.flag_buf_ptr++) = TTY_BREAK;
+	*(tty->flip.char_buf_ptr++) = 0;
+	tty->flip.count++;
+
+	queue_task(&tty->flip.tqueue, &tq_timer);
+}
+
+static _INLINE_ void transmit_chars(ser_info_t *info)
+{
+
+	if ((info->flags & TX_WAKEUP) ||
+	    (info->tty->flags & (1 << TTY_DO_WRITE_WAKEUP))) {
+		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+	}
+
+#ifdef SERIAL_DEBUG_INTR
+	printk("THRE...");
+#endif
+}
+
+#ifdef notdef
+	/* I need to do this for the SCCs, so it is left as a reminder.
+	*/
+static _INLINE_ void check_modem_status(struct async_struct *info)
+{
+	int	status;
+	/* struct	async_icount *icount; */
+	struct	async_icount_24 *icount;
+	
+	status = serial_in(info, UART_MSR);
+
+	if (status & UART_MSR_ANY_DELTA) {
+		icount = &info->state->icount;
+		/* update input line counters */
+		if (status & UART_MSR_TERI)
+			icount->rng++;
+		if (status & UART_MSR_DDSR)
+			icount->dsr++;
+		if (status & UART_MSR_DDCD) {
+			icount->dcd++;
+#ifdef CONFIG_HARD_PPS
+			if ((info->flags & ASYNC_HARDPPS_CD) &&
+			    (status & UART_MSR_DCD))
+				hardpps();
+#endif
+		}
+		if (status & UART_MSR_DCTS)
+			icount->cts++;
+		wake_up_interruptible(&info->delta_msr_wait);
+	}
+
+	if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) {
+#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR))
+		printk("ttys%d CD now %s...", info->line,
+		       (status & UART_MSR_DCD) ? "on" : "off");
+#endif		
+		if (status & UART_MSR_DCD)
+			wake_up_interruptible(&info->open_wait);
+		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+			   (info->flags & ASYNC_CALLOUT_NOHUP))) {
+#ifdef SERIAL_DEBUG_OPEN
+			printk("scheduling hangup...");
+#endif
+			queue_task(&info->tqueue_hangup,
+					   &tq_scheduler);
+		}
+	}
+	if (info->flags & ASYNC_CTS_FLOW) {
+		if (info->tty->hw_stopped) {
+			if (status & UART_MSR_CTS) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+				printk("CTS tx start...");
+#endif
+				info->tty->hw_stopped = 0;
+				info->IER |= UART_IER_THRI;
+				serial_out(info, UART_IER, info->IER);
+				rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
+				return;
+			}
+		} else {
+			if (!(status & UART_MSR_CTS)) {
+#if (defined(SERIAL_DEBUG_INTR) || defined(SERIAL_DEBUG_FLOW))
+				printk("CTS tx stop...");
+#endif
+				info->tty->hw_stopped = 1;
+				info->IER &= ~UART_IER_THRI;
+				serial_out(info, UART_IER, info->IER);
+			}
+		}
+	}
+}
+#endif
+
+/*
+ * This is the serial driver's interrupt routine for a single port
+ */
+/* static void rs_360_interrupt(void *dev_id) */ /* until and if we start servicing irqs here */
+static void rs_360_interrupt(int vec, void *dev_id, struct pt_regs *fp)
+{
+	u_char	events;
+	int	idx;
+	ser_info_t *info;
+	volatile struct smc_regs *smcp;
+	volatile struct scc_regs *sccp;
+	
+	info = (ser_info_t *)dev_id;
+
+	idx = PORT_NUM(info->state->smc_scc_num);
+	if (info->state->smc_scc_num & NUM_IS_SCC) {
+		sccp = &pquicc->scc_regs[idx];
+		events = sccp->scc_scce;
+		if (events & SCCM_RX)
+			receive_chars(info);
+		if (events & SCCM_TX)
+			transmit_chars(info);
+		sccp->scc_scce = events;
+	} else {
+		smcp = &pquicc->smc_regs[idx];
+		events = smcp->smc_smce;
+		if (events & SMCM_BRKE)
+			receive_break(info);
+		if (events & SMCM_RX)
+			receive_chars(info);
+		if (events & SMCM_TX)
+			transmit_chars(info);
+		smcp->smc_smce = events;
+	}
+	
+#ifdef SERIAL_DEBUG_INTR
+	printk("rs_interrupt_single(%d, %x)...",
+					info->state->smc_scc_num, events);
+#endif
+#ifdef modem_control
+	check_modem_status(info);
+#endif
+	info->last_active = jiffies;
+#ifdef SERIAL_DEBUG_INTR
+	printk("end.\n");
+#endif
+}
+
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+/*
+ * This routine is used to handle the "bottom half" processing for the
+ * serial driver, known also the "software interrupt" processing.
+ * This processing is done at the kernel interrupt level, after the
+ * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This
+ * is where time-consuming activities which can not be done in the
+ * interrupt driver proper are done; the interrupt driver schedules
+ * them using rs_sched_event(), and they get done here.
+ */
+static void do_serial_bh(void)
+{
+	run_task_queue(&tq_serial);
+}
+
+static void do_softint(void *private_)
+{
+	ser_info_t	*info = (ser_info_t *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+
+
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred.  The path of
+ * hangup processing is:
+ *
+ * 	serial interrupt routine -> (scheduler tqueue) ->
+ * 	do_serial_hangup() -> tty->hangup() -> rs_hangup()
+ * 
+ */
+static void do_serial_hangup(void *private_)
+{
+	struct async_struct	*info = (struct async_struct *) private_;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	tty_hangup(tty);
+}
+
+/*static void rs_360_timer(void)
+{
+	printk("rs_360_timer\n");
+}*/
+
+
+static int startup(ser_info_t *info)
+{
+	unsigned long flags;
+	int	retval=0;
+	int	idx;
+	/*struct serial_state *state = info->state;*/
+	volatile struct smc_regs *smcp;
+	volatile struct scc_regs *sccp;
+	volatile struct smc_uart_pram	*up;
+	volatile struct uart_pram	    *scup;
+
+
+	local_irq_save(flags);
+
+	if (info->flags & ASYNC_INITIALIZED) {
+		goto errout;
+	}
+
+#ifdef maybe
+	if (!state->port || !state->type) {
+		if (info->tty)
+			set_bit(TTY_IO_ERROR, &info->tty->flags);
+		goto errout;
+	}
+#endif
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttys%d (irq %d)...", info->line, state->irq);
+#endif
+
+
+#ifdef modem_control
+	info->MCR = 0;
+	if (info->tty->termios->c_cflag & CBAUD)
+		info->MCR = UART_MCR_DTR | UART_MCR_RTS;
+#endif
+	
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	/*
+	 * and set the speed of the serial port
+	 */
+	change_speed(info);
+
+	idx = PORT_NUM(info->state->smc_scc_num);
+	if (info->state->smc_scc_num & NUM_IS_SCC) {
+		sccp = &pquicc->scc_regs[idx];
+		scup = &pquicc->pram[info->state->port].scc.pscc.u;
+
+		scup->mrblr = RX_BUF_SIZE;
+		scup->max_idl = RX_BUF_SIZE;
+
+		sccp->scc_sccm |= (UART_SCCM_TX | UART_SCCM_RX);
+		sccp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	} else {
+		smcp = &pquicc->smc_regs[idx];
+
+		/* Enable interrupts and I/O.
+		*/
+		smcp->smc_smcm |= (SMCM_RX | SMCM_TX);
+		smcp->smc_smcmr |= (SMCMR_REN | SMCMR_TEN);
+
+		/* We can tune the buffer length and idle characters
+		 * to take advantage of the entire incoming buffer size.
+		 * If mrblr is something other than 1, maxidl has to be
+		 * non-zero or we never get an interrupt.  The maxidl
+		 * is the number of character times we wait after reception
+		 * of the last character before we decide no more characters
+		 * are coming.
+		 */
+		/* up = (smc_uart_t *)&pquicc->cp_dparam[state->port]; */
+		/* holy unionized structures, Batman: */
+		up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
+
+		up->mrblr = RX_BUF_SIZE;
+		up->max_idl = RX_BUF_SIZE;
+
+		up->brkcr = 1;	/* number of break chars */
+	}
+
+	info->flags |= ASYNC_INITIALIZED;
+	local_irq_restore(flags);
+	return 0;
+	
+errout:
+	local_irq_restore(flags);
+	return retval;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(ser_info_t *info)
+{
+	unsigned long	flags;
+	struct serial_state *state;
+	int		idx;
+	volatile struct smc_regs	*smcp;
+	volatile struct scc_regs	*sccp;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+	state = info->state;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Shutting down serial port %d (irq %d)....", info->line,
+	       state->irq);
+#endif
+	
+	local_irq_save(flags);
+
+	idx = PORT_NUM(state->smc_scc_num);
+	if (state->smc_scc_num & NUM_IS_SCC) {
+		sccp = &pquicc->scc_regs[idx];
+		sccp->scc_gsmr.w.low &= ~(SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#ifdef CONFIG_SERIAL_CONSOLE
+		/* We can't disable the transmitter if this is the
+		 * system console.
+		 */
+		if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
+#endif
+		sccp->scc_sccm &= ~(UART_SCCM_TX | UART_SCCM_RX);
+	} else {
+		smcp = &pquicc->smc_regs[idx];
+
+		/* Disable interrupts and I/O.
+		 */
+		smcp->smc_smcm &= ~(SMCM_RX | SMCM_TX);
+#ifdef CONFIG_SERIAL_CONSOLE
+		/* We can't disable the transmitter if this is the
+		 * system console.
+		 */
+		if ((state - rs_table) != CONFIG_SERIAL_CONSOLE_PORT)
+#endif
+			smcp->smc_smcmr &= ~(SMCMR_REN | SMCMR_TEN);
+	}
+	
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+
+	info->flags &= ~ASYNC_INITIALIZED;
+	local_irq_restore(flags);
+}
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void change_speed(ser_info_t *info)
+{
+	int	baud_rate;
+	unsigned cflag, cval, scval, prev_mode;
+	int	i, bits, sbits, idx;
+	unsigned long	flags;
+	struct serial_state *state;
+	volatile struct smc_regs	*smcp;
+	volatile struct scc_regs	*sccp;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+
+	state = info->state;
+
+	/* Character length programmed into the mode register is the
+	 * sum of: 1 start bit, number of data bits, 0 or 1 parity bit,
+	 * 1 or 2 stop bits, minus 1.
+	 * The value 'bits' counts this for us.
+	 */
+	cval = 0;
+	scval = 0;
+
+	/* byte size and parity */
+	switch (cflag & CSIZE) {
+	      case CS5: bits = 5; break;
+	      case CS6: bits = 6; break;
+	      case CS7: bits = 7; break;
+	      case CS8: bits = 8; break;
+	      /* Never happens, but GCC is too dumb to figure it out */
+	      default:  bits = 8; break;
+	}
+	sbits = bits - 5;
+
+	if (cflag & CSTOPB) {
+		cval |= SMCMR_SL;	/* Two stops */
+		scval |= SCU_PMSR_SL;
+		bits++;
+	}
+	if (cflag & PARENB) {
+		cval |= SMCMR_PEN;
+		scval |= SCU_PMSR_PEN;
+		bits++;
+	}
+	if (!(cflag & PARODD)) {
+		cval |= SMCMR_PM_EVEN;
+		scval |= (SCU_PMSR_REVP | SCU_PMSR_TEVP);
+	}
+
+	/* Determine divisor based on baud rate */
+	i = cflag & CBAUD;
+	if (i >= (sizeof(baud_table)/sizeof(int)))
+		baud_rate = 9600;
+	else
+		baud_rate = baud_table[i];
+
+	info->timeout = (TX_BUF_SIZE*HZ*bits);
+	info->timeout += HZ/50;		/* Add .02 seconds of slop */
+
+#ifdef modem_control
+	/* CTS flow control flag and modem status interrupts */
+	info->IER &= ~UART_IER_MSI;
+	if (info->flags & ASYNC_HARDPPS_CD)
+		info->IER |= UART_IER_MSI;
+	if (cflag & CRTSCTS) {
+		info->flags |= ASYNC_CTS_FLOW;
+		info->IER |= UART_IER_MSI;
+	} else
+		info->flags &= ~ASYNC_CTS_FLOW;
+	if (cflag & CLOCAL)
+		info->flags &= ~ASYNC_CHECK_CD;
+	else {
+		info->flags |= ASYNC_CHECK_CD;
+		info->IER |= UART_IER_MSI;
+	}
+	serial_out(info, UART_IER, info->IER);
+#endif
+
+	/*
+	 * Set up parity check flag
+	 */
+#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
+
+	info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV);
+	if (I_INPCK(info->tty))
+		info->read_status_mask |= BD_SC_FR | BD_SC_PR;
+	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
+		info->read_status_mask |= BD_SC_BR;
+	
+	/*
+	 * Characters to ignore
+	 */
+	info->ignore_status_mask = 0;
+	if (I_IGNPAR(info->tty))
+		info->ignore_status_mask |= BD_SC_PR | BD_SC_FR;
+	if (I_IGNBRK(info->tty)) {
+		info->ignore_status_mask |= BD_SC_BR;
+		/*
+		 * If we're ignore parity and break indicators, ignore 
+		 * overruns too.  (For real raw support).
+		 */
+		if (I_IGNPAR(info->tty))
+			info->ignore_status_mask |= BD_SC_OV;
+	}
+	/*
+	 * !!! ignore all characters if CREAD is not set
+	 */
+	if ((cflag & CREAD) == 0)
+	 info->read_status_mask &= ~BD_SC_EMPTY;
+	 local_irq_save(flags);
+
+	 /* Start bit has not been added (so don't, because we would just
+	  * subtract it later), and we need to add one for the number of
+	  * stops bits (there is always at least one).
+	  */
+	 bits++;
+	 idx = PORT_NUM(state->smc_scc_num);
+	 if (state->smc_scc_num & NUM_IS_SCC) {
+         sccp = &pquicc->scc_regs[idx];
+         sccp->scc_psmr = (sbits << 12) | scval;
+     } else {
+         smcp = &pquicc->smc_regs[idx];
+
+		/* Set the mode register.  We want to keep a copy of the
+		 * enables, because we want to put them back if they were
+		 * present.
+		 */
+		prev_mode = smcp->smc_smcmr;
+		smcp->smc_smcmr = smcr_mk_clen(bits) | cval |  SMCMR_SM_UART;
+		smcp->smc_smcmr |= (prev_mode & (SMCMR_REN | SMCMR_TEN));
+	}
+
+	m360_cpm_setbrg((state - rs_table), baud_rate);
+
+	local_irq_restore(flags);
+}
+
+static void rs_360_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	volatile QUICC_BD	*bdp;
+
+	if (serial_paranoia_check(info, tty->device, "rs_put_char"))
+		return;
+
+	if (!tty)
+		return;
+
+	bdp = info->tx_cur;
+	while (bdp->status & BD_SC_READY);
+
+	/* *((char *)__va(bdp->buf)) = ch; */
+	*((char *)bdp->buf) = ch;
+	bdp->length = 1;
+	bdp->status |= BD_SC_READY;
+
+	/* Get next BD.
+	*/
+	if (bdp->status & BD_SC_WRAP)
+		bdp = info->tx_bd_base;
+	else
+		bdp++;
+
+	info->tx_cur = (QUICC_BD *)bdp;
+
+}
+
+static int rs_360_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	int	c, ret = 0;
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	volatile QUICC_BD *bdp;
+
+#ifdef CONFIG_KGDB
+	/* Try to let stub handle output. Returns true if it did. */ 
+	if (kgdb_output_string(buf, count))
+		return ret;
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_write"))
+		return 0;
+
+	if (!tty) 
+		return 0;
+
+	bdp = info->tx_cur;
+
+	while (1) {
+		c = min(count, TX_BUF_SIZE);
+
+		if (c <= 0)
+			break;
+
+		if (bdp->status & BD_SC_READY) {
+			info->flags |= TX_WAKEUP;
+			break;
+		}
+
+		if (from_user) {
+			if (copy_from_user((void *)bdp->buf, buf, c)) {
+				if (!ret)
+					ret = -EFAULT;
+				break;
+			}
+		} else {
+			/* memcpy(__va(bdp->buf), buf, c); */
+			memcpy((void *)bdp->buf, buf, c);
+		}
+
+		bdp->length = c;
+		bdp->status |= BD_SC_READY;
+
+		buf += c;
+		count -= c;
+		ret += c;
+
+		/* Get next BD.
+		*/
+		if (bdp->status & BD_SC_WRAP)
+			bdp = info->tx_bd_base;
+		else
+			bdp++;
+		info->tx_cur = (QUICC_BD *)bdp;
+	}
+	return ret;
+}
+
+static int rs_360_write_room(struct tty_struct *tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	int	ret;
+
+	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
+		return 0;
+
+	if ((info->tx_cur->status & BD_SC_READY) == 0) {
+		info->flags &= ~TX_WAKEUP;
+		ret = TX_BUF_SIZE;
+	}
+	else {
+		info->flags |= TX_WAKEUP;
+		ret = 0;
+	}
+	return ret;
+}
+
+/* I could track this with transmit counters....maybe later.
+*/
+static int rs_360_chars_in_buffer(struct tty_struct *tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
+		return 0;
+	return 0;
+}
+
+static void rs_360_flush_buffer(struct tty_struct *tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
+		return;
+
+	/* There is nothing to "flush", whatever we gave the CPM
+	 * is on its way out.
+	 */
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+	info->flags &= ~TX_WAKEUP;
+}
+
+/*
+ * This function is used to send a high-priority XON/XOFF character to
+ * the device
+ */
+static void rs_360_send_xchar(struct tty_struct *tty, char ch)
+{
+	volatile QUICC_BD	*bdp;
+
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+	if (serial_paranoia_check(info, tty->device, "rs_send_char"))
+		return;
+
+	bdp = info->tx_cur;
+	while (bdp->status & BD_SC_READY);
+
+	/* *((char *)__va(bdp->buf)) = ch; */
+	*((char *)bdp->buf) = ch;
+	bdp->length = 1;
+	bdp->status |= BD_SC_READY;
+
+	/* Get next BD.
+	*/
+	if (bdp->status & BD_SC_WRAP)
+		bdp = info->tx_bd_base;
+	else
+		bdp++;
+
+	info->tx_cur = (QUICC_BD *)bdp;
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void rs_360_throttle(struct tty_struct * tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("throttle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_throttle"))
+		return;
+	
+	if (I_IXOFF(tty))
+		rs_360_send_xchar(tty, STOP_CHAR(tty));
+
+#ifdef modem_control
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR &= ~UART_MCR_RTS;
+
+	local_irq_disable();
+	serial_out(info, UART_MCR, info->MCR);
+	local_irq_enable();
+#endif
+}
+
+static void rs_360_unthrottle(struct tty_struct * tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			rs_360_send_xchar(tty, START_CHAR(tty));
+	}
+#ifdef modem_control
+	if (tty->termios->c_cflag & CRTSCTS)
+		info->MCR |= UART_MCR_RTS;
+	local_irq_disable();
+	serial_out(info, UART_MCR, info->MCR);
+	local_irq_enable();
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+#ifdef maybe
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * 	    is emptied.  On bus types like RS485, the transmitter must
+ * 	    release the bus after transmitting. This must be done when
+ * 	    the transmit shift register is empty, not be done when the
+ * 	    transmit holding register is empty.  This functionality
+ * 	    allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct async_struct * info, unsigned int *value)
+{
+	unsigned char status;
+	unsigned int result;
+
+	local_irq_disable();
+	status = serial_in(info, UART_LSR);
+	local_irq_enable();
+	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
+	return put_user(result,value);
+}
+#endif
+
+static int get_modem_info(ser_info_t *info, unsigned int *value)
+{
+	unsigned int result = 0;
+#ifdef modem_control
+	unsigned char control, status;
+
+	control = info->MCR;
+	local_irq_disable();
+	status = serial_in(info, UART_MSR);
+	local_irq_enable();
+	result =  ((control & UART_MCR_RTS) ? TIOCM_RTS : 0)
+		| ((control & UART_MCR_DTR) ? TIOCM_DTR : 0)
+#ifdef TIOCM_OUT1
+		| ((control & UART_MCR_OUT1) ? TIOCM_OUT1 : 0)
+		| ((control & UART_MCR_OUT2) ? TIOCM_OUT2 : 0)
+#endif
+		| ((status  & UART_MSR_DCD) ? TIOCM_CAR : 0)
+		| ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
+		| ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
+		| ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
+#endif
+	/* return put_user(result,value); */
+	put_user(result,value);
+	return (0);
+}
+
+static int set_modem_info(ser_info_t *info, unsigned int cmd,
+			  unsigned int *value)
+{
+	int error;
+ 	unsigned int arg; 
+
+	error = get_user(arg,value);
+	if (error)
+		return error;
+#ifdef modem_control
+	switch (cmd) {
+	case TIOCMBIS: 
+		if (arg & TIOCM_RTS)
+			info->MCR |= UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR |= UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+		if (arg & TIOCM_OUT1)
+			info->MCR |= UART_MCR_OUT1;
+		if (arg & TIOCM_OUT2)
+			info->MCR |= UART_MCR_OUT2;
+#endif
+		break;
+	case TIOCMBIC:
+		if (arg & TIOCM_RTS)
+			info->MCR &= ~UART_MCR_RTS;
+		if (arg & TIOCM_DTR)
+			info->MCR &= ~UART_MCR_DTR;
+#ifdef TIOCM_OUT1
+		if (arg & TIOCM_OUT1)
+			info->MCR &= ~UART_MCR_OUT1;
+		if (arg & TIOCM_OUT2)
+			info->MCR &= ~UART_MCR_OUT2;
+#endif
+		break;
+	case TIOCMSET:
+		info->MCR = ((info->MCR & ~(UART_MCR_RTS |
+#ifdef TIOCM_OUT1
+					    UART_MCR_OUT1 |
+					    UART_MCR_OUT2 |
+#endif
+					    UART_MCR_DTR))
+			     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
+#ifdef TIOCM_OUT1
+			     | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
+			     | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
+#endif
+			     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
+		break;
+	default:
+		return -EINVAL;
+	}
+	local_irq_disable();
+	serial_out(info, UART_MCR, info->MCR);
+	local_irq_enable();
+#endif
+	return 0;
+}
+
+/* Sending a break is a two step process on the SMC/SCC.  It is accomplished
+ * by sending a STOP TRANSMIT command followed by a RESTART TRANSMIT
+ * command.  We take advantage of the begin/end functions to make this
+ * happen.
+ */
+static ushort	smc_chan_map[] = {
+	CPM_CR_CH_SMC1,
+	CPM_CR_CH_SMC2
+};
+
+static ushort	scc_chan_map[] = {
+	CPM_CR_CH_SCC1,
+	CPM_CR_CH_SCC2,
+	CPM_CR_CH_SCC3,
+	CPM_CR_CH_SCC4
+};
+
+static void begin_break(ser_info_t *info)
+{
+	volatile QUICC *cp;
+	ushort	chan;
+	int     idx;
+
+	cp = pquicc;
+
+	idx = PORT_NUM(info->state->smc_scc_num);
+	if (info->state->smc_scc_num & NUM_IS_SCC)
+		chan = scc_chan_map[idx];
+	else
+		chan = smc_chan_map[idx];
+
+	cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG;
+	while (cp->cp_cr & CPM_CR_FLG);
+}
+
+static void end_break(ser_info_t *info)
+{
+	volatile QUICC *cp;
+	ushort	chan;
+	int idx;
+
+	cp = pquicc;
+
+	idx = PORT_NUM(info->state->smc_scc_num);
+	if (info->state->smc_scc_num & NUM_IS_SCC)
+		chan = scc_chan_map[idx];
+	else
+		chan = smc_chan_map[idx];
+
+	cp->cp_cr = mk_cr_cmd(chan, CPM_CR_RESTART_TX) | CPM_CR_FLG;
+	while (cp->cp_cr & CPM_CR_FLG);
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(ser_info_t *info, int duration)
+{
+	current->state = TASK_INTERRUPTIBLE;
+#ifdef SERIAL_DEBUG_SEND_BREAK
+	printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
+#endif
+	begin_break(info);
+	schedule_timeout(duration);
+	end_break(info);
+#ifdef SERIAL_DEBUG_SEND_BREAK
+	printk("done jiffies=%lu\n", jiffies);
+#endif
+}
+
+
+static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	int error;
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	int retval;
+	struct async_icount cnow; 
+	/* struct async_icount_24 cnow;*/ 	/* kernel counter temps */
+	struct serial_icounter_struct *p_cuser;	/* user space */
+
+	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+	
+	switch (cmd) {
+		case TCSBRK:	/* SVID version: non-zero arg --> no break */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (signal_pending(current))
+				return -EINTR;
+			if (!arg) {
+				send_break(info, HZ/4);	/* 1/4 second */
+				if (signal_pending(current))
+					return -EINTR;
+			}
+			return 0;
+		case TCSBRKP:	/* support for POSIX tcsendbreak() */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (signal_pending(current))
+				return -EINTR;
+			send_break(info, arg ? arg*(HZ/10) : HZ/4);
+			if (signal_pending(current))
+				return -EINTR;
+			return 0;
+		case TIOCSBRK:
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			begin_break(info);
+			return 0;
+		case TIOCCBRK:
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			end_break(info);
+			return 0;
+		case TIOCGSOFTCAR:
+			/* return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg); */
+			put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg);
+			return 0;
+		case TIOCSSOFTCAR:
+			error = get_user(arg, (unsigned int *) arg); 
+			if (error)
+				return error;
+			tty->termios->c_cflag =
+				((tty->termios->c_cflag & ~CLOCAL) |
+				 (arg ? CLOCAL : 0));
+			return 0;
+		case TIOCMGET:
+			return get_modem_info(info, (unsigned int *) arg);
+		case TIOCMBIS:
+		case TIOCMBIC:
+		case TIOCMSET:
+			return set_modem_info(info, cmd, (unsigned int *) arg);
+#ifdef maybe
+		case TIOCSERGETLSR: /* Get line status register */
+			return get_lsr_info(info, (unsigned int *) arg);
+#endif
+		/*
+		 * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change
+		 * - mask passed in arg for lines of interest
+ 		 *   (use |'ed TIOCM_RNG/DSR/CD/CTS for masking)
+		 * Caller should use TIOCGICOUNT to see which one it was
+		 */
+		 case TIOCMIWAIT:
+#ifdef modem_control
+			local_irq_disable();
+			/* note the counters on entry */
+			cprev = info->state->icount;
+			local_irq_enable();
+			while (1) {
+				interruptible_sleep_on(&info->delta_msr_wait);
+				/* see if a signal did it */
+				if (signal_pending(current))
+					return -ERESTARTSYS;
+				local_irq_disable();
+				cnow = info->state->icount; /* atomic copy */
+				local_irq_enable();
+				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;
+			}
+			/* NOTREACHED */
+#else
+			return 0;
+#endif
+
+		/* 
+		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)
+		 * Return: write counters to the user passed counter struct
+		 * NB: both 1->0 and 0->1 transitions are counted except for
+		 *     RI where only 0->1 is counted.
+		 */
+		case TIOCGICOUNT:
+			local_irq_disable();
+			cnow = info->state->icount;
+			local_irq_enable();
+			p_cuser = (struct serial_icounter_struct *) arg;
+/* 			error = put_user(cnow.cts, &p_cuser->cts); */
+/* 			if (error) return error; */
+/* 			error = put_user(cnow.dsr, &p_cuser->dsr); */
+/* 			if (error) return error; */
+/* 			error = put_user(cnow.rng, &p_cuser->rng); */
+/* 			if (error) return error; */
+/* 			error = put_user(cnow.dcd, &p_cuser->dcd); */
+/* 			if (error) return error; */
+
+			put_user(cnow.cts, &p_cuser->cts);
+			put_user(cnow.dsr, &p_cuser->dsr);
+			put_user(cnow.rng, &p_cuser->rng);
+			put_user(cnow.dcd, &p_cuser->dcd);
+			return 0;
+
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+/* FIX UP modem control here someday......
+*/
+static void rs_360_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+
+	if (   (tty->termios->c_cflag == old_termios->c_cflag)
+	    && (   RELEVANT_IFLAG(tty->termios->c_iflag) 
+		== RELEVANT_IFLAG(old_termios->c_iflag)))
+	  return;
+
+	change_speed(info);
+
+#ifdef modem_control
+	/* Handle transition to B0 status */
+	if ((old_termios->c_cflag & CBAUD) &&
+	    !(tty->termios->c_cflag & CBAUD)) {
+		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);
+		local_irq_disable();
+		serial_out(info, UART_MCR, info->MCR);
+		local_irq_enable();
+	}
+	
+	/* Handle transition away from B0 status */
+	if (!(old_termios->c_cflag & CBAUD) &&
+	    (tty->termios->c_cflag & CBAUD)) {
+		info->MCR |= UART_MCR_DTR;
+		if (!tty->hw_stopped ||
+		    !(tty->termios->c_cflag & CRTSCTS)) {
+			info->MCR |= UART_MCR_RTS;
+		}
+		local_irq_disable();
+		serial_out(info, UART_MCR, info->MCR);
+		local_irq_enable();
+	}
+	
+	/* Handle turning off CRTSCTS */
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		rs_360_start(tty);
+	}
+#endif
+
+#if 0
+	/*
+	 * No need to wake up processes in open wait, since they
+	 * sample the CLOCAL flag once, and don't recheck it.
+	 * XXX  It's not clear whether the current behavior is correct
+	 * or not.  Hence, this may change.....
+	 */
+	if (!(old_termios->c_cflag & CLOCAL) &&
+	    (tty->termios->c_cflag & CLOCAL))
+		wake_up_interruptible(&info->open_wait);
+#endif
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_360_close(struct tty_struct *tty, struct file * filp)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	/* struct async_state *state; */
+	struct serial_state *state;
+	unsigned long	flags;
+	int		idx;
+	volatile struct smc_regs	*smcp;
+	volatile struct scc_regs	*sccp;
+
+	if (!info || serial_paranoia_check(info, tty->device, "rs_close"))
+		return;
+
+	state = info->state;
+	
+	local_irq_save(flags);
+	
+	if (tty_hung_up_p(filp)) {
+		DBG_CNT("before DEC-hung");
+		MOD_DEC_USE_COUNT;
+		local_irq_restore(flags);
+		return;
+	}
+	
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_close ttys%d, count = %d\n", info->line, state->count);
+#endif
+	if ((tty->count == 1) && (state->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  state->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("rs_close: bad serial port count; tty->count is 1, "
+		       "state->count is %d\n", state->count);
+		state->count = 1;
+	}
+	if (--state->count < 0) {
+		printk("rs_close: bad serial port count for ttys%d: %d\n",
+		       info->line, state->count);
+		state->count = 0;
+	}
+	if (state->count) {
+		DBG_CNT("before DEC-2");
+		MOD_DEC_USE_COUNT;
+		local_irq_restore(flags);
+		return;
+	}
+	info->flags |= ASYNC_CLOSING;
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->state->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->state->callout_termios = *tty->termios;
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	info->read_status_mask &= ~BD_SC_EMPTY;
+	if (info->flags & ASYNC_INITIALIZED) {
+
+		idx = PORT_NUM(info->state->smc_scc_num);
+		if (info->state->smc_scc_num & NUM_IS_SCC) {
+			sccp = &pquicc->scc_regs[idx];
+			sccp->scc_sccm &= ~UART_SCCM_RX;
+			sccp->scc_gsmr.w.low &= ~SCC_GSMRL_ENR;
+		} else {
+			smcp = &pquicc->smc_regs[idx];
+			smcp->smc_smcm &= ~SMCM_RX;
+			smcp->smc_smcmr &= ~SMCMR_REN;
+		}
+		/*
+		 * Before we drop DTR, make sure the UART transmitter
+		 * has completely drained; this is especially
+		 * important if there is a transmit FIFO!
+		 */
+		rs_360_wait_until_sent(tty, info->timeout);
+	}
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	MOD_DEC_USE_COUNT;
+	local_irq_restore(flags);
+}
+
+/*
+ * rs_wait_until_sent() --- wait until the transmitter is empty
+ */
+static void rs_360_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	unsigned long orig_jiffies, char_time;
+	/*int lsr;*/
+	volatile QUICC_BD *bdp;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_wait_until_sent"))
+		return;
+
+#ifdef maybe
+	if (info->state->type == PORT_UNKNOWN)
+		return;
+#endif
+
+	orig_jiffies = jiffies;
+	/*
+	 * Set the check interval to be 1/5 of the estimated time to
+	 * send a single character, and make it at least 1.  The check
+	 * interval should also be less than the timeout.
+	 * 
+	 * Note: we have to use pretty tight timings here to satisfy
+	 * the NIST-PCTS.
+	 */
+	char_time = 1;
+	if (timeout)
+		char_time = min(char_time, timeout);
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time);
+	printk("jiff=%lu...", jiffies);
+#endif
+
+	/* We go through the loop at least once because we can't tell
+	 * exactly when the last character exits the shifter.  There can
+	 * be at least two characters waiting to be sent after the buffers
+	 * are empty.
+	 */
+	do {
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
+#endif
+		current->state = TASK_INTERRUPTIBLE;
+/*		current->counter = 0;	 make us low-priority */
+		schedule_timeout(char_time);
+		if (signal_pending(current))
+			break;
+		if (timeout && ((orig_jiffies + timeout) < jiffies))
+			break;
+		/* The 'tx_cur' is really the next buffer to send.  We
+		 * have to back up to the previous BD and wait for it
+		 * to go.  This isn't perfect, because all this indicates
+		 * is the buffer is available.  There are still characters
+		 * in the CPM FIFO.
+		 */
+		bdp = info->tx_cur;
+		if (bdp == info->tx_bd_base)
+			bdp += (TX_NUM_FIFO-1);
+		else
+			bdp--;
+	} while (bdp->status & BD_SC_READY);
+	current->state = TASK_RUNNING;
+#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+	printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
+#endif
+}
+
+/*
+ * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+static void rs_360_hangup(struct tty_struct *tty)
+{
+	ser_info_t *info = (ser_info_t *)tty->driver_data;
+	struct serial_state *state = info->state;
+	
+	if (serial_paranoia_check(info, tty->device, "rs_hangup"))
+		return;
+
+	state = info->state;
+	
+	rs_360_flush_buffer(tty);
+	shutdown(info);
+	info->event = 0;
+	state->count = 0;
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * rs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   ser_info_t *info)
+{
+#ifdef DO_THIS_LATER
+	DECLARE_WAITQUEUE(wait, current);
+#endif
+	struct serial_state *state = info->state;
+	int		retval;
+	int		do_clocal = 0;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (tty_hung_up_p(filp) ||
+	    (info->flags & ASYNC_CLOSING)) {
+		if (info->flags & ASYNC_CLOSING)
+			interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		if (info->flags & ASYNC_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+#else
+		return -EAGAIN;
+#endif
+	}
+
+
+#if 0 /* FIXME */
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+#endif	
+
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 * If this is an SMC port, we don't have modem control to wait
+	 * for, so just get out here.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR)) ||
+	    !(info->state->smc_scc_num & NUM_IS_SCC)) {
+		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (state->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, state->count is dropped by one, so that
+	 * rs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+#ifdef DO_THIS_LATER
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttys%d, count = %d\n",
+	       state->line, state->count);
+#endif
+	local_irq_disable();
+	if (!tty_hung_up_p(filp)) 
+		state->count--;
+	local_irq_enable();
+	info->blocked_open++;
+	while (1) {
+		local_irq_disable();
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (tty->termios->c_cflag & CBAUD))
+			serial_out(info, UART_MCR,
+				   serial_inp(info, UART_MCR) |
+				   (UART_MCR_DTR | UART_MCR_RTS));
+		local_irq_enable();
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    !(info->flags & ASYNC_CLOSING) &&
+		    (do_clocal || (serial_in(info, UART_MSR) &
+				   UART_MSR_DCD)))
+			break;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		printk("block_til_ready blocking: ttys%d, count = %d\n",
+		       info->line, state->count);
+#endif
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&info->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		state->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttys%d, count = %d\n",
+	       info->line, state->count);
+#endif
+#endif /* DO_THIS_LATER */
+	if (retval)
+		return retval;
+	info->flags |= ASYNC_NORMAL_ACTIVE;
+	return 0;
+}
+
+static int get_async_struct(int line, ser_info_t **ret_info)
+{
+	struct serial_state *sstate;
+
+	sstate = rs_table + line;
+	if (sstate->info) {
+		sstate->count++;
+		*ret_info = (ser_info_t *)sstate->info;
+		return 0;
+	}
+	else {
+		return -ENOMEM;
+	}
+}
+
+/*
+ * This routine is called whenever a serial port is opened.  It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+static int rs_360_open(struct tty_struct *tty, struct file * filp)
+{
+	ser_info_t	*info;
+	int 		retval, line;
+
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS))
+		return -ENODEV;
+	retval = get_async_struct(line, &info);
+	if (retval)
+		return retval;
+	if (serial_paranoia_check(info, tty->device, "rs_open"))
+		return -ENODEV;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
+	       info->state->count);
+#endif
+	tty->driver_data = info;
+	info->tty = tty;
+
+	/*
+	 * Start up serial port
+	 */
+	retval = startup(info);
+	if (retval)
+		return retval;
+
+	MOD_INC_USE_COUNT;
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+		printk("rs_open returning after block_til_ready with %d\n",
+		       retval);
+#endif
+		MOD_DEC_USE_COUNT;
+		return retval;
+	}
+
+	if ((info->state->count == 1) &&
+	    (info->flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->state->normal_termios;
+		else 
+			*tty->termios = info->state->callout_termios;
+		change_speed(info);
+	}
+
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("rs_open ttys%d successful...", info->line);
+#endif
+	return 0;
+}
+
+/*
+ * /proc fs routines....
+ */
+
+static int inline line_info(char *buf, struct serial_state *state)
+{
+#ifdef notdef
+	struct async_struct *info = state->info, scr_info;
+	char	stat_buf[30], control, status;
+#endif
+	int	ret;
+
+	ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
+		      state->line,
+		      (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC",
+		      (unsigned int)(state->port), state->irq);
+
+	if (!state->port || (state->type == PORT_UNKNOWN)) {
+		ret += sprintf(buf+ret, "\n");
+		return ret;
+	}
+
+#ifdef notdef
+	/*
+	 * Figure out the current RS-232 lines
+	 */
+	if (!info) {
+		info = &scr_info;	/* This is just for serial_{in,out} */
+
+		info->magic = SERIAL_MAGIC;
+		info->port = state->port;
+		info->flags = state->flags;
+		info->quot = 0;
+		info->tty = 0;
+	}
+	local_irq_disable();
+	status = serial_in(info, UART_MSR);
+	control = info ? info->MCR : serial_in(info, UART_MCR);
+	local_irq_enable();
+	
+	stat_buf[0] = 0;
+	stat_buf[1] = 0;
+	if (control & UART_MCR_RTS)
+		strcat(stat_buf, "|RTS");
+	if (status & UART_MSR_CTS)
+		strcat(stat_buf, "|CTS");
+	if (control & UART_MCR_DTR)
+		strcat(stat_buf, "|DTR");
+	if (status & UART_MSR_DSR)
+		strcat(stat_buf, "|DSR");
+	if (status & UART_MSR_DCD)
+		strcat(stat_buf, "|CD");
+	if (status & UART_MSR_RI)
+		strcat(stat_buf, "|RI");
+
+	if (info->quot) {
+		ret += sprintf(buf+ret, " baud:%d",
+			       state->baud_base / info->quot);
+	}
+
+	ret += sprintf(buf+ret, " tx:%d rx:%d",
+		      state->icount.tx, state->icount.rx);
+
+	if (state->icount.frame)
+		ret += sprintf(buf+ret, " fe:%d", state->icount.frame);
+	
+	if (state->icount.parity)
+		ret += sprintf(buf+ret, " pe:%d", state->icount.parity);
+	
+	if (state->icount.brk)
+		ret += sprintf(buf+ret, " brk:%d", state->icount.brk);	
+
+	if (state->icount.overrun)
+		ret += sprintf(buf+ret, " oe:%d", state->icount.overrun);
+
+	/*
+	 * Last thing is the RS-232 status lines
+	 */
+	ret += sprintf(buf+ret, " %s\n", stat_buf+1);
+#endif
+	return ret;
+}
+
+int rs_360_read_proc(char *page, char **start, off_t off, int count,
+		 int *eof, void *data)
+{
+	int i, len = 0;
+	off_t	begin = 0;
+
+	len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+	for (i = 0; i < NR_PORTS && len < 4000; i++) {
+		len += line_info(page + len, &rs_table[i]);
+		if (len+begin > off+count)
+			goto done;
+		if (len+begin < off) {
+			begin += len;
+			len = 0;
+		}
+	}
+	*eof = 1;
+done:
+	if (off >= len+begin)
+		return 0;
+	*start = page + (begin-off);
+	return ((count < begin+len-off) ? count : begin+len-off);
+}
+
+/*
+ * ---------------------------------------------------------------------
+ * rs_init() and friends
+ *
+ * rs_init() is called at boot-time to initialize the serial driver.
+ * ---------------------------------------------------------------------
+ */
+
+/*
+ * This routine prints out the appropriate serial driver version
+ * number, and identifies which options were configured into this
+ * driver.
+ */
+static _INLINE_ void show_serial_version(void)
+{
+ 	printk(KERN_INFO "%s version %s\n", serial_name, serial_version);
+}
+
+
+/*
+ * The serial console driver used during boot.  Note that these names
+ * clash with those found in "serial.c", so we currently can't support
+ * the 16xxx uarts and these at the same time.  I will fix this to become
+ * an indirect function call from tty_io.c (or something).
+ */
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+/*
+ * Print a string to the serial port trying not to disturb any possible
+ * real use of the port...
+ */
+static void my_console_write(int idx, const char *s,
+				unsigned count)
+{
+	struct		serial_state	*ser;
+	ser_info_t		*info;
+	unsigned		i;
+	QUICC_BD		*bdp, *bdbase;
+	volatile struct smc_uart_pram	*up;
+	volatile	u_char		*cp;
+
+	ser = rs_table + idx;
+
+
+	/* If the port has been initialized for general use, we have
+	 * to use the buffer descriptors allocated there.  Otherwise,
+	 * we simply use the single buffer allocated.
+	 */
+	if ((info = (ser_info_t *)ser->info) != NULL) {
+		bdp = info->tx_cur;
+		bdbase = info->tx_bd_base;
+	}
+	else {
+		/* Pointer to UART in parameter ram.
+		*/
+		/* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
+		up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
+
+		/* Get the address of the host memory buffer.
+		 */
+		bdp = bdbase = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
+	}
+
+	/*
+	 * We need to gracefully shut down the transmitter, disable
+	 * interrupts, then send our bytes out.
+	 */
+
+	/*
+	 * Now, do each character.  This is not as bad as it looks
+	 * since this is a holding FIFO and not a transmitting FIFO.
+	 * We could add the complexity of filling the entire transmit
+	 * buffer, but we would just wait longer between accesses......
+	 */
+	for (i = 0; i < count; i++, s++) {
+		/* Wait for transmitter fifo to empty.
+		 * Ready indicates output is ready, and xmt is doing
+		 * that, not that it is ready for us to send.
+		 */
+		while (bdp->status & BD_SC_READY);
+
+		/* Send the character out.
+		 */
+		cp = bdp->buf;
+		*cp = *s;
+		
+		bdp->length = 1;
+		bdp->status |= BD_SC_READY;
+
+		if (bdp->status & BD_SC_WRAP)
+			bdp = bdbase;
+		else
+			bdp++;
+
+		/* if a LF, also do CR... */
+		if (*s == 10) {
+			while (bdp->status & BD_SC_READY);
+			/* cp = __va(bdp->buf); */
+			cp = bdp->buf;
+			*cp = 13;
+			bdp->length = 1;
+			bdp->status |= BD_SC_READY;
+
+			if (bdp->status & BD_SC_WRAP) {
+				bdp = bdbase;
+			}
+			else {
+				bdp++;
+			}
+		}
+	}
+
+	/*
+	 * Finally, Wait for transmitter & holding register to empty
+	 *  and restore the IER
+	 */
+	while (bdp->status & BD_SC_READY);
+
+	if (info)
+		info->tx_cur = (QUICC_BD *)bdp;
+}
+
+static void serial_console_write(struct console *c, const char *s,
+				unsigned count)
+{
+#ifdef CONFIG_KGDB
+	/* Try to let stub handle output. Returns true if it did. */ 
+	if (kgdb_output_string(s, count))
+		return;
+#endif
+	my_console_write(c->index, s, count);
+}
+
+
+
+/*void console_print_68360(const char *p)
+{
+	const char *cp = p;
+	int i;
+
+	for (i=0;cp[i]!=0;i++);
+
+	serial_console_write (p, i);
+
+	//Comment this if you want to have a strict interrupt-driven output
+	//rs_fair_output();
+
+	return;
+}*/
+
+
+
+
+
+
+#ifdef CONFIG_XMON
+int
+xmon_360_write(const char *s, unsigned count)
+{
+	my_console_write(0, s, count);
+	return(count);
+}
+#endif
+
+#ifdef CONFIG_KGDB
+void
+putDebugChar(char ch)
+{
+	my_console_write(0, &ch, 1);
+}
+#endif
+
+/*
+ * Receive character from the serial port.  This only works well
+ * before the port is initialized for real use.
+ */
+static int my_console_wait_key(int idx, int xmon, char *obuf)
+{
+	struct serial_state		*ser;
+	u_char			c, *cp;
+	ser_info_t		*info;
+	QUICC_BD		*bdp;
+	volatile struct smc_uart_pram	*up;
+	int				i;
+
+	ser = rs_table + idx;
+
+	/* Get the address of the host memory buffer.
+	 * If the port has been initialized for general use, we must
+	 * use information from the port structure.
+	 */
+	if ((info = (ser_info_t *)ser->info))
+		bdp = info->rx_cur;
+	else
+		/* bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase]; */
+		bdp = (QUICC_BD *)((uint)pquicc + (uint)up->tbase);
+
+	/* Pointer to UART in parameter ram.
+	 */
+	/* up = (smc_uart_t *)&cpmp->cp_dparam[ser->port]; */
+	up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
+
+	/*
+	 * We need to gracefully shut down the receiver, disable
+	 * interrupts, then read the input.
+	 * XMON just wants a poll.  If no character, return -1, else
+	 * return the character.
+	 */
+	if (!xmon) {
+		while (bdp->status & BD_SC_EMPTY);
+	}
+	else {
+		if (bdp->status & BD_SC_EMPTY)
+			return -1;
+	}
+
+	cp = (char *)bdp->buf;
+
+	if (obuf) {
+		i = c = bdp->length;
+		while (i-- > 0)
+			*obuf++ = *cp++;
+	}
+	else {
+		c = *cp;
+	}
+	bdp->status |= BD_SC_EMPTY;
+
+	if (info) {
+		if (bdp->status & BD_SC_WRAP) {
+			bdp = info->rx_bd_base;
+		}
+		else {
+			bdp++;
+		}
+		info->rx_cur = (QUICC_BD *)bdp;
+	}
+
+	return((int)c);
+}
+
+static int serial_console_wait_key(struct console *co)
+{
+	return(my_console_wait_key(co->index, 0, NULL));
+}
+
+#ifdef CONFIG_XMON
+int
+xmon_360_read_poll(void)
+{
+	return(my_console_wait_key(0, 1, NULL));
+}
+
+int
+xmon_360_read_char(void)
+{
+	return(my_console_wait_key(0, 0, NULL));
+}
+#endif
+
+#ifdef CONFIG_KGDB
+static char kgdb_buf[RX_BUF_SIZE], *kgdp;
+static int kgdb_chars;
+
+unsigned char
+getDebugChar(void)
+{
+	if (kgdb_chars <= 0) {
+		kgdb_chars = my_console_wait_key(0, 0, kgdb_buf);
+		kgdp = kgdb_buf;
+	}
+	kgdb_chars--;
+
+	return(*kgdp++);
+}
+
+void kgdb_interruptible(int state)
+{
+}
+void kgdb_map_scc(void)
+{
+	struct		serial_state *ser;
+	uint		mem_addr;
+	volatile	QUICC_BD		*bdp;
+	volatile	smc_uart_t	*up;
+
+	cpmp = (cpm360_t *)&(((immap_t *)IMAP_ADDR)->im_cpm);
+
+	/* To avoid data cache CPM DMA coherency problems, allocate a
+	 * buffer in the CPM DPRAM.  This will work until the CPM and
+	 * serial ports are initialized.  At that time a memory buffer
+	 * will be allocated.
+	 * The port is already initialized from the boot procedure, all
+	 * we do here is give it a different buffer and make it a FIFO.
+	 */
+
+	ser = rs_table;
+
+	/* Right now, assume we are using SMCs.
+	*/
+	up = (smc_uart_t *)&cpmp->cp_dparam[ser->port];
+
+	/* Allocate space for an input FIFO, plus a few bytes for output.
+	 * Allocate bytes to maintain word alignment.
+	 */
+	mem_addr = (uint)(&cpmp->cp_dpmem[0x1000]);
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+	bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_rbase];
+	bdp->buf = mem_addr;
+
+	bdp = (QUICC_BD *)&cpmp->cp_dpmem[up->smc_tbase];
+	bdp->buf = mem_addr+RX_BUF_SIZE;
+
+	up->smc_mrblr = RX_BUF_SIZE;		/* receive buffer length */
+	up->smc_maxidl = RX_BUF_SIZE;
+}
+#endif
+
+static kdev_t serial_console_device(struct console *c)
+{
+	return MKDEV(TTY_MAJOR, 64 + c->index);
+}
+
+
+struct console sercons = {
+ 	name:		"ttyS",
+ 	write:		serial_console_write,
+ 	device:		serial_console_device,
+ 	wait_key:	serial_console_wait_key,
+ 	setup:		serial_console_setup,
+ 	flags:		CON_PRINTBUFFER,
+ 	index:		CONFIG_SERIAL_CONSOLE_PORT, 
+};
+
+
+
+/*
+ *	Register console.
+ */
+long console_360_init(long kmem_start, long kmem_end)
+{
+	register_console(&sercons);
+	/*register_console (console_print_68360); - 2.0.38 only required a write
+      function pointer. */
+	return kmem_start;
+}
+
+#endif
+
+/* Index in baud rate table of the default console baud rate.
+*/
+static	int	baud_idx;
+
+
+/* int __init rs_360_init(void) */
+int rs_360_init(void)
+{
+	struct serial_state * state;
+	ser_info_t	*info;
+	void       *mem_addr;
+	uint 		dp_addr, iobits;
+	int		    i, j, idx;
+	ushort		chan;
+	QUICC_BD	*bdp;
+	volatile	QUICC		*cp;
+	volatile	struct smc_regs	*sp;
+	volatile	struct smc_uart_pram	*up;
+	volatile	struct scc_regs	*scp;
+	volatile	struct uart_pram	*sup;
+	/* volatile	immap_t		*immap; */
+	
+	init_bh(SERIAL_BH, do_serial_bh);
+
+	show_serial_version();
+
+	/* Initialize the tty_driver structure */
+	
+	/* __clear_user(&serial_driver,sizeof(struct tty_driver)); */
+	memset(&serial_driver, 0, sizeof(struct tty_driver));
+
+	serial_driver.magic = TTY_DRIVER_MAGIC;
+	/* serial_driver.driver_name = "serial"; */
+	serial_driver.name = "ttyS";
+	serial_driver.major = TTY_MAJOR;
+	serial_driver.minor_start = 64;
+	serial_driver.num = NR_PORTS;
+	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	serial_driver.init_termios = tty_std_termios;
+	serial_driver.init_termios.c_cflag =
+		baud_idx | CS8 | CREAD | HUPCL | CLOCAL;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.refcount = &serial_refcount;
+	serial_driver.table = serial_table;
+	serial_driver.termios = serial_termios;
+	serial_driver.termios_locked = serial_termios_locked;
+
+	serial_driver.open = rs_360_open;
+	serial_driver.close = rs_360_close;
+	serial_driver.write = rs_360_write;
+	serial_driver.put_char = rs_360_put_char;
+	serial_driver.write_room = rs_360_write_room;
+	serial_driver.chars_in_buffer = rs_360_chars_in_buffer;
+	serial_driver.flush_buffer = rs_360_flush_buffer;
+	serial_driver.ioctl = rs_360_ioctl;
+	serial_driver.throttle = rs_360_throttle;
+	serial_driver.unthrottle = rs_360_unthrottle;
+	/* serial_driver.send_xchar = rs_360_send_xchar; */
+	serial_driver.set_termios = rs_360_set_termios;
+	serial_driver.stop = rs_360_stop;
+	serial_driver.start = rs_360_start;
+	serial_driver.hangup = rs_360_hangup;
+	/* serial_driver.wait_until_sent = rs_360_wait_until_sent; */
+	/* serial_driver.read_proc = rs_360_read_proc; */
+	
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	callout_driver = serial_driver;
+	callout_driver.name = "cua";
+	callout_driver.major = TTYAUX_MAJOR;
+	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+	/* callout_driver.read_proc = 0; */
+	/* callout_driver.proc_entry = 0; */
+
+	if (tty_register_driver(&serial_driver))
+		panic("Couldn't register serial driver\n");
+	if (tty_register_driver(&callout_driver))
+		panic("Couldn't register callout driver\n");
+	
+	cp = pquicc;	/* Get pointer to Communication Processor */
+	/* immap = (immap_t *)IMAP_ADDR; */	/* and to internal registers */
+
+
+	/* Configure SCC2, SCC3, and SCC4 instead of port A parallel I/O.
+	 */
+	/* The "standard" configuration through the 860.
+	*/
+/* 	immap->im_ioport.iop_papar |= 0x00fc; */
+/* 	immap->im_ioport.iop_padir &= ~0x00fc; */
+/* 	immap->im_ioport.iop_paodr &= ~0x00fc; */
+	cp->pio_papar |= 0x00fc;
+	cp->pio_padir &= ~0x00fc;
+	/* cp->pio_paodr &= ~0x00fc; */
+
+
+	/* Since we don't yet do modem control, connect the port C pins
+	 * as general purpose I/O.  This will assert CTS and CD for the
+	 * SCC ports.
+	 */
+	/* FIXME: see 360um p.7-365 and 860um p.34-12 
+	 * I can't make sense of these bits - mleslie*/
+/* 	immap->im_ioport.iop_pcdir |= 0x03c6; */
+/* 	immap->im_ioport.iop_pcpar &= ~0x03c6; */
+
+/* 	cp->pio_pcdir |= 0x03c6; */
+/* 	cp->pio_pcpar &= ~0x03c6; */
+
+
+
+	/* Connect SCC2 and SCC3 to NMSI.  Connect BRG3 to SCC2 and
+	 * BRG4 to SCC3.
+	 */
+	cp->si_sicr &= ~0x00ffff00;
+	cp->si_sicr |=  0x001b1200;
+
+#ifdef CONFIG_PP04
+	/* Frequentis PP04 forced to RS-232 until we know better.
+	 * Port C 12 and 13 low enables RS-232 on SCC3 and SCC4.
+	 */
+	immap->im_ioport.iop_pcdir |= 0x000c;
+	immap->im_ioport.iop_pcpar &= ~0x000c;
+	immap->im_ioport.iop_pcdat &= ~0x000c;
+
+	/* This enables the TX driver.
+	*/
+	cp->cp_pbpar &= ~0x6000;
+	cp->cp_pbdat &= ~0x6000;
+#endif
+
+	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
+		state->magic = SSTATE_MAGIC;
+		state->line = i;
+		state->type = PORT_UNKNOWN;
+		state->custom_divisor = 0;
+		state->close_delay = 5*HZ/10;
+		state->closing_wait = 30*HZ;
+		state->callout_termios = callout_driver.init_termios;
+		state->normal_termios = serial_driver.init_termios;
+		state->icount.cts = state->icount.dsr = 
+			state->icount.rng = state->icount.dcd = 0;
+		state->icount.rx = state->icount.tx = 0;
+		state->icount.frame = state->icount.parity = 0;
+		state->icount.overrun = state->icount.brk = 0;
+		printk(KERN_INFO "ttyS%02d at irq 0x%02x is an %s\n",
+		       i, (unsigned int)(state->irq),
+		       (state->smc_scc_num & NUM_IS_SCC) ? "SCC" : "SMC");
+
+#ifdef CONFIG_SERIAL_CONSOLE
+		/* If we just printed the message on the console port, and
+		 * we are about to initialize it for general use, we have
+		 * to wait a couple of character times for the CR/NL to
+		 * make it out of the transmit buffer.
+		 */
+		if (i == CONFIG_SERIAL_CONSOLE_PORT)
+			mdelay(8);
+
+
+/* 		idx = PORT_NUM(info->state->smc_scc_num); */
+/* 		if (info->state->smc_scc_num & NUM_IS_SCC) */
+/* 			chan = scc_chan_map[idx]; */
+/* 		else */
+/* 			chan = smc_chan_map[idx]; */
+
+/* 		cp->cp_cr = mk_cr_cmd(chan, CPM_CR_STOP_TX) | CPM_CR_FLG; */
+/* 		while (cp->cp_cr & CPM_CR_FLG); */
+
+#endif
+		/* info = kmalloc(sizeof(ser_info_t), GFP_KERNEL); */
+		info = &quicc_ser_info[i];
+		if (info) {
+			/* __clear_user(info,sizeof(ser_info_t)); */
+			memset (info, 0, sizeof(ser_info_t));
+			init_waitqueue_head(&info->open_wait);
+			init_waitqueue_head(&info->close_wait);
+			info->magic = SERIAL_MAGIC;
+			info->flags = state->flags;
+			info->tqueue.routine = do_softint;
+			info->tqueue.data = info;
+			info->tqueue_hangup.routine = do_serial_hangup;
+			info->tqueue_hangup.data = info;
+			info->line = i;
+			info->state = state;
+			state->info = (struct async_struct *)info;
+
+			/* We need to allocate a transmit and receive buffer
+			 * descriptors from dual port ram, and a character
+			 * buffer area from host mem.
+			 */
+			dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * RX_NUM_FIFO);
+
+			/* Allocate space for FIFOs in the host memory.
+			 *  (for now this is from a static array of buffers :(
+			 */
+			/* mem_addr = m360_cpm_hostalloc(RX_NUM_FIFO * RX_BUF_SIZE); */
+			/* mem_addr = kmalloc (RX_NUM_FIFO * RX_BUF_SIZE, GFP_BUFFER); */
+			mem_addr = &rx_buf_pool[i * RX_NUM_FIFO * RX_BUF_SIZE];
+
+			/* Set the physical address of the host memory
+			 * buffers in the buffer descriptors, and the
+			 * virtual address for us to work with.
+			 */
+			bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
+			info->rx_cur = info->rx_bd_base = bdp;
+
+			/* initialize rx buffer descriptors */
+			for (j=0; j<(RX_NUM_FIFO-1); j++) {
+				bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
+				bdp->status = BD_SC_EMPTY | BD_SC_INTRPT;
+				mem_addr += RX_BUF_SIZE;
+				bdp++;
+			}
+			bdp->buf = &rx_buf_pool[(i * RX_NUM_FIFO + j ) * RX_BUF_SIZE];
+			bdp->status = BD_SC_WRAP | BD_SC_EMPTY | BD_SC_INTRPT;
+
+
+			idx = PORT_NUM(info->state->smc_scc_num);
+			if (info->state->smc_scc_num & NUM_IS_SCC) {
+
+#if defined (CONFIG_UCQUICC) && 1
+				/* set the transceiver mode to RS232 */
+				sipex_mode_bits &= ~(uint)SIPEX_MODE(idx,0x0f); /* clear current mode */
+				sipex_mode_bits |= (uint)SIPEX_MODE(idx,0x02);
+				*(uint *)_periph_base = sipex_mode_bits;
+				/* printk ("sipex bits = 0x%08x\n", sipex_mode_bits); */
+#endif
+
+				scp = &pquicc->scc_regs[idx];
+				sup = &pquicc->pram[info->state->port].scc.pscc.u;
+				sup->rbase = dp_addr;
+			}
+			else {
+				sp = &cp->smc_regs[idx];
+				up = &pquicc->pram[info->state->port].scc.pothers.idma_smc.psmc.u;
+				up->rbase = dp_addr;
+			}
+
+			dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * TX_NUM_FIFO);
+
+			/* Allocate space for FIFOs in the host memory.
+			*/
+			/* mem_addr = m360_cpm_hostalloc(TX_NUM_FIFO * TX_BUF_SIZE); */
+			/* mem_addr = kmalloc (TX_NUM_FIFO * TX_BUF_SIZE, GFP_BUFFER); */
+			mem_addr = &tx_buf_pool[i * TX_NUM_FIFO * TX_BUF_SIZE];
+
+			/* Set the physical address of the host memory
+			 * buffers in the buffer descriptors, and the
+			 * virtual address for us to work with.
+			 */
+			/* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
+			bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
+			info->tx_cur = info->tx_bd_base = (QUICC_BD *)bdp;
+
+			/* initialize tx buffer descriptors */
+			for (j=0; j<(TX_NUM_FIFO-1); j++) {
+				bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
+				bdp->status = BD_SC_INTRPT;
+				mem_addr += TX_BUF_SIZE;
+				bdp++;
+			}
+			bdp->buf = &tx_buf_pool[(i * TX_NUM_FIFO + j ) * TX_BUF_SIZE];
+			bdp->status = (BD_SC_WRAP | BD_SC_INTRPT);
+
+			if (info->state->smc_scc_num & NUM_IS_SCC) {
+				sup->tbase = dp_addr;
+
+				/* Set up the uart parameters in the
+				 * parameter ram.
+				 */
+				sup->rfcr = SMC_EB;
+				sup->tfcr = SMC_EB;
+
+				/* Set this to 1 for now, so we get single
+				 * character interrupts.  Using idle charater
+				 * time requires some additional tuning.
+				 */
+				sup->mrblr = 1;
+				sup->max_idl = 0;
+				sup->brkcr = 1;
+				sup->parec = 0;
+				sup->frmer = 0;
+				sup->nosec = 0;
+				sup->brkec = 0;
+				sup->uaddr1 = 0;
+				sup->uaddr2 = 0;
+				sup->toseq = 0;
+				{
+					int i;
+					for (i=0;i<8;i++)
+						sup->cc[i] = 0x8000;
+				}
+				sup->rccm = 0xc0ff;
+
+				/* Send the CPM an initialize command.
+				*/
+				chan = scc_chan_map[idx];
+
+				/* execute the INIT RX & TX PARAMS command for this channel. */
+				cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+				while (cp->cp_cr & CPM_CR_FLG);
+
+				/* Set UART mode, 8 bit, no parity, one stop.
+				 * Enable receive and transmit.
+				 */
+				scp->scc_gsmr.w.high = 0;
+				scp->scc_gsmr.w.low = 
+					(SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+				/* Disable all interrupts and clear all pending
+				 * events.
+				 */
+				scp->scc_sccm = 0;
+				scp->scc_scce = 0xffff;
+				scp->scc_dsr = 0x7e7e;
+				scp->scc_psmr = 0x3000;
+
+				/* If the port is the console, enable Rx and Tx.
+				*/
+#ifdef CONFIG_SERIAL_CONSOLE
+				if (i == CONFIG_SERIAL_CONSOLE_PORT)
+					scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+#endif
+			}
+			else {
+				/* Configure SMCs Tx/Rx instead of port B
+				 * parallel I/O.
+				 */
+
+				iobits = 0xc0 << (idx * 4);
+				cp->pip_pbpar |= iobits;
+				cp->pip_pbdir &= ~iobits;
+				cp->pip_pbodr &= ~iobits;
+
+
+				/* Connect the baud rate generator to the
+				 * SMC based upon index in rs_table.  Also
+				 * make sure it is connected to NMSI.
+				 */
+				cp->si_simode &= ~(0xffff << (idx * 16));
+				cp->si_simode |= (i << ((idx * 16) + 12));
+
+				up->tbase = dp_addr;
+
+				/* Set up the uart parameters in the
+				 * parameter ram.
+				 */
+				up->rfcr = SMC_EB;
+				up->tfcr = SMC_EB;
+
+				/* Set this to 1 for now, so we get single
+				 * character interrupts.  Using idle charater
+				 * time requires some additional tuning.
+				 */
+				up->mrblr = 1;
+				up->max_idl = 0;
+				up->brkcr = 1;
+
+				/* Send the CPM an initialize command.
+				*/
+				chan = smc_chan_map[idx];
+
+				cp->cp_cr = mk_cr_cmd(chan,
+									  CPM_CR_INIT_TRX) | CPM_CR_FLG;
+#ifdef CONFIG_SERIAL_CONSOLE
+				if (i == CONFIG_SERIAL_CONSOLE_PORT)
+					printk("");
+#endif
+				while (cp->cp_cr & CPM_CR_FLG);
+
+				/* Set UART mode, 8 bit, no parity, one stop.
+				 * Enable receive and transmit.
+				 */
+				sp->smc_smcmr = smcr_mk_clen(9) | SMCMR_SM_UART;
+
+				/* Disable all interrupts and clear all pending
+				 * events.
+				 */
+				sp->smc_smcm = 0;
+				sp->smc_smce = 0xff;
+
+				/* If the port is the console, enable Rx and Tx.
+				*/
+#ifdef CONFIG_SERIAL_CONSOLE
+				if (i == CONFIG_SERIAL_CONSOLE_PORT)
+					sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+#endif
+			}
+
+			/* Install interrupt handler.
+			*/
+			/* cpm_install_handler(IRQ_MACHSPEC | state->irq, rs_360_interrupt, info);  */
+			/*request_irq(IRQ_MACHSPEC | state->irq, rs_360_interrupt, */
+			request_irq(state->irq, rs_360_interrupt,
+						IRQ_FLG_LOCK, serial_driver.name, (void *)info);
+
+			/* Set up the baud rate generator.
+			*/
+			m360_cpm_setbrg(i, baud_table[baud_idx]);
+
+		}
+	}
+
+	return 0;
+}
+
+
+
+
+
+/* This must always be called before the rs_360_init() function, otherwise
+ * it blows away the port control information.
+ */
+//static int __init serial_console_setup( struct console *co, char *options)
+int serial_console_setup( struct console *co, char *options)
+{
+	struct		serial_state	*ser;
+	uint       mem_addr, dp_addr, bidx, idx, iobits;
+	int i;
+	ushort		chan;
+	QUICC_BD	*bdp;
+	volatile	QUICC			*cp;
+	volatile	struct smc_regs	*sp;
+	volatile	struct scc_regs	*scp;
+	volatile	struct smc_uart_pram	*up;
+	volatile	struct uart_pram		*sup;
+
+/* mleslie TODO:
+ * add something to the 68k bootloader to store a desired initial console baud rate */
+
+/* 	bd_t						*bd; */ /* a board info struct used by EPPC-bug */
+/* 	bd = (bd_t *)__res; */
+
+ 	for (bidx = 0; bidx < (sizeof(baud_table) / sizeof(int)); bidx++)
+	 /* if (bd->bi_baudrate == baud_table[bidx]) */
+ 		if (CONSOLE_BAUDRATE == baud_table[bidx])
+			break;
+
+	/* co->cflag = CREAD|CLOCAL|bidx|CS8; */
+	baud_idx = bidx;
+
+	ser = rs_table + CONFIG_SERIAL_CONSOLE_PORT;
+
+	cp = pquicc;	/* Get pointer to Communication Processor */
+
+	idx = PORT_NUM(ser->smc_scc_num);
+	if (ser->smc_scc_num & NUM_IS_SCC) {
+		scp = &cp->scc_regs[idx];
+		/* sup = (scc_uart_t *)&cp->cp_dparam[ser->port]; */
+		sup = &pquicc->pram[ser->port].scc.pscc.u;
+
+		/* TODO: need to set up SCC pin assignment etc. here */
+		
+	}
+	else {
+		sp = &cp->smc_regs[idx];
+		/* up = (smc_uart_t *)&cp->cp_dparam[ser->port]; */
+		up = &pquicc->pram[ser->port].scc.pothers.idma_smc.psmc.u;
+
+		iobits = 0xc0 << (idx * 4);
+		cp->pip_pbpar |= iobits;
+		cp->pip_pbdir &= ~iobits;
+		cp->pip_pbodr &= ~iobits;
+
+		/* Connect the baud rate generator to the
+		 * SMC based upon index in rs_table.  Also
+		 * make sure it is connected to NMSI.
+		 */
+		cp->si_simode &= ~(0xffff << (idx * 16));
+		cp->si_simode |= (idx << ((idx * 16) + 12));
+	}
+
+	/* When we get here, the CPM has been reset, so we need
+	 * to configure the port.
+	 * We need to allocate a transmit and receive buffer descriptor
+	 * from dual port ram, and a character buffer area from host mem.
+	 */
+
+	/* Allocate space for two buffer descriptors in the DP ram.
+	*/
+	dp_addr = m360_cpm_dpalloc(sizeof(QUICC_BD) * CONSOLE_NUM_FIFO);
+
+	/* Allocate space for two 2 byte FIFOs in the host memory.
+	 */
+	/* mem_addr = m360_cpm_hostalloc(8); */
+	mem_addr = (uint)console_fifos;
+
+
+	/* Set the physical address of the host memory buffers in
+	 * the buffer descriptors.
+	 */
+	/* bdp = (QUICC_BD *)&cp->cp_dpmem[dp_addr]; */
+	bdp = (QUICC_BD *)((uint)pquicc + dp_addr);
+	bdp->buf = (char *)mem_addr;
+	(bdp+1)->buf = (char *)(mem_addr+4);
+
+	/* For the receive, set empty and wrap.
+	 * For transmit, set wrap.
+	 */
+	bdp->status = BD_SC_EMPTY | BD_SC_WRAP;
+	(bdp+1)->status = BD_SC_WRAP;
+
+	/* Set up the uart parameters in the parameter ram.
+	 */
+	if (ser->smc_scc_num & NUM_IS_SCC) {
+
+		sup->rbase = dp_addr;
+		sup->tbase = dp_addr + sizeof(QUICC_BD);
+
+		/* Set up the uart parameters in the
+		 * parameter ram.
+		 */
+		sup->rfcr = SMC_EB;
+		sup->tfcr = SMC_EB;
+
+		/* Set this to 1 for now, so we get single
+		 * character interrupts.  Using idle charater
+		 * time requires some additional tuning.
+		 */
+		sup->mrblr = 1;
+		sup->max_idl = 0;
+		sup->brkcr = 1;
+		sup->parec = 0;
+		sup->frmer = 0;
+		sup->nosec = 0;
+		sup->brkec = 0;
+		sup->uaddr1 = 0;
+		sup->uaddr2 = 0;
+		sup->toseq = 0;
+		{
+			int i;
+			for (i=0;i<8;i++)
+				sup->cc[i] = 0x8000;
+		}
+		sup->rccm = 0xc0ff;
+
+		/* Send the CPM an initialize command.
+		*/
+		chan = scc_chan_map[idx];
+
+		cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+		while (cp->cp_cr & CPM_CR_FLG);
+
+		/* Set UART mode, 8 bit, no parity, one stop.
+		 * Enable receive and transmit.
+		 */
+		scp->scc_gsmr.w.high = 0;
+		scp->scc_gsmr.w.low = 
+			(SCC_GSMRL_MODE_UART | SCC_GSMRL_TDCR_16 | SCC_GSMRL_RDCR_16);
+
+		/* Disable all interrupts and clear all pending
+		 * events.
+		 */
+		scp->scc_sccm = 0;
+		scp->scc_scce = 0xffff;
+		scp->scc_dsr = 0x7e7e;
+		scp->scc_psmr = 0x3000;
+
+		scp->scc_gsmr.w.low |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT);
+
+	}
+	else {
+		up->rbase = dp_addr;	/* Base of receive buffer desc. */
+		up->tbase = dp_addr+sizeof(QUICC_BD);	/* Base of xmt buffer desc. */
+		up->rfcr = SMC_EB;
+		up->tfcr = SMC_EB;
+
+		/* Set this to 1 for now, so we get single character interrupts.
+		*/
+		up->mrblr = 1;		/* receive buffer length */
+		up->max_idl = 0;		/* wait forever for next char */
+
+		/* Send the CPM an initialize command.
+		*/
+		chan = smc_chan_map[idx];
+		cp->cp_cr = mk_cr_cmd(chan, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+		printk("");
+		while (cp->cp_cr & CPM_CR_FLG);
+
+		/* Set UART mode, 8 bit, no parity, one stop.
+		 * Enable receive and transmit.
+		 */
+		sp->smc_smcmr = smcr_mk_clen(9) |  SMCMR_SM_UART;
+
+		/* And finally, enable Rx and Tx.
+		*/
+		sp->smc_smcmr |= SMCMR_REN | SMCMR_TEN;
+	}
+
+	/* Set up the baud rate generator.
+	*/
+	/* m360_cpm_setbrg((ser - rs_table), bd->bi_baudrate); */
+	m360_cpm_setbrg((ser - rs_table), CONSOLE_BAUDRATE);
+
+	return 0;
+}
+
+/*
+ * Local variables:
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
diff -Nru a/drivers/serial/Kconfig b/drivers/serial/Kconfig
--- a/drivers/serial/Kconfig	Sun Nov 10 19:28:41 2002
+++ b/drivers/serial/Kconfig	Sun Nov 10 19:28:41 2002
@@ -325,15 +325,58 @@
 	  (PCI) UltraSPARC systems.  Say Y or M if you want to be able to these
 	  serial ports.
 
+config V850E_NB85E_UART
+	bool "NEC V850E on-chip UART support"
+	depends on V850E_NB85E || V850E2_ANNA
+	default y
+
+config V850E_NB85E_UART_CONSOLE
+	bool "Use NEC V850E on-chip UART for console"
+	depends on V850E_NB85E_UART
+
 config SERIAL_CORE
 	tristate
-	default m if SERIAL_AMBA!=y && SERIAL_CLPS711X!=y && SERIAL_21285!=y && !SERIAL_SA1100 && !SERIAL_ANAKIN && !SERIAL_UART00 && SERIAL_8250!=y && !SERIAL_ROCKETPORT && !SERIAL_SUNCORE && (SERIAL_AMBA=m || SERIAL_CLPS711X=m || SERIAL_21285=m || SERIAL_8250=m)
-	default y if SERIAL_AMBA=y || SERIAL_CLPS711X=y || SERIAL_21285=y || SERIAL_SA1100 || SERIAL_ANAKIN || SERIAL_UART00 || SERIAL_8250=y || SERIAL_ROCKETPORT || SERIAL_SUNCORE
+	default m if SERIAL_AMBA!=y && SERIAL_CLPS711X!=y && SERIAL_21285!=y && !SERIAL_SA1100 && !SERIAL_ANAKIN && !SERIAL_UART00 && SERIAL_8250!=y && !SERIAL_ROCKETPORT && !SERIAL_SUNCORE && !V850E_NB85E_UART && (SERIAL_AMBA=m || SERIAL_CLPS711X=m || SERIAL_21285=m || SERIAL_8250=m)
+	default y if SERIAL_AMBA=y || SERIAL_CLPS711X=y || SERIAL_21285=y || SERIAL_SA1100 || SERIAL_ANAKIN || SERIAL_UART00 || SERIAL_8250=y || SERIAL_ROCKETPORT || SERIAL_SUNCORE || V850E_NB85E_UART
 
 config SERIAL_CORE_CONSOLE
 	bool
-	depends on SERIAL_AMBA_CONSOLE || SERIAL_CLPS711X_CONSOLE || SERIAL_21285_CONSOLE || SERIAL_SA1100_CONSOLE || SERIAL_ANAKIN_CONSOLE || SERIAL_UART00_CONSOLE || SERIAL_8250_CONSOLE || SERIAL_SUNCORE
+	depends on SERIAL_AMBA_CONSOLE || SERIAL_CLPS711X_CONSOLE || SERIAL_21285_CONSOLE || SERIAL_SA1100_CONSOLE || SERIAL_ANAKIN_CONSOLE || SERIAL_UART00_CONSOLE || SERIAL_8250_CONSOLE || SERIAL_SUNCORE || V850E_NB85E_UART_CONSOLE
 	default y
+
+config SERIAL_68328
+	bool "68328 serial support"
+	depends on M68328 || M68EZ328 || M68VZ328
+	help
+	  This driver supports the built-in serial port of the Motorola 68328
+	  (standard, EZ and VZ varities).
+
+config SERIAL_68328_RTS_CTS
+	bool "Support RTS/CTS on 68328 serial port"
+	depends on SERIAL_68328
+
+config SERIAL_COLDFIRE
+	bool "ColdFire serial support"
+	depends on COLDFIRE
+	help
+	  This driver supports the built-in serial ports of the Motorola ColdFire
+	  family of CPUs.
+
+config SERIAL_68360_SMC
+	bool "68360 SMC uart support"
+	depends on M68360
+	help
+	  This driver supports the SMC serial ports of the Motorola 68360 CPU.
+
+config SERIAL_68360_SCC
+	bool "68360 SCC uart support"
+	depends on M68360
+	help
+	  This driver supports the SCC serial ports of the Motorola 68360 CPU.
+
+config 68360_SERIAL
+	bool
+	depends on SERIAL_68360_SMC || SERIAL_68630_SCC
 
 endmenu
 
diff -Nru a/drivers/serial/Makefile b/drivers/serial/Makefile
--- a/drivers/serial/Makefile	Sun Nov 10 19:28:39 2002
+++ b/drivers/serial/Makefile	Sun Nov 10 19:28:39 2002
@@ -24,5 +24,9 @@
 obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o
 obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o
 obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o
+obj-$(CONFIG_SERIAL_68328) += 68328serial.o
+obj-$(CONFIG_SERIAL_68360) += 68360serial.o
+obj-$(CONFIG_SERIAL_COLDFIRE) += mcfserial.o
+obj-$(CONFIG_V850E_NB85E_UART) += nb85e_uart.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/drivers/serial/amba.c b/drivers/serial/amba.c
--- a/drivers/serial/amba.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/serial/amba.c	Sun Nov 10 19:28:37 2002
@@ -231,7 +231,7 @@
 		return;
 	}
 	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-		ambauart_stop_tx(port);
+		ambauart_stop_tx(port, 0);
 		return;
 	}
 
@@ -248,7 +248,7 @@
 		uart_write_wakeup(port);
 
 	if (uart_circ_empty(xmit))
-		ambauart_stop_tx(port);
+		ambauart_stop_tx(port, 0);
 }
 
 static void ambauart_modem_status(struct uart_port *port)
diff -Nru a/drivers/serial/anakin.c b/drivers/serial/anakin.c
--- a/drivers/serial/anakin.c	Sun Nov 10 19:28:37 2002
+++ b/drivers/serial/anakin.c	Sun Nov 10 19:28:37 2002
@@ -69,7 +69,8 @@
 {
 	struct circ_buf *xmit = &port->info->xmit;
 
-	while (!(anakin_in(port, 0x10) & TXEMPTY));
+	while (!(anakin_in(port, 0x10) & TXEMPTY))
+		barrier();
 	anakin_out(port, 0x14, xmit->buf[xmit->tail]);
 	anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);
 	xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
@@ -386,7 +387,8 @@
 	 *	Now, do each character
 	 */
 	for (i = 0; i < count; i++, s++) {
-		while (!(anakin_in(port, 0x10) & TXEMPTY));
+		while (!(anakin_in(port, 0x10) & TXEMPTY))
+			barrier();
 
 		/*
 		 *	Send the character out.
@@ -396,7 +398,8 @@
 		anakin_out(port, 0x18, anakin_in(port, 0x18) | SENDREQUEST);
 
 		if (*s == 10) {
-			while (!(anakin_in(port, 0x10) & TXEMPTY));
+			while (!(anakin_in(port, 0x10) & TXEMPTY))
+				barrier();
 			anakin_out(port, 0x14, 13);
 			anakin_out(port, 0x18, anakin_in(port, 0x18)
 					| SENDREQUEST);
@@ -407,7 +410,8 @@
 	 *	Finally, wait for transmitter to become empty
 	 *	and restore the interrupts
 	 */
-	while (!(anakin_in(port, 0x10) & TXEMPTY));
+	while (!(anakin_in(port, 0x10) & TXEMPTY))
+		barrier();
 
 	if (status & IRQENABLE) {
 		local_irq_save(flags);
diff -Nru a/drivers/serial/clps711x.c b/drivers/serial/clps711x.c
--- a/drivers/serial/clps711x.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/serial/clps711x.c	Sun Nov 10 19:28:38 2002
@@ -193,7 +193,7 @@
 		return;
 	}
 	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
-		clps711xuart_stop_tx(port);
+		clps711xuart_stop_tx(port, 0);
 		return;
 	}
 
@@ -210,7 +210,7 @@
 		uart_write_wakeup(port);
 
 	if (uart_circ_empty(xmit))
-		clps711xuart_stop_tx(port);
+		clps711xuart_stop_tx(port, 0);
 }
 
 static unsigned int clps711xuart_tx_empty(struct uart_port *port)
@@ -425,6 +425,7 @@
 		.uartclk	= 3686400,
 		.fifosize	= 16,
 		.ops		= &clps711x_pops,
+		.line		= 0,
 		.flags		= ASYNC_BOOT_AUTOCONF,
 	},
 	{
@@ -433,6 +434,7 @@
 		.uartclk	= 3686400,
 		.fifosize	= 16,
 		.ops		= &clps711x_pops,
+		.line		= 1,
 		.flags		= ASYNC_BOOT_AUTOCONF,
 	}
 };
diff -Nru a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/serial/mcfserial.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,1869 @@
+/*
+ * mcfserial.c -- serial driver for ColdFire internal UARTS.
+ *
+ * Copyright (C) 1999-2002 Greg Ungerer <gerg@snapgear.com>
+ * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com> 
+ * Copyright (C) 2001-2002 SnapGear Inc. <www.snapgear.com> 
+ *
+ * Based on code from 68332serial.c which was:
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 TSHG
+ * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org>
+ */
+ 
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/config.h>
+#include <linux/major.h>
+#include <linux/string.h>
+#include <linux/fcntl.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#ifdef CONFIG_LEDMAN
+#include <linux/ledman.h>
+#endif
+#include <linux/console.h>
+#include <linux/version.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/semaphore.h>
+#include <asm/bitops.h>
+#include <asm/delay.h>
+#include <asm/coldfire.h>
+#include <asm/mcfsim.h>
+#include <asm/mcfuart.h>
+#include <asm/nettel.h>
+#include <asm/uaccess.h>
+#include "mcfserial.h"
+
+/*
+ *	the only event we use
+ */
+#undef RS_EVENT_WRITE_WAKEUP
+#define RS_EVENT_WRITE_WAKEUP 0
+
+struct timer_list mcfrs_timer_struct;
+
+/*
+ *	Default console baud rate,  we use this as the default
+ *	for all ports so init can just open /dev/console and
+ *	keep going.  Perhaps one day the cflag settings for the
+ *	console can be used instead.
+ */
+#if defined(CONFIG_ARNEWSH) || defined(CONFIG_MOTOROLA) || defined(CONFIG_senTec)
+#define	CONSOLE_BAUD_RATE	19200
+#define	DEFAULT_CBAUD		B19200
+#endif
+
+#ifndef CONSOLE_BAUD_RATE
+#define	CONSOLE_BAUD_RATE	9600
+#define	DEFAULT_CBAUD		B9600
+#endif
+
+int mcfrs_console_inited = 0;
+int mcfrs_console_port = -1;
+int mcfrs_console_baud = CONSOLE_BAUD_RATE;
+int mcfrs_console_cbaud = DEFAULT_CBAUD;
+
+/*
+ *	Driver data structures.
+ */
+struct tty_driver	mcfrs_serial_driver, mcfrs_callout_driver;
+static int		mcfrs_serial_refcount;
+
+/* serial subtype definitions */
+#define SERIAL_TYPE_NORMAL	1
+#define SERIAL_TYPE_CALLOUT	2
+  
+/* number of characters left in xmit buffer before we ask for more */
+#define WAKEUP_CHARS 256
+
+/* Debugging...
+ */
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+
+#define _INLINE_ inline
+
+#define	IRQBASE	73
+
+/*
+ *	Configuration table, UARTs to look for at startup.
+ */
+static struct mcf_serial mcfrs_table[] = {
+  { 0, (MCF_MBAR+MCFUART_BASE1), IRQBASE,   ASYNC_BOOT_AUTOCONF },  /* ttyS0 */
+  { 0, (MCF_MBAR+MCFUART_BASE2), IRQBASE+1, ASYNC_BOOT_AUTOCONF },  /* ttyS1 */
+};
+
+
+#define	NR_PORTS	(sizeof(mcfrs_table) / sizeof(struct mcf_serial))
+
+static struct tty_struct	*mcfrs_serial_table[NR_PORTS];
+static struct termios		*mcfrs_serial_termios[NR_PORTS];
+static struct termios		*mcfrs_serial_termios_locked[NR_PORTS];
+
+/*
+ * This is used to figure out the divisor speeds and the timeouts.
+ */
+static int mcfrs_baud_table[] = {
+	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
+	9600, 19200, 38400, 57600, 115200, 230400, 460800, 0
+};
+#define MCFRS_BAUD_TABLE_SIZE \
+			(sizeof(mcfrs_baud_table)/sizeof(mcfrs_baud_table[0]))
+
+
+#ifdef CONFIG_MAGIC_SYSRQ
+/*
+ *	Magic system request keys. Used for debugging...
+ */
+extern int	magic_sysrq_key(int ch);
+#endif
+
+
+/*
+ * tmp_buf is used as a temporary buffer by serial_write.  We need to
+ * lock it in case the copy_from_user blocks while swapping in a page,
+ * and some other program tries to do a serial write at the same time.
+ * Since the lock will only come under contention when the system is
+ * swapping and available memory is low, it makes sense to share one
+ * buffer across all the serial ports, since it significantly saves
+ * memory if large numbers of serial ports are open.
+ */
+static unsigned char mcfrs_tmp_buf[4096]; /* This is cheating */
+static DECLARE_MUTEX(mcfrs_tmp_buf_sem);
+
+/*
+ *	Forware declarations...
+ */
+static void	mcfrs_change_speed(struct mcf_serial *info);
+
+
+static inline int serial_paranoia_check(struct mcf_serial *info,
+					kdev_t device, const char *routine)
+{
+#ifdef SERIAL_PARANOIA_CHECK
+	static const char *badmagic =
+		"MCFRS(warning): bad magic number for serial struct (%d, %d) in %s\n";
+	static const char *badinfo =
+		"MCFRS(warning): null mcf_serial for (%d, %d) in %s\n";
+
+	if (!info) {
+		printk(badinfo, MAJOR(device), MINOR(device), routine);
+		return 1;
+	}
+	if (info->magic != SERIAL_MAGIC) {
+		printk(badmagic, MAJOR(device), MINOR(device), routine);
+		return 1;
+	}
+#endif
+	return 0;
+}
+
+/*
+ *	Sets or clears DTR and RTS on the requested line.
+ */
+static void mcfrs_setsignals(struct mcf_serial *info, int dtr, int rts)
+{
+	volatile unsigned char	*uartp;
+	unsigned long		flags;
+	
+#if 0
+	printk("%s(%d): mcfrs_setsignals(info=%x,dtr=%d,rts=%d)\n",
+		__FILE__, __LINE__, info, dtr, rts);
+#endif
+
+	local_irq_save(flags);
+	if (dtr >= 0) {
+#ifdef MCFPP_DTR0
+		if (info->line)
+			mcf_setppdata(MCFPP_DTR1, (dtr ? 0 : MCFPP_DTR1));
+		else
+			mcf_setppdata(MCFPP_DTR0, (dtr ? 0 : MCFPP_DTR0));
+#endif
+	}
+	if (rts >= 0) {
+		uartp = (volatile unsigned char *) info->addr;
+		if (rts) {
+			info->sigs |= TIOCM_RTS;
+			uartp[MCFUART_UOP1] = MCFUART_UOP_RTS;
+		} else {
+			info->sigs &= ~TIOCM_RTS;
+			uartp[MCFUART_UOP0] = MCFUART_UOP_RTS;
+		}
+	}
+	local_irq_restore(flags);
+	return;
+}
+
+/*
+ *	Gets values of serial signals.
+ */
+static int mcfrs_getsignals(struct mcf_serial *info)
+{
+	volatile unsigned char	*uartp;
+	unsigned long		flags;
+	int			sigs;
+#if defined(CONFIG_NETtel) && defined(CONFIG_M5307)
+	unsigned short		ppdata;
+#endif
+
+#if 0
+	printk("%s(%d): mcfrs_getsignals(info=%x)\n", __FILE__, __LINE__);
+#endif
+
+	local_irq_save(flags);
+	uartp = (volatile unsigned char *) info->addr;
+	sigs = (uartp[MCFUART_UIPR] & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS;
+	sigs |= (info->sigs & TIOCM_RTS);
+
+#ifdef MCFPP_DCD0
+{
+	unsigned int ppdata;
+	ppdata = mcf_getppdata();
+	if (info->line == 0) {
+		sigs |= (ppdata & MCFPP_DCD0) ? 0 : TIOCM_CD;
+		sigs |= (ppdata & MCFPP_DTR0) ? 0 : TIOCM_DTR;
+	} else if (info->line == 1) {
+		sigs |= (ppdata & MCFPP_DCD1) ? 0 : TIOCM_CD;
+		sigs |= (ppdata & MCFPP_DTR1) ? 0 : TIOCM_DTR;
+	}
+}
+#endif
+
+	local_irq_restore(flags);
+	return(sigs);
+}
+
+/*
+ * ------------------------------------------------------------
+ * mcfrs_stop() and mcfrs_start()
+ *
+ * This routines are called before setting or resetting tty->stopped.
+ * They enable or disable transmitter interrupts, as necessary.
+ * ------------------------------------------------------------
+ */
+static void mcfrs_stop(struct tty_struct *tty)
+{
+	volatile unsigned char	*uartp;
+	struct mcf_serial	*info = (struct mcf_serial *)tty->driver_data;
+	unsigned long		flags;
+
+	if (serial_paranoia_check(info, tty->device, "mcfrs_stop"))
+		return;
+	
+	local_irq_save(flags);
+	uartp = (volatile unsigned char *) info->addr;
+	info->imr &= ~MCFUART_UIR_TXREADY;
+	uartp[MCFUART_UIMR] = info->imr;
+	local_irq_restore(flags);
+}
+
+static void mcfrs_start(struct tty_struct *tty)
+{
+	volatile unsigned char	*uartp;
+	struct mcf_serial	*info = (struct mcf_serial *)tty->driver_data;
+	unsigned long		flags;
+	
+	if (serial_paranoia_check(info, tty->device, "mcfrs_start"))
+		return;
+
+	local_irq_save(flags);
+	if (info->xmit_cnt && info->xmit_buf) {
+		uartp = (volatile unsigned char *) info->addr;
+		info->imr |= MCFUART_UIR_TXREADY;
+		uartp[MCFUART_UIMR] = info->imr;
+	}
+	local_irq_restore(flags);
+}
+
+/*
+ * ----------------------------------------------------------------------
+ *
+ * Here starts the interrupt handling routines.  All of the following
+ * subroutines are declared as inline and are folded into
+ * mcfrs_interrupt().  They were separated out for readability's sake.
+ *
+ * Note: mcfrs_interrupt() is a "fast" interrupt, which means that it
+ * runs with interrupts turned off.  People who may want to modify
+ * mcfrs_interrupt() should try to keep the interrupt handler as fast as
+ * possible.  After you are done making modifications, it is not a bad
+ * idea to do:
+ * 
+ * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c
+ *
+ * and look at the resulting assemble code in serial.s.
+ *
+ * 				- Ted Ts'o (tytso@mit.edu), 7-Mar-93
+ * -----------------------------------------------------------------------
+ */
+
+static _INLINE_ void receive_chars(struct mcf_serial *info, struct pt_regs *regs, unsigned short rx)
+{
+	volatile unsigned char	*uartp;
+	struct tty_struct	*tty = info->tty;
+	unsigned char		status, ch;
+
+	if (!tty)
+		return;
+
+#if defined(CONFIG_LEDMAN)
+	ledman_cmd(LEDMAN_CMD_SET, info->line ? LEDMAN_COM2_RX : LEDMAN_COM1_RX);
+#endif
+
+	uartp = (volatile unsigned char *) info->addr;
+
+	while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) {
+
+		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+			break;
+
+		ch = uartp[MCFUART_URB];
+		info->stats.rx++;
+
+#ifdef CONFIG_MAGIC_SYSRQ
+		if (mcfrs_console_inited && (info->line == mcfrs_console_port)) {
+			if (magic_sysrq_key(ch))
+				continue;
+		}
+#endif
+
+		tty->flip.count++;
+		if (status & MCFUART_USR_RXERR)
+			uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETERR;
+		if (status & MCFUART_USR_RXBREAK) {
+			info->stats.rxbreak++;
+			*tty->flip.flag_buf_ptr++ = TTY_BREAK;
+		} else if (status & MCFUART_USR_RXPARITY) {
+			info->stats.rxparity++;
+			*tty->flip.flag_buf_ptr++ = TTY_PARITY;
+		} else if (status & MCFUART_USR_RXOVERRUN) {
+			info->stats.rxoverrun++;
+			*tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
+		} else if (status & MCFUART_USR_RXFRAMING) {
+			info->stats.rxframing++;
+			*tty->flip.flag_buf_ptr++ = TTY_FRAME;
+		} else {
+			*tty->flip.flag_buf_ptr++ = 0;
+		}
+		*tty->flip.char_buf_ptr++ = ch;
+	}
+
+	schedule_work(&tty->flip.work);
+	return;
+}
+
+static _INLINE_ void transmit_chars(struct mcf_serial *info)
+{
+	volatile unsigned char	*uartp;
+
+#if defined(CONFIG_LEDMAN)
+	ledman_cmd(LEDMAN_CMD_SET, info->line ? LEDMAN_COM2_TX : LEDMAN_COM1_TX);
+#endif
+
+	uartp = (volatile unsigned char *) info->addr;
+
+	if (info->x_char) {
+		/* Send special char - probably flow control */
+		uartp[MCFUART_UTB] = info->x_char;
+		info->x_char = 0;
+		info->stats.tx++;
+	}
+
+	if ((info->xmit_cnt <= 0) || info->tty->stopped) {
+		info->imr &= ~MCFUART_UIR_TXREADY;
+		uartp[MCFUART_UIMR] = info->imr;
+		return;
+	}
+
+	while (uartp[MCFUART_USR] & MCFUART_USR_TXREADY) {
+		uartp[MCFUART_UTB] = info->xmit_buf[info->xmit_tail++];
+		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+		info->stats.tx++;
+		if (--info->xmit_cnt <= 0)
+			break;
+	}
+
+	if (info->xmit_cnt < WAKEUP_CHARS)
+		schedule_work(&info->tqueue);
+	return;
+}
+
+/*
+ * This is the serial driver's generic interrupt routine
+ */
+void mcfrs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct mcf_serial	*info;
+	unsigned char		isr;
+
+	info = &mcfrs_table[(irq - IRQBASE)];
+	isr = (((volatile unsigned char *)info->addr)[MCFUART_UISR]) & info->imr;
+
+	if (isr & MCFUART_UIR_RXREADY)
+		receive_chars(info, regs, isr);
+	if (isr & MCFUART_UIR_TXREADY)
+		transmit_chars(info);
+#if 0
+	if (isr & MCFUART_UIR_DELTABREAK) {
+		printk("%s(%d): delta break!\n", __FILE__, __LINE__);
+		receive_chars(info, regs, isr);
+	}
+#endif
+
+	return;
+}
+
+/*
+ * -------------------------------------------------------------------
+ * Here ends the serial interrupt routines.
+ * -------------------------------------------------------------------
+ */
+
+static void mcfrs_offintr(void *private)
+{
+	struct mcf_serial	*info = (struct mcf_serial *) private;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {
+		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		    tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+		wake_up_interruptible(&tty->write_wait);
+	}
+}
+
+
+/*
+ *	Change of state on a DCD line.
+ */
+void mcfrs_modem_change(struct mcf_serial *info, int dcd)
+{
+	if (info->count == 0)
+		return;
+
+	if (info->flags & ASYNC_CHECK_CD) {
+		if (dcd) {
+			wake_up_interruptible(&info->open_wait);
+		} else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_CALLOUT_NOHUP))) {
+			schedule_work(&info->tqueue_hangup);
+		}
+	}
+}
+
+
+#ifdef MCFPP_DCD0
+
+unsigned short	mcfrs_ppstatus;
+
+/*
+ * This subroutine is called when the RS_TIMER goes off. It is used
+ * to monitor the state of the DCD lines - since they have no edge
+ * sensors and interrupt generators.
+ */
+static void mcfrs_timer(void)
+{
+	unsigned int	ppstatus, dcdval, i;
+
+	ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);
+
+	if (ppstatus != mcfrs_ppstatus) {
+		for (i = 0; (i < 2); i++) {
+			dcdval = (i ? MCFPP_DCD1 : MCFPP_DCD0);
+			if ((ppstatus & dcdval) != (mcfrs_ppstatus & dcdval)) {
+				mcfrs_modem_change(&mcfrs_table[i],
+					((ppstatus & dcdval) ? 0 : 1));
+			}
+		}
+	}
+	mcfrs_ppstatus = ppstatus;
+
+	/* Re-arm timer */
+	mcfrs_timer_struct.expires = jiffies + HZ/25;
+	add_timer(&mcfrs_timer_struct);
+}
+
+#endif	/* MCFPP_DCD0 */
+
+
+/*
+ * This routine is called from the scheduler tqueue when the interrupt
+ * routine has signalled that a hangup has occurred. The path of
+ * hangup processing is:
+ *
+ * 	serial interrupt routine -> (scheduler tqueue) ->
+ * 	do_serial_hangup() -> tty->hangup() -> mcfrs_hangup()
+ * 
+ */
+static void do_serial_hangup(void *private)
+{
+	struct mcf_serial	*info = (struct mcf_serial *) private;
+	struct tty_struct	*tty;
+	
+	tty = info->tty;
+	if (!tty)
+		return;
+
+	tty_hangup(tty);
+}
+
+static int startup(struct mcf_serial * info)
+{
+	volatile unsigned char	*uartp;
+	unsigned long		flags;
+	
+	if (info->flags & ASYNC_INITIALIZED)
+		return 0;
+
+	if (!info->xmit_buf) {
+		info->xmit_buf = (unsigned char *) __get_free_page(GFP_KERNEL);
+		if (!info->xmit_buf)
+			return -ENOMEM;
+	}
+
+	local_irq_save(flags);
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
+#endif
+
+	/*
+	 *	Reset UART, get it into known state...
+	 */
+	uartp = (volatile unsigned char *) info->addr;
+	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */
+	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
+	mcfrs_setsignals(info, 1, 1);
+
+	if (info->tty)
+		clear_bit(TTY_IO_ERROR, &info->tty->flags);
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+
+	/*
+	 * and set the speed of the serial port
+	 */
+	mcfrs_change_speed(info);
+
+	/*
+	 * Lastly enable the UART transmitter and receiver, and
+	 * interrupt enables.
+	 */
+	info->imr = MCFUART_UIR_RXREADY;
+	uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
+	uartp[MCFUART_UIMR] = info->imr;
+
+	info->flags |= ASYNC_INITIALIZED;
+	local_irq_restore(flags);
+	return 0;
+}
+
+/*
+ * This routine will shutdown a serial port; interrupts are disabled, and
+ * DTR is dropped if the hangup on close termio flag is on.
+ */
+static void shutdown(struct mcf_serial * info)
+{
+	volatile unsigned char	*uartp;
+	unsigned long		flags;
+
+	if (!(info->flags & ASYNC_INITIALIZED))
+		return;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("Shutting down serial port %d (irq %d)....\n", info->line,
+	       info->irq);
+#endif
+	
+	local_irq_save(flags);
+
+	uartp = (volatile unsigned char *) info->addr;
+	uartp[MCFUART_UIMR] = 0;  /* mask all interrupts */
+	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */
+	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
+
+	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
+		mcfrs_setsignals(info, 0, 0);
+
+	if (info->xmit_buf) {
+		free_page((unsigned long) info->xmit_buf);
+		info->xmit_buf = 0;
+	}
+
+	if (info->tty)
+		set_bit(TTY_IO_ERROR, &info->tty->flags);
+	
+	info->flags &= ~ASYNC_INITIALIZED;
+	local_irq_restore(flags);
+}
+
+
+/*
+ * This routine is called to set the UART divisor registers to match
+ * the specified baud rate for a serial port.
+ */
+static void mcfrs_change_speed(struct mcf_serial *info)
+{
+	volatile unsigned char	*uartp;
+	unsigned int		baudclk, cflag;
+	unsigned long		flags;
+	unsigned char		mr1, mr2;
+	int			i;
+
+	if (!info->tty || !info->tty->termios)
+		return;
+	cflag = info->tty->termios->c_cflag;
+	if (info->addr == 0)
+		return;
+
+#if 0
+	printk("%s(%d): mcfrs_change_speed()\n", __FILE__, __LINE__);
+#endif
+
+	i = cflag & CBAUD;
+	if (i & CBAUDEX) {
+		i &= ~CBAUDEX;
+		if (i < 1 || i > 4)
+			info->tty->termios->c_cflag &= ~CBAUDEX;
+		else
+			i += 15;
+	}
+	if (i == 0) {
+		mcfrs_setsignals(info, 0, -1);
+		return;
+	}
+	baudclk = ((MCF_BUSCLK / mcfrs_baud_table[i]) + 16) / 32;
+	info->baud = mcfrs_baud_table[i];
+
+	mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
+	mr2 = 0;
+
+	switch (cflag & CSIZE) {
+	case CS5:	mr1 |= MCFUART_MR1_CS5; break;
+	case CS6:	mr1 |= MCFUART_MR1_CS6; break;
+	case CS7:	mr1 |= MCFUART_MR1_CS7; break;
+	case CS8:
+	default:	mr1 |= MCFUART_MR1_CS8; break;
+	}
+
+	if (cflag & PARENB) {
+		if (cflag & PARODD)
+			mr1 |= MCFUART_MR1_PARITYODD;
+		else
+			mr1 |= MCFUART_MR1_PARITYEVEN;
+	} else {
+		mr1 |= MCFUART_MR1_PARITYNONE;
+	}
+
+	if (cflag & CSTOPB)
+		mr2 |= MCFUART_MR2_STOP2;
+	else
+		mr2 |= MCFUART_MR2_STOP1;
+
+	if (cflag & CRTSCTS) {
+		mr1 |= MCFUART_MR1_RXRTS;
+		mr2 |= MCFUART_MR2_TXCTS;
+	}
+
+	if (cflag & CLOCAL)
+		info->flags &= ~ASYNC_CHECK_CD;
+	else
+		info->flags |= ASYNC_CHECK_CD;
+
+	uartp = (volatile unsigned char *) info->addr;
+
+	local_irq_save(flags);
+#if 0
+	printk("%s(%d): mr1=%x mr2=%x baudclk=%x\n", __FILE__, __LINE__,
+		mr1, mr2, baudclk);
+#endif
+	/*
+	  Note: pg 12-16 of MCF5206e User's Manual states that a
+	  software reset should be performed prior to changing
+	  UMR1,2, UCSR, UACR, bit 7
+	*/
+	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;    /* reset RX */
+	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;    /* reset TX */
+	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR;	/* reset MR pointer */
+	uartp[MCFUART_UMR] = mr1;
+	uartp[MCFUART_UMR] = mr2;
+	uartp[MCFUART_UBG1] = (baudclk & 0xff00) >> 8;	/* set msb byte */
+	uartp[MCFUART_UBG2] = (baudclk & 0xff);		/* set lsb byte */
+	uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;
+	uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
+	mcfrs_setsignals(info, 1, -1);
+	local_irq_restore(flags);
+	return;
+}
+
+static void mcfrs_flush_chars(struct tty_struct *tty)
+{
+	volatile unsigned char	*uartp;
+	struct mcf_serial	*info = (struct mcf_serial *)tty->driver_data;
+	unsigned long		flags;
+
+	if (serial_paranoia_check(info, tty->device, "mcfrs_flush_chars"))
+		return;
+
+	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
+	    !info->xmit_buf)
+		return;
+
+	/* Enable transmitter */
+	local_irq_save(flags);
+	uartp = (volatile unsigned char *) info->addr;
+	info->imr |= MCFUART_UIR_TXREADY;
+	uartp[MCFUART_UIMR] = info->imr;
+	local_irq_restore(flags);
+}
+
+static int mcfrs_write(struct tty_struct * tty, int from_user,
+		    const unsigned char *buf, int count)
+{
+	volatile unsigned char	*uartp;
+	struct mcf_serial	*info = (struct mcf_serial *)tty->driver_data;
+	unsigned long		flags;
+	int			c, total = 0;
+
+#if 0
+	printk("%s(%d): mcfrs_write(tty=%x,from_user=%d,buf=%x,count=%d)\n",
+		__FILE__, __LINE__, tty, from_user, buf, count);
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "mcfrs_write"))
+		return 0;
+
+	if (!tty || !info->xmit_buf)
+		return 0;
+	
+	local_save_flags(flags);
+	while (1) {
+		local_irq_disable();		
+		c = min(count, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				   SERIAL_XMIT_SIZE - info->xmit_head));
+
+		if (c <= 0) {
+			local_irq_restore(flags);
+			break;
+		}
+
+		if (from_user) {
+			down(&mcfrs_tmp_buf_sem);
+			copy_from_user(mcfrs_tmp_buf, buf, c);
+			local_irq_restore(flags);
+			local_irq_disable();
+			c = min(c, min(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
+				       SERIAL_XMIT_SIZE - info->xmit_head));
+			memcpy(info->xmit_buf + info->xmit_head, mcfrs_tmp_buf, c);
+			up(&mcfrs_tmp_buf_sem);
+		} else
+			memcpy(info->xmit_buf + info->xmit_head, buf, c);
+
+		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
+		info->xmit_cnt += c;
+		local_irq_restore(flags);
+
+		buf += c;
+		count -= c;
+		total += c;
+	}
+
+	local_irq_disable();
+	uartp = (volatile unsigned char *) info->addr;
+	info->imr |= MCFUART_UIR_TXREADY;
+	uartp[MCFUART_UIMR] = info->imr;
+	local_irq_restore(flags);
+
+	return total;
+}
+
+static int mcfrs_write_room(struct tty_struct *tty)
+{
+	struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
+	int	ret;
+				
+	if (serial_paranoia_check(info, tty->device, "mcfrs_write_room"))
+		return 0;
+	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
+	if (ret < 0)
+		ret = 0;
+	return ret;
+}
+
+static int mcfrs_chars_in_buffer(struct tty_struct *tty)
+{
+	struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
+				
+	if (serial_paranoia_check(info, tty->device, "mcfrs_chars_in_buffer"))
+		return 0;
+	return info->xmit_cnt;
+}
+
+static void mcfrs_flush_buffer(struct tty_struct *tty)
+{
+	struct mcf_serial	*info = (struct mcf_serial *)tty->driver_data;
+	unsigned long		flags;
+				
+	if (serial_paranoia_check(info, tty->device, "mcfrs_flush_buffer"))
+		return;
+
+	local_irq_save(flags);
+	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	local_irq_restore(flags);
+
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+	    tty->ldisc.write_wakeup)
+		(tty->ldisc.write_wakeup)(tty);
+}
+
+/*
+ * ------------------------------------------------------------
+ * mcfrs_throttle()
+ * 
+ * This routine is called by the upper-layer tty layer to signal that
+ * incoming characters should be throttled.
+ * ------------------------------------------------------------
+ */
+static void mcfrs_throttle(struct tty_struct * tty)
+{
+	struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("throttle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "mcfrs_throttle"))
+		return;
+	
+	if (I_IXOFF(tty))
+		info->x_char = STOP_CHAR(tty);
+
+	/* Turn off RTS line (do this atomic) */
+}
+
+static void mcfrs_unthrottle(struct tty_struct * tty)
+{
+	struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
+#ifdef SERIAL_DEBUG_THROTTLE
+	char	buf[64];
+	
+	printk("unthrottle %s: %d....\n", _tty_name(tty, buf),
+	       tty->ldisc.chars_in_buffer(tty));
+#endif
+
+	if (serial_paranoia_check(info, tty->device, "mcfrs_unthrottle"))
+		return;
+	
+	if (I_IXOFF(tty)) {
+		if (info->x_char)
+			info->x_char = 0;
+		else
+			info->x_char = START_CHAR(tty);
+	}
+
+	/* Assert RTS line (do this atomic) */
+}
+
+/*
+ * ------------------------------------------------------------
+ * mcfrs_ioctl() and friends
+ * ------------------------------------------------------------
+ */
+
+static int get_serial_info(struct mcf_serial * info,
+			   struct serial_struct * retinfo)
+{
+	struct serial_struct tmp;
+  
+	if (!retinfo)
+		return -EFAULT;
+	memset(&tmp, 0, sizeof(tmp));
+	tmp.type = info->type;
+	tmp.line = info->line;
+	tmp.port = info->addr;
+	tmp.irq = info->irq;
+	tmp.flags = info->flags;
+	tmp.baud_base = info->baud_base;
+	tmp.close_delay = info->close_delay;
+	tmp.closing_wait = info->closing_wait;
+	tmp.custom_divisor = info->custom_divisor;
+	copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+	return 0;
+}
+
+static int set_serial_info(struct mcf_serial * info,
+			   struct serial_struct * new_info)
+{
+	struct serial_struct new_serial;
+	struct mcf_serial old_info;
+	int 	retval = 0;
+
+	if (!new_info)
+		return -EFAULT;
+	copy_from_user(&new_serial,new_info,sizeof(new_serial));
+	old_info = *info;
+
+	if (!capable(CAP_SYS_ADMIN)) {
+		if ((new_serial.baud_base != info->baud_base) ||
+		    (new_serial.type != info->type) ||
+		    (new_serial.close_delay != info->close_delay) ||
+		    ((new_serial.flags & ~ASYNC_USR_MASK) !=
+		     (info->flags & ~ASYNC_USR_MASK)))
+			return -EPERM;
+		info->flags = ((info->flags & ~ASYNC_USR_MASK) |
+			       (new_serial.flags & ASYNC_USR_MASK));
+		info->custom_divisor = new_serial.custom_divisor;
+		goto check_and_exit;
+	}
+
+	if (info->count > 1)
+		return -EBUSY;
+
+	/*
+	 * OK, past this point, all the error checking has been done.
+	 * At this point, we start making changes.....
+	 */
+
+	info->baud_base = new_serial.baud_base;
+	info->flags = ((info->flags & ~ASYNC_FLAGS) |
+			(new_serial.flags & ASYNC_FLAGS));
+	info->type = new_serial.type;
+	info->close_delay = new_serial.close_delay;
+	info->closing_wait = new_serial.closing_wait;
+
+check_and_exit:
+	retval = startup(info);
+	return retval;
+}
+
+/*
+ * get_lsr_info - get line status register info
+ *
+ * Purpose: Let user call ioctl() to get info when the UART physically
+ * 	    is emptied.  On bus types like RS485, the transmitter must
+ * 	    release the bus after transmitting. This must be done when
+ * 	    the transmit shift register is empty, not be done when the
+ * 	    transmit holding register is empty.  This functionality
+ * 	    allows an RS485 driver to be written in user space. 
+ */
+static int get_lsr_info(struct mcf_serial * info, unsigned int *value)
+{
+	volatile unsigned char	*uartp;
+	unsigned long		flags;
+	unsigned char		status;
+
+	local_irq_save(flags);
+	uartp = (volatile unsigned char *) info->addr;
+	status = (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0;
+	local_irq_restore(flags);
+
+	put_user(status,value);
+	return 0;
+}
+
+/*
+ * This routine sends a break character out the serial port.
+ */
+static void send_break(	struct mcf_serial * info, int duration)
+{
+	volatile unsigned char	*uartp;
+	unsigned long		flags;
+
+	if (!info->addr)
+		return;
+	current->state = TASK_INTERRUPTIBLE;
+	uartp = (volatile unsigned char *) info->addr;
+
+	local_irq_save(flags);
+	uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTART;
+	schedule_timeout(jiffies + duration);
+	uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTOP;
+	local_irq_restore(flags);
+}
+
+static int mcfrs_ioctl(struct tty_struct *tty, struct file * file,
+		    unsigned int cmd, unsigned long arg)
+{
+	struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
+	unsigned int val;
+	int retval, error;
+	int dtr, rts;
+
+	if (serial_paranoia_check(info, tty->device, "mcfrs_ioctl"))
+		return -ENODEV;
+
+	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
+	    (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD)  &&
+	    (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) {
+		if (tty->flags & (1 << TTY_IO_ERROR))
+		    return -EIO;
+	}
+	
+	switch (cmd) {
+		case TCSBRK:	/* SVID version: non-zero arg --> no break */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (!arg)
+				send_break(info, HZ/4);	/* 1/4 second */
+			return 0;
+		case TCSBRKP:	/* support for POSIX tcsendbreak() */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			send_break(info, arg ? arg*(HZ/10) : HZ/4);
+			return 0;
+		case TIOCGSOFTCAR:
+			error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
+			if (error)
+				return error;
+			put_user(C_CLOCAL(tty) ? 1 : 0,
+				    (unsigned long *) arg);
+			return 0;
+		case TIOCSSOFTCAR:
+			get_user(arg, (unsigned long *) arg);
+			tty->termios->c_cflag =
+				((tty->termios->c_cflag & ~CLOCAL) |
+				 (arg ? CLOCAL : 0));
+			return 0;
+		case TIOCGSERIAL:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+						sizeof(struct serial_struct));
+			if (error)
+				return error;
+			return get_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSSERIAL:
+			return set_serial_info(info,
+					       (struct serial_struct *) arg);
+		case TIOCSERGETLSR: /* Get line status register */
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+				sizeof(unsigned int));
+			if (error)
+				return error;
+			else
+			    return get_lsr_info(info, (unsigned int *) arg);
+
+		case TIOCSERGSTRUCT:
+			error = verify_area(VERIFY_WRITE, (void *) arg,
+						sizeof(struct mcf_serial));
+			if (error)
+				return error;
+			copy_to_user((struct mcf_serial *) arg,
+				    info, sizeof(struct mcf_serial));
+			return 0;
+			
+		case TIOCMGET:
+			if ((error = verify_area(VERIFY_WRITE, (void *) arg,
+                            sizeof(unsigned int))))
+                                return(error);
+			val = mcfrs_getsignals(info);
+			put_user(val, (unsigned int *) arg);
+			break;
+
+                case TIOCMBIS:
+			if ((error = verify_area(VERIFY_WRITE, (void *) arg,
+                            sizeof(unsigned int))))
+				return(error);
+
+			get_user(val, (unsigned int *) arg);
+			rts = (val & TIOCM_RTS) ? 1 : -1;
+			dtr = (val & TIOCM_DTR) ? 1 : -1;
+			mcfrs_setsignals(info, dtr, rts);
+			break;
+
+                case TIOCMBIC:
+			if ((error = verify_area(VERIFY_WRITE, (void *) arg,
+                            sizeof(unsigned int))))
+				return(error);
+			get_user(val, (unsigned int *) arg);
+			rts = (val & TIOCM_RTS) ? 0 : -1;
+			dtr = (val & TIOCM_DTR) ? 0 : -1;
+			mcfrs_setsignals(info, dtr, rts);
+			break;
+
+                case TIOCMSET:
+			if ((error = verify_area(VERIFY_WRITE, (void *) arg,
+                            sizeof(unsigned int))))
+				return(error);
+			get_user(val, (unsigned int *) arg);
+			rts = (val & TIOCM_RTS) ? 1 : 0;
+			dtr = (val & TIOCM_DTR) ? 1 : 0;
+			mcfrs_setsignals(info, dtr, rts);
+			break;
+
+#ifdef TIOCSET422
+		case TIOCSET422:
+			get_user(val, (unsigned int *) arg);
+			mcf_setpa(MCFPP_PA11, (val ? 0 : MCFPP_PA11));
+			break;
+		case TIOCGET422:
+			val = (mcf_getpa() & MCFPP_PA11) ? 0 : 1;
+			put_user(val, (unsigned int *) arg);
+			break;
+#endif
+
+		default:
+			return -ENOIOCTLCMD;
+		}
+	return 0;
+}
+
+static void mcfrs_set_termios(struct tty_struct *tty, struct termios *old_termios)
+{
+	struct mcf_serial *info = (struct mcf_serial *)tty->driver_data;
+
+	if (tty->termios->c_cflag == old_termios->c_cflag)
+		return;
+
+	mcfrs_change_speed(info);
+
+	if ((old_termios->c_cflag & CRTSCTS) &&
+	    !(tty->termios->c_cflag & CRTSCTS)) {
+		tty->hw_stopped = 0;
+		mcfrs_setsignals(info, -1, 1);
+#if 0
+		mcfrs_start(tty);
+#endif
+	}
+}
+
+/*
+ * ------------------------------------------------------------
+ * mcfrs_close()
+ * 
+ * This routine is called when the serial port gets closed.  First, we
+ * wait for the last remaining data to be sent.  Then, we unlink its
+ * S structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void mcfrs_close(struct tty_struct *tty, struct file * filp)
+{
+	volatile unsigned char	*uartp;
+	struct mcf_serial	*info = (struct mcf_serial *)tty->driver_data;
+	unsigned long		flags;
+
+	if (!info || serial_paranoia_check(info, tty->device, "mcfrs_close"))
+		return;
+	
+	local_irq_save(flags);
+	
+	if (tty_hung_up_p(filp)) {
+		local_irq_restore(flags);
+		return;
+	}
+	
+#ifdef SERIAL_DEBUG_OPEN
+	printk("mcfrs_close ttyS%d, count = %d\n", info->line, info->count);
+#endif
+	if ((tty->count == 1) && (info->count != 1)) {
+		/*
+		 * Uh, oh.  tty->count is 1, which means that the tty
+		 * structure will be freed.  Info->count should always
+		 * be one in these conditions.  If it's greater than
+		 * one, we've got real problems, since it means the
+		 * serial port won't be shutdown.
+		 */
+		printk("MCFRS: bad serial port count; tty->count is 1, "
+		       "info->count is %d\n", info->count);
+		info->count = 1;
+	}
+	if (--info->count < 0) {
+		printk("MCFRS: bad serial port count for ttyS%d: %d\n",
+		       info->line, info->count);
+		info->count = 0;
+	}
+	if (info->count) {
+		local_irq_restore(flags);
+		return;
+	}
+	info->flags |= ASYNC_CLOSING;
+
+	/*
+	 * Save the termios structure, since this port may have
+	 * separate termios for callout and dialin.
+	 */
+	if (info->flags & ASYNC_NORMAL_ACTIVE)
+		info->normal_termios = *tty->termios;
+	if (info->flags & ASYNC_CALLOUT_ACTIVE)
+		info->callout_termios = *tty->termios;
+
+	/*
+	 * Now we wait for the transmit buffer to clear; and we notify 
+	 * the line discipline to only process XON/XOFF characters.
+	 */
+	tty->closing = 1;
+	if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
+		tty_wait_until_sent(tty, info->closing_wait);
+
+	/*
+	 * At this point we stop accepting input.  To do this, we
+	 * disable the receive line status interrupts, and tell the
+	 * interrupt driver to stop checking the data ready bit in the
+	 * line status register.
+	 */
+	info->imr &= ~MCFUART_UIR_RXREADY;
+	uartp = (volatile unsigned char *) info->addr;
+	uartp[MCFUART_UIMR] = info->imr;
+
+#if 0
+	/* FIXME: do we need to keep this enabled for console?? */
+	if (mcfrs_console_inited && (mcfrs_console_port == info->line)) {
+		/* Do not disable the UART */ ;
+	} else
+#endif
+	shutdown(info);
+	if (tty->driver.flush_buffer)
+		tty->driver.flush_buffer(tty);
+	if (tty->ldisc.flush_buffer)
+		tty->ldisc.flush_buffer(tty);
+	tty->closing = 0;
+	info->event = 0;
+	info->tty = 0;
+	if (tty->ldisc.num != ldiscs[N_TTY].num) {
+		if (tty->ldisc.close)
+			(tty->ldisc.close)(tty);
+		tty->ldisc = ldiscs[N_TTY];
+		tty->termios->c_line = N_TTY;
+		if (tty->ldisc.open)
+			(tty->ldisc.open)(tty);
+	}
+	if (info->blocked_open) {
+		if (info->close_delay) {
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(info->close_delay);
+		}
+		wake_up_interruptible(&info->open_wait);
+	}
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
+			 ASYNC_CLOSING);
+	wake_up_interruptible(&info->close_wait);
+	local_irq_restore(flags);
+}
+
+/*
+ * mcfrs_hangup() --- called by tty_hangup() when a hangup is signaled.
+ */
+void mcfrs_hangup(struct tty_struct *tty)
+{
+	struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
+	
+	if (serial_paranoia_check(info, tty->device, "mcfrs_hangup"))
+		return;
+	
+	mcfrs_flush_buffer(tty);
+	shutdown(info);
+	info->event = 0;
+	info->count = 0;
+	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);
+	info->tty = 0;
+	wake_up_interruptible(&info->open_wait);
+}
+
+/*
+ * ------------------------------------------------------------
+ * mcfrs_open() and friends
+ * ------------------------------------------------------------
+ */
+static int block_til_ready(struct tty_struct *tty, struct file * filp,
+			   struct mcf_serial *info)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int	retval;
+	int	do_clocal = 0;
+
+	/*
+	 * If the device is in the middle of being closed, then block
+	 * until it's done, and then try again.
+	 */
+	if (info->flags & ASYNC_CLOSING) {
+		interruptible_sleep_on(&info->close_wait);
+#ifdef SERIAL_DO_RESTART
+		if (info->flags & ASYNC_HUP_NOTIFY)
+			return -EAGAIN;
+		else
+			return -ERESTARTSYS;
+#else
+		return -EAGAIN;
+#endif
+	}
+
+	/*
+	 * If this is a callout device, then just make sure the normal
+	 * device isn't being used.
+	 */
+	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {
+		if (info->flags & ASYNC_NORMAL_ACTIVE)
+			return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_SESSION_LOCKOUT) &&
+		    (info->session != current->session))
+		    return -EBUSY;
+		if ((info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    (info->flags & ASYNC_PGRP_LOCKOUT) &&
+		    (info->pgrp != current->pgrp))
+		    return -EBUSY;
+		info->flags |= ASYNC_CALLOUT_ACTIVE;
+		return 0;
+	}
+	
+	/*
+	 * If non-blocking mode is set, or the port is not enabled,
+	 * then make the check up front and then exit.
+	 */
+	if ((filp->f_flags & O_NONBLOCK) ||
+	    (tty->flags & (1 << TTY_IO_ERROR))) {
+		if (info->flags & ASYNC_CALLOUT_ACTIVE)
+			return -EBUSY;
+		info->flags |= ASYNC_NORMAL_ACTIVE;
+		return 0;
+	}
+
+	if (info->flags & ASYNC_CALLOUT_ACTIVE) {
+		if (info->normal_termios.c_cflag & CLOCAL)
+			do_clocal = 1;
+	} else {
+		if (tty->termios->c_cflag & CLOCAL)
+			do_clocal = 1;
+	}
+	
+	/*
+	 * Block waiting for the carrier detect and the line to become
+	 * free (i.e., not in use by the callout).  While we are in
+	 * this loop, info->count is dropped by one, so that
+	 * mcfrs_close() knows when to free things.  We restore it upon
+	 * exit, either normal or abnormal.
+	 */
+	retval = 0;
+	add_wait_queue(&info->open_wait, &wait);
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready before block: ttyS%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	info->count--;
+	info->blocked_open++;
+	while (1) {
+		local_irq_disable();
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE))
+			mcfrs_setsignals(info, 1, 1);
+		local_irq_enable();
+		current->state = TASK_INTERRUPTIBLE;
+		if (tty_hung_up_p(filp) ||
+		    !(info->flags & ASYNC_INITIALIZED)) {
+#ifdef SERIAL_DO_RESTART
+			if (info->flags & ASYNC_HUP_NOTIFY)
+				retval = -EAGAIN;
+			else
+				retval = -ERESTARTSYS;	
+#else
+			retval = -EAGAIN;
+#endif
+			break;
+		}
+		if (!(info->flags & ASYNC_CALLOUT_ACTIVE) &&
+		    !(info->flags & ASYNC_CLOSING) &&
+		    (do_clocal || (mcfrs_getsignals(info) & TIOCM_CD)))
+			break;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+#ifdef SERIAL_DEBUG_OPEN
+		printk("block_til_ready blocking: ttyS%d, count = %d\n",
+		       info->line, info->count);
+#endif
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	remove_wait_queue(&info->open_wait, &wait);
+	if (!tty_hung_up_p(filp))
+		info->count++;
+	info->blocked_open--;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("block_til_ready after blocking: ttyS%d, count = %d\n",
+	       info->line, info->count);
+#endif
+	if (retval)
+		return retval;
+	info->flags |= ASYNC_NORMAL_ACTIVE;
+	return 0;
+}	
+
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port, linking in its structure into
+ * the IRQ chain.   It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+int mcfrs_open(struct tty_struct *tty, struct file * filp)
+{
+	struct mcf_serial	*info;
+	int 			retval, line;
+
+	line = minor(tty->device) - tty->driver.minor_start;
+	if ((line < 0) || (line >= NR_PORTS))
+		return -ENODEV;
+	info = mcfrs_table + line;
+	if (serial_paranoia_check(info, tty->device, "mcfrs_open"))
+		return -ENODEV;
+#ifdef SERIAL_DEBUG_OPEN
+	printk("mcfrs_open %s%d, count = %d\n", tty->driver.name, info->line,
+	       info->count);
+#endif
+	info->count++;
+	tty->driver_data = info;
+	info->tty = tty;
+
+	/*
+	 * Start up serial port
+	 */
+	retval = startup(info);
+	if (retval)
+		return retval;
+
+	retval = block_til_ready(tty, filp, info);
+	if (retval) {
+#ifdef SERIAL_DEBUG_OPEN
+		printk("mcfrs_open returning after block_til_ready with %d\n",
+		       retval);
+#endif
+		return retval;
+	}
+
+	if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) {
+		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)
+			*tty->termios = info->normal_termios;
+		else 
+			*tty->termios = info->callout_termios;
+		mcfrs_change_speed(info);
+	}
+
+	info->session = current->session;
+	info->pgrp = current->pgrp;
+
+#ifdef SERIAL_DEBUG_OPEN
+	printk("mcfrs_open ttyS%d successful...\n", info->line);
+#endif
+	return 0;
+}
+
+/*
+ *	Based on the line number set up the internal interrupt stuff.
+ */
+static void mcfrs_irqinit(struct mcf_serial *info)
+{
+#ifdef CONFIG_M5272
+	volatile unsigned long	*icrp;
+	volatile unsigned long	*portp;
+	volatile unsigned char	*uartp;
+
+	uartp = (volatile unsigned char *) info->addr;
+	icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2);
+
+	switch (info->line) {
+	case 0:
+		*icrp = 0xe0000000;
+		break;
+	case 1:
+		*icrp = 0x0e000000;
+		break;
+	default:
+		printk("MCFRS: don't know how to handle UART %d interrupt?\n",
+			info->line);
+		return;
+	}
+
+	/* Enable the output lines for the serial ports */
+	portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PBCNT);
+	*portp = (*portp & ~0x000000ff) | 0x00000055;
+	portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT);
+	*portp = (*portp & ~0x000003fc) | 0x000002a8;
+#else
+	volatile unsigned char	*icrp, *uartp;
+
+	switch (info->line) {
+	case 0:
+		icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART1ICR);
+		*icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |
+			MCFSIM_ICR_PRI1;
+		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART1);
+		break;
+	case 1:
+		icrp = (volatile unsigned char *) (MCF_MBAR + MCFSIM_UART2ICR);
+		*icrp = /*MCFSIM_ICR_AUTOVEC |*/ MCFSIM_ICR_LEVEL6 |
+			MCFSIM_ICR_PRI2;
+		mcf_setimr(mcf_getimr() & ~MCFSIM_IMR_UART2);
+		break;
+	default:
+		printk("MCFRS: don't know how to handle UART %d interrupt?\n",
+			info->line);
+		return;
+	}
+
+	uartp = (volatile unsigned char *) info->addr;
+	uartp[MCFUART_UIVR] = info->irq;
+#endif
+
+	/* Clear mask, so no surprise interrupts. */
+	uartp[MCFUART_UIMR] = 0;
+
+	if (request_irq(info->irq, mcfrs_interrupt, SA_INTERRUPT,
+	    "ColdFire UART", NULL)) {
+		printk("MCFRS: Unable to attach ColdFire UART %d interrupt "
+			"vector=%d\n", info->line, info->irq);
+	}
+
+	return;
+}
+
+
+char *mcfrs_drivername = "ColdFire internal UART serial driver version 1.00\n";
+
+
+/*
+ * Serial stats reporting...
+ */
+int mcfrs_readproc(char *page, char **start, off_t off, int count,
+		         int *eof, void *data)
+{
+	struct mcf_serial	*info;
+	char			str[20];
+	int			len, sigs, i;
+
+	len = sprintf(page, mcfrs_drivername);
+	for (i = 0; (i < NR_PORTS); i++) {
+		info = &mcfrs_table[i];
+		len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ",
+			i, info->addr, info->irq, info->baud);
+		if (info->stats.rx || info->stats.tx)
+			len += sprintf((page + len), "tx:%d rx:%d ",
+			info->stats.tx, info->stats.rx);
+		if (info->stats.rxframing)
+			len += sprintf((page + len), "fe:%d ",
+			info->stats.rxframing);
+		if (info->stats.rxparity)
+			len += sprintf((page + len), "pe:%d ",
+			info->stats.rxparity);
+		if (info->stats.rxbreak)
+			len += sprintf((page + len), "brk:%d ",
+			info->stats.rxbreak);
+		if (info->stats.rxoverrun)
+			len += sprintf((page + len), "oe:%d ",
+			info->stats.rxoverrun);
+
+		str[0] = str[1] = 0;
+		if ((sigs = mcfrs_getsignals(info))) {
+			if (sigs & TIOCM_RTS)
+				strcat(str, "|RTS");
+			if (sigs & TIOCM_CTS)
+				strcat(str, "|CTS");
+			if (sigs & TIOCM_DTR)
+				strcat(str, "|DTR");
+			if (sigs & TIOCM_CD)
+				strcat(str, "|CD");
+		}
+
+		len += sprintf((page + len), "%s\n", &str[1]);
+	}
+
+	return(len);
+}
+
+
+/* Finally, routines used to initialize the serial driver. */
+
+static void show_serial_version(void)
+{
+	printk(mcfrs_drivername);
+}
+
+/* mcfrs_init inits the driver */
+static int __init
+mcfrs_init(void)
+{
+	struct mcf_serial	*info;
+	unsigned long		flags;
+	int			i;
+
+	/* Setup base handler, and timer table. */
+#ifdef MCFPP_DCD0
+	init_timer(&mcfrs_timer_struct);
+	mcfrs_timer_struct.function = mcfrs_timer;
+	mcfrs_timer_struct.data = 0;
+	mcfrs_timer_struct.expires = jiffies + HZ/25;
+	add_timer(&mcfrs_timer_struct);
+	mcfrs_ppstatus = mcf_getppdata() & (MCFPP_DCD0 | MCFPP_DCD1);
+#endif
+
+	show_serial_version();
+
+	/* Initialize the tty_driver structure */
+	memset(&mcfrs_serial_driver, 0, sizeof(struct tty_driver));
+	mcfrs_serial_driver.magic = TTY_DRIVER_MAGIC;
+	mcfrs_serial_driver.name = "ttyS";
+	mcfrs_serial_driver.major = TTY_MAJOR;
+	mcfrs_serial_driver.minor_start = 64;
+	mcfrs_serial_driver.num = NR_PORTS;
+	mcfrs_serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	mcfrs_serial_driver.subtype = SERIAL_TYPE_NORMAL;
+	mcfrs_serial_driver.init_termios = tty_std_termios;
+
+	mcfrs_serial_driver.init_termios.c_cflag =
+		mcfrs_console_cbaud | CS8 | CREAD | HUPCL | CLOCAL;
+	mcfrs_serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	mcfrs_serial_driver.refcount = &mcfrs_serial_refcount;
+	mcfrs_serial_driver.table = mcfrs_serial_table;
+	mcfrs_serial_driver.termios = mcfrs_serial_termios;
+	mcfrs_serial_driver.termios_locked = mcfrs_serial_termios_locked;
+
+	mcfrs_serial_driver.open = mcfrs_open;
+	mcfrs_serial_driver.close = mcfrs_close;
+	mcfrs_serial_driver.write = mcfrs_write;
+	mcfrs_serial_driver.flush_chars = mcfrs_flush_chars;
+	mcfrs_serial_driver.write_room = mcfrs_write_room;
+	mcfrs_serial_driver.chars_in_buffer = mcfrs_chars_in_buffer;
+	mcfrs_serial_driver.flush_buffer = mcfrs_flush_buffer;
+	mcfrs_serial_driver.ioctl = mcfrs_ioctl;
+	mcfrs_serial_driver.throttle = mcfrs_throttle;
+	mcfrs_serial_driver.unthrottle = mcfrs_unthrottle;
+	mcfrs_serial_driver.set_termios = mcfrs_set_termios;
+	mcfrs_serial_driver.stop = mcfrs_stop;
+	mcfrs_serial_driver.start = mcfrs_start;
+	mcfrs_serial_driver.hangup = mcfrs_hangup;
+	mcfrs_serial_driver.read_proc = mcfrs_readproc;
+	mcfrs_serial_driver.driver_name = "serial";
+
+	/*
+	 * The callout device is just like normal device except for
+	 * major number and the subtype code.
+	 */
+	mcfrs_callout_driver = mcfrs_serial_driver;
+	mcfrs_callout_driver.name = "cua";
+	mcfrs_callout_driver.major = TTYAUX_MAJOR;
+	mcfrs_callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+	mcfrs_callout_driver.read_proc = 0;
+	mcfrs_callout_driver.proc_entry = 0;
+
+	if (tty_register_driver(&mcfrs_serial_driver)) {
+		printk("MCFRS: Couldn't register serial driver\n");
+		return(-EBUSY);
+	}
+	if (tty_register_driver(&mcfrs_callout_driver)) {
+		printk("MCFRS: Couldn't register callout driver\n");
+		return(-EBUSY);
+	}
+	
+	local_irq_save(flags);
+
+	/*
+	 *	Configure all the attached serial ports.
+	 */
+	for (i = 0, info = mcfrs_table; (i < NR_PORTS); i++, info++) {
+		info->magic = SERIAL_MAGIC;
+		info->line = i;
+		info->tty = 0;
+		info->custom_divisor = 16;
+		info->close_delay = 50;
+		info->closing_wait = 3000;
+		info->x_char = 0;
+		info->event = 0;
+		info->count = 0;
+		info->blocked_open = 0;
+		INIT_WORK(&info->tqueue, mcfrs_offintr, info);
+		INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info);
+		info->callout_termios = mcfrs_callout_driver.init_termios;
+		info->normal_termios = mcfrs_serial_driver.init_termios;
+		init_waitqueue_head(&info->open_wait);
+		init_waitqueue_head(&info->close_wait);
+
+		info->imr = 0;
+		mcfrs_setsignals(info, 0, 0);
+		mcfrs_irqinit(info);
+
+		printk("%s%d at 0x%04x (irq = %d)", mcfrs_serial_driver.name,
+			info->line, info->addr, info->irq);
+		printk(" is a builtin ColdFire UART\n");
+	}
+
+	local_irq_restore(flags);
+	return 0;
+}
+
+module_init(mcfrs_init);
+/* DAVIDM module_exit(mcfrs_fini); */
+
+/****************************************************************************/
+/*                          Serial Console                                  */
+/****************************************************************************/
+
+/*
+ *	Quick and dirty UART initialization, for console output.
+ */
+
+void mcfrs_init_console(void)
+{
+	volatile unsigned char	*uartp;
+	unsigned int		clk;
+
+	/*
+	 *	Reset UART, get it into known state...
+	 */
+	uartp = (volatile unsigned char *) (MCF_MBAR +
+		(mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));
+
+	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX;  /* reset RX */
+	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX;  /* reset TX */
+	uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETMRPTR;  /* reset MR pointer */
+
+	/*
+	 * Set port for defined baud , 8 data bits, 1 stop bit, no parity.
+	 */
+	uartp[MCFUART_UMR] = MCFUART_MR1_PARITYNONE | MCFUART_MR1_CS8;
+	uartp[MCFUART_UMR] = MCFUART_MR2_STOP1;
+
+	clk = ((MCF_BUSCLK / mcfrs_console_baud) + 16) / 32; /* set baud */
+	uartp[MCFUART_UBG1] = (clk & 0xff00) >> 8;  /* set msb baud */
+	uartp[MCFUART_UBG2] = (clk & 0xff);  /* set lsb baud */
+
+	uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;
+	uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
+
+	mcfrs_console_inited++;
+	return;
+}
+
+
+/*
+ *	Setup for console. Argument comes from the boot command line.
+ */
+
+int mcfrs_console_setup(struct console *cp, char *arg)
+{
+	int		i, n = CONSOLE_BAUD_RATE;
+
+	if (!cp)
+		return(-1);
+
+	if (!strncmp(cp->name, "ttyS", 4))
+		mcfrs_console_port = cp->index;
+	else if (!strncmp(cp->name, "cua", 3))
+		mcfrs_console_port = cp->index;
+	else
+		return(-1);
+
+	if (arg)
+		n = simple_strtoul(arg,NULL,0);
+	for (i = 0; i < MCFRS_BAUD_TABLE_SIZE; i++)
+		if (mcfrs_baud_table[i] == n)
+			break;
+	if (i < MCFRS_BAUD_TABLE_SIZE) {
+		mcfrs_console_baud = n;
+		mcfrs_console_cbaud = 0;
+		if (i > 15) {
+			mcfrs_console_cbaud |= CBAUDEX;
+			i -= 15;
+		}
+		mcfrs_console_cbaud |= i;
+	}
+	mcfrs_init_console(); /* make sure baud rate changes */
+	return(0);
+}
+
+
+static kdev_t mcfrs_console_device(struct console *c)
+{
+	return mk_kdev(TTY_MAJOR, 64 + c->index);
+}
+
+
+/*
+ *	Output a single character, using UART polled mode.
+ *	This is used for console output.
+ */
+
+void mcfrs_put_char(char ch)
+{
+	volatile unsigned char	*uartp;
+	unsigned long		flags;
+	int			i;
+
+	uartp = (volatile unsigned char *) (MCF_MBAR +
+		(mcfrs_console_port ? MCFUART_BASE2 : MCFUART_BASE1));
+
+	local_irq_save(flags);
+	for (i = 0; (i < 0x10000); i++) {
+		if (uartp[MCFUART_USR] & MCFUART_USR_TXREADY)
+			break;
+	}
+	if (i < 0x10000) {
+		uartp[MCFUART_UTB] = ch;
+		for (i = 0; (i < 0x10000); i++)
+			if (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY)
+				break;
+	}
+	if (i >= 0x10000)
+		mcfrs_init_console(); /* try and get it back */
+	local_irq_restore(flags);
+
+	return;
+}
+
+
+/*
+ * rs_console_write is registered for printk output.
+ */
+
+void mcfrs_console_write(struct console *cp, const char *p, unsigned len)
+{
+	if (!mcfrs_console_inited)
+		mcfrs_init_console();
+	while (len-- > 0) {
+		if (*p == '\n')
+			mcfrs_put_char('\r');
+		mcfrs_put_char(*p++);
+	}
+}
+
+/*
+ * declare our consoles
+ */
+
+struct console mcfrs_console = {
+	name:		"ttyS",
+	write:		mcfrs_console_write,
+	device:		mcfrs_console_device,
+	setup:		mcfrs_console_setup,
+	flags:		CON_PRINTBUFFER,
+	index:		-1,
+};
+
+void __init mcfrs_console_init(void)
+{
+	register_console(&mcfrs_console);
+}
+
+/****************************************************************************/
diff -Nru a/drivers/serial/mcfserial.h b/drivers/serial/mcfserial.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/serial/mcfserial.h	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,84 @@
+/*
+ * mcfserial.c -- serial driver for ColdFire internal UARTS.
+ *
+ * Copyright (c) 1999 Greg Ungerer <gerg@snapgear.com>
+ * Copyright (c) 2000-2001 Lineo, Inc. <www.lineo.com>
+ * Copyright (c) 2002 SnapGear Inc., <www.snapgear.com>
+ *
+ * Based on code from 68332serial.c which was:
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1998 TSHG
+ * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org>
+ */ 
+#ifndef _MCF_SERIAL_H
+#define _MCF_SERIAL_H
+
+#include <linux/config.h>
+#include <linux/serial.h>
+
+#ifdef __KERNEL__
+
+/*
+ *	Define a local serial stats structure.
+ */
+
+struct mcf_stats {
+	unsigned int	rx;
+	unsigned int	tx;
+	unsigned int	rxbreak;
+	unsigned int	rxframing;
+	unsigned int	rxparity;
+	unsigned int	rxoverrun;
+};
+
+
+/*
+ * This is our internal structure for each serial port's state.
+ * Each serial port has one of these structures associated with it.
+ */
+
+struct mcf_serial {
+	int			magic;
+	unsigned int		addr;		/* UART memory address */
+	int			irq;
+	int			flags; 		/* defined in tty.h */
+	int			type; 		/* UART type */
+	struct tty_struct 	*tty;
+	unsigned char		imr;		/* Software imr register */
+	unsigned int		baud;
+	int			sigs;
+	int			custom_divisor;
+	int			x_char;	/* xon/xoff character */
+	int			baud_base;
+	int			close_delay;
+	unsigned short		closing_wait;
+	unsigned short		closing_wait2;
+	unsigned long		event;
+	int			line;
+	int			count;	    /* # of fd on device */
+	int			blocked_open; /* # of blocked opens */
+	long			session; /* Session of opening process */
+	long			pgrp; /* pgrp of opening process */
+	unsigned char 		*xmit_buf;
+	int			xmit_head;
+	int			xmit_tail;
+	int			xmit_cnt;
+	struct mcf_stats	stats;
+	struct work_struct	tqueue;
+	struct work_struct	tqueue_hangup;
+	struct termios		normal_termios;
+	struct termios		callout_termios;
+#if LINUX_VERSION_CODE <= 0x020100
+	struct wait_queue	*open_wait;
+	struct wait_queue	*close_wait;
+#else
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
+#endif
+
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* _MCF_SERIAL_H */
diff -Nru a/drivers/serial/nb85e_uart.c b/drivers/serial/nb85e_uart.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/serial/nb85e_uart.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,590 @@
+/*
+ * drivers/serial/nb85e_uart.c -- Serial I/O using V850E/NB85E on-chip UART
+ *
+ *  Copyright (C) 2001,02  NEC Corporation
+ *  Copyright (C) 2001,02  Miles Bader <miles@gnu.org>
+ *
+ * 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.
+ *
+ * Written by Miles Bader <miles@gnu.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+
+#include <asm/nb85e_uart.h>
+#include <asm/nb85e_utils.h>
+
+/* Initial UART state.  This may be overridden by machine-dependent headers. */
+#ifndef NB85E_UART_INIT_BAUD
+#define NB85E_UART_INIT_BAUD	38400
+#endif
+#ifndef NB85E_UART_INIT_CFLAGS
+#define NB85E_UART_INIT_CFLAGS	(B38400 | CS8 | CREAD)
+#endif
+
+/* A string used for prefixing printed descriptions; since the same UART
+   macro is actually used on other chips than the V850E/NB85E.  This must
+   be a constant string.  */
+#ifndef NB85E_UART_CHIP_NAME
+#define NB85E_UART_CHIP_NAME "V850E/NB85E"
+#endif
+
+
+/* Low-level UART functions.  */
+
+/* These masks define which control bits affect TX/RX modes, respectively.  */
+#define RX_BITS \
+  (NB85E_UART_ASIM_PS_MASK | NB85E_UART_ASIM_CL_8 | NB85E_UART_ASIM_ISRM)
+#define TX_BITS \
+  (NB85E_UART_ASIM_PS_MASK | NB85E_UART_ASIM_CL_8 | NB85E_UART_ASIM_SL_2)
+
+/* The UART require various delays after writing control registers.  */
+static inline void nb85e_uart_delay (unsigned cycles)
+{
+	/* The loop takes 2 insns, so loop CYCLES / 2 times.  */
+	register unsigned count = cycles >> 1;
+	while (--count != 0)
+		/* nothing */;
+}
+
+/* Configure and turn on uart channel CHAN, using the termios `control
+   modes' bits in CFLAGS, and a baud-rate of BAUD.  */
+void nb85e_uart_configure (unsigned chan, unsigned cflags, unsigned baud)
+{
+	int cksr_min, flags;
+	unsigned new_config = 0; /* What we'll write to the control reg. */
+	unsigned new_clk_divlog2; /* New baud-rate generate clock divider. */
+	unsigned new_brgen_count; /* New counter max for baud-rate generator.*/
+	/* These are the current values corresponding to the above.  */
+	unsigned old_config, old_clk_divlog2, old_brgen_count;
+
+	/* Calculate new baud-rate generator config values.  */
+	cksr_min = 0;
+	while ((NB85E_UART_BASE_FREQ >> cksr_min) > NB85E_UART_CKSR_MAX_FREQ)
+		cksr_min++;
+	/* Calculate the log2 clock divider and baud-rate counter values
+	   (note that the UART divides the resulting clock by 2, so
+	   multiply BAUD by 2 here to compensate).  */
+	calc_counter_params (NB85E_UART_BASE_FREQ, baud * 2,
+			     cksr_min, NB85E_UART_CKSR_MAX, 8/*bits*/,
+			     &new_clk_divlog2, &new_brgen_count);
+
+	/* Figure out new configuration of control register.  */
+	if (cflags & CSTOPB)
+		/* Number of stop bits, 1 or 2.  */
+		new_config |= NB85E_UART_ASIM_SL_2;
+	if ((cflags & CSIZE) == CS8)
+		/* Number of data bits, 7 or 8.  */
+		new_config |= NB85E_UART_ASIM_CL_8;
+	if (! (cflags & PARENB))
+		/* No parity check/generation.  */
+		new_config |= NB85E_UART_ASIM_PS_NONE;
+	else if (cflags & PARODD)
+		/* Odd parity check/generation.  */
+		new_config |= NB85E_UART_ASIM_PS_ODD;
+	else
+		/* Even parity check/generation.  */
+		new_config |= NB85E_UART_ASIM_PS_EVEN;
+	if (cflags & CREAD)
+		/* Reading enabled.  */
+		new_config |= NB85E_UART_ASIM_RXE;
+
+	new_config |= NB85E_UART_ASIM_TXE; /* Writing is always enabled.  */
+	new_config |= NB85E_UART_ASIM_CAE;
+	new_config |= NB85E_UART_ASIM_ISRM; /* Errors generate a read-irq.  */
+
+	/* Disable interrupts while we're twiddling the hardware.  */
+	local_irq_save (flags);
+
+#ifdef NB85E_UART_PRE_CONFIGURE
+	NB85E_UART_PRE_CONFIGURE (chan, cflags, baud);
+#endif
+
+	old_config = NB85E_UART_ASIM (chan);
+	old_clk_divlog2 = NB85E_UART_CKSR (chan);
+	old_brgen_count = NB85E_UART_BRGC (chan);
+
+	if (new_clk_divlog2 != old_clk_divlog2
+	    || new_brgen_count != old_brgen_count)
+	{
+		/* The baud rate has changed.  First, disable the UART.  */
+		NB85E_UART_ASIM (chan) = 0;
+		old_config = 0;
+		/* Reprogram the baud-rate generator.  */
+		NB85E_UART_CKSR (chan) = new_clk_divlog2;
+		NB85E_UART_BRGC (chan) = new_brgen_count;
+	}
+
+	if (! (old_config & NB85E_UART_ASIM_CAE)) {
+		/* If we are enabling the uart for the first time, start
+		   by turning on the enable bit, which must be done
+		   before turning on any other bits.  */
+		NB85E_UART_ASIM (chan) = NB85E_UART_ASIM_CAE;
+		/* Enabling the uart also resets it.  */
+		old_config = NB85E_UART_ASIM_CAE;
+	}
+
+	if (new_config != old_config) {
+		/* Which of the TXE/RXE bits we'll temporarily turn off
+		   before changing other control bits.  */
+		unsigned temp_disable = 0;
+		/* Which of the TXE/RXE bits will be enabled.  */
+		unsigned enable = 0;
+		unsigned changed_bits = new_config ^ old_config;
+
+		/* Which of RX/TX will be enabled in the new configuration.  */
+		if (new_config & RX_BITS)
+			enable |= (new_config & NB85E_UART_ASIM_RXE);
+		if (new_config & TX_BITS)
+			enable |= (new_config & NB85E_UART_ASIM_TXE);
+
+		/* Figure out which of RX/TX needs to be disabled; note
+		   that this will only happen if they're not already
+		   disabled.  */
+		if (changed_bits & RX_BITS)
+			temp_disable |= (old_config & NB85E_UART_ASIM_RXE);
+		if (changed_bits & TX_BITS)
+			temp_disable |= (old_config & NB85E_UART_ASIM_TXE);
+
+		/* We have to turn off RX and/or TX mode before changing
+		   any associated control bits.  */
+		if (temp_disable)
+			NB85E_UART_ASIM (chan) = old_config & ~temp_disable;
+
+		/* Write the new control bits, while RX/TX are disabled. */ 
+		if (changed_bits & ~enable)
+			NB85E_UART_ASIM (chan) = new_config & ~enable;
+
+		/* The UART may not be reset properly unless we
+		   wait at least 2 `basic-clocks' until turning
+		   on the TXE/RXE bits again.  A `basic clock'
+		   is the clock used by the baud-rate generator, i.e.,
+		   the cpu clock divided by the 2^new_clk_divlog2.  */
+		nb85e_uart_delay (1 << (new_clk_divlog2 + 1));
+
+		/* Write the final version, with enable bits turned on.  */
+		NB85E_UART_ASIM (chan) = new_config;
+	}
+
+	local_irq_restore (flags);
+}
+
+
+/*  Low-level console. */
+
+#ifdef CONFIG_V850E_NB85E_UART_CONSOLE
+
+static void nb85e_uart_cons_write (struct console *co,
+				   const char *s, unsigned count)
+{
+	if (count > 0) {
+		unsigned chan = co->index;
+		unsigned irq = IRQ_INTST (chan);
+		int irq_was_enabled, irq_was_pending, flags;
+
+		/* We don't want to get `transmission completed' (INTST)
+		   interrupts, since we're busy-waiting, so we disable
+		   them while sending (we don't disable interrupts
+		   entirely because sending over a serial line is really
+		   slow).  We save the status of INTST and restore it
+		   when we're done so that using printk doesn't
+		   interfere with normal serial transmission (other than
+		   interleaving the output, of course!).  This should
+		   work correctly even if this function is interrupted
+		   and the interrupt printks something.  */
+
+		/* Disable interrupts while fiddling with INTST.  */
+		local_irq_save (flags);
+		/* Get current INTST status.  */
+		irq_was_enabled = nb85e_intc_irq_enabled (irq);
+		irq_was_pending = nb85e_intc_irq_pending (irq);
+		/* Disable INTST if necessary.  */
+		if (irq_was_enabled)
+			nb85e_intc_disable_irq (irq);
+		/* Turn interrupts back on.  */
+		local_irq_restore (flags);
+
+		/* Send characters.  */
+		while (count > 0) {
+			int ch = *s++;
+
+			if (ch == '\n') {
+				/* We don't have the benefit of a tty
+				   driver, so translate NL into CR LF.  */
+				nb85e_uart_wait_for_xmit_ok (chan);
+				nb85e_uart_putc (chan, '\r');
+			}
+
+			nb85e_uart_wait_for_xmit_ok (chan);
+			nb85e_uart_putc (chan, ch);
+
+			count--;
+		}
+
+		/* Restore saved INTST status.  */
+		if (irq_was_enabled) {
+			/* Wait for the last character we sent to be
+			   completely transmitted (as we'll get an INTST
+			   interrupt at that point).  */
+			nb85e_uart_wait_for_xmit_done (chan);
+			/* Clear pending interrupts received due
+			   to our transmission, unless there was already
+			   one pending, in which case we want the
+			   handler to be called.  */
+			if (! irq_was_pending)
+				nb85e_intc_clear_pending_irq (irq);
+			/* ... and then turn back on handling.  */
+			nb85e_intc_enable_irq (irq);
+		}
+	}
+}
+
+static kdev_t nb85e_uart_cons_device (struct console *c)
+{
+        return mk_kdev (TTY_MAJOR, NB85E_UART_MINOR_BASE + c->index);
+}
+
+static struct console nb85e_uart_cons =
+{
+    name:	"ttyS",
+    write:	nb85e_uart_cons_write,
+    device:	nb85e_uart_cons_device,
+    flags:	CON_PRINTBUFFER,
+    cflag:	NB85E_UART_INIT_CFLAGS,
+    index:	-1,
+};
+
+void nb85e_uart_cons_init (unsigned chan)
+{
+	nb85e_uart_configure (chan, NB85E_UART_INIT_CFLAGS,
+			      NB85E_UART_INIT_BAUD);
+	nb85e_uart_cons.index = chan;
+	register_console (&nb85e_uart_cons);
+	printk ("Console: %s on-chip UART channel %d\n",
+		NB85E_UART_CHIP_NAME, chan);
+}
+
+#define NB85E_UART_CONSOLE &nb85e_uart_cons
+
+#else /* !CONFIG_V850E_NB85E_UART_CONSOLE */
+#define NB85E_UART_CONSOLE 0
+#endif /* CONFIG_V850E_NB85E_UART_CONSOLE */
+
+/* TX/RX interrupt handlers.  */
+
+static void nb85e_uart_stop_tx (struct uart_port *port, unsigned tty_stop);
+
+void nb85e_uart_tx (struct uart_port *port)
+{
+	struct circ_buf *xmit = &port->info->xmit;
+	int stopped = uart_tx_stopped (port);
+
+	if (nb85e_uart_xmit_ok (port->line)) {
+		int tx_ch;
+
+		if (port->x_char) {
+			tx_ch = port->x_char;
+			port->x_char = 0;
+		} else if (!uart_circ_empty (xmit) && !stopped) {
+			tx_ch = xmit->buf[xmit->tail];
+			xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		} else
+			goto no_xmit;
+
+		nb85e_uart_putc (port->line, tx_ch);
+		port->icount.tx++;
+
+		if (uart_circ_chars_pending (xmit) < WAKEUP_CHARS)
+			uart_event (port, EVT_WRITE_WAKEUP);
+	}
+
+ no_xmit:
+	if (uart_circ_empty (xmit) || stopped)
+		nb85e_uart_stop_tx (port, stopped);
+}
+
+static void nb85e_uart_tx_irq (int irq, void *data, struct pt_regs *regs)
+{
+	struct uart_port *port = data;
+	nb85e_uart_tx (port);
+}
+
+static void nb85e_uart_rx_irq (int irq, void *data, struct pt_regs *regs)
+{
+	struct uart_port *port = data;
+	unsigned ch_stat = TTY_NORMAL;
+	unsigned ch = NB85E_UART_RXB (port->line);
+	unsigned err = NB85E_UART_ASIS (port->line);
+
+	if (err) {
+		if (err & NB85E_UART_ASIS_OVE) {
+			ch_stat = TTY_OVERRUN;
+			port->icount.overrun++;
+		} else if (err & NB85E_UART_ASIS_FE) {
+			ch_stat = TTY_FRAME;
+			port->icount.frame++;
+		} else if (err & NB85E_UART_ASIS_PE) {
+			ch_stat = TTY_PARITY;
+			port->icount.parity++;
+		}
+	}
+
+	port->icount.rx++;
+
+	tty_insert_flip_char (port->info->tty, ch, ch_stat);
+	tty_schedule_flip (port->info->tty);
+}
+
+/* Control functions for the serial framework.  */
+
+static void nb85e_uart_nop (struct uart_port *port) { }
+static int nb85e_uart_success (struct uart_port *port) { return 0; }
+
+static unsigned nb85e_uart_tx_empty (struct uart_port *port)
+{
+	return TIOCSER_TEMT;	/* Can't detect.  */
+}
+
+static void nb85e_uart_set_mctrl (struct uart_port *port, unsigned mctrl)
+{
+#ifdef NB85E_UART_SET_RTS
+	NB85E_UART_SET_RTS (port->line, (mctrl & TIOCM_RTS));
+#endif
+}
+
+static unsigned nb85e_uart_get_mctrl (struct uart_port *port)
+{
+	/* We don't support DCD or DSR, so consider them permanently active. */
+	int mctrl = TIOCM_CAR | TIOCM_DSR;
+
+	/* We may support CTS.  */
+#ifdef NB85E_UART_CTS
+	mctrl |= NB85E_UART_CTS(port->line) ? TIOCM_CTS : 0;
+#else
+	mctrl |= TIOCM_CTS;
+#endif
+
+	return mctrl;
+}
+
+static void nb85e_uart_start_tx (struct uart_port *port, unsigned tty_start)
+{
+	nb85e_intc_disable_irq (IRQ_INTST (port->line));
+	nb85e_uart_tx (port);
+	nb85e_intc_enable_irq (IRQ_INTST (port->line));
+}
+
+static void nb85e_uart_stop_tx (struct uart_port *port, unsigned tty_stop)
+{
+	nb85e_intc_disable_irq (IRQ_INTST (port->line));
+}
+
+static void nb85e_uart_start_rx (struct uart_port *port)
+{
+	nb85e_intc_enable_irq (IRQ_INTSR (port->line));
+}
+
+static void nb85e_uart_stop_rx (struct uart_port *port)
+{
+	nb85e_intc_disable_irq (IRQ_INTSR (port->line));
+}
+
+static void nb85e_uart_break_ctl (struct uart_port *port, int break_ctl)
+{
+	/* Umm, do this later.  */
+}
+
+static int nb85e_uart_startup (struct uart_port *port)
+{
+	int err;
+
+	/* Alloc RX irq.  */
+	err = request_irq (IRQ_INTSR (port->line), nb85e_uart_rx_irq,
+			   SA_INTERRUPT, "nb85e_uart", port);
+	if (err)
+		return err;
+
+	/* Alloc TX irq.  */
+	err = request_irq (IRQ_INTST (port->line), nb85e_uart_tx_irq,
+			   SA_INTERRUPT, "nb85e_uart", port);
+	if (err) {
+		free_irq (IRQ_INTSR (port->line), port);
+		return err;
+	}
+
+	nb85e_uart_start_rx (port);
+
+	return 0;
+}
+
+static void nb85e_uart_shutdown (struct uart_port *port)
+{
+	/* Disable port interrupts.  */
+	free_irq (IRQ_INTST (port->line), port);
+	free_irq (IRQ_INTSR (port->line), port);
+
+	/* Turn off xmit/recv enable bits.  */
+	NB85E_UART_ASIM (port->line)
+		&= ~(NB85E_UART_ASIM_TXE | NB85E_UART_ASIM_RXE);
+	/* Then reset the channel.  */
+	NB85E_UART_ASIM (port->line) = 0;
+}
+
+static void
+nb85e_uart_change_speed (struct uart_port *port, unsigned cflags,
+			 unsigned iflag, unsigned quot)
+{
+	/* The serial framework doesn't give us the baud rate directly, but
+	   insists on calculating a `quotient' from it, and giving us that
+	   instead.  Get the real baud rate from the tty code instead.  */
+	int baud = tty_get_baud_rate (port->info->tty);
+
+	nb85e_uart_configure (port->line, cflags, baud);
+}
+
+static const char *nb85e_uart_type (struct uart_port *port)
+{
+	return port->type == PORT_NB85E_UART ? "nb85e_uart" : 0;
+}
+
+static void nb85e_uart_config_port (struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE)
+		port->type = PORT_NB85E_UART;
+}
+
+static int
+nb85e_uart_verify_port (struct uart_port *port, struct serial_struct *ser)
+{
+	if (ser->type != PORT_UNKNOWN && ser->type != PORT_NB85E_UART)
+		return -EINVAL;
+	if (ser->irq != IRQ_INTST (port->line))
+		return -EINVAL;
+	return 0;
+}
+
+static struct uart_ops nb85e_uart_ops = {
+	.tx_empty	= nb85e_uart_tx_empty,
+	.get_mctrl	= nb85e_uart_get_mctrl,
+	.set_mctrl	= nb85e_uart_set_mctrl,
+	.start_tx	= nb85e_uart_start_tx,
+	.stop_tx	= nb85e_uart_stop_tx,
+	.stop_rx	= nb85e_uart_stop_rx,
+	.enable_ms	= nb85e_uart_nop,
+	.break_ctl	= nb85e_uart_break_ctl,
+	.startup	= nb85e_uart_startup,
+	.shutdown	= nb85e_uart_shutdown,
+	.change_speed	= nb85e_uart_change_speed,
+	.type		= nb85e_uart_type,
+	.release_port	= nb85e_uart_nop,
+	.request_port	= nb85e_uart_success,
+	.config_port	= nb85e_uart_config_port,
+	.verify_port	= nb85e_uart_verify_port,
+};
+
+/* Initialization and cleanup.  */
+
+static struct uart_driver nb85e_uart_driver = {
+	.owner			= THIS_MODULE,
+	.driver_name		= "nb85e_uart",
+#ifdef CONFIG_DEVFS_FS
+	.dev_name		= "tts/%d",
+#else
+	.dev_name		= "ttyS",
+#endif
+	.major			= TTY_MAJOR,
+	.minor			= NB85E_UART_MINOR_BASE,
+	.nr			= NB85E_UART_NUM_CHANNELS,
+	.cons			= NB85E_UART_CONSOLE,
+};
+
+
+static struct uart_port nb85e_uart_ports[NB85E_UART_NUM_CHANNELS];
+
+static int __init nb85e_uart_init (void)
+{
+	int rval;
+
+	printk (KERN_INFO "%s on-chip UART\n", NB85E_UART_CHIP_NAME);
+
+	rval = uart_register_driver (&nb85e_uart_driver);
+	if (rval == 0) {
+		unsigned chan;
+
+		for (chan = 0; chan < NB85E_UART_NUM_CHANNELS; chan++) {
+			int cksr_min;
+			struct uart_port *port = &nb85e_uart_ports[chan];
+			
+			memset (port, 0, sizeof *port);
+
+			port->ops = &nb85e_uart_ops;
+			port->line = chan;
+			port->iotype = SERIAL_IO_MEM;
+			port->flags = UPF_BOOT_AUTOCONF;
+
+			/* We actually use multiple IRQs, but the serial
+			   framework seems to mainly use this for
+			   informational purposes anyway.  Here we use the TX
+			   irq.  */
+			port->irq = IRQ_INTST (chan);
+
+			/* The serial framework doesn't really use these
+			   membase/mapbase fields for anything useful, but
+			   it requires that they be something non-zero to
+			   consider the port `valid', and also uses them
+			   for informational purposes.  */
+			port->membase = (void *)NB85E_UART_BASE_ADDR (chan);
+			port->mapbase = NB85E_UART_BASE_ADDR (chan);
+
+			/* The framework insists on knowing the uart's master
+			   clock freq, though it doesn't seem to do anything
+			   useful for us with it.  We must make it at least
+			   higher than (the maximum baud rate * 16), otherwise
+			   the framework will puke during its internal
+			   calculations, and force the baud rate to be 9600.
+			   To be accurate though, just repeat the calculation
+			   we use when actually setting the speed.  */
+			cksr_min = 0;
+			while ((NB85E_UART_BASE_FREQ >> cksr_min)
+			       > NB85E_UART_CKSR_MAX_FREQ)
+				cksr_min++;
+			/* The `* 8' means `* 16 / 2':  16 to account for for
+			   the serial framework's built-in bias, and 2 because
+			   there's an additional / 2 in the hardware.  */
+			port->uartclk = (NB85E_UART_BASE_FREQ >> cksr_min) * 8;
+
+			uart_add_one_port (&nb85e_uart_driver, port);
+		}
+	}
+
+	return rval;
+}
+
+static void __exit nb85e_uart_exit (void)
+{
+	unsigned chan;
+
+	for (chan = 0; chan < NB85E_UART_NUM_CHANNELS; chan++)
+		uart_remove_one_port (&nb85e_uart_driver,
+				      &nb85e_uart_ports[chan]);
+
+	uart_unregister_driver (&nb85e_uart_driver);
+}
+
+module_init (nb85e_uart_init);
+module_exit (nb85e_uart_exit);
+
+EXPORT_NO_SYMBOLS;
+
+MODULE_AUTHOR ("Miles Bader");
+MODULE_DESCRIPTION ("NEC " NB85E_UART_CHIP_NAME " on-chip UART");
+MODULE_LICENSE ("GPL");
diff -Nru a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
--- a/drivers/serial/sunzilog.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/serial/sunzilog.c	Sun Nov 10 19:28:41 2002
@@ -7,7 +7,7 @@
  * This is based on the old drivers/sbus/char/zs.c code.  A lot
  * of code has been simply moved over directly from there but
  * much has been rewritten.  Credits therefore go out to Eddie
- * C. Dost, Peter Zaitcev, Ted Ts'o and Alex Buell for their
+ * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their
  * work there.
  *
  *  Copyright (C) 2002 David S. Miller (davem@redhat.com)
@@ -714,7 +714,7 @@
 		port->icount.tx++;
 
 		if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
-			uart_event(&up->port, EVT_WRITE_WAKEUP);
+			uart_write_wakeup(&up->port);
 	}
 }
 
@@ -992,7 +992,6 @@
 
 static struct uart_sunzilog_port *sunzilog_port_table;
 static struct zilog_layout **sunzilog_chip_regs;
-static int *sunzilog_nodes;
 
 static struct uart_sunzilog_port *sunzilog_irq_chain;
 static int zilog_irq = -1;
@@ -1025,12 +1024,8 @@
 		alloc_one_table(NUM_CHANNELS * sizeof(struct uart_sunzilog_port));
 	sunzilog_chip_regs = (struct zilog_layout **)
 		alloc_one_table(NUM_SUNZILOG * sizeof(struct zilog_layout *));
-	sunzilog_nodes = (int *)
-		alloc_one_table(NUM_SUNZILOG * sizeof(int));
 
-	if (sunzilog_port_table == NULL ||
-	    sunzilog_chip_regs == NULL ||
-	    sunzilog_nodes == NULL) {
+	if (sunzilog_port_table == NULL || sunzilog_chip_regs == NULL) {
 		prom_printf("sunzilog_init: Cannot alloc SunZilog tables.\n");
 		prom_halt();
 	}
@@ -1041,24 +1036,13 @@
 /* We used to attempt to use the address property of the Zilog device node
  * but that totally is not necessary on sparc64.
  */
-static struct zilog_layout * __init get_zs_sun4u(int chip)
+static struct zilog_layout * __init get_zs_sun4u(int chip, int node)
 {
 	unsigned long mapped_addr = 0xdeadbeefUL;
 	unsigned int sun4u_ino;
-	int busnode, zsnode, seen;
+	int zsnode, seen;
 
-	if (central_bus)
-		busnode = central_bus->child->prom_node;
-	else
-		busnode = prom_searchsiblings(prom_getchild(prom_root_node), "sbus");
-
-	if (busnode == 0 || busnode == -1) {
-		prom_printf("SunZilog: Cannot find bus of Zilog %d in get_zs_sun4u.\n",
-			    chip);
-		prom_halt();
-	}
-
-	zsnode = prom_getchild(busnode);
+	zsnode = node;
 	seen = 0;
 	while (zsnode) {
 		int slave;
@@ -1111,7 +1095,6 @@
 					((u64)zsregs[0].phys_addr);
 			}
 
-			sunzilog_nodes[chip] = zsnode;
 			if (zilog_irq == -1) {
 				if (central_bus) {
 					unsigned long iclr, imap;
@@ -1142,31 +1125,35 @@
 	return (struct zilog_layout *) mapped_addr;
 }
 #else /* CONFIG_SPARC64 */
-static struct zilog_layout * __init get_zs_sun4cmd(int chip)
+
+/*
+ * XXX The sun4d case is utterly screwed: it tries to re-walk the tree
+ * (for the 3rd time) in order to find bootbus and cpu. Streamline it.
+ */
+static struct zilog_layout * __init get_zs_sun4cmd(int chip, int node)
 {
 	struct linux_prom_irqs irq_info[2];
 	unsigned long mapped_addr = 0;
-	int zsnode, chipid, cpunode, bbnode;
+	int zsnode, cpunode, bbnode;
+	struct linux_prom_registers zsreg[4];
+	struct resource res;
 
 	if (sparc_cpu_model == sun4d) {
-		int walk, no;
+		int walk;
 
 		zsnode = 0;
 		bbnode = 0;
-		no = 0;
+		cpunode = 0;
 		for (walk = prom_getchild(prom_root_node);
 		     (walk = prom_searchsiblings(walk, "cpu-unit")) != 0;
 		     walk = prom_getsibling(walk)) {
 			bbnode = prom_getchild(walk);
 			if (bbnode &&
 			    (bbnode = prom_searchsiblings(bbnode, "bootbus"))) {
-				if (no == (chip / 2)) {
+				if ((zsnode = prom_getchild(bbnode)) == node) {
 					cpunode = walk;
-					zsnode = prom_getchild(bbnode);
-					chipid = (chip & 1);
 					break;
 				}
-				no++;
 			}
 		}
 		if (!walk) {
@@ -1174,80 +1161,61 @@
 				    (chip / 2));
 			prom_halt();
 		}
-	} else {
-		int tmp;
 
-		zsnode = prom_getchild(prom_root_node);
-		if ((tmp = prom_searchsiblings(zsnode, "obio"))) {
-			zsnode = prom_getchild(tmp);
-			if (!zsnode) {
-				prom_printf("SunZilog: Child of obio node does "
-					    "not exist.\n");
-				prom_halt();
-			}
+		if (prom_getproperty(zsnode, "reg",
+				     (char *) zsreg, sizeof(zsreg)) == -1) {
+			prom_printf("SunZilog: Cannot map Zilog %d\n", chip);
+			prom_halt();
 		}
-		chipid = 0;
-	}
-
-	while (zsnode) {
-		struct linux_prom_registers zsreg[4];
-		struct resource res;
+		/* XXX Looks like an off by one? */
+		prom_apply_generic_ranges(bbnode, cpunode, zsreg, 1);
+		res.start = zsreg[0].phys_addr;
+		res.end = res.start + (8 - 1);
+		res.flags = zsreg[0].which_io | IORESOURCE_IO;
+		mapped_addr = sbus_ioremap(&res, 0, 8, "Zilog Serial");
 
-		zsnode = prom_searchsiblings(zsnode, "zs");
-		if (zsnode == 0 || zsnode == -1)
-			break;
+	} else {
+		zsnode = node;
 
+#if 0 /* XXX When was this used? */
 		if (prom_getintdefault(zsnode, "slave", -1) != chipid) {
 			zsnode = prom_getsibling(zsnode);
 			continue;
 		}
+#endif
 
-		if (sparc_cpu_model == sun4d) {
-			/* Sun4d Zilog nodes lack the address property, so just
-			 * map it like a normal device.
-			 */
-			if (prom_getproperty(zsnode, "reg",
-					     (char *) zsreg, sizeof(zsreg)) == -1) {
-				prom_printf("SunZilog: Cannot map Zilog %d "
-					    "regs on sun4c.\n", chip);
-				prom_halt();
-			}
-			prom_apply_generic_ranges(bbnode, cpunode, zsreg, 1);
-			res.start = zsreg[0].phys_addr;
-			res.end = res.start + (8 - 1);
-			res.flags = zsreg[0].which_io | IORESOURCE_IO;
-			mapped_addr = sbus_ioremap(&res, 0, 8, "Zilog Serial");
-		} else {
-			unsigned int vaddr[2];
+		/*
+		 * "address" is only present on ports that OBP opened
+		 * (from Mitch Bradley's "Hitchhiker's Guide to OBP").
+		 * We do not use it.
+		 */
 
-			if (prom_getproperty(zsnode, "address",
-					     (void *) vaddr, sizeof(vaddr))
-			    % sizeof(unsigned int)) {
-				prom_printf("SunZilog: Cannot get address property for "
-					    "Zilog %d.\n", chip);
-				prom_halt();
-			}
-			mapped_addr = (unsigned long) vaddr[0];
-		}
-		sunzilog_nodes[chip] = zsnode;
-		if (prom_getproperty(zsnode, "intr",
-				     (char *) irq_info, sizeof(irq_info))
-		    % sizeof(struct linux_prom_irqs)) {
-			prom_printf("SunZilog: Cannot get IRQ property for "
-				    "Zilog %d.\n", chip);
-			prom_halt();
-		}
-		if (zilog_irq == -1) {
-			zilog_irq = irq_info[0].pri;
-		} else if (zilog_irq != irq_info[0].pri) {
-			prom_printf("SunZilog: Inconsistent IRQ layout for Zilog %d.\n",
-				    chip);
+		if (prom_getproperty(zsnode, "reg",
+				     (char *) zsreg, sizeof(zsreg)) == -1) {
+			prom_printf("SunZilog: Cannot map Zilog %d\n", chip);
 			prom_halt();
 		}
-		break;
+		if (sparc_cpu_model == sun4m)	/* Crude. Pass parent. XXX */
+			prom_apply_obio_ranges(zsreg, 1);
+		res.start = zsreg[0].phys_addr;
+		res.end = res.start + (8 - 1);
+		res.flags = zsreg[0].which_io | IORESOURCE_IO;
+		mapped_addr = sbus_ioremap(&res, 0, 8, "Zilog Serial");
+	}
+
+	if (prom_getproperty(zsnode, "intr",
+			     (char *) irq_info, sizeof(irq_info))
+		    % sizeof(struct linux_prom_irqs)) {
+		prom_printf("SunZilog: Cannot get IRQ property for Zilog %d.\n",
+			    chip);
+		prom_halt();
 	}
-	if (!zsnode) {
-		prom_printf("SunZilog: OBP node for Zilog %d not found.\n", chip);
+	if (zilog_irq == -1) {
+		zilog_irq = irq_info[0].pri;
+	} else if (zilog_irq != irq_info[0].pri) {
+		/* XXX. Dumb. Should handle per-chip IRQ, for add-ons. */
+		prom_printf("SunZilog: Inconsistent IRQ layout for Zilog %d.\n",
+			    chip);
 		prom_halt();
 	}
 
@@ -1256,7 +1224,7 @@
 #endif /* !(CONFIG_SPARC64) */
 
 /* Get the address of the registers for SunZilog instance CHIP.  */
-static struct zilog_layout * __init get_zs(int chip)
+static struct zilog_layout * __init get_zs(int chip, int node)
 {
 	if (chip < 0 || chip >= NUM_SUNZILOG) {
 		prom_printf("SunZilog: Illegal chip number %d in get_zs.\n", chip);
@@ -1264,7 +1232,7 @@
 	}
 
 #ifdef CONFIG_SPARC64
-	return get_zs_sun4u(chip);
+	return get_zs_sun4u(chip, node);
 #else
 
 	if (sparc_cpu_model == sun4) {
@@ -1279,14 +1247,13 @@
 			res.start = 0xf0000000;
 			break;
 		};
-		sunzilog_nodes[chip] = 0;
 		zilog_irq = 12;
 		res.end = (res.start + (8 - 1));
 		res.flags = IORESOURCE_IO;
 		return (struct zilog_layout *) sbus_ioremap(&res, 0, 8, "SunZilog");
 	}
 
-	return get_zs_sun4cmd(chip);
+	return get_zs_sun4cmd(chip, node);
 #endif
 }
 
@@ -1459,6 +1426,52 @@
 	return 0;
 }
 
+/*
+ * We scan the PROM tree recursively. This is the most reliable way
+ * to find Zilog nodes on various platforms. However, we face an extreme
+ * shortage of kernel stack, so we must be very careful. To that end,
+ * we scan only to a certain depth, and we use a common property buffer
+ * in the scan structure.
+ */
+#define ZS_PROPSIZE  128
+#define ZS_SCAN_DEPTH	5
+
+struct zs_probe_scan {
+	int depth;
+	void (*scanner)(struct zs_probe_scan *t, int node);
+
+	int devices;
+	char prop[ZS_PROPSIZE];
+};
+
+static int __inline__ sunzilog_node_ok(int node, const char *name, int len)
+{
+	if (strncmp(name, "zs", len) == 0)
+		return 1;
+	/* Don't fold this procedure just yet. Compare to su_node_ok(). */
+	return 0;
+}
+
+static void __init sunzilog_scan(struct zs_probe_scan *t, int node)
+{
+	int len;
+
+	for (; node != 0; node = prom_getsibling(node)) {
+		len = prom_getproperty(node, "name", t->prop, ZS_PROPSIZE);
+		if (len <= 1)
+			continue;		/* Broken PROM node */
+		if (sunzilog_node_ok(node, t->prop, len)) {
+			(*t->scanner)(t, node);
+		} else {
+			if (t->depth < ZS_SCAN_DEPTH) {
+				t->depth++;
+				sunzilog_scan(t, prom_getchild(node));
+				--t->depth;
+			}
+		}
+	}
+}
+
 static void __init sunzilog_prepare(void)
 {
 	struct uart_sunzilog_port *up;
@@ -1471,12 +1484,9 @@
 	up[channel].next = NULL;
 
 	for (chip = 0; chip < NUM_SUNZILOG; chip++) {
-		if (!sunzilog_chip_regs[chip]) {
-			sunzilog_chip_regs[chip] = rp = get_zs(chip);
-
-			up[(chip * 2) + 0].port.membase = (char *) &rp->channelA;
-			up[(chip * 2) + 1].port.membase = (char *) &rp->channelB;
-		}
+		rp = sunzilog_chip_regs[chip];
+		up[(chip * 2) + 0].port.membase = (char *) &rp->channelA;
+		up[(chip * 2) + 1].port.membase = (char *) &rp->channelB;
 
 		/* Channel A */
 		up[(chip * 2) + 0].port.iotype = SERIAL_IO_MEM;
@@ -1593,11 +1603,25 @@
 	}
 }
 
+static struct zilog_layout * __init get_zs(int chip, int node);
+
+static void __init sunzilog_scan_probe(struct zs_probe_scan *t, int node)
+{
+	sunzilog_chip_regs[t->devices] = get_zs(t->devices, node);
+	t->devices++;
+}
+
 static int __init sunzilog_ports_init(void)
 {
+	struct zs_probe_scan scan;
 	int ret;
 
-	printk(KERN_INFO "Serial: Sun Zilog driver.\n");
+	printk(KERN_INFO "Serial: Sun Zilog driver (%d chips).\n", NUM_SUNZILOG);
+
+	scan.scanner = sunzilog_scan_probe;
+	scan.depth = 0;
+	scan.devices = 0;
+	sunzilog_scan(&scan, prom_getchild(prom_root_node));
 
 	sunzilog_prepare();
 
@@ -1635,56 +1659,34 @@
 	return ret;
 }
 
-static int __init sunzilog_init(void)
+static void __init sunzilog_scan_count(struct zs_probe_scan *t, int node)
 {
-	int node;
+	t->devices++;
+}
+
+static int __init sunzilog_ports_count(void)
+{
+	struct zs_probe_scan scan;
 
 	/* Sun4 Zilog setup is hard coded, no probing to do.  */
-	if (sparc_cpu_model == sun4) {
-		NUM_SUNZILOG = 2;
-	} else if (sparc_cpu_model == sun4d) {
-		int bbnode;
-
-		node = prom_getchild(prom_root_node);
-		NUM_SUNZILOG = 0;
-		while (node &&
-		       (node = prom_searchsiblings(node, "cpu-unit"))) {
-			bbnode = prom_getchild(node);
-			if (bbnode && prom_searchsiblings(bbnode, "bootbus"))
-				NUM_SUNZILOG += 2;
-			node = prom_getsibling(node);
-		}
-	} else if (sparc_cpu_model == sun4u) {
-		int central_node;
+	if (sparc_cpu_model == sun4)
+		return 2;
 
-		/* Central bus zilogs must be checked for first,
-		 * since Enterprise boxes might have SBUSes as well.
-		 */
-		central_node = prom_finddevice("/central");
-		if (central_node != 0 && central_node != -1)
-			node = prom_searchsiblings(prom_getchild(central_node), "fhc");
-		else
-			node = prom_searchsiblings(prom_getchild(prom_root_node), "sbus");
-		if (node != 0 && node != -1)
-			node = prom_getchild(node);
-		if (node == 0 || node == -1)
-			return -ENODEV;
-
-		node = prom_searchsiblings(node, "zs");
-		if (!node)
-			return -ENODEV;
-		
-		NUM_SUNZILOG = 2;
-	} else {
-		node = prom_getchild(prom_root_node);
-		node = prom_searchsiblings(node, "obio");
-		if (node)
-			node = prom_getchild(node);
-		if (!node)
-			return -ENODEV;
+	scan.scanner = sunzilog_scan_count;
+	scan.depth = 0;
+	scan.devices = 0;
 
-		NUM_SUNZILOG = 2;
-	}
+	sunzilog_scan(&scan, prom_getchild(prom_root_node));
+
+	return scan.devices;
+}
+
+static int __init sunzilog_init(void)
+{
+
+	NUM_SUNZILOG = sunzilog_ports_count();
+	if (NUM_SUNZILOG == 0)
+		return -ENODEV;
 
 	sunzilog_alloc_tables();
 
diff -Nru a/drivers/serial/uart00.c b/drivers/serial/uart00.c
--- a/drivers/serial/uart00.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/serial/uart00.c	Sun Nov 10 19:28:39 2002
@@ -193,7 +193,8 @@
 	int count;
 
 	if (port->x_char) {
-		while ((UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK) == 15);
+		while ((UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK) == 15)
+			barrier();
 		UART_PUT_CHAR(port, port->x_char);
 		port->icount.tx++;
 		port->x_char = 0;
@@ -206,7 +207,8 @@
 
 	count = port->fifosize >> 1;
 	do {
-		while ((UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK) == 15);
+		while ((UART_GET_TSR(port) & UART_TSR_TX_LEVEL_MSK) == 15)
+			barrier();
 		UART_PUT_CHAR(port, xmit->buf[xmit->tail]);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
 		port->icount.tx++;
diff -Nru a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
--- a/drivers/usb/class/Kconfig	Sun Nov 10 19:28:36 2002
+++ b/drivers/usb/class/Kconfig	Sun Nov 10 19:28:36 2002
@@ -38,7 +38,7 @@
 
 config USB_MIDI
 	tristate "USB MIDI support"
-	depends on USB
+	depends on USB && SOUND
 	---help---
 	  Say Y here if you want to connect a USB MIDI device to your
 	  computer's USB port. This driver is for devices that comply with
diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/usb/core/devio.c	Sun Nov 10 19:28:39 2002
@@ -751,7 +751,7 @@
 	struct async *as;
 	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
-	int ret;
+	int ret, interval = 0;
 
 	if (copy_from_user(&uurb, arg, sizeof(uurb)))
 		return -EFAULT;
@@ -838,6 +838,9 @@
 
 	case USBDEVFS_URB_TYPE_INTERRUPT:
 		uurb.number_of_packets = 0;
+		if (!(ep_desc = usb_epnum_to_ep_desc(ps->dev, uurb.endpoint)))
+			return -ENOENT;
+		interval = ep_desc->bInterval;
 		if (uurb.buffer_length > 16384)
 			return -EINVAL;
 		if (!access_ok((uurb.endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb.buffer, uurb.buffer_length))
@@ -869,6 +872,7 @@
 	as->urb->setup_packet = (unsigned char*)dr;
 	as->urb->start_frame = uurb.start_frame;
 	as->urb->number_of_packets = uurb.number_of_packets;
+	as->urb->interval = interval;
         as->urb->context = as;
         as->urb->complete = async_completed;
 	for (totlen = u = 0; u < uurb.number_of_packets; u++) {
diff -Nru a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
--- a/drivers/usb/core/hcd.h	Sun Nov 10 19:28:38 2002
+++ b/drivers/usb/core/hcd.h	Sun Nov 10 19:28:38 2002
@@ -77,6 +77,7 @@
 
 	/* a few non-PCI controllers exist, mostly for OHCI */
 	struct pci_dev		*pdev;		/* pci is typical */
+	struct device		*parent;	/* parent device driver */
 #ifdef	CONFIG_PCI
 	int			region;		/* pci region for regs */
 	u32			pci_state [16];	/* for PM state save */
diff -Nru a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
--- a/drivers/usb/host/ohci-dbg.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/usb/host/ohci-dbg.c	Sun Nov 10 19:28:41 2002
@@ -394,15 +394,14 @@
 static ssize_t
 show_async (struct device *dev, char *buf, size_t count, loff_t off)
 {
-	struct pci_dev		*pdev;
 	struct ohci_hcd		*ohci;
 	size_t			temp;
 	unsigned long		flags;
 
 	if (off != 0)
 		return 0;
-	pdev = container_of (dev, struct pci_dev, dev);
-	ohci = container_of (pci_get_drvdata (pdev), struct ohci_hcd, hcd);
+
+	ohci = dev_to_ohci(dev);
 
 	/* display control and bulk lists together, for simplicity */
 	spin_lock_irqsave (&ohci->lock, flags);
@@ -420,7 +419,6 @@
 static ssize_t
 show_periodic (struct device *dev, char *buf, size_t count, loff_t off)
 {
-	struct pci_dev		*pdev;
 	struct ohci_hcd		*ohci;
 	struct ed		**seen, *ed;
 	unsigned long		flags;
@@ -434,8 +432,7 @@
 		return 0;
 	seen_count = 0;
 
-	pdev = container_of (dev, struct pci_dev, dev);
-	ohci = container_of (pci_get_drvdata (pdev), struct ohci_hcd, hcd);
+	ohci = dev_to_ohci(dev);
 	next = buf;
 	size = count;
 
@@ -513,16 +510,16 @@
 
 static inline void create_debug_files (struct ohci_hcd *bus)
 {
-	device_create_file (&bus->hcd.pdev->dev, &dev_attr_async);
-	device_create_file (&bus->hcd.pdev->dev, &dev_attr_periodic);
+	device_create_file (bus->hcd.parent, &dev_attr_async);
+	device_create_file (bus->hcd.parent, &dev_attr_periodic);
 	// registers
 	dbg ("%s: created debug files", bus->hcd.self.bus_name);
 }
 
 static inline void remove_debug_files (struct ohci_hcd *bus)
 {
-	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_async);
-	device_remove_file (&bus->hcd.pdev->dev, &dev_attr_periodic);
+	device_remove_file (bus->hcd.parent, &dev_attr_async);
+	device_remove_file (bus->hcd.parent, &dev_attr_periodic);
 }
 
 #else /* empty stubs for creating those files */
diff -Nru a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
--- a/drivers/usb/host/ohci-pci.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/usb/host/ohci-pci.c	Sun Nov 10 19:28:40 2002
@@ -29,6 +29,17 @@
 
 /*-------------------------------------------------------------------------*/
 
+struct ohci_hcd *dev_to_ohci(struct device *dev) {
+	struct pci_dev *pdev = 
+		container_of (dev, struct pci_dev, dev);
+	struct ohci_hcd	*ohci = 
+		container_of (pci_get_drvdata (pdev), struct ohci_hcd, hcd);
+
+	return ohci;
+}
+
+/*-------------------------------------------------------------------------*/
+
 static int __devinit
 ohci_pci_start (struct usb_hcd *hcd)
 {
diff -Nru a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
--- a/drivers/usb/host/ohci-q.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/usb/host/ohci-q.c	Sun Nov 10 19:28:41 2002
@@ -83,7 +83,7 @@
 	 */
 	for (i = 0; i < interval ; i++) {
 		if (branch < 0 || ohci->load [branch] > ohci->load [i]) {
-#ifdef CONFIG_USB_BANDWIDTH
+#if 1	/* CONFIG_USB_BANDWIDTH */
 			int	j;
 
 			/* usb 1.1 says 90% of one frame */
@@ -276,7 +276,7 @@
 			ohci->ed_controltail = ed->ed_prev;
 			if (ohci->ed_controltail)
 				ohci->ed_controltail->ed_next = 0;
-		} else {
+		} else if (ed->ed_next) {
 			ed->ed_next->ed_prev = ed->ed_prev;
 		}
 		break;
@@ -297,7 +297,7 @@
 			ohci->ed_bulktail = ed->ed_prev;
 			if (ohci->ed_bulktail)
 				ohci->ed_bulktail->ed_next = 0;
-		} else {
+		} else if (ed->ed_next) {
 			ed->ed_next->ed_prev = ed->ed_prev;
 		}
 		break;
diff -Nru a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
--- a/drivers/usb/host/ohci-sa1111.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/usb/host/ohci-sa1111.c	Sun Nov 10 19:28:40 2002
@@ -27,6 +27,14 @@
 
 /*-------------------------------------------------------------------------*/
 
+struct ohci_hcd *dev_to_ohci(struct device *dev) {
+	struct usb_hcd *hcd = dev->driver_data;
+
+	return hcd_to_ohci(hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
 static void sa1111_start_hc(struct sa1111_dev *dev)
 {
 	unsigned int usb_rst = 0;
@@ -120,7 +128,7 @@
 	}
 #endif
 
-	usb_hcd_irq(irq, __hcd, r);
+	usb_hcd_irq(irq, hcd, r);
 }
 
 /*-------------------------------------------------------------------------*/
diff -Nru a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
--- a/drivers/usb/host/ohci.h	Sun Nov 10 19:28:41 2002
+++ b/drivers/usb/host/ohci.h	Sun Nov 10 19:28:41 2002
@@ -400,3 +400,4 @@
 
 #define hcd_to_ohci(hcd_ptr) container_of(hcd_ptr, struct ohci_hcd, hcd)
 
+struct ohci_hcd *dev_to_ohci(struct device *);
diff -Nru a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c
--- a/drivers/usb/image/scanner.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/usb/image/scanner.c	Sun Nov 10 19:28:38 2002
@@ -840,7 +840,7 @@
 	struct usb_device *dev = interface_to_usbdev (intf);
 	struct scn_usb_data *scn;
 	struct usb_host_interface *interface;
-	struct usb_endpoint_descriptor *endpoint;
+	struct usb_host_endpoint *endpoint;
 
 	int ep_cnt;
 	int ix;
@@ -911,7 +911,7 @@
 	}
 
 	interface = intf->altsetting;
-	endpoint = &interface->endpoint[0].desc;
+	endpoint = &interface->endpoint[0];
 
 /*
  * Start checking for two bulk endpoints OR two bulk endpoints *and* one
diff -Nru a/drivers/usb/image/scanner.h b/drivers/usb/image/scanner.h
--- a/drivers/usb/image/scanner.h	Sun Nov 10 19:28:39 2002
+++ b/drivers/usb/image/scanner.h	Sun Nov 10 19:28:39 2002
@@ -211,10 +211,10 @@
 
 MODULE_DEVICE_TABLE (usb, scanner_device_ids);
 
-#define IS_EP_BULK(ep)  ((ep).bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0)
-#define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
-#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
-#define IS_EP_INTR(ep) ((ep).bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0)
+#define IS_EP_BULK(ep)  ((ep).desc.bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0)
+#define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep).desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).desc.bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
+#define IS_EP_INTR(ep) ((ep).desc.bmAttributes == USB_ENDPOINT_XFER_INT ? 1 : 0)
 
 #define USB_SCN_MINOR(X) minor((X)->i_rdev) - SCN_BASE_MNR
 
diff -Nru a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
--- a/drivers/usb/media/vicam.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/usb/media/vicam.c	Sun Nov 10 19:28:38 2002
@@ -761,23 +761,19 @@
 		return -EBUSY;
 	}
 
+	cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
 	if (!cam->raw_image) {
-		cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
-		if (!cam->raw_image) {
-			up(&cam->busy_lock);
-			return -ENOMEM;
-		}
+		up(&cam->busy_lock);
+		return -ENOMEM;
 	}
 
+	cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
 	if (!cam->framebuf) {
-		cam->framebuf =
-		    rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
-		if (!cam->framebuf) {
-			kfree(cam->raw_image);
-			up(&cam->busy_lock);
-			return -ENOMEM;
-		}
+		kfree(cam->raw_image);
+		up(&cam->busy_lock);
+		return -ENOMEM;
 	}
+
 	// First upload firmware, then turn the camera on
 
 	if (!cam->is_initialized) {
@@ -805,6 +801,9 @@
 	DBG("close\n");
 	set_camera_power(cam, 0);
 
+	kfree(cam->raw_image);
+	rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
+
 	cam->open_count--;
 
 	return 0;
@@ -989,6 +988,7 @@
 
 	if (*ppos >= VICAM_MAX_FRAME_SIZE) {
 		*ppos = 0;
+		up(&cam->busy_lock);
 		return 0;
 	}
 
@@ -1038,15 +1038,6 @@
 	if (down_interruptible(&cam->busy_lock))
 		return -EINTR;
 
-	if (!cam->framebuf) {	/* we do lazy allocation */
-		cam->framebuf =
-		    rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
-		if (!cam->framebuf) {
-			up(&cam->busy_lock);
-			return -ENOMEM;
-		}
-	}
-
 	pos = (unsigned long)cam->framebuf;
 	while (size > 0) {
 		page = kvirt_to_pa(pos);
@@ -1319,7 +1310,6 @@
 	struct vicam_camera *cam = dev_get_drvdata(&intf->dev);
 
 	dev_set_drvdata ( &intf->dev, NULL );
-	usb_put_dev(cam->udev);
 	
 	cam->udev = NULL;
 	
@@ -1328,12 +1318,6 @@
 #ifdef CONFIG_PROC_FS
 	vicam_destroy_proc_entry(cam);
 #endif
-
-	if (cam->raw_image)
-		kfree(cam->raw_image);
-	if (cam->framebuf)
-		rvfree(cam->framebuf,
-		       VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
 
 	kfree(cam);
 
diff -Nru a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
--- a/drivers/usb/misc/Kconfig	Sun Nov 10 19:28:41 2002
+++ b/drivers/usb/misc/Kconfig	Sun Nov 10 19:28:41 2002
@@ -99,10 +99,13 @@
 
 config USB_TEST
 	tristate "USB testing driver (DEVELOPMENT)"
-	depends on USB_DEVICEFS && EXPERIMENTAL
+	depends on USB && USB_DEVICEFS && EXPERIMENTAL
 	help
 
 	  This driver is for testing host controller software.  It is used
 	  with specialized device firmware for regression and stress testing,
-	  to help prevent problems from cropping up with 'real" drivers.
+	  to help prevent problems from cropping up with "real" drivers.
+
+	  See <http://www.linux-usb.org/usbtest> for more information,
+	  including sample test device firmware and "how to use it".
 
diff -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
--- a/drivers/usb/misc/usbtest.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/usb/misc/usbtest.c	Sun Nov 10 19:28:41 2002
@@ -51,14 +51,10 @@
 };
 
 /* this is accessed only through usbfs ioctl calls.
- * one ioctl to issue a test ... no locking needed!!!
+ * one ioctl to issue a test ... one lock per device.
  * tests create other threads if they need them.
  * urbs and buffers are allocated dynamically,
  * and data generated deterministically.
- *
- * there's a minor complication on rmmod, since
- * usbfs.disconnect() waits till our ioctl completes.
- * unplug works fine since we'll see real i/o errors.
  */
 struct usbtest_dev {
 	struct usb_interface	*intf;
@@ -66,6 +62,7 @@
 	char			id [32];
 	int			in_pipe;
 	int			out_pipe;
+	struct semaphore	sem;
 
 #define TBUF_SIZE	256
 	u8			*buf;
@@ -282,6 +279,10 @@
  * or remote wakeup (which needs human interaction).
  */
 
+static int realworld = 1;
+MODULE_PARM (realworld, "i");
+MODULE_PARM_DESC (realworld, "clear to demand stricter ch9 compliance");
+
 static int get_altsetting (struct usbtest_dev *dev)
 {
 	struct usb_interface	*iface = dev->intf;
@@ -366,13 +367,11 @@
 	case USB_DT_OTHER_SPEED_CONFIG:
 		if (config->bLength != 9)
 			return 0;
-#if 0
 		/* this bit 'must be 1' but often isn't */
-		if (!(config->bmAttributes & 0x80)) {
+		if (!realworld && !(config->bmAttributes & 0x80)) {
 			dbg ("high bit of config attributes not set");
 			return 0;
 		}
-#endif
 		if (config->bmAttributes & 0x1f)	/* reserved == 0 */
 			return 0;
 		break;
@@ -424,7 +423,7 @@
 		}
 
 		/* [real world] get/set unimplemented if there's only one */
-		if (iface->num_altsetting == 1)
+		if (realworld && iface->num_altsetting == 1)
 			continue;
 
 		/* [9.4.10] set_interface */
@@ -446,7 +445,7 @@
 	}
 
 	/* [real world] get_config unimplemented if there's only one */
-	if (udev->descriptor.bNumConfigurations != 1) {
+	if (!realworld || udev->descriptor.bNumConfigurations != 1) {
 		int	expected = udev->actconfig->desc.bConfigurationValue;
 
 		/* [9.4.2] get_configuration always works
@@ -454,7 +453,8 @@
 		 * won't return config descriptors except before set_config.
 		 */
 		retval = usb_control_msg (udev, usb_rcvctrlpipe (udev, 0),
-				USB_REQ_GET_CONFIGURATION, USB_RECIP_DEVICE,
+				USB_REQ_GET_CONFIGURATION,
+				USB_DIR_IN | USB_RECIP_DEVICE,
 				0, 0, dev->buf, 1, HZ * USB_CTRL_GET_TIMEOUT);
 		if (retval != 1 || dev->buf [0] != expected) {
 			dbg ("%s get config --> %d (%d)", dev->id, retval,
@@ -563,7 +563,8 @@
  * threads and request completion.
  */
 
-static int usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
+static int
+usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
 {
 	struct usbtest_dev	*dev = dev_get_drvdata (&intf->dev);
 	struct usb_device	*udev = testdev_to_usbdev (dev);
@@ -584,6 +585,9 @@
 			|| param->sglen < 0 || param->vary < 0)
 		return -EINVAL;
 
+	if (down_interruptible (&dev->sem))
+		return -ERESTARTSYS;
+
 	/* some devices, like ez-usb default devices, need a non-default
 	 * altsetting to have any active endpoints.  some tests change
 	 * altsettings; force a default so most tests don't need to check.
@@ -591,12 +595,15 @@
 	if (dev->info->alt >= 0) {
 	    	int	res;
 
-		if (intf->altsetting->desc.bInterfaceNumber)
+		if (intf->altsetting->desc.bInterfaceNumber) {
+			up (&dev->sem);
 			return -ENODEV;
+		}
 		res = set_altsetting (dev, dev->info->alt);
 		if (res) {
 			err ("%s: set altsetting to %d failed, %d",
 					dev->id, dev->info->alt, res);
+			up (&dev->sem);
 			return res;
 		}
 	}
@@ -770,6 +777,7 @@
 		param->duration.tv_usec += 1000 * 1000;
 		param->duration.tv_sec -= 1;
 	}
+	up (&dev->sem);
 	return retval;
 }
 
@@ -819,6 +827,7 @@
 	memset (dev, 0, sizeof *dev);
 	info = (struct usbtest_info *) id->driver_info;
 	dev->info = info;
+	init_MUTEX (&dev->sem);
 
 	/* use the same kind of id the hid driver shows */
 	snprintf (dev->id, sizeof dev->id, "%s-%s:%d",
@@ -873,6 +882,8 @@
 static void usbtest_disconnect (struct usb_interface *intf)
 {
 	struct usbtest_dev	*dev = dev_get_drvdata (&intf->dev);
+
+	down (&dev->sem);
 
 	dev_set_drvdata (&intf->dev, 0);
 	info ("unbound %s", dev->id);
diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
--- a/drivers/usb/serial/visor.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/usb/serial/visor.c	Sun Nov 10 19:28:38 2002
@@ -185,6 +185,7 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
 	{ USB_DEVICE(HANDSPRING_VENDOR_ID, HANDSPRING_VISOR_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
@@ -207,6 +208,7 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_I705_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M125_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_M130_ID) },
+	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
diff -Nru a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
--- a/drivers/usb/serial/visor.h	Sun Nov 10 19:28:38 2002
+++ b/drivers/usb/serial/visor.h	Sun Nov 10 19:28:38 2002
@@ -27,6 +27,7 @@
 #define PALM_I705_ID			0x0020
 #define PALM_M125_ID			0x0040
 #define PALM_M130_ID			0x0050
+#define PALM_TUNGSTEN_T_ID		0x0060
 #define PALM_ZIRE_ID			0x0070
 
 #define SONY_VENDOR_ID			0x054C
diff -Nru a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
--- a/drivers/usb/storage/datafab.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/usb/storage/datafab.c	Sun Nov 10 19:28:41 2002
@@ -520,7 +520,6 @@
 		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
 	};
 
-	srb->resid = 0;
 	if (!us->extra) {
 		us->extra = kmalloc(sizeof(struct datafab_info), GFP_NOIO);
 		if (!us->extra) {
diff -Nru a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
--- a/drivers/usb/storage/freecom.c	Sun Nov 10 19:28:41 2002
+++ b/drivers/usb/storage/freecom.c	Sun Nov 10 19:28:41 2002
@@ -127,7 +127,7 @@
         /* Issue the transfer command. */
         result = usb_stor_bulk_msg (us, fxfr, opipe,
                         FCM_PACKET_LENGTH, &partial);
-        if (result != 0) {
+        if (result != USB_STOR_XFER_GOOD) {
                 US_DEBUGP ("Freecom readdata xpot failure: r=%d, p=%d\n",
                                 result, partial);
 
@@ -146,7 +146,9 @@
 	result = usb_stor_bulk_transfer_srb(us, ipipe, srb, count);
         US_DEBUGP("freecom_readdata done!\n");
 
-        return result;
+	if (result > USB_STOR_XFER_SHORT)
+		return USB_STOR_TRANSPORT_ERROR;
+	return USB_STOR_TRANSPORT_GOOD;
 }
 
 static int
@@ -168,7 +170,7 @@
         /* Issue the transfer command. */
         result = usb_stor_bulk_msg (us, fxfr, opipe,
                         FCM_PACKET_LENGTH, &partial);
-        if (result != 0) {
+        if (result != USB_STOR_XFER_GOOD) {
                 US_DEBUGP ("Freecom writedata xpot failure: r=%d, p=%d\n",
                                 result, partial);
 
@@ -188,7 +190,9 @@
 	result = usb_stor_bulk_transfer_srb(us, opipe, srb, count);
 
         US_DEBUGP("freecom_writedata done!\n");
-        return result;
+	if (result > USB_STOR_XFER_SHORT)
+		return USB_STOR_TRANSPORT_ERROR;
+	return USB_STOR_TRANSPORT_GOOD;
 }
 
 /*
@@ -231,7 +235,7 @@
         /* The Freecom device will only fail if there is something wrong in
          * USB land.  It returns the status in its own registers, which
          * come back in the bulk pipe. */
-        if (result != 0) {
+        if (result != USB_STOR_XFER_GOOD) {
                 US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
                                 result, partial);
 
@@ -255,6 +259,8 @@
 		US_DEBUGP("freecom_transport(): transfer aborted\n");
 		return USB_STOR_TRANSPORT_ABORTED;
 	}
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 
         US_DEBUG(pdump ((void *) fst, partial));
 
@@ -284,7 +290,7 @@
 		 * wrong in USB land.  It returns the status in its own
 		 * registers, which come back in the bulk pipe.
 		 */
-		if (result != 0) {
+		if (result != USB_STOR_XFER_GOOD) {
 			US_DEBUGP ("freecom xport failure: r=%d, p=%d\n",
 					result, partial);
 
@@ -308,13 +314,14 @@
 			US_DEBUGP("freecom_transport(): transfer aborted\n");
 			return USB_STOR_TRANSPORT_ABORTED;
 		}
+		if (result > USB_STOR_XFER_SHORT)
+	                return USB_STOR_TRANSPORT_ERROR;
 
 		US_DEBUG(pdump ((void *) fst, partial));
 	}
 
-        if (partial != 4 || result != 0) {
+        if (partial != 4)
                 return USB_STOR_TRANSPORT_ERROR;
-        }
         if ((fst->Status & 1) != 0) {
                 US_DEBUGP("operation failed\n");
                 return USB_STOR_TRANSPORT_FAILED;
@@ -369,7 +376,7 @@
                         US_DEBUGP ("freecom_transport: transfer aborted\n");
                         return USB_STOR_TRANSPORT_ABORTED;
                 }
-                if (partial != 4 || result != 0)
+                if (partial != 4 || result > USB_STOR_XFER_SHORT)
                         return USB_STOR_TRANSPORT_ERROR;
                 if ((fst->Status & ERR_STAT) != 0) {
                         US_DEBUGP("operation failed\n");
@@ -398,7 +405,7 @@
                         US_DEBUGP ("freecom_transport: transfer aborted\n");
                         return USB_STOR_TRANSPORT_ABORTED;
                 }
-                if (partial != 4 || result != 0)
+                if (partial != 4 || result > USB_STOR_XFER_SHORT)
                         return USB_STOR_TRANSPORT_ERROR;
                 if ((fst->Status & ERR_STAT) != 0) {
                         US_DEBUGP("operation failed\n");
diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
--- a/drivers/usb/storage/isd200.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/usb/storage/isd200.c	Sun Nov 10 19:28:39 2002
@@ -31,6 +31,8 @@
  *
  * History:
  *
+ *  2002-10-19: Removed the specialized transfer routines.
+ *		(Alan Stern <stern@rowland.harvard.edu>)
  *  2001-02-24: Removed lots of duplicate code and simplified the structure.
  *              (bjorn@haxx.se)
  *  2002-01-16: Fixed endianness bug so it works on the ppc arch.
@@ -386,147 +388,6 @@
         }
 }
 
-/***********************************************************************
- * Data transfer routines
- ***********************************************************************/
-
-
-/**************************************************************************
- * Transfer one SCSI scatter-gather buffer via bulk transfer
- *
- * Note that this function is necessary because we want the ability to
- * use scatter-gather memory.  Good performance is achieved by a combination
- * of scatter-gather and clustering (which makes each chunk bigger).
- *
- * Note that the lower layer will always retry when a NAK occurs, up to the
- * timeout limit.  Thus we don't have to worry about it for individual
- * packets.
- */
-static int isd200_transfer_partial( struct us_data *us, 
-				    unsigned char dataDirection,
-				    char *buf, int length )
-{
-        int result;
-        int partial;
-        unsigned int pipe;
-
-        /* calculate the appropriate pipe information */
-	if (dataDirection == SCSI_DATA_READ)
-                pipe = us->recv_bulk_pipe;
-        else
-                pipe = us->send_bulk_pipe;
-
-        /* transfer the data */
-        US_DEBUGP("isd200_transfer_partial(): xfer %d bytes\n", length);
-        result = usb_stor_bulk_msg(us, buf, pipe, length, &partial);
-        US_DEBUGP("usb_stor_bulk_msg() returned %d xferred %d/%d\n",
-                  result, partial, length);
-
-        /* if we stall, we need to clear it before we go on */
-        if (result == -EPIPE) {
-                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n", pipe);
-                if (usb_stor_clear_halt(us, pipe) < 0)
-			return ISD200_TRANSPORT_FAILED;
-        }
-    
-        /* did we send all the data? */
-        if (partial == length) {
-                US_DEBUGP("isd200_transfer_partial(): transfer complete\n");
-                return ISD200_TRANSPORT_GOOD;
-        }
-
-	/* did we abort this command? */
-	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-                US_DEBUGP("isd200_transfer_partial(): transfer aborted\n");
-		return ISD200_TRANSPORT_ABORTED;
-	}
-
-        /* uh oh... we have an error code, so something went wrong. */
-        if (result) {
-                /* NAK - that means we've retried a few times already */
-                if (result == -ETIMEDOUT) {
-                        US_DEBUGP("isd200_transfer_partial(): device NAKed\n");
-                        return ISD200_TRANSPORT_FAILED;
-                }
-
-                /* the catch-all case */
-                US_DEBUGP("isd200_transfer_partial(): unknown error\n");
-                return ISD200_TRANSPORT_FAILED;
-        }
-
-        /* no error code, so we must have transferred some data, 
-         * just not all of it */
-        return ISD200_TRANSPORT_SHORT;
-}
-
-
-/**************************************************************************
- * Transfer an entire SCSI command's worth of data payload over the bulk
- * pipe.
- *
- * Note that this uses us_transfer_partial to achieve it's goals -- this
- * function simply determines if we're going to use scatter-gather or not,
- * and acts appropriately.  For now, it also re-interprets the error codes.
- */
-static void isd200_transfer( struct us_data *us, Scsi_Cmnd *srb )
-{
-        int i;
-        int result = -1;
-        struct scatterlist *sg;
-        unsigned int total_transferred = 0;
-        unsigned int transfer_amount;
-
-        /* calculate how much we want to transfer */
-	int dir = srb->sc_data_direction;
-	srb->sc_data_direction = SCSI_DATA_WRITE;
-        transfer_amount = usb_stor_transfer_length(srb);
-	srb->sc_data_direction = dir;
-
-        /* was someone foolish enough to request more data than available
-         * buffer space? */
-        if (transfer_amount > srb->request_bufflen)
-                transfer_amount = srb->request_bufflen;
-
-        /* are we scatter-gathering? */
-        if (srb->use_sg) {
-
-                /* loop over all the scatter gather structures and 
-                 * make the appropriate requests for each, until done
-                 */
-                sg = (struct scatterlist *) srb->request_buffer;
-                for (i = 0; i < srb->use_sg; i++) {
-
-                        /* transfer the lesser of the next buffer or the
-                         * remaining data */
-                        if (transfer_amount - total_transferred >= 
-                            sg[i].length) {
-                                result = isd200_transfer_partial(us, 
-                                                                 srb->sc_data_direction,
-                                                                 sg_address(sg[i]), 
-                                                                 sg[i].length);
-                                total_transferred += sg[i].length;
-                        } else
-                                result = isd200_transfer_partial(us, 
-                                                                 srb->sc_data_direction,                            
-                                                                 sg_address(sg[i]), 
-                                                                 transfer_amount - total_transferred);
-
-                        /* if we get an error, end the loop here */
-                        if (result)
-                                break;
-                }
-        }
-        else
-                /* no scatter-gather, just make the request */
-                result = isd200_transfer_partial(us, 
-                                                 srb->sc_data_direction,
-                                                 srb->request_buffer, 
-                                                 transfer_amount);
-
-        /* return the result in the data structure itself */
-        srb->result = result;
-}
-
 
 /***********************************************************************
  * Transport routines
@@ -546,23 +407,21 @@
         struct bulk_cb_wrap bcb;
         struct bulk_cs_wrap bcs;
         int result;
-        int partial;
-        unsigned int transfer_amount;
+        unsigned int transfer_length;
 
 	int dir = srb->sc_data_direction;
 	srb->sc_data_direction = SCSI_DATA_WRITE;
-        transfer_amount = usb_stor_transfer_length(srb);
+        transfer_length = usb_stor_transfer_length(srb);
 	srb->sc_data_direction = dir;
     
         /* set up the command wrapper */
         bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
-        bcb.DataTransferLength = cpu_to_le32(transfer_amount);
+        bcb.DataTransferLength = cpu_to_le32(transfer_length);
         bcb.Flags = srb->sc_data_direction == SCSI_DATA_READ ? 1 << 7 : 0;
         bcb.Tag = srb->serial_number;
         bcb.Lun = srb->cmnd[1] >> 5;
         if (us->flags & US_FL_SCM_MULT_TARG)
                 bcb.Lun |= srb->target << 4;
-
         bcb.Length = AtaCdbLength;
     
         /* copy the command payload */
@@ -572,33 +431,32 @@
         /* send it to out endpoint */
         US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
                   le32_to_cpu(bcb.Signature), bcb.Tag,
-                  (bcb.Lun >> 4), (bcb.Lun & 0xFF), 
+                  (bcb.Lun >> 4), (bcb.Lun & 0x0F), 
                   le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length);
-        result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe,
-				US_BULK_CB_WRAP_LEN, &partial);
+	result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+				(char *) &bcb, US_BULK_CB_WRAP_LEN, NULL);
         US_DEBUGP("Bulk command transfer result=%d\n", result);
     
 	/* did we abort this command? */
 	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
 		return ISD200_TRANSPORT_ABORTED;
 	}
-
-	else if (result == -EPIPE) {
-		/* if we stall, we need to clear it before we go on */
-                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n",
-				us->send_bulk_pipe);
-                if (usb_stor_clear_halt(us, us->send_bulk_pipe) < 0)
-			return ISD200_TRANSPORT_ERROR;
-	} else if (result)  
+	if (result != USB_STOR_XFER_GOOD)  
                 return ISD200_TRANSPORT_ERROR;
     
         /* if the command transfered well, then we go to the data stage */
-        if (!result && bcb.DataTransferLength) {
-		isd200_transfer(us, srb);
-		US_DEBUGP("Bulk data transfer result 0x%x\n", srb->result);
-		
-		if (srb->result == ISD200_TRANSPORT_ABORTED)
+	if (transfer_length) {
+		unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? 
+				us->recv_bulk_pipe : us->send_bulk_pipe;
+		result = usb_stor_bulk_transfer_srb(us, pipe, srb,
+					transfer_length);
+		US_DEBUGP("Bulk data transfer result 0x%x\n", result);
+
+		/* if it was aborted, we need to indicate that */
+		if (result == USB_STOR_XFER_ABORTED)
 			return ISD200_TRANSPORT_ABORTED;
+		if (result == USB_STOR_XFER_ERROR)
+			return ISD200_TRANSPORT_ERROR;
         }
     
         /* See flow chart on pg 15 of the Bulk Only Transport spec for
@@ -607,42 +465,31 @@
     
         /* get CSW for device status */
         US_DEBUGP("Attempting to get CSW...\n");
-        result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe,
-				US_BULK_CS_WRAP_LEN, &partial);
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
+
 	/* did we abort this command? */
 	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
 		return ISD200_TRANSPORT_ABORTED;
 	}
 
         /* did the attempt to read the CSW fail? */
-        if (result == -EPIPE) {
-                US_DEBUGP("clearing endpoint halt for pipe 0x%x\n",
-				us->recv_bulk_pipe);
-                if (usb_stor_clear_halt(us, us->recv_bulk_pipe) < 0)
-			return ISD200_TRANSPORT_ERROR;
+	if (result == USB_STOR_XFER_STALLED) {
            
                 /* get the status again */
                 US_DEBUGP("Attempting to get CSW (2nd try)...\n");
-                result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe,
-                                           US_BULK_CS_WRAP_LEN, &partial);
+		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
 
                 /* if the command was aborted, indicate that */
 		if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
 			return ISD200_TRANSPORT_ABORTED;
 		}
-        
-                /* if it fails again, we need a reset and return an error*/
-                if (result == -EPIPE) {
-                        US_DEBUGP("clearing halt for pipe 0x%x\n",
-					us->recv_bulk_pipe);
-                        usb_stor_clear_halt(us, us->recv_bulk_pipe);
-                        return ISD200_TRANSPORT_ERROR;
-                }
         }
     
         /* if we still have a failure at this point, we're in trouble */
         US_DEBUGP("Bulk status result = %d\n", result);
-        if (result)
+        if (result != USB_STOR_XFER_GOOD)
                 return ISD200_TRANSPORT_ERROR;
     
         /* check bulk status */
@@ -651,7 +498,7 @@
                   bcs.Residue, bcs.Status);
         if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || 
             bcs.Tag != bcb.Tag || 
-            bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
+            bcs.Status > US_BULK_STAT_PHASE) {
                 US_DEBUGP("Bulk logical error\n");
                 return ISD200_TRANSPORT_ERROR;
         }
@@ -660,6 +507,8 @@
         switch (bcs.Status) {
         case US_BULK_STAT_OK:
                 /* command good -- note that we could be short on data */
+		if (srb->resid > 0)
+			return ISD200_TRANSPORT_SHORT;
                 return ISD200_TRANSPORT_GOOD;
 
         case US_BULK_STAT_FAIL:
@@ -764,7 +613,8 @@
 	}
 
 	status = isd200_Bulk_transport(us, &srb, &ata, sizeof(ata.generic));
-	if (status != ISD200_TRANSPORT_GOOD) {
+	if (status != ISD200_TRANSPORT_GOOD &&
+			status != ISD200_TRANSPORT_SHORT) {
 		US_DEBUGP("   isd200_action(0x%02x) error: %d\n",action,status);
 		status = ISD200_ERROR;
 		/* need to reset device here */
@@ -815,10 +665,22 @@
 {
 	int need_auto_sense = 0;
 	int transferStatus;
+	int result;
 
 	/* send the command to the transport layer */
+	srb->resid = 0;
 	transferStatus = isd200_Bulk_transport(us, srb, ataCdb,
 					       sizeof(ataCdb->generic));
+
+	/* if the command gets aborted by the higher layers, we need to
+	 * short-circuit all other processing
+	 */
+	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
+		US_DEBUGP("-- transport indicates command was aborted\n");
+		srb->result = DID_ABORT << 16;
+		return;
+	}
+
 	switch (transferStatus) {
 
 	case ISD200_TRANSPORT_GOOD:
@@ -845,6 +707,7 @@
 		break;
 
 	case ISD200_TRANSPORT_SHORT:
+		srb->result = GOOD << 1;
 		if (!((srb->cmnd[0] == REQUEST_SENSE) ||
 		      (srb->cmnd[0] == INQUIRY) ||
 		      (srb->cmnd[0] == MODE_SENSE) ||
@@ -861,9 +724,14 @@
        
 	}
 
-	if (need_auto_sense)
-		if (isd200_read_regs(us) == ISD200_GOOD)
+	if (need_auto_sense) {
+		result = isd200_read_regs(us);
+		if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
+			US_DEBUGP("-- auto-sense aborted\n");
+			srb->result = DID_ABORT << 16;
+		} else if (result == ISD200_GOOD)
 			isd200_build_sense(us, srb);
+	}
 
 	/* Regardless of auto-sense, if we _know_ we have an error
 	 * condition, show that in the result code
diff -Nru a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
--- a/drivers/usb/storage/jumpshot.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/usb/storage/jumpshot.c	Sun Nov 10 19:28:36 2002
@@ -464,7 +464,6 @@
 		0x00, 0x80, 0x00, 0x01, 0x1F, 0x00, 0x00, 0x00
 	};
 
-	srb->resid = 0;
 	if (!us->extra) {
 		us->extra = kmalloc(sizeof(struct jumpshot_info), GFP_NOIO);
 		if (!us->extra) {
diff -Nru a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
--- a/drivers/usb/storage/sddr09.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/usb/storage/sddr09.c	Sun Nov 10 19:28:40 2002
@@ -1372,7 +1372,6 @@
 		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 	};
 
-	srb->resid = 0;
 	info = (struct sddr09_card_info *)us->extra;
 	if (!info) {
 		nand_init_ecc();
diff -Nru a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
--- a/drivers/usb/storage/sddr55.c	Sun Nov 10 19:28:38 2002
+++ b/drivers/usb/storage/sddr55.c	Sun Nov 10 19:28:38 2002
@@ -746,7 +746,6 @@
 	unsigned short pages;
 	struct sddr55_card_info *info;
 
-	srb->resid = 0;
 	if (!us->extra) {
 		us->extra = kmalloc(
 			sizeof(struct sddr55_card_info), GFP_NOIO);
diff -Nru a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
--- a/drivers/usb/storage/shuttle_usbat.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/usb/storage/shuttle_usbat.c	Sun Nov 10 19:28:36 2002
@@ -775,7 +775,6 @@
 	int i;
 	char string[64];
 
-	srb->resid = 0;
 	len = srb->request_bufflen;
 
 	/* Send A0 (ATA PACKET COMMAND).
@@ -805,7 +804,8 @@
 
 	result = usbat_read(us, USBAT_ATA, 0x17, &status);
 	US_DEBUGP("Status = %02X\n", status);
-
+	if (result != USB_STOR_XFER_GOOD)
+		return USB_STOR_TRANSPORT_ERROR;
 	if (srb->cmnd[0] == TEST_UNIT_READY)
 		transferred = 0;
 
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c	Sun Nov 10 19:28:39 2002
+++ b/drivers/usb/storage/transport.c	Sun Nov 10 19:28:39 2002
@@ -784,18 +784,20 @@
 	int result;
 
 	/* send the command to the transport layer */
+	srb->resid = 0;
 	result = us->transport(srb, us);
 
 	/* if the command gets aborted by the higher layers, we need to
 	 * short-circuit all other processing
 	 */
-	if (result == USB_STOR_TRANSPORT_ABORTED) {
+	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
 		US_DEBUGP("-- transport indicates command was aborted\n");
 		srb->result = DID_ABORT << 16;
 		return;
 	}
 
 	/* if there is a transport error, reset and don't auto-sense */
+	/* What if we want to abort during the reset? */
 	if (result == USB_STOR_TRANSPORT_ERROR) {
 		US_DEBUGP("-- transport indicates error, resetting\n");
 		us->transport_reset(us);
@@ -903,7 +905,7 @@
 		srb->sc_data_direction = old_sc_data_direction;
 		memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE);
 
-		if (temp_result == USB_STOR_TRANSPORT_ABORTED) {
+		if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
 			US_DEBUGP("-- auto-sense aborted\n");
 			srb->result = DID_ABORT << 16;
 			return;
@@ -916,6 +918,7 @@
 			 * auto-sense is perfectly valid
 			 */
 			if (!(us->flags & US_FL_SCM_MULT_TARG)) {
+				/* What if we try to abort during the reset? */
 				us->transport_reset(us);
 			}
 			srb->result = DID_ERROR << 16;
@@ -1293,7 +1296,6 @@
 	struct bulk_cs_wrap bcs;
 	unsigned int transfer_length = usb_stor_transfer_length(srb);
 	int result;
-	int partial;
 
 	/* set up the command wrapper */
 	bcb.Signature = cpu_to_le32(US_BULK_CB_SIGN);
@@ -1313,9 +1315,9 @@
 	US_DEBUGP("Bulk command S 0x%x T 0x%x Trg %d LUN %d L %d F %d CL %d\n",
 		  le32_to_cpu(bcb.Signature), bcb.Tag,
 		  (bcb.Lun >> 4), (bcb.Lun & 0x0F), 
-		  bcb.DataTransferLength, bcb.Flags, bcb.Length);
-	result = usb_stor_bulk_msg(us, &bcb, us->send_bulk_pipe,
-				US_BULK_CB_WRAP_LEN, &partial);
+		  le32_to_cpu(bcb.DataTransferLength), bcb.Flags, bcb.Length);
+	result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
+				(char *) &bcb, US_BULK_CB_WRAP_LEN, NULL);
 	US_DEBUGP("Bulk command transfer result=%d\n", result);
 
 	/* did we abort this command? */
@@ -1323,23 +1325,8 @@
 		US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
 		return USB_STOR_TRANSPORT_ABORTED;
 	}
-
-	/* if we stall, we need to clear it before we go on */
-	if (result == -EPIPE) {
-		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n",
-				us->send_bulk_pipe);
-		result = usb_stor_clear_halt(us, us->send_bulk_pipe);
-
-		/* did we abort this command? */
-		if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-			US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
-			return USB_STOR_TRANSPORT_ABORTED;
-		}
+	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
-	} else if (result) {
-		/* unknown error -- we've got a problem */
-		return USB_STOR_TRANSPORT_ERROR;
-	}
 
 	/* DATA STAGE */
 	/* send/receive data payload, if there is any */
@@ -1363,8 +1350,8 @@
 
 	/* get CSW for device status */
 	US_DEBUGP("Attempting to get CSW...\n");
-	result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe,
-				US_BULK_CS_WRAP_LEN, &partial);
+	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
 
 	/* did we abort this command? */
 	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
@@ -1373,50 +1360,24 @@
 	}
 
 	/* did the attempt to read the CSW fail? */
-	if (result == -EPIPE) {
-		US_DEBUGP("clearing endpoint halt for pipe 0x%x\n",
-				us->recv_bulk_pipe);
-		result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
-
-		/* did we abort this command? */
-		if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-			US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
-			return USB_STOR_TRANSPORT_ABORTED;
-		}
-		if (result < 0)
-			return USB_STOR_TRANSPORT_ERROR;
+	if (result == USB_STOR_XFER_STALLED) {
 
 		/* get the status again */
 		US_DEBUGP("Attempting to get CSW (2nd try)...\n");
-		result = usb_stor_bulk_msg(us, &bcs, us->recv_bulk_pipe,
-					   US_BULK_CS_WRAP_LEN, &partial);
+		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
+				(char *) &bcs, US_BULK_CS_WRAP_LEN, NULL);
 
 		/* did we abort this command? */
 		if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
 			US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
 			return USB_STOR_TRANSPORT_ABORTED;
 		}
-
-		/* if it fails again, we need a reset and return an error*/
-		if (result == -EPIPE) {
-			US_DEBUGP("clearing halt for pipe 0x%x\n",
-					us->recv_bulk_pipe);
-			result = usb_stor_clear_halt(us, us->recv_bulk_pipe);
-
-			/* did we abort this command? */
-			if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-				US_DEBUGP("usb_stor_Bulk_transport(): transfer aborted\n");
-				return USB_STOR_TRANSPORT_ABORTED;
-			}
-			return USB_STOR_TRANSPORT_ERROR;
-		}
 	}
 
 	/* if we still have a failure at this point, we're in trouble */
 	US_DEBUGP("Bulk status result = %d\n", result);
-	if (result) {
+	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
-	}
 
 	/* check bulk status */
 	US_DEBUGP("Bulk status Sig 0x%x T 0x%x R %d Stat 0x%x\n",
@@ -1424,7 +1385,7 @@
 		  bcs.Residue, bcs.Status);
 	if (bcs.Signature != cpu_to_le32(US_BULK_CS_SIGN) || 
 	    bcs.Tag != bcb.Tag || 
-	    bcs.Status > US_BULK_STAT_PHASE || partial != 13) {
+	    bcs.Status > US_BULK_STAT_PHASE) {
 		US_DEBUGP("Bulk logical error\n");
 		return USB_STOR_TRANSPORT_ERROR;
 	}
diff -Nru a/drivers/video/fbcon.c b/drivers/video/fbcon.c
--- a/drivers/video/fbcon.c	Sun Nov 10 19:28:40 2002
+++ b/drivers/video/fbcon.c	Sun Nov 10 19:28:40 2002
@@ -230,9 +230,8 @@
 
 static void cursor_timer_handler(unsigned long dev_addr);
 
-static struct timer_list cursor_timer = {
-    function: cursor_timer_handler
-};
+static struct timer_list cursor_timer =
+		TIMER_INITIALIZER(cursor_timer_handler, 0, 0);
 
 static void cursor_timer_handler(unsigned long dev_addr)
 {
diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	Sun Nov 10 19:28:36 2002
+++ b/drivers/video/fbmem.c	Sun Nov 10 19:28:36 2002
@@ -612,7 +612,7 @@
 #if defined(__mc68000__)
 #if defined(CONFIG_SUN3)
 	pgprot_val(vma->vm_page_prot) |= SUN3_PAGE_NOCACHE;
-#else
+#elif defined(CONFIG_MMU)
 	if (CPU_IS_020_OR_030)
 		pgprot_val(vma->vm_page_prot) |= _PAGE_NOCACHE030;
 	if (CPU_IS_040_OR_060) {
diff -Nru a/fs/Kconfig b/fs/Kconfig
--- a/fs/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/fs/Kconfig	Sun Nov 10 19:28:40 2002
@@ -1156,6 +1156,18 @@
 	  with or without the generic quota support enabled (CONFIG_QUOTA) -
 	  they are completely independent subsystems.
 
+config XFS_POSIX_ACL
+	bool "ACL support"
+	depends on XFS_FS
+	---help---
+	  Posix Access Control Lists (ACLs) support permissions for users and
+	  groups beyond the owner/group/world scheme.
+
+	  To learn more about Access Control Lists, visit the Posix ACLs for
+	  Linux website <http://acl.bestbits.at/>.
+
+	  If you don't know what Access Control Lists are, say N
+
 
 menu "Network File Systems"
 	depends on NET
@@ -1477,6 +1489,10 @@
 	default m if EXT2_FS=m || EXT3_FS=m
 
 # Posix ACL utility routines (for now, only ext2/ext3/jfs)
+#
+# NOTE: you can implement Posix ACLs without these helpers (XFS does).
+# 	Never use this symbol for ifdefs.
+#
 config FS_POSIX_ACL
 	bool
 	depends on EXT2_FS_POSIX_ACL || EXT3_FS_POSIX_ACL || JFS_POSIX_ACL
diff -Nru a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
--- a/fs/affs/amigaffs.c	Sun Nov 10 19:28:38 2002
+++ b/fs/affs/amigaffs.c	Sun Nov 10 19:28:38 2002
@@ -69,7 +69,7 @@
 	affs_brelse(dir_bh);
 
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-	dir->i_version = ++event;
+	dir->i_version++;
 	mark_inode_dirty(dir);
 
 	return 0;
@@ -121,7 +121,7 @@
 	affs_brelse(bh);
 
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-	dir->i_version = ++event;
+	dir->i_version++;
 	mark_inode_dirty(dir);
 
 	return retval;
diff -Nru a/fs/affs/dir.c b/fs/affs/dir.c
--- a/fs/affs/dir.c	Sun Nov 10 19:28:41 2002
+++ b/fs/affs/dir.c	Sun Nov 10 19:28:41 2002
@@ -28,24 +28,24 @@
 static int affs_readdir(struct file *, void *, filldir_t);
 
 struct file_operations affs_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	affs_readdir,
-	fsync:		file_fsync,
+	.read		= generic_read_dir,
+	.readdir	= affs_readdir,
+	.fsync		= file_fsync,
 };
 
 /*
  * directories can handle most operations...
  */
 struct inode_operations affs_dir_inode_operations = {
-	create:		affs_create,
-	lookup:		affs_lookup,
-	link:		affs_link,
-	unlink:		affs_unlink,
-	symlink:	affs_symlink,
-	mkdir:		affs_mkdir,
-	rmdir:		affs_rmdir,
-	rename:		affs_rename,
-	setattr:	affs_notify_change,
+	.create		= affs_create,
+	.lookup		= affs_lookup,
+	.link		= affs_link,
+	.unlink		= affs_unlink,
+	.symlink	= affs_symlink,
+	.mkdir		= affs_mkdir,
+	.rmdir		= affs_rmdir,
+	.rename		= affs_rename,
+	.setattr	= affs_notify_change,
 };
 
 static int
diff -Nru a/fs/affs/file.c b/fs/affs/file.c
--- a/fs/affs/file.c	Sun Nov 10 19:28:39 2002
+++ b/fs/affs/file.c	Sun Nov 10 19:28:39 2002
@@ -44,19 +44,19 @@
 static int affs_file_release(struct inode *inode, struct file *filp);
 
 struct file_operations affs_file_operations = {
-	llseek:		generic_file_llseek,
-	read:		generic_file_read,
-	write:		affs_file_write,
-	mmap:		generic_file_mmap,
-	open:		affs_file_open,
-	release:	affs_file_release,
-	fsync:		file_fsync,
-	sendfile:	generic_file_sendfile,
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.write		= affs_file_write,
+	.mmap		= generic_file_mmap,
+	.open		= affs_file_open,
+	.release	= affs_file_release,
+	.fsync		= file_fsync,
+	.sendfile	= generic_file_sendfile,
 };
 
 struct inode_operations affs_file_inode_operations = {
-	truncate:	affs_truncate,
-	setattr:	affs_notify_change,
+	.truncate	= affs_truncate,
+	.setattr	= affs_notify_change,
 };
 
 static int
@@ -428,12 +428,12 @@
 	return generic_block_bmap(mapping,block,affs_get_block);
 }
 struct address_space_operations affs_aops = {
-	readpage: affs_readpage,
-	writepage: affs_writepage,
-	sync_page: block_sync_page,
-	prepare_write: affs_prepare_write,
-	commit_write: generic_commit_write,
-	bmap: _affs_bmap
+	.readpage = affs_readpage,
+	.writepage = affs_writepage,
+	.sync_page = block_sync_page,
+	.prepare_write = affs_prepare_write,
+	.commit_write = generic_commit_write,
+	.bmap = _affs_bmap
 };
 
 static inline struct buffer_head *
@@ -795,11 +795,11 @@
 }
 
 struct address_space_operations affs_aops_ofs = {
-	readpage: affs_readpage_ofs,
+	.readpage = affs_readpage_ofs,
 	//writepage: affs_writepage_ofs,
 	//sync_page: affs_sync_page_ofs,
-	prepare_write: affs_prepare_write_ofs,
-	commit_write: affs_commit_write_ofs
+	.prepare_write = affs_prepare_write_ofs,
+	.commit_write = affs_commit_write_ofs
 };
 
 /* Free any preallocated blocks. */
diff -Nru a/fs/affs/namei.c b/fs/affs/namei.c
--- a/fs/affs/namei.c	Sun Nov 10 19:28:38 2002
+++ b/fs/affs/namei.c	Sun Nov 10 19:28:38 2002
@@ -33,13 +33,13 @@
 static int       affs_intl_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
 
 struct dentry_operations affs_dentry_operations = {
-	d_hash:		affs_hash_dentry,
-	d_compare:	affs_compare_dentry,
+	.d_hash		= affs_hash_dentry,
+	.d_compare	= affs_compare_dentry,
 };
 
 struct dentry_operations affs_intl_dentry_operations = {
-	d_hash:		affs_intl_hash_dentry,
-	d_compare:	affs_intl_compare_dentry,
+	.d_hash		= affs_intl_hash_dentry,
+	.d_compare	= affs_intl_compare_dentry,
 };
 
 
diff -Nru a/fs/affs/super.c b/fs/affs/super.c
--- a/fs/affs/super.c	Sun Nov 10 19:28:40 2002
+++ b/fs/affs/super.c	Sun Nov 10 19:28:40 2002
@@ -92,6 +92,7 @@
 	ei = (struct affs_inode_info *)kmem_cache_alloc(affs_inode_cachep, SLAB_KERNEL);
 	if (!ei)
 		return NULL;
+	ei->vfs_inode.i_version = 1;
 	return &ei->vfs_inode;
 }
 
diff -Nru a/fs/affs/symlink.c b/fs/affs/symlink.c
--- a/fs/affs/symlink.c	Sun Nov 10 19:28:37 2002
+++ b/fs/affs/symlink.c	Sun Nov 10 19:28:37 2002
@@ -78,11 +78,11 @@
 }
 
 struct address_space_operations affs_symlink_aops = {
-	readpage:	affs_symlink_readpage,
+	.readpage	= affs_symlink_readpage,
 };
 
 struct inode_operations affs_symlink_inode_operations = {
-	readlink:	page_readlink,
-	follow_link:	page_follow_link,
-	setattr:	affs_notify_change,
+	.readlink	= page_readlink,
+	.follow_link	= page_follow_link,
+	.setattr	= affs_notify_change,
 };
diff -Nru a/fs/afs/main.c b/fs/afs/main.c
--- a/fs/afs/main.c	Sun Nov 10 19:28:38 2002
+++ b/fs/afs/main.c	Sun Nov 10 19:28:38 2002
@@ -113,7 +113,7 @@
 /*
  * clean up on module removal
  */
-static void afs_exit(void)
+static void __exit afs_exit(void)
 {
 	printk(KERN_INFO "kAFS: Red Hat AFS client v0.1 unregistering.\n");
 
diff -Nru a/fs/attr.c b/fs/attr.c
--- a/fs/attr.c	Sun Nov 10 19:28:37 2002
+++ b/fs/attr.c	Sun Nov 10 19:28:37 2002
@@ -134,6 +134,7 @@
 	if (!(ia_valid & ATTR_MTIME_SET))
 		attr->ia_mtime = now;
 	if (ia_valid & ATTR_KILL_SUID) {
+		attr->ia_valid &= ~ATTR_KILL_SUID;
 		if (mode & S_ISUID) {
 			if (!(ia_valid & ATTR_MODE)) {
 				ia_valid = attr->ia_valid |= ATTR_MODE;
@@ -143,6 +144,7 @@
 		}
 	}
 	if (ia_valid & ATTR_KILL_SGID) {
+		attr->ia_valid &= ~ ATTR_KILL_SGID;
 		if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
 			if (!(ia_valid & ATTR_MODE)) {
 				ia_valid = attr->ia_valid |= ATTR_MODE;
@@ -151,6 +153,8 @@
 			attr->ia_mode &= ~S_ISGID;
 		}
 	}
+	if (!attr->ia_valid)
+		return 0;
 
 	if (inode->i_op && inode->i_op->setattr) {
 		error = security_ops->inode_setattr(dentry, attr);
diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
--- a/fs/binfmt_elf.c	Sun Nov 10 19:28:39 2002
+++ b/fs/binfmt_elf.c	Sun Nov 10 19:28:39 2002
@@ -30,6 +30,7 @@
 #include <linux/elfcore.h>
 #include <linux/init.h>
 #include <linux/highuid.h>
+#include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/compiler.h>
 #include <linux/highmem.h>
@@ -108,7 +109,7 @@
 }
 
 /* Let's use some macros to make this stack manipulation a litle clearer */
-#ifdef ARCH_STACK_GROWSUP
+#ifdef CONFIG_STACK_GROWSUP
 #define STACK_ADD(sp, items) ((elf_addr_t *)(sp) + (items))
 #define STACK_ROUND(sp, items) \
 	((15 + (unsigned long) ((sp) + (items))) &~ 15UL)
@@ -206,7 +207,7 @@
 	bprm->p = STACK_ROUND(sp, items);
 
 	/* Point sp at the lowest address on the stack */
-#ifdef ARCH_STACK_GROWSUP
+#ifdef CONFIG_STACK_GROWSUP
 	sp = (elf_addr_t *)bprm->p - items - ei_index;
 	bprm->exec = (unsigned long) sp; /* XXX: PARISC HACK */
 #else
@@ -534,9 +535,6 @@
 			if (strcmp(elf_interpreter,"/usr/lib/libc.so.1") == 0 ||
 			    strcmp(elf_interpreter,"/usr/lib/ld.so.1") == 0)
 				ibcs2_interpreter = 1;
-#if 0
-			printk("Using ELF interpreter %s\n", elf_interpreter);
-#endif
 
 			SET_PERSONALITY(elf_ex, ibcs2_interpreter);
 
@@ -760,16 +758,6 @@
 
 	padzero(elf_bss);
 
-#if 0
-	printk("(start_brk) %lx\n" , (long) current->mm->start_brk);
-	printk("(end_code) %lx\n" , (long) current->mm->end_code);
-	printk("(start_code) %lx\n" , (long) current->mm->start_code);
-	printk("(start_data) %lx\n" , (long) current->mm->start_data);
-	printk("(end_data) %lx\n" , (long) current->mm->end_data);
-	printk("(start_stack) %lx\n" , (long) current->mm->start_stack);
-	printk("(brk) %lx\n" , (long) current->mm->brk);
-#endif
-
 	if (current->personality & MMAP_PAGE_ZERO) {
 		/* Why this, you ask???  Well SVr4 maps page 0 as read-only,
 		   and some applications "depend" upon this behavior.
@@ -972,26 +960,6 @@
 	return sz;
 }
 
-/* #define DEBUG */
-
-#ifdef DEBUG
-static void dump_regs(const char *str, elf_greg_t *r)
-{
-	int i;
-	static const char *regs[] = { "ebx", "ecx", "edx", "esi", "edi", "ebp",
-					      "eax", "ds", "es", "fs", "gs",
-					      "orig_eax", "eip", "cs",
-					      "efl", "uesp", "ss"};
-	printk("Registers: %s\n", str);
-
-	for(i = 0; i < ELF_NGREG; i++)
-	{
-		unsigned long val = r[i];
-		printk("   %-2d %-5s=%08lx %lu\n", i, regs[i], val, val);
-	}
-}
-#endif
-
 #define DUMP_WRITE(addr, nr)	\
 	do { if (!dump_write(file, (addr), (nr))) return 0; } while(0)
 #define DUMP_SEEK(off)	\
@@ -1023,6 +991,164 @@
 #define DUMP_SEEK(off)	\
 	if (!dump_seek(file, (off))) \
 		goto end_coredump;
+
+static inline void fill_elf_header(struct elfhdr *elf, int segs)
+{
+	memcpy(elf->e_ident, ELFMAG, SELFMAG);
+	elf->e_ident[EI_CLASS] = ELF_CLASS;
+	elf->e_ident[EI_DATA] = ELF_DATA;
+	elf->e_ident[EI_VERSION] = EV_CURRENT;
+	memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+
+	elf->e_type = ET_CORE;
+	elf->e_machine = ELF_ARCH;
+	elf->e_version = EV_CURRENT;
+	elf->e_entry = 0;
+	elf->e_phoff = sizeof(struct elfhdr);
+	elf->e_shoff = 0;
+	elf->e_flags = 0;
+	elf->e_ehsize = sizeof(struct elfhdr);
+	elf->e_phentsize = sizeof(struct elf_phdr);
+	elf->e_phnum = segs;
+	elf->e_shentsize = 0;
+	elf->e_shnum = 0;
+	elf->e_shstrndx = 0;
+	return;
+}
+
+static inline void fill_elf_note_phdr(struct elf_phdr *phdr, int sz, off_t offset)
+{
+	phdr->p_type = PT_NOTE;
+	phdr->p_offset = offset;
+	phdr->p_vaddr = 0;
+	phdr->p_paddr = 0;
+	phdr->p_filesz = sz;
+	phdr->p_memsz = 0;
+	phdr->p_flags = 0;
+	phdr->p_align = 0;
+	return;
+}
+
+static inline void fill_note(struct memelfnote *note, const char *name, int type, 
+		unsigned int sz, void *data)
+{
+	note->name = name;
+	note->type = type;
+	note->datasz = sz;
+	note->data = data;
+	return;
+}
+
+/*
+ * fill up all the fields in prstatus from the given task struct, except registers
+ * which need to be filled up seperately.
+ */
+static inline void fill_prstatus(struct elf_prstatus *prstatus, struct task_struct *p, long signr) 
+{
+	prstatus->pr_info.si_signo = prstatus->pr_cursig = signr;
+	prstatus->pr_sigpend = p->pending.signal.sig[0];
+	prstatus->pr_sighold = p->blocked.sig[0];
+	prstatus->pr_pid = p->pid;
+	prstatus->pr_ppid = p->parent->pid;
+	prstatus->pr_pgrp = p->pgrp;
+	prstatus->pr_sid = p->session;
+	jiffies_to_timeval(p->utime, &prstatus->pr_utime);
+	jiffies_to_timeval(p->stime, &prstatus->pr_stime);
+	jiffies_to_timeval(p->cutime, &prstatus->pr_cutime);
+	jiffies_to_timeval(p->cstime, &prstatus->pr_cstime);
+}
+
+static inline void fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p)
+{
+	int i, len;
+	
+	/* first copy the parameters from user space */
+	memset(psinfo, 0, sizeof(struct elf_prpsinfo));
+
+	len = p->mm->arg_end - p->mm->arg_start;
+	if (len >= ELF_PRARGSZ)
+		len = ELF_PRARGSZ-1;
+	copy_from_user(&psinfo->pr_psargs,
+		      (const char *)p->mm->arg_start, len);
+	for(i = 0; i < len; i++)
+		if (psinfo->pr_psargs[i] == 0)
+			psinfo->pr_psargs[i] = ' ';
+	psinfo->pr_psargs[len] = 0;
+
+	psinfo->pr_pid = p->pid;
+	psinfo->pr_ppid = p->parent->pid;
+	psinfo->pr_pgrp = p->pgrp;
+	psinfo->pr_sid = p->session;
+
+	i = p->state ? ffz(~p->state) + 1 : 0;
+	psinfo->pr_state = i;
+	psinfo->pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i];
+	psinfo->pr_zomb = psinfo->pr_sname == 'Z';
+	psinfo->pr_nice = task_nice(p);
+	psinfo->pr_flag = p->flags;
+	psinfo->pr_uid = NEW_TO_OLD_UID(p->uid);
+	psinfo->pr_gid = NEW_TO_OLD_GID(p->gid);
+	strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
+	
+	return;
+}
+
+/* Here is the structure in which status of each thread is captured. */
+struct elf_thread_status
+{
+	struct list_head list;
+	struct elf_prstatus prstatus;	/* NT_PRSTATUS */
+	elf_fpregset_t fpu;		/* NT_PRFPREG */
+#ifdef ELF_CORE_COPY_XFPREGS
+	elf_fpxregset_t xfpu;		/* NT_PRXFPREG */
+#endif
+	struct memelfnote notes[3];
+	int num_notes;
+};
+
+/*
+ * In order to add the specific thread information for the elf file format,
+ * we need to keep a linked list of every threads pr_status and then
+ * create a single section for them in the final core file.
+ */
+static int elf_dump_thread_status(long signr, struct task_struct * p, struct list_head * thread_list)
+{
+
+	struct elf_thread_status *t;
+	int sz = 0;
+
+	t = kmalloc(sizeof(*t), GFP_ATOMIC);
+	if (!t)
+		return 0;
+	memset(t, 0, sizeof(*t));
+
+	INIT_LIST_HEAD(&t->list);
+	t->num_notes = 0;
+
+	fill_prstatus(&t->prstatus, p, signr);
+	elf_core_copy_task_regs(p, &t->prstatus.pr_reg);	
+	
+	fill_note(&t->notes[0], "CORE", NT_PRSTATUS, sizeof(t->prstatus), &(t->prstatus));
+	t->num_notes++;
+	sz += notesize(&t->notes[0]);
+
+	if ((t->prstatus.pr_fpvalid = elf_core_copy_task_fpregs(p, &t->fpu))) {
+		fill_note(&t->notes[1], "CORE", NT_PRFPREG, sizeof(t->fpu), &(t->fpu));
+		t->num_notes++;
+		sz += notesize(&t->notes[1]);
+	}
+
+#ifdef ELF_CORE_COPY_XFPREGS
+	if (elf_core_copy_task_xfpregs(p, &t->xfpu)) {
+		fill_note(&t->notes[2], "LINUX", NT_PRXFPREG, sizeof(t->xfpu), &t->xfpu);
+		t->num_notes++;
+		sz += notesize(&t->notes[2]);
+	}
+#endif	
+	list_add(&t->list, thread_list);
+	return sz;
+}
+
 /*
  * Actual dumper
  *
@@ -1041,74 +1167,56 @@
 	struct elfhdr elf;
 	off_t offset = 0, dataoff;
 	unsigned long limit = current->rlim[RLIMIT_CORE].rlim_cur;
-	int numnote = 4;
-	struct memelfnote notes[4];
+	int numnote = 5;
+	struct memelfnote notes[5];
 	struct elf_prstatus prstatus;	/* NT_PRSTATUS */
-	elf_fpregset_t fpu;		/* NT_PRFPREG */
 	struct elf_prpsinfo psinfo;	/* NT_PRPSINFO */
-
-	/* first copy the parameters from user space */
-	memset(&psinfo, 0, sizeof(psinfo));
-	{
-		int i, len;
-
-		len = current->mm->arg_end - current->mm->arg_start;
-		if (len >= ELF_PRARGSZ)
-			len = ELF_PRARGSZ-1;
-		copy_from_user(&psinfo.pr_psargs,
-			      (const char *)current->mm->arg_start, len);
-		for(i = 0; i < len; i++)
-			if (psinfo.pr_psargs[i] == 0)
-				psinfo.pr_psargs[i] = ' ';
-		psinfo.pr_psargs[len] = 0;
-
-	}
-
-	memset(&prstatus, 0, sizeof(prstatus));
-	/*
-	 * This transfers the registers from regs into the standard
-	 * coredump arrangement, whatever that is.
+ 	struct task_struct *g, *p;
+ 	LIST_HEAD(thread_list);
+ 	struct list_head *t;
+	elf_fpregset_t fpu;
+#ifdef ELF_CORE_COPY_XFPREGS
+	elf_fpxregset_t xfpu;
+#endif
+	int thread_status_size = 0;
+	
+	/* We no longer stop all vm operations
+	 * 
+	 * This because those proceses that could possibly 
+	 * change map_count or the mmap / vma pages are now blocked in do_exit on current finishing
+	 * this core dump.
+	 *
+	 * Only ptrace can touch these memory addresses, but it doesn't change
+	 * the map_count or the pages allocated.  So no possibility of crashing exists while dumping
+	 * the mm->vm_next areas to the core file.
+	 *
 	 */
-#ifdef ELF_CORE_COPY_REGS
-	ELF_CORE_COPY_REGS(prstatus.pr_reg, regs)
-#else
-	if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
-	{
-		printk("sizeof(elf_gregset_t) (%ld) != sizeof(struct pt_regs) (%ld)\n",
-			(long)sizeof(elf_gregset_t), (long)sizeof(struct pt_regs));
+  	
+	 /* capture the status of all other threads */
+	if (signr) {
+		read_lock(&tasklist_lock);
+		do_each_thread(g,p)
+			if (current->mm == p->mm && current != p) {
+				int sz = elf_dump_thread_status(signr, p, &thread_list);
+				if (!sz) {
+					read_unlock(&tasklist_lock);
+					goto cleanup;
+				} else
+					thread_status_size += sz;
+			}
+		while_each_thread(g,p);
+		read_unlock(&tasklist_lock);
 	}
-	else
-		*(struct pt_regs *)&prstatus.pr_reg = *regs;
-#endif
 
-	/* now stop all vm operations */
-	down_write(&current->mm->mmap_sem);
+	/* now collect the dump for the current */
+	memset(&prstatus, 0, sizeof(prstatus));
+	fill_prstatus(&prstatus, current, signr);
+	elf_core_copy_regs(&prstatus.pr_reg, regs);
+	
 	segs = current->mm->map_count;
 
-#ifdef DEBUG
-	printk("elf_core_dump: %d segs %lu limit\n", segs, limit);
-#endif
-
 	/* Set up header */
-	memcpy(elf.e_ident, ELFMAG, SELFMAG);
-	elf.e_ident[EI_CLASS] = ELF_CLASS;
-	elf.e_ident[EI_DATA] = ELF_DATA;
-	elf.e_ident[EI_VERSION] = EV_CURRENT;
-	memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
-
-	elf.e_type = ET_CORE;
-	elf.e_machine = ELF_ARCH;
-	elf.e_version = EV_CURRENT;
-	elf.e_entry = 0;
-	elf.e_phoff = sizeof(elf);
-	elf.e_shoff = 0;
-	elf.e_flags = 0;
-	elf.e_ehsize = sizeof(elf);
-	elf.e_phentsize = sizeof(struct elf_phdr);
-	elf.e_phnum = segs+1;		/* Include notes */
-	elf.e_shentsize = 0;
-	elf.e_shnum = 0;
-	elf.e_shstrndx = 0;
+	fill_elf_header(&elf, segs+1); /* including notes section*/
 
 	fs = get_fs();
 	set_fs(KERNEL_DS);
@@ -1125,60 +1233,27 @@
 	 * with info from their /proc.
 	 */
 
-	notes[0].name = "CORE";
-	notes[0].type = NT_PRSTATUS;
-	notes[0].datasz = sizeof(prstatus);
-	notes[0].data = &prstatus;
-	prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
-	prstatus.pr_sigpend = current->pending.signal.sig[0];
-	prstatus.pr_sighold = current->blocked.sig[0];
-	psinfo.pr_pid = prstatus.pr_pid = current->pid;
-	psinfo.pr_ppid = prstatus.pr_ppid = current->parent->pid;
-	psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
-	psinfo.pr_sid = prstatus.pr_sid = current->session;
-	jiffies_to_timeval(current->utime, &prstatus.pr_utime);
-	jiffies_to_timeval(current->stime, &prstatus.pr_stime);
-	jiffies_to_timeval(current->cutime, &prstatus.pr_cutime);
-	jiffies_to_timeval(current->cstime, &prstatus.pr_cstime);
-
-#ifdef DEBUG
-	dump_regs("Passed in regs", (elf_greg_t *)regs);
-	dump_regs("prstatus regs", (elf_greg_t *)&prstatus.pr_reg);
-#endif
-
-	notes[1].name = "CORE";
-	notes[1].type = NT_PRPSINFO;
-	notes[1].datasz = sizeof(psinfo);
-	notes[1].data = &psinfo;
-	i = current->state ? ffz(~current->state) + 1 : 0;
-	psinfo.pr_state = i;
-	psinfo.pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i];
-	psinfo.pr_zomb = psinfo.pr_sname == 'Z';
-	psinfo.pr_nice = task_nice(current);
-	psinfo.pr_flag = current->flags;
-	psinfo.pr_uid = NEW_TO_OLD_UID(current->uid);
-	psinfo.pr_gid = NEW_TO_OLD_GID(current->gid);
-	strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname));
-
-	notes[2].name = "CORE";
-	notes[2].type = NT_TASKSTRUCT;
-	notes[2].datasz = sizeof(*current);
-	notes[2].data = current;
-
-	/* Try to dump the FPU. */
-	prstatus.pr_fpvalid = dump_fpu (regs, &fpu);
-	if (!prstatus.pr_fpvalid)
-	{
-		numnote--;
-	}
-	else
-	{
-		notes[3].name = "CORE";
-		notes[3].type = NT_PRFPREG;
-		notes[3].datasz = sizeof(fpu);
-		notes[3].data = &fpu;
-	}
+	fill_note(&notes[0], "CORE", NT_PRSTATUS, sizeof(prstatus), &prstatus);
+	
+	fill_psinfo(&psinfo, current->group_leader);
+	fill_note(&notes[1], "CORE", NT_PRPSINFO, sizeof(psinfo), &psinfo);
 	
+	fill_note(&notes[2], "CORE", NT_TASKSTRUCT, sizeof(*current), current);
+  
+  	/* Try to dump the FPU. */
+	if ((prstatus.pr_fpvalid = elf_core_copy_task_fpregs(current, &fpu)))
+		fill_note(&notes[3], "CORE", NT_PRFPREG, sizeof(fpu), &fpu);
+	else
+		--numnote;
+#ifdef ELF_CORE_COPY_XFPREGS
+	if (elf_core_copy_task_xfpregs(current, &xfpu))
+		fill_note(&notes[4], "LINUX", NT_PRXFPREG, sizeof(xfpu), &xfpu);
+	else
+		--numnote;
+#else
+	numnote --;
+#endif	
+  
 	/* Write notes phdr entry */
 	{
 		struct elf_phdr phdr;
@@ -1186,17 +1261,11 @@
 
 		for(i = 0; i < numnote; i++)
 			sz += notesize(&notes[i]);
+		
+		sz += thread_status_size;
 
-		phdr.p_type = PT_NOTE;
-		phdr.p_offset = offset;
-		phdr.p_vaddr = 0;
-		phdr.p_paddr = 0;
-		phdr.p_filesz = sz;
-		phdr.p_memsz = 0;
-		phdr.p_flags = 0;
-		phdr.p_align = 0;
-
-		offset += phdr.p_filesz;
+		fill_elf_note_phdr(&phdr, sz, offset);
+		offset += sz;
 		DUMP_WRITE(&phdr, sizeof(phdr));
 	}
 
@@ -1225,10 +1294,19 @@
 		DUMP_WRITE(&phdr, sizeof(phdr));
 	}
 
+ 	/* write out the notes section */
 	for(i = 0; i < numnote; i++)
 		if (!writenote(&notes[i], file))
 			goto end_coredump;
 
+	/* write out the thread status notes section */
+	list_for_each(t, &thread_list) {
+		struct elf_thread_status *tmp = list_entry(t, struct elf_thread_status, list);
+		for (i = 0; i < tmp->num_notes; i++)
+			if (!writenote(&tmp->notes[i], file))
+				goto end_coredump;
+	}
+ 
 	DUMP_SEEK(dataoff);
 
 	for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
@@ -1237,10 +1315,6 @@
 		if (!maydump(vma))
 			continue;
 
-#ifdef DEBUG
-		printk("elf_core_dump: writing %08lx-%08lx\n", vma->vm_start, vma->vm_end);
-#endif
-
 		for (addr = vma->vm_start;
 		     addr < vma->vm_end;
 		     addr += PAGE_SIZE) {
@@ -1272,11 +1346,19 @@
 		       (off_t) file->f_pos, offset);
 	}
 
- end_coredump:
+end_coredump:
 	set_fs(fs);
-	up_write(&current->mm->mmap_sem);
+
+cleanup:
+	while(!list_empty(&thread_list)) {
+		struct list_head *tmp = thread_list.next;
+		list_del(tmp);
+		kfree(list_entry(tmp, struct elf_thread_status, list));
+	}
+
 	return has_dumped;
 }
+
 #endif		/* USE_ELF_CORE_DUMP */
 
 static int __init init_elf_binfmt(void)
diff -Nru a/fs/binfmt_misc.c b/fs/binfmt_misc.c
--- a/fs/binfmt_misc.c	Sun Nov 10 19:28:39 2002
+++ b/fs/binfmt_misc.c	Sun Nov 10 19:28:39 2002
@@ -36,6 +36,7 @@
 static int enabled = 1;
 
 enum {Enabled, Magic};
+#define MISC_FMT_PRESERVE_ARGV0 (1<<31)
 
 typedef struct {
 	struct list_head list;
@@ -124,7 +125,9 @@
 	bprm->file = NULL;
 
 	/* Build args for interpreter */
-	remove_arg_zero(bprm);
+	if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
+		remove_arg_zero(bprm);
+	}
 	retval = copy_strings_kernel(1, &bprm->filename, bprm);
 	if (retval < 0) goto _ret; 
 	bprm->argc++;
@@ -289,6 +292,11 @@
 	*p++ = '\0';
 	if (!e->interpreter[0])
 		goto Einval;
+
+	if (*p == 'P') {
+		p++;
+		e->flags |= MISC_FMT_PRESERVE_ARGV0;
+	}
 
 	if (*p == '\n')
 		p++;
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Sun Nov 10 19:28:41 2002
+++ b/fs/block_dev.c	Sun Nov 10 19:28:41 2002
@@ -168,7 +168,6 @@
 	if (offset >= 0 && offset <= size) {
 		if (offset != file->f_pos) {
 			file->f_pos = offset;
-			file->f_version = ++event;
 		}
 		retval = offset;
 	}
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Sun Nov 10 19:28:40 2002
+++ b/fs/buffer.c	Sun Nov 10 19:28:40 2002
@@ -367,7 +367,7 @@
  * succeeds, there is no need to take private_lock. (But if
  * private_lock is contended then so is mapping->page_lock).
  */
-struct buffer_head *
+static struct buffer_head *
 __find_get_block_slow(struct block_device *bdev, sector_t block, int unused)
 {
 	struct inode *bd_inode = bdev->bd_inode;
@@ -1077,18 +1077,6 @@
 	return 1;
 }
 
-/*
- * __getblk will locate (and, if necessary, create) the buffer_head
- * which corresponds to the passed block_device, block and size. The
- * returned buffer has its reference count incremented.
- *
- * __getblk() cannot fail - it just keeps trying.  If you pass it an
- * illegal block number, __getblk() will happily return a buffer_head
- * which represents the non-existent block.  Very weird.
- *
- * __getblk() will lock up the machine if grow_dev_page's try_to_free_buffers()
- * attempt is failing.  FIXME, perhaps?
- */
 struct buffer_head *
 __getblk_slow(struct block_device *bdev, sector_t block, int size)
 {
@@ -1096,10 +1084,8 @@
 		struct buffer_head * bh;
 
 		bh = __find_get_block(bdev, block, size);
-		if (bh) {
-			touch_buffer(bh);
+		if (bh)
 			return bh;
-		}
 
 		if (!grow_buffers(bdev, block, size))
 			free_more_memory();
@@ -1182,21 +1168,8 @@
 	__brelse(bh);
 }
 
-/**
- *  __bread() - reads a specified block and returns the bh
- *  @block: number of block
- *  @size: size (in bytes) to read
- * 
- *  Reads a specified block, and returns buffer head that contains it.
- *  It returns NULL if the block was unreadable.
- */
-struct buffer_head *
-__bread_slow(struct block_device *bdev, sector_t block, int size)
+static struct buffer_head *__bread_slow(struct buffer_head *bh)
 {
-	struct buffer_head *bh = __getblk(bdev, block, size);
-
-	if (buffer_uptodate(bh))
-		return bh;
 	lock_buffer(bh);
 	if (buffer_uptodate(bh)) {
 		unlock_buffer(bh);
@@ -1260,9 +1233,6 @@
 	struct buffer_head *evictee = NULL;
 	struct bh_lru *lru;
 
-	if (bh == NULL)
-		return;
-
 	check_irqs_on();
 	bh_lru_lock();
 	lru = &per_cpu(bh_lrus, smp_processor_id());
@@ -1293,14 +1263,15 @@
 	}
 	bh_lru_unlock();
 
-	if (evictee) {
-		touch_buffer(evictee);
+	if (evictee)
 		__brelse(evictee);
-	}
 }
 
+/*
+ * Look up the bh in this cpu's LRU.  If it's there, move it to the head.
+ */
 static inline struct buffer_head *
-lookup_bh(struct block_device *bdev, sector_t block, int size)
+lookup_bh_lru(struct block_device *bdev, sector_t block, int size)
 {
 	struct buffer_head *ret = NULL;
 	struct bh_lru *lru;
@@ -1330,44 +1301,65 @@
 	return ret;
 }
 
+/*
+ * Perform a pagecache lookup for the matching buffer.  If it's there, refresh
+ * it in the LRU and mark it as accessed.  If it is not present then return
+ * NULL
+ */
 struct buffer_head *
 __find_get_block(struct block_device *bdev, sector_t block, int size)
 {
-	struct buffer_head *bh = lookup_bh(bdev, block, size);
+	struct buffer_head *bh = lookup_bh_lru(bdev, block, size);
 
 	if (bh == NULL) {
 		bh = __find_get_block_slow(bdev, block, size);
-		bh_lru_install(bh);
+		if (bh)
+			bh_lru_install(bh);
 	}
+	if (bh)
+		touch_buffer(bh);
 	return bh;
 }
 EXPORT_SYMBOL(__find_get_block);
 
+/*
+ * __getblk will locate (and, if necessary, create) the buffer_head
+ * which corresponds to the passed block_device, block and size. The
+ * returned buffer has its reference count incremented.
+ *
+ * __getblk() cannot fail - it just keeps trying.  If you pass it an
+ * illegal block number, __getblk() will happily return a buffer_head
+ * which represents the non-existent block.  Very weird.
+ *
+ * __getblk() will lock up the machine if grow_dev_page's try_to_free_buffers()
+ * attempt is failing.  FIXME, perhaps?
+ */
 struct buffer_head *
 __getblk(struct block_device *bdev, sector_t block, int size)
 {
 	struct buffer_head *bh = __find_get_block(bdev, block, size);
 
-	if (bh == NULL) {
+	if (bh == NULL)
 		bh = __getblk_slow(bdev, block, size);
-		bh_lru_install(bh);
-	}
 	return bh;
 }
 EXPORT_SYMBOL(__getblk);
 
+/**
+ *  __bread() - reads a specified block and returns the bh
+ *  @block: number of block
+ *  @size: size (in bytes) to read
+ * 
+ *  Reads a specified block, and returns buffer head that contains it.
+ *  It returns NULL if the block was unreadable.
+ */
 struct buffer_head *
 __bread(struct block_device *bdev, sector_t block, int size)
 {
 	struct buffer_head *bh = __getblk(bdev, block, size);
 
-	if (bh) {
-		if (buffer_uptodate(bh))
-			return bh;
-		__brelse(bh);
-	}
-	bh = __bread_slow(bdev, block, size);
-	bh_lru_install(bh);
+	if (!buffer_uptodate(bh))
+		bh = __bread_slow(bh);
 	return bh;
 }
 EXPORT_SYMBOL(__bread);
@@ -1565,7 +1557,7 @@
 {
 	struct buffer_head *old_bh;
 
-	old_bh = __find_get_block(bdev, block, 0);
+	old_bh = __find_get_block_slow(bdev, block, 0);
 	if (old_bh) {
 #if 0	/* This happens.  Later. */
 		if (buffer_dirty(old_bh))
diff -Nru a/fs/devfs/base.c b/fs/devfs/base.c
--- a/fs/devfs/base.c	Sun Nov 10 19:28:37 2002
+++ b/fs/devfs/base.c	Sun Nov 10 19:28:37 2002
@@ -648,6 +648,11 @@
     20020820   Richard Gooch <rgooch@atnf.csiro.au>
 	       Fixed module unload race in <devfs_open>.
   v1.21
+    20021013   Richard Gooch <rgooch@atnf.csiro.au>
+	       Removed DEVFS_ FL_AUTO_OWNER.
+	       Switched lingering structure field initialiser to ISO C.
+	       Added locking when updating FCB flags.
+  v1.22
 */
 #include <linux/types.h>
 #include <linux/errno.h>
@@ -680,7 +685,7 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
-#define DEVFS_VERSION            "1.21 (20020820)"
+#define DEVFS_VERSION            "1.22 (20021013)"
 
 #define DEVFS_NAME "devfs"
 
@@ -778,7 +783,7 @@
 	struct device_type device;
     }
     u;
-    unsigned char auto_owner:1;
+    spinlock_t lock;            /*  Lock for changes                         */
     unsigned char aopen_notify:1;
     unsigned char removable:1;  /*  Belongs in device_type, but save space   */
     unsigned char open:1;       /*  Not entirely correct                     */
@@ -860,7 +865,7 @@
     wait_queue_head_t revalidate_wait_queue;  /*  Wake when devfsd sleeps    */
 };
 
-static struct fs_info fs_info = {devfsd_buffer_lock: SPIN_LOCK_UNLOCKED};
+static struct fs_info fs_info = {.devfsd_buffer_lock = SPIN_LOCK_UNLOCKED};
 static kmem_cache_t *devfsd_buf_cache;
 #ifdef CONFIG_DEVFS_DEBUG
 static unsigned int devfs_debug_init __initdata = DEBUG_NONE;
@@ -1011,6 +1016,8 @@
     memset (new, 0, sizeof *new + namelen);  /*  Will set '\0' on name  */
     new->mode = mode;
     if ( S_ISDIR (mode) ) rwlock_init (&new->u.dir.lock);
+    else if ( S_ISREG (mode) || S_ISCHR (mode) || S_ISBLK (mode) )
+	spin_lock_init (&new->u.fcb.lock);
     atomic_set (&new->refcount, 1);
     spin_lock (&counter_lock);
     new->inode.ino = inode_counter++;
@@ -1480,6 +1487,7 @@
  *	@uid: The user ID.
  *	@gid: The group ID.
  *	@fs_info: The filesystem info.
+ *	@atomic: If TRUE, an atomic allocation is required.
  *
  *	Returns %TRUE if an event was queued and devfsd woken up, else %FALSE.
  */
@@ -1626,7 +1634,6 @@
 	de->inode.gid = 0;
     }
     de->u.fcb.ops = ops;
-    de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE;
     de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE : FALSE;
     de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
     if (flags & DEVFS_FL_REMOVABLE) de->u.fcb.removable = TRUE;
@@ -1893,7 +1900,7 @@
 					  type, traverse_symlinks);
     devfs_unregister (de);
     devfs_put (de);
-}
+}   /*  End Function devfs_find_and_unregister  */
 
 
 /**
@@ -1913,7 +1920,6 @@
     if (de->hide) fl |= DEVFS_FL_HIDE;
     if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
     {
-	if (de->u.fcb.auto_owner) fl |= DEVFS_FL_AUTO_OWNER;
 	if (de->u.fcb.aopen_notify) fl |= DEVFS_FL_AOPEN_NOTIFY;
 	if (de->u.fcb.removable) fl |= DEVFS_FL_REMOVABLE;
     }
@@ -1938,8 +1944,9 @@
     de->hide = (flags & DEVFS_FL_HIDE) ? TRUE : FALSE;
     if ( S_ISCHR (de->mode) || S_ISBLK (de->mode) || S_ISREG (de->mode) )
     {
-	de->u.fcb.auto_owner = (flags & DEVFS_FL_AUTO_OWNER) ? TRUE : FALSE;
+	spin_lock (&de->u.fcb.lock);
 	de->u.fcb.aopen_notify = (flags & DEVFS_FL_AOPEN_NOTIFY) ? TRUE:FALSE;
+	spin_unlock (&de->u.fcb.lock);
     }
     return 0;
 }   /*  End Function devfs_set_flags  */
@@ -2484,13 +2491,9 @@
 	     (int) inode->i_mode, (int) inode->i_uid, (int) inode->i_gid);
     /*  Inode is not on hash chains, thus must save permissions here rather
 	than in a write_inode() method  */
-    if ( ( !S_ISREG (inode->i_mode) && !S_ISCHR (inode->i_mode) &&
-	   !S_ISBLK (inode->i_mode) ) || !de->u.fcb.auto_owner )
-    {
-	de->mode = inode->i_mode;
-	de->inode.uid = inode->i_uid;
-	de->inode.gid = inode->i_gid;
-    }
+    de->mode = inode->i_mode;
+    de->inode.uid = inode->i_uid;
+    de->inode.gid = inode->i_gid;
     de->inode.atime = inode->i_atime;
     de->inode.mtime = inode->i_mtime;
     de->inode.ctime = inode->i_ctime;
@@ -2589,9 +2592,7 @@
 	inode->i_op = &devfs_symlink_iops;
 	inode->i_size = de->u.symlink.length;
     }
-    if (is_fcb && de->u.fcb.auto_owner)
-	inode->i_mode = (de->mode & S_IFMT) | S_IRUGO | S_IWUGO;
-    else inode->i_mode = de->mode;
+    inode->i_mode = de->mode;
     inode->i_uid = de->inode.uid;
     inode->i_gid = de->inode.gid;
     inode->i_atime = de->inode.atime;
@@ -2708,15 +2709,11 @@
     }
     if (err < 0) return err;
     /*  Open was successful  */
-    if (df->open) return 0;
-    df->open = TRUE;  /*  This is the first open  */
-    if (df->auto_owner)
-    {
-	/*  Change the ownership/protection to what driver specified  */
-	inode->i_mode = de->mode;
-	inode->i_uid = current->euid;
-	inode->i_gid = current->egid;
-    }
+    spin_lock (&df->lock);
+    err = df->open;
+    if (!err) df->open = TRUE;  /*  Was not already open    */
+    spin_unlock (&df->lock);
+    if (err) return 0;          /*  Was already open        */
     if ( df->aopen_notify && !is_devfsd_or_child (fs_info) )
 	devfsd_notify_de (de, DEVFSD_NOTIFY_ASYNC_OPEN, inode->i_mode,
 			  current->euid, current->egid, fs_info, 0);
@@ -2796,6 +2793,7 @@
 
 static int devfs_d_delete (struct dentry *dentry)
 {
+    int was_open;
     struct inode *inode = dentry->d_inode;
     struct devfs_entry *de;
     struct fs_info *fs_info;
@@ -2814,16 +2812,14 @@
     if (de == NULL) return 0;
     if ( !S_ISCHR (de->mode) && !S_ISBLK (de->mode) && !S_ISREG (de->mode) )
 	return 0;
-    if (!de->u.fcb.open) return 0;
-    de->u.fcb.open = FALSE;
+    spin_lock (&de->u.fcb.lock);
+    was_open = de->u.fcb.open;
+    if (was_open) de->u.fcb.open = FALSE;
+    spin_unlock (&de->u.fcb.lock);
+    if (!was_open) return 0;
     if (de->u.fcb.aopen_notify)
 	devfsd_notify_de (de, DEVFSD_NOTIFY_CLOSE, inode->i_mode,
 			  current->euid, current->egid, fs_info, 1);
-    if (!de->u.fcb.auto_owner) return 0;
-    /*  Change the ownership/protection back  */
-    inode->i_mode = (de->mode & S_IFMT) | S_IRUGO | S_IWUGO;
-    inode->i_uid = de->inode.uid;
-    inode->i_gid = de->inode.gid;
     return 0;
 }   /*  End Function devfs_d_delete  */
 
diff -Nru a/fs/devfs/util.c b/fs/devfs/util.c
--- a/fs/devfs/util.c	Sun Nov 10 19:28:40 2002
+++ b/fs/devfs/util.c	Sun Nov 10 19:28:40 2002
@@ -58,6 +58,8 @@
                Fixed shift warning on 64 bit machines.
     20020428   Richard Gooch <rgooch@atnf.csiro.au>
                Copied and used macro for error messages from fs/devfs/base.c 
+    20021013   Richard Gooch <rgooch@atnf.csiro.au>
+               Documentation fix.
 */
 #include <linux/module.h>
 #include <linux/init.h>
@@ -309,7 +311,7 @@
  *	@type: The type (DEVFS_SPECIAL_CHR or DEVFS_SPECIAL_BLK).
  *	@devnum: The device number.
  *
- *	This routine is thread safe and does not block.
+ *	This routine is thread safe and may block.
  */
 
 void devfs_dealloc_devnum (char type, kdev_t devnum)
diff -Nru a/fs/eventpoll.c b/fs/eventpoll.c
--- a/fs/eventpoll.c	Sun Nov 10 19:28:39 2002
+++ b/fs/eventpoll.c	Sun Nov 10 19:28:39 2002
@@ -25,6 +25,7 @@
 #include <linux/smp_lock.h>
 #include <linux/string.h>
 #include <linux/list.h>
+#include <linux/hash.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
 #include <asm/bitops.h>
@@ -58,11 +59,12 @@
 #endif /* #if DEBUG_DPI != 0 */
 
 
-/* Maximum storage for the eventpoll interest set */
-#define EP_MAX_FDS_SIZE (1024 * 128)
+/* Maximum size of the hash in bits ( 2^N ) */
+#define EP_MAX_HASH_BITS 17
+
+/* Minimum size of the hash in bits ( 2^N ) */
+#define EP_MIN_HASH_BITS 9
 
-/* We don't want the hash to be smaller than this */
-#define EP_MIN_HASH_SIZE 101
 /*
  * Event buffer dimension used to cache events before sending them in
  * userspace with a __copy_to_user(). The event buffer is in stack,
@@ -77,7 +79,11 @@
 #define EP_HENTRY_X_PAGE (PAGE_SIZE / sizeof(struct list_head))
 
 /* Maximum size of the hash in pages */
-#define EP_MAX_HPAGES (EP_MAX_FDS_SIZE / EP_HENTRY_X_PAGE + 1)
+#define EP_MAX_HPAGES ((1 << EP_MAX_HASH_BITS) / EP_HENTRY_X_PAGE + 1)
+
+/* Number of pages allocated for an "hbits" sized hash table */
+#define EP_HASH_PAGES(hbits) ((int) ((1 << (hbits)) / EP_HENTRY_X_PAGE + \
+				     ((1 << (hbits)) % EP_HENTRY_X_PAGE ? 1: 0)))
 
 /* Macro to allocate a "struct epitem" from the slab cache */
 #define DPI_MEM_ALLOC()	(struct epitem *) kmem_cache_alloc(dpi_cache, SLAB_KERNEL)
@@ -127,10 +133,7 @@
 	struct list_head rdllist;
 
 	/* Size of the hash */
-	int hsize;
-
-	/* Number of pages currently allocated for the hash */
-	int nhpages;
+	unsigned int hashbits;
 
 	/* Pages for the "struct epitem" hash */
 	char *hpages[EP_MAX_HPAGES];
@@ -186,22 +189,20 @@
 
 
 
-
-static int ep_is_prime(int n);
+static unsigned int ep_get_hash_bits(unsigned int hintsize);
 static int ep_getfd(int *efd, struct inode **einode, struct file **efile);
 static int ep_alloc_pages(char **pages, int numpages);
 static int ep_free_pages(char **pages, int numpages);
-static int ep_file_init(struct file *file, int hsize);
-static int ep_hash_index(struct eventpoll *ep, struct file *file);
-static struct list_head *ep_hash_entry(struct eventpoll *ep, int index);
-static int ep_init(struct eventpoll *ep, int hsize);
+static int ep_file_init(struct file *file, unsigned int hashbits);
+static unsigned int ep_hash_index(struct eventpoll *ep, struct file *file);
+static struct list_head *ep_hash_entry(struct eventpoll *ep, unsigned int index);
+static int ep_init(struct eventpoll *ep, unsigned int hashbits);
 static void ep_free(struct eventpoll *ep);
 static struct epitem *ep_find(struct eventpoll *ep, struct file *file);
 static void ep_use_epitem(struct epitem *dpi);
 static void ep_release_epitem(struct epitem *dpi);
 static void ep_ptable_queue_proc(void *priv, wait_queue_head_t *whead);
 static int ep_insert(struct eventpoll *ep, struct pollfd *pfd, struct file *tfile);
-static unsigned int ep_get_file_events(struct file *file);
 static int ep_modify(struct eventpoll *ep, struct epitem *dpi, unsigned int events);
 static int ep_unlink(struct eventpoll *ep, struct epitem *dpi);
 static int ep_remove(struct eventpoll *ep, struct epitem *dpi);
@@ -217,6 +218,7 @@
 					      int flags, char *dev_name, void *data);
 
 
+
 /* Use to link togheter all the "struct eventpoll" */
 static struct list_head eplist;
 
@@ -252,21 +254,16 @@
 
 
 
-/* Report if the number is prime. Needed to correctly size the hash  */
-static int ep_is_prime(int n)
+/*
+ * Calculate the size of the hash in bits. The returned size will be
+ * bounded between EP_MIN_HASH_BITS and EP_MAX_HASH_BITS.
+ */
+static unsigned int ep_get_hash_bits(unsigned int hintsize)
 {
+	unsigned int i, val;
 
-	if (n > 3) {
-		if (n & 1) {
-			int i, hn = n / 2;
-
-			for (i = 3; i < hn; i += 2)
-				if (!(n % i))
-					return 0;
-		} else
-			return 0;
-	}
-	return 1;
+	for (i = 0, val = 1; val < hintsize && i < EP_MAX_HASH_BITS; i++, val <<= 1);
+	return i <  EP_MIN_HASH_BITS ?  EP_MIN_HASH_BITS: i;
 }
 
 
@@ -298,21 +295,23 @@
 
 /*
  * It opens an eventpoll file descriptor by suggesting a storage of "size"
- * file descriptors. It is the kernel part of the userspace epoll_create(2).
+ * file descriptors. The size parameter is just an hint about how to size
+ * data structures. It won't prevent the user to store more than "size"
+ * file descriptors inside the epoll interface. It is the kernel part of
+ * the userspace epoll_create(2).
  */
 asmlinkage int sys_epoll_create(int size)
 {
 	int error, fd;
+	unsigned int hashbits;
 	struct inode *inode;
 	struct file *file;
 
 	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_create(%d)\n",
 		     current, size));
 
-	/* Search the nearest prime number higher than "size" */
-	for (; !ep_is_prime(size); size++);
-	if (size < EP_MIN_HASH_SIZE)
-		size = EP_MIN_HASH_SIZE;
+	/* Correctly size the hash */
+	hashbits = ep_get_hash_bits((unsigned int) size);
 
 	/*
 	 * Creates all the items needed to setup an eventpoll file. That is,
@@ -323,7 +322,7 @@
 		goto eexit_1;
 
 	/* Setup the file internal data structure ( "struct eventpoll" ) */
-	error = ep_file_init(file, size);
+	error = ep_file_init(file, hashbits);
 	if (error)
 		goto eexit_2;
 
@@ -457,6 +456,10 @@
 	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: sys_epoll_wait(%d, %p, %d, %d)\n",
 		     current, epfd, events, maxevents, timeout));
 
+	/* The maximum number of event must be greater than zero */
+	if (maxevents <= 0)
+		return -EINVAL;
+
 	/* Verify that the area passed by the user is writeable */
 	if ((error = verify_area(VERIFY_WRITE, events, maxevents * sizeof(struct pollfd))))
 		goto eexit_1;
@@ -602,7 +605,7 @@
 }
 
 
-static int ep_file_init(struct file *file, int hsize)
+static int ep_file_init(struct file *file, unsigned int hashbits)
 {
 	int error;
 	unsigned long flags;
@@ -613,7 +616,7 @@
 
 	memset(ep, 0, sizeof(*ep));
 
-	error = ep_init(ep, hsize);
+	error = ep_init(ep, hashbits);
 	if (error) {
 		kfree(ep);
 		return error;
@@ -635,17 +638,17 @@
 /*
  * Calculate the index of the hash relative to "file".
  */
-static int ep_hash_index(struct eventpoll *ep, struct file *file)
+static unsigned int ep_hash_index(struct eventpoll *ep, struct file *file)
 {
 
-	return (int) ((((unsigned long) file) / sizeof(struct file)) % ep->hsize);
+	return (unsigned int) hash_ptr(file, ep->hashbits);
 }
 
 
 /*
  * Returns the hash entry ( struct list_head * ) of the passed index.
  */
-static struct list_head *ep_hash_entry(struct eventpoll *ep, int index)
+static struct list_head *ep_hash_entry(struct eventpoll *ep, unsigned int index)
 {
 
 	return (struct list_head *) (ep->hpages[index / EP_HENTRY_X_PAGE] +
@@ -653,9 +656,10 @@
 }
 
 
-static int ep_init(struct eventpoll *ep, int hsize)
+static int ep_init(struct eventpoll *ep, unsigned int hashbits)
 {
-	int error, i;
+	int error;
+	unsigned int i, hsize;
 
 	INIT_LIST_HEAD(&ep->llink);
 	rwlock_init(&ep->lock);
@@ -664,14 +668,13 @@
 	INIT_LIST_HEAD(&ep->rdllist);
 
 	/* Hash allocation and setup */
-	ep->hsize = hsize;
-	ep->nhpages = hsize / EP_HENTRY_X_PAGE + (hsize % EP_HENTRY_X_PAGE ? 1: 0);
-	error = ep_alloc_pages(ep->hpages, ep->nhpages);
+	ep->hashbits = hashbits;
+	error = ep_alloc_pages(ep->hpages, EP_HASH_PAGES(ep->hashbits));
 	if (error)
 		goto eexit_1;
 
 	/* Initialize hash buckets */
-	for (i = 0; i < ep->hsize; i++)
+	for (i = 0, hsize = 1 << hashbits; i < hsize; i++)
 		INIT_LIST_HEAD(ep_hash_entry(ep, i));
 
 	return 0;
@@ -682,7 +685,7 @@
 
 static void ep_free(struct eventpoll *ep)
 {
-	int i;
+	unsigned int i, hsize;
 	unsigned long flags;
 	struct list_head *lsthead;
 
@@ -690,7 +693,7 @@
 	 * Walks through the whole hash by unregistering file callbacks and
 	 * freeing each "struct epitem".
 	 */
-	for (i = 0; i < ep->hsize; i++) {
+	for (i = 0, hsize = 1 << ep->hashbits; i < hsize; i++) {
 		lsthead = ep_hash_entry(ep, i);
 
 		/*
@@ -723,8 +726,7 @@
 	write_unlock_irqrestore(&eplock, flags);
 
 	/* Free hash pages */
-	if (ep->nhpages > 0)
-		ep_free_pages(ep->hpages, ep->nhpages);
+	ep_free_pages(ep->hpages, EP_HASH_PAGES(ep->hashbits));
 }
 
 
@@ -827,22 +829,33 @@
 		dpi->wait[i].base = dpi;
 	}
 
-	/* Attach the item to the poll hooks */
+	/* Initialize the poll table using the queue callback */
 	poll_initwait_ex(&pt, 1, ep_ptable_queue_proc, dpi);
-	revents = tfile->f_op->poll(tfile, &pt);
-	poll_freewait(&pt);
 
 	/* We have to drop the new item inside our item list to keep track of it */
 	write_lock_irqsave(&ep->lock, flags);
 
+	/* Add the current item to the hash table */
 	list_add(&dpi->llink, ep_hash_entry(ep, ep_hash_index(ep, tfile)));
 
+	/* Attach the item to the poll hooks and get current event bits */
+	revents = tfile->f_op->poll(tfile, &pt);
+
 	/* If the file is already "ready" we drop it inside the ready list */
-	if ((revents & pfd->events) && !EP_IS_LINKED(&dpi->rdllink))
-		list_add(&dpi->rdllink, &ep->rdllist);
+	if ((revents & pfd->events) && !EP_IS_LINKED(&dpi->rdllink)) {
+		list_add_tail(&dpi->rdllink, &ep->rdllist);
+
+		/* Notify waiting tasks that events are available */
+		if (waitqueue_active(&ep->wq))
+			wake_up(&ep->wq);
+		if (waitqueue_active(&ep->poll_wait))
+			wake_up(&ep->poll_wait);
+	}
 
 	write_unlock_irqrestore(&ep->lock, flags);
 
+	poll_freewait(&pt);
+
 	DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_insert(%p, %d)\n",
 		     current, ep, pfd->fd));
 
@@ -854,12 +867,13 @@
 
 
 /*
- * Returns the current events of the given file. It uses the special
- * poll table initialization to avoid any poll queue insertion.
+ * Modify the interest event mask by dropping an event if the new mask
+ * has a match in the current file status.
  */
-static unsigned int ep_get_file_events(struct file *file)
+static int ep_modify(struct eventpoll *ep, struct epitem *dpi, unsigned int events)
 {
 	unsigned int revents;
+	unsigned long flags;
 	poll_table pt;
 
 	/*
@@ -870,34 +884,30 @@
 	 */
 	poll_initwait_ex(&pt, 0, NULL, NULL);
 
-	revents = file->f_op->poll(file, &pt);
-
-	poll_freewait(&pt);
-	return revents;
-}
-
-
-/*
- * Modify the interest event mask by dropping an event if the new mask
- * has a match in the current file status.
- */
-static int ep_modify(struct eventpoll *ep, struct epitem *dpi, unsigned int events)
-{
-	unsigned int revents;
-	unsigned long flags;
-
-	revents = ep_get_file_events(dpi->file);
-
 	write_lock_irqsave(&ep->lock, flags);
 
+	/* Get current event bits */
+	revents = dpi->file->f_op->poll(dpi->file, &pt);
+
+	/* Set the new event interest mask */
 	dpi->pfd.events = events;
 
 	/* If the file is already "ready" we drop it inside the ready list */
-	if ((revents & events) && EP_IS_LINKED(&dpi->llink) && !EP_IS_LINKED(&dpi->rdllink))
-		list_add(&dpi->rdllink, &ep->rdllist);
+	if ((revents & events) && EP_IS_LINKED(&dpi->llink) &&
+	    !EP_IS_LINKED(&dpi->rdllink)) {
+		list_add_tail(&dpi->rdllink, &ep->rdllist);
+
+		/* Notify waiting tasks that events are available */
+		if (waitqueue_active(&ep->wq))
+			wake_up(&ep->wq);
+		if (waitqueue_active(&ep->poll_wait))
+			wake_up(&ep->poll_wait);
+	}
 
 	write_unlock_irqrestore(&ep->lock, flags);
 
+	poll_freewait(&pt);
+
 	return 0;
 }
 
@@ -996,7 +1006,7 @@
 	if (EP_IS_LINKED(&dpi->rdllink))
 		goto is_linked;
 
-	list_add(&dpi->rdllink, &ep->rdllist);
+	list_add_tail(&dpi->rdllink, &ep->rdllist);
 
 is_linked:
 	/*
@@ -1068,12 +1078,20 @@
 
 	write_lock_irqsave(&ep->lock, flags);
 
-	for (eventcnt = 0, ebufcnt = 0; eventcnt < maxevents && !list_empty(lsthead);) {
+	for (eventcnt = 0, ebufcnt = 0; (eventcnt + ebufcnt) < maxevents && !list_empty(lsthead);) {
 		struct epitem *dpi = list_entry(lsthead->next, struct epitem, rdllink);
 
 		/* Remove the item from the ready list */
 		EP_LIST_DEL(&dpi->rdllink);
 
+		/*
+		 * If the item is not linked to the main hash table this means that
+		 * it's on the way to be removed and we don't want to send events
+		 * for such file descriptor.
+		 */
+		if (!EP_IS_LINKED(&dpi->llink))
+			continue;
+
 		/* Fetch event bits from the signaled file */
 		revents = dpi->file->f_op->poll(dpi->file, &pt);
 
@@ -1120,18 +1138,16 @@
 static int ep_poll(struct eventpoll *ep, struct pollfd *events, int maxevents,
 		   int timeout)
 {
-	int res = 0, eavail;
+	int res, eavail;
 	unsigned long flags;
 	long jtimeout;
 	wait_queue_t wait;
 
 	/*
-	 * Calculate the timeout by checking for the "infinite" value ( -1 )
-	 * and the overflow condition ( > MAX_SCHEDULE_TIMEOUT / HZ ). The
-	 * passed timeout is in milliseconds, that why (t * HZ) / 1000.
+	 * Calculate the timeout by checking for the "infinite" value ( -1 ).
+	 * The passed timeout is in milliseconds, that why (t * HZ) / 1000.
 	 */
-	jtimeout = timeout == -1 || timeout > MAX_SCHEDULE_TIMEOUT / HZ ?
-		MAX_SCHEDULE_TIMEOUT: (timeout * HZ) / 1000;
+	jtimeout = timeout == -1 ? MAX_SCHEDULE_TIMEOUT: (timeout * HZ) / 1000;
 
 retry:
 	write_lock_irqsave(&ep->lock, flags);
diff -Nru a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c	Sun Nov 10 19:28:39 2002
+++ b/fs/exec.c	Sun Nov 10 19:28:39 2002
@@ -279,6 +279,7 @@
 	return r; 
 }
 
+#ifdef CONFIG_MMU
 /*
  * This routine is used to map in a page into an address space: needed by
  * execve() for the initial stack and environment pages.
@@ -293,6 +294,7 @@
 
 	if (page_count(page) != 1)
 		printk(KERN_ERR "mem_map disagrees with %p at %08lx\n", page, address);
+
 	pgd = pgd_offset(tsk->mm, address);
 
 	spin_lock(&tsk->mm->page_table_lock);
@@ -331,7 +333,7 @@
 	struct mm_struct *mm = current->mm;
 	int i;
 
-#ifdef ARCH_STACK_GROWSUP
+#ifdef CONFIG_STACK_GROWSUP
 	/* Move the argument and environment strings to the bottom of the
 	 * stack space.
 	 */
@@ -390,7 +392,7 @@
 	down_write(&mm->mmap_sem);
 	{
 		mpnt->vm_mm = mm;
-#ifdef ARCH_STACK_GROWSUP
+#ifdef CONFIG_STACK_GROWSUP
 		mpnt->vm_start = stack_base;
 		mpnt->vm_end = PAGE_MASK &
 			(PAGE_SIZE - 1 + (unsigned long) bprm->p);
@@ -422,6 +424,25 @@
 	return 0;
 }
 
+#define free_arg_pages(bprm) do { } while (0)
+
+#else
+
+#define put_dirty_page(tsk, page, address)
+#define setup_arg_pages(bprm)			(0)
+static inline void free_arg_pages(struct linux_binprm *bprm)
+{
+	int i;
+
+	for (i = 0 ; i < MAX_ARG_PAGES ; i++) {
+		if (bprm->page[i])
+		__free_page(bprm->page[i]);
+		bprm->page[i] = NULL;
+	}
+}
+
+#endif /* CONFIG_MMU */
+
 struct file *open_exec(const char *name)
 {
 	struct nameidata nd;
@@ -1056,6 +1077,8 @@
 
 	retval = search_binary_handler(&bprm,regs);
 	if (retval >= 0) {
+		free_arg_pages(&bprm);
+
 		/* execve success */
 		security_ops->bprm_free_security(&bprm);
 		return retval;
@@ -1209,6 +1232,35 @@
 	*out_ptr = 0;
 }
 
+static void zap_threads (struct mm_struct *mm)
+{
+	struct task_struct *g, *p;
+
+	/* give other threads a chance to run: */
+	yield();
+
+	read_lock(&tasklist_lock);
+	do_each_thread(g,p)
+		if (mm == p->mm && !p->core_waiter)
+			force_sig_specific(SIGKILL, p);
+	while_each_thread(g,p);
+	read_unlock(&tasklist_lock);
+}
+
+static void coredump_wait(struct mm_struct *mm)
+{
+	DECLARE_WAITQUEUE(wait, current);
+
+	atomic_inc(&mm->core_waiters);
+	add_wait_queue(&mm->core_wait, &wait);
+	zap_threads(mm);
+	current->state = TASK_UNINTERRUPTIBLE;
+	if (atomic_read(&mm->core_waiters) != atomic_read(&mm->mm_users))
+		schedule();
+	else
+		current->state = TASK_RUNNING;
+}
+
 int do_coredump(long signr, struct pt_regs * regs)
 {
 	struct linux_binfmt * binfmt;
@@ -1224,13 +1276,16 @@
 	if (!current->mm->dumpable)
 		goto fail;
 	current->mm->dumpable = 0;
+	if (down_trylock(&current->mm->core_sem))
+		BUG();
+	coredump_wait(current->mm);
 	if (current->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
-		goto fail;
+		goto fail_unlock;
 
  	format_corename(corename, core_pattern, signr);
 	file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW, 0600);
 	if (IS_ERR(file))
-		goto fail;
+		goto fail_unlock;
 	inode = file->f_dentry->d_inode;
 	if (inode->i_nlink > 1)
 		goto close_fail;	/* multiple links - don't dump */
@@ -1250,6 +1305,8 @@
 
 close_fail:
 	filp_close(file, NULL);
+fail_unlock:
+	up(&current->mm->core_sem);
 fail:
 	unlock_kernel();
 	return retval;
diff -Nru a/fs/ext2/acl.c b/fs/ext2/acl.c
--- a/fs/ext2/acl.c	Sun Nov 10 19:28:40 2002
+++ b/fs/ext2/acl.c	Sun Nov 10 19:28:40 2002
@@ -530,17 +530,17 @@
 }
 
 struct ext2_xattr_handler ext2_xattr_acl_access_handler = {
-	prefix:	XATTR_NAME_ACL_ACCESS,
-	list:	ext2_xattr_list_acl_access,
-	get:	ext2_xattr_get_acl_access,
-	set:	ext2_xattr_set_acl_access,
+	.prefix	= XATTR_NAME_ACL_ACCESS,
+	.list	= ext2_xattr_list_acl_access,
+	.get	= ext2_xattr_get_acl_access,
+	.set	= ext2_xattr_set_acl_access,
 };
 
 struct ext2_xattr_handler ext2_xattr_acl_default_handler = {
-	prefix:	XATTR_NAME_ACL_DEFAULT,
-	list:	ext2_xattr_list_acl_default,
-	get:	ext2_xattr_get_acl_default,
-	set:	ext2_xattr_set_acl_default,
+	.prefix	= XATTR_NAME_ACL_DEFAULT,
+	.list	= ext2_xattr_list_acl_default,
+	.get	= ext2_xattr_get_acl_default,
+	.set	= ext2_xattr_set_acl_default,
 };
 
 void
diff -Nru a/fs/ext2/dir.c b/fs/ext2/dir.c
--- a/fs/ext2/dir.c	Sun Nov 10 19:28:40 2002
+++ b/fs/ext2/dir.c	Sun Nov 10 19:28:40 2002
@@ -66,7 +66,7 @@
 {
 	struct inode *dir = page->mapping->host;
 	int err = 0;
-	dir->i_version = ++event;
+	dir->i_version++;
 	page->mapping->a_ops->commit_write(NULL, page, from, to);
 	if (IS_DIRSYNC(dir))
 		err = write_one_page(page, 1);
diff -Nru a/fs/ext2/inode.c b/fs/ext2/inode.c
--- a/fs/ext2/inode.c	Sun Nov 10 19:28:37 2002
+++ b/fs/ext2/inode.c	Sun Nov 10 19:28:37 2002
@@ -599,7 +599,7 @@
 }
 
 static int
-ext2_readpages(struct address_space *mapping,
+ext2_readpages(struct file *file, struct address_space *mapping,
 		struct list_head *pages, unsigned nr_pages)
 {
 	return mpage_readpages(mapping, pages, nr_pages, ext2_get_block);
@@ -1015,7 +1015,6 @@
 	}
 	inode->i_blksize = PAGE_SIZE;	/* This is the optimal IO size (for stat), not the fs block size */
 	inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
-	inode->i_version = ++event;
 	ei->i_flags = le32_to_cpu(raw_inode->i_flags);
 	ei->i_faddr = le32_to_cpu(raw_inode->i_faddr);
 	ei->i_frag_no = raw_inode->i_frag;
diff -Nru a/fs/ext2/super.c b/fs/ext2/super.c
--- a/fs/ext2/super.c	Sun Nov 10 19:28:40 2002
+++ b/fs/ext2/super.c	Sun Nov 10 19:28:40 2002
@@ -160,6 +160,7 @@
 	ei->i_acl = EXT2_ACL_NOT_CACHED;
 	ei->i_default_acl = EXT2_ACL_NOT_CACHED;
 #endif
+	ei->vfs_inode.i_version = 1;
 	return &ei->vfs_inode;
 }
 
@@ -528,6 +529,7 @@
 {
 	struct ext2_sb_info *sbi = EXT2_SB(sb);
 	unsigned long bg, first_data_block, first_meta_bg;
+	int has_super = 0;
 	
 	first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block);
 	first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
@@ -536,7 +538,9 @@
 	    nr < first_meta_bg)
 		return (logic_sb_block + nr + 1);
 	bg = sbi->s_desc_per_block * nr;
-	return (first_data_block + 1 + (bg * sbi->s_blocks_per_group));
+	if (ext2_bg_has_super(sb, bg))
+		has_super = 1;
+	return (first_data_block + has_super + (bg * sbi->s_blocks_per_group));
 }
 
 static int ext2_fill_super(struct super_block *sb, void *data, int silent)
diff -Nru a/fs/ext2/xattr_user.c b/fs/ext2/xattr_user.c
--- a/fs/ext2/xattr_user.c	Sun Nov 10 19:28:40 2002
+++ b/fs/ext2/xattr_user.c	Sun Nov 10 19:28:40 2002
@@ -81,10 +81,10 @@
 }
 
 struct ext2_xattr_handler ext2_xattr_user_handler = {
-	prefix:	XATTR_USER_PREFIX,
-	list:	ext2_xattr_user_list,
-	get:	ext2_xattr_user_get,
-	set:	ext2_xattr_user_set,
+	.prefix	= XATTR_USER_PREFIX,
+	.list	= ext2_xattr_user_list,
+	.get	= ext2_xattr_user_get,
+	.set	= ext2_xattr_user_set,
 };
 
 int __init
diff -Nru a/fs/ext3/acl.c b/fs/ext3/acl.c
--- a/fs/ext3/acl.c	Sun Nov 10 19:28:38 2002
+++ b/fs/ext3/acl.c	Sun Nov 10 19:28:38 2002
@@ -547,17 +547,17 @@
 }
 
 struct ext3_xattr_handler ext3_xattr_acl_access_handler = {
-	prefix:	XATTR_NAME_ACL_ACCESS,
-	list:	ext3_xattr_list_acl_access,
-	get:	ext3_xattr_get_acl_access,
-	set:	ext3_xattr_set_acl_access,
+	.prefix	= XATTR_NAME_ACL_ACCESS,
+	.list	= ext3_xattr_list_acl_access,
+	.get	= ext3_xattr_get_acl_access,
+	.set	= ext3_xattr_set_acl_access,
 };
 
 struct ext3_xattr_handler ext3_xattr_acl_default_handler = {
-	prefix:	XATTR_NAME_ACL_DEFAULT,
-	list:	ext3_xattr_list_acl_default,
-	get:	ext3_xattr_get_acl_default,
-	set:	ext3_xattr_set_acl_default,
+	.prefix	= XATTR_NAME_ACL_DEFAULT,
+	.list	= ext3_xattr_list_acl_default,
+	.get	= ext3_xattr_get_acl_default,
+	.set	= ext3_xattr_set_acl_default,
 };
 
 void
diff -Nru a/fs/ext3/dir.c b/fs/ext3/dir.c
--- a/fs/ext3/dir.c	Sun Nov 10 19:28:40 2002
+++ b/fs/ext3/dir.c	Sun Nov 10 19:28:40 2002
@@ -314,7 +314,7 @@
 /*
  * Given a directory entry, enter it into the fname rb tree.
  */
-void ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
+int ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
 			     __u32 minor_hash,
 			     struct ext3_dir_entry_2 *dirent)
 {
@@ -329,6 +329,8 @@
 	/* Create and allocate the fname structure */
 	len = sizeof(struct fname) + dirent->name_len + 1;
 	new_fn = kmalloc(len, GFP_KERNEL);
+	if (!new_fn)
+		return -ENOMEM;
 	memset(new_fn, 0, len);
 	new_fn->hash = hash;
 	new_fn->minor_hash = minor_hash;
@@ -350,7 +352,7 @@
 		    (new_fn->minor_hash == fname->minor_hash)) {
 			new_fn->next = fname->next;
 			fname->next = new_fn;
-			return;
+			return 0;
 		}
 			
 		if (new_fn->hash < fname->hash)
@@ -365,6 +367,7 @@
 
 	rb_link_node(&new_fn->rb_hash, parent, p);
 	rb_insert_color(&new_fn->rb_hash, &info->root);
+	return 0;
 }
 
 
diff -Nru a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c
--- a/fs/ext3/ialloc.c	Sun Nov 10 19:28:39 2002
+++ b/fs/ext3/ialloc.c	Sun Nov 10 19:28:39 2002
@@ -208,7 +208,7 @@
 	int ngroups = EXT3_SB(sb)->s_groups_count;
 	int avefreei = le32_to_cpu(es->s_free_inodes_count) / ngroups;
 	struct ext3_group_desc *desc, *best_desc = NULL;
-	struct buffer_head *bh, *best_bh = NULL;
+	struct buffer_head *bh;
 	int group, best_group = -1;
 
 	for (group = 0; group < ngroups; group++) {
@@ -222,16 +222,8 @@
 		     le16_to_cpu(best_desc->bg_free_blocks_count))) {
 			best_group = group;
 			best_desc = desc;
-			best_bh = bh;
 		}
 	}
-	if (!best_desc)
-		return -1;
-	best_desc->bg_free_inodes_count =
-		cpu_to_le16(le16_to_cpu(best_desc->bg_free_inodes_count) - 1);
-	best_desc->bg_used_dirs_count =
-		cpu_to_le16(le16_to_cpu(best_desc->bg_used_dirs_count) + 1);
-	mark_buffer_dirty(best_bh);
 	return best_group;
 }
 
@@ -281,8 +273,6 @@
 
 	if ((parent == sb->s_root->d_inode) ||
 	    (parent->i_flags & EXT3_TOPDIR_FL)) {
-		struct ext3_group_desc *best_desc = NULL;
-		struct buffer_head *best_bh = NULL;
 		int best_ndir = inodes_per_group;
 		int best_group = -1;
 
@@ -301,15 +291,9 @@
 				continue;
 			best_group = group;
 			best_ndir = le16_to_cpu(desc->bg_used_dirs_count);
-			best_desc = desc;
-			best_bh = bh;
-		}
-		if (best_group >= 0) {
-			desc = best_desc;
-			bh = best_bh;
-			group = best_group;
-			goto found;
 		}
+		if (best_group >= 0)
+			return best_group;
 		goto fallback;
 	}
 
@@ -341,7 +325,7 @@
 			continue;
 		if (le16_to_cpu(desc->bg_free_blocks_count) < min_blocks)
 			continue;
-		goto found;
+		return group;
 	}
 
 fallback:
@@ -351,19 +335,10 @@
 		if (!desc || !desc->bg_free_inodes_count)
 			continue;
 		if (le16_to_cpu(desc->bg_free_inodes_count) >= avefreei)
-			goto found;
+			return group;
 	}
 
 	return -1;
-
-found:
-	desc->bg_free_inodes_count =
-		cpu_to_le16(le16_to_cpu(desc->bg_free_inodes_count) - 1);
-	desc->bg_used_dirs_count =
-		cpu_to_le16(le16_to_cpu(desc->bg_used_dirs_count) + 1);
-	sbi->s_dir_count++;
-	mark_buffer_dirty(bh);
-	return group;
 }
 
 static int find_group_other(struct super_block *sb, struct inode *parent)
@@ -380,7 +355,7 @@
 	group = parent_group;
 	desc = ext3_get_group_desc (sb, group, &bh);
 	if (desc && le16_to_cpu(desc->bg_free_inodes_count))
-		goto found;
+		return group;
 
 	/*
 	 * Use a quadratic hash to find a group with a
@@ -392,7 +367,7 @@
 			group -= ngroups;
 		desc = ext3_get_group_desc (sb, group, &bh);
 		if (desc && le16_to_cpu(desc->bg_free_inodes_count))
-			goto found;
+			return group;
 	}
 
 	/*
@@ -404,16 +379,10 @@
 			group = 0;
 		desc = ext3_get_group_desc (sb, group, &bh);
 		if (desc && le16_to_cpu(desc->bg_free_inodes_count))
-			goto found;
+			return group;
 	}
 
 	return -1;
-
-found:
-	desc->bg_free_inodes_count =
-		cpu_to_le16(le16_to_cpu(desc->bg_free_inodes_count) - 1);
-	mark_buffer_dirty(bh);
-	return group;
 }
 
 /*
@@ -521,9 +490,11 @@
 	if (err) goto fail;
 	gdp->bg_free_inodes_count =
 		cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
-	if (S_ISDIR(mode))
+	if (S_ISDIR(mode)) {
 		gdp->bg_used_dirs_count =
 			cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
+		EXT3_SB(sb)->s_dir_count++;
+	}
 	BUFFER_TRACE(bh2, "call ext3_journal_dirty_metadata");
 	err = ext3_journal_dirty_metadata(handle, bh2);
 	if (err) goto fail;
diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c
--- a/fs/ext3/inode.c	Sun Nov 10 19:28:40 2002
+++ b/fs/ext3/inode.c	Sun Nov 10 19:28:40 2002
@@ -1385,7 +1385,7 @@
 }
 
 static int
-ext3_readpages(struct address_space *mapping,
+ext3_readpages(struct file *file, struct address_space *mapping,
 		struct list_head *pages, unsigned nr_pages)
 {
 	return mpage_readpages(mapping, pages, nr_pages, ext3_get_block);
@@ -2248,7 +2248,6 @@
 					 * (for stat), not the fs block
 					 * size */  
 	inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
-	inode->i_version = ++event;
 	ei->i_flags = le32_to_cpu(raw_inode->i_flags);
 #ifdef EXT3_FRAGMENTS
 	ei->i_faddr = le32_to_cpu(raw_inode->i_faddr);
diff -Nru a/fs/ext3/namei.c b/fs/ext3/namei.c
--- a/fs/ext3/namei.c	Sun Nov 10 19:28:40 2002
+++ b/fs/ext3/namei.c	Sun Nov 10 19:28:40 2002
@@ -549,6 +549,17 @@
 	if (!frame)
 		return err;
 
+	/* Add '.' and '..' from the htree header */
+	if (!start_hash && !start_minor_hash) {
+		de = (struct ext3_dir_entry_2 *) frames[0].bh->b_data;
+		if ((err = ext3_htree_store_dirent(dir_file, 0, 0, de)) != 0)
+			goto errout;
+		de = ext3_next_entry(de);
+		if ((err = ext3_htree_store_dirent(dir_file, 0, 0, de)) != 0)
+			goto errout;
+		count += 2;
+	}
+
 	while (1) {
 		block = dx_get_block(frame->at);
 		dxtrace(printk("Reading block %d\n", block));
@@ -564,8 +575,9 @@
 			    ((hinfo.hash == start_hash) &&
 			     (hinfo.minor_hash < start_minor_hash)))
 				continue;
-			ext3_htree_store_dirent(dir_file, hinfo.hash,
-						hinfo.minor_hash, de);
+			if ((err = ext3_htree_store_dirent(dir_file,
+				   hinfo.hash, hinfo.minor_hash, de)) != 0)
+				goto errout;
 			count++;
 		}
 		brelse (bh);
@@ -1201,7 +1213,7 @@
 	 */
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
 	ext3_update_dx_flag(dir);
-	dir->i_version = ++event;
+	dir->i_version++;
 	ext3_mark_inode_dirty(handle, dir);
 	BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
 	err = ext3_journal_dirty_metadata(handle, bh);
@@ -1520,7 +1532,7 @@
 						    le16_to_cpu(de->rec_len));
 			else
 				de->inode = 0;
-			dir->i_version = ++event;
+			dir->i_version++;
 			BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
 			ext3_journal_dirty_metadata(handle, bh);
 			return 0;
@@ -1964,7 +1976,7 @@
 		ext3_warning (inode->i_sb, "ext3_rmdir",
 			      "empty directory has nlink!=2 (%d)",
 			      inode->i_nlink);
-	inode->i_version = ++event;
+	inode->i_version++;
 	inode->i_nlink = 0;
 	/* There's no need to set i_disksize: the fact that i_nlink is
 	 * zero will ensure that the right thing happens during any
@@ -2214,7 +2226,7 @@
 		if (EXT3_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
 					      EXT3_FEATURE_INCOMPAT_FILETYPE))
 			new_de->file_type = old_de->file_type;
-		new_dir->i_version = ++event;
+		new_dir->i_version++;
 		BUFFER_TRACE(new_bh, "call ext3_journal_dirty_metadata");
 		ext3_journal_dirty_metadata(handle, new_bh);
 		brelse(new_bh);
@@ -2231,7 +2243,26 @@
 	/*
 	 * ok, that's it
 	 */
-	ext3_delete_entry(handle, old_dir, old_de, old_bh);
+	retval = ext3_delete_entry(handle, old_dir, old_de, old_bh);
+	if (retval == -ENOENT) {
+		/*
+		 * old_de could have moved out from under us.
+		 */
+		struct buffer_head *old_bh2;
+		struct ext3_dir_entry_2 *old_de2;
+		
+		old_bh2 = ext3_find_entry(old_dentry, &old_de2);
+		if (old_bh2) {
+			retval = ext3_delete_entry(handle, old_dir,
+						   old_de2, old_bh2);
+			brelse(old_bh2);
+		}
+	}
+	if (retval) {
+		ext3_warning(old_dir->i_sb, "ext3_rename",
+				"Deleting old file (%lu), %d, error=%d",
+				old_dir->i_ino, old_dir->i_nlink, retval);
+	}
 
 	if (new_inode) {
 		new_inode->i_nlink--;
diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c
--- a/fs/ext3/super.c	Sun Nov 10 19:28:41 2002
+++ b/fs/ext3/super.c	Sun Nov 10 19:28:41 2002
@@ -434,6 +434,7 @@
 	ei->i_acl = EXT3_ACL_NOT_CACHED;
 	ei->i_default_acl = EXT3_ACL_NOT_CACHED;
 #endif
+	ei->vfs_inode.i_version = 1;
 	return &ei->vfs_inode;
 }
 
@@ -978,6 +979,7 @@
 {
 	struct ext3_sb_info *sbi = EXT3_SB(sb);
 	unsigned long bg, first_data_block, first_meta_bg;
+	int has_super = 0;
 	
 	first_data_block = le32_to_cpu(sbi->s_es->s_first_data_block);
 	first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
@@ -986,7 +988,9 @@
 	    nr < first_meta_bg)
 		return (logic_sb_block + nr + 1);
 	bg = sbi->s_desc_per_block * nr;
-	return (first_data_block + 1 + (bg * sbi->s_blocks_per_group));
+	if (ext3_bg_has_super(sb, bg))
+		has_super = 1;
+	return (first_data_block + has_super + (bg * sbi->s_blocks_per_group));
 }
 
 
@@ -1017,6 +1021,7 @@
 	sbi->s_mount_opt = 0;
 	sbi->s_resuid = EXT3_DEF_RESUID;
 	sbi->s_resgid = EXT3_DEF_RESGID;
+	setup_ro_after(sb);
 
 	blocksize = sb_min_blocksize(sb, EXT3_MIN_BLOCK_SIZE);
 	if (!blocksize) {
diff -Nru a/fs/ext3/xattr_user.c b/fs/ext3/xattr_user.c
--- a/fs/ext3/xattr_user.c	Sun Nov 10 19:28:37 2002
+++ b/fs/ext3/xattr_user.c	Sun Nov 10 19:28:37 2002
@@ -92,8 +92,8 @@
 }
 
 struct ext3_xattr_handler ext3_xattr_user_handler = {
-	prefix:	XATTR_USER_PREFIX,
-	list:	ext3_xattr_user_list,
-	get:	ext3_xattr_user_get,
-	set:	ext3_xattr_user_set,
+	.prefix	= XATTR_USER_PREFIX,
+	.list	= ext3_xattr_user_list,
+	.get	= ext3_xattr_user_get,
+	.set	= ext3_xattr_user_set,
 };
diff -Nru a/fs/fat/dir.c b/fs/fat/dir.c
--- a/fs/fat/dir.c	Sun Nov 10 19:28:36 2002
+++ b/fs/fat/dir.c	Sun Nov 10 19:28:36 2002
@@ -23,10 +23,10 @@
 #include <asm/uaccess.h>
 
 struct file_operations fat_dir_operations = {
-	read:		generic_read_dir,
-	readdir:	fat_readdir,
-	ioctl:		fat_dir_ioctl,
-	fsync:		file_fsync,
+	.read		= generic_read_dir,
+	.readdir	= fat_readdir,
+	.ioctl		= fat_dir_ioctl,
+	.fsync		= file_fsync,
 };
 
 /*
diff -Nru a/fs/fat/file.c b/fs/fat/file.c
--- a/fs/fat/file.c	Sun Nov 10 19:28:38 2002
+++ b/fs/fat/file.c	Sun Nov 10 19:28:38 2002
@@ -15,17 +15,17 @@
 			      loff_t *ppos);
 
 struct file_operations fat_file_operations = {
-	llseek:		generic_file_llseek,
-	read:		generic_file_read,
-	write:		fat_file_write,
-	mmap:		generic_file_mmap,
-	fsync:		file_fsync,
-	sendfile:	generic_file_sendfile,
+	.llseek		= generic_file_llseek,
+	.read		= generic_file_read,
+	.write		= fat_file_write,
+	.mmap		= generic_file_mmap,
+	.fsync		= file_fsync,
+	.sendfile	= generic_file_sendfile,
 };
 
 struct inode_operations fat_file_inode_operations = {
-	truncate:	fat_truncate,
-	setattr:	fat_notify_change,
+	.truncate	= fat_truncate,
+	.setattr	= fat_notify_change,
 };
 
 int fat_get_block(struct inode *inode, sector_t iblock,
diff -Nru a/fs/fat/inode.c b/fs/fat/inode.c
--- a/fs/fat/inode.c	Sun Nov 10 19:28:39 2002
+++ b/fs/fat/inode.c	Sun Nov 10 19:28:39 2002
@@ -119,7 +119,7 @@
 	if (!inode)
 		goto out;
 	inode->i_ino = iunique(sb, MSDOS_ROOT_INO);
-	inode->i_version = 0;
+	inode->i_version = 1;
 	*res = fat_fill_inode(inode, de);
 	if (*res < 0) {
 		iput(inode);
@@ -701,24 +701,24 @@
 }
 
 static struct super_operations fat_sops = { 
-	alloc_inode:	fat_alloc_inode,
-	destroy_inode:	fat_destroy_inode,
-	write_inode:	fat_write_inode,
-	delete_inode:	fat_delete_inode,
-	put_super:	fat_put_super,
-	statfs:		fat_statfs,
-	clear_inode:	fat_clear_inode,
+	.alloc_inode	= fat_alloc_inode,
+	.destroy_inode	= fat_destroy_inode,
+	.write_inode	= fat_write_inode,
+	.delete_inode	= fat_delete_inode,
+	.put_super	= fat_put_super,
+	.statfs		= fat_statfs,
+	.clear_inode	= fat_clear_inode,
 
-	read_inode:	make_bad_inode,
+	.read_inode	= make_bad_inode,
 
-	show_options:	fat_show_options,
+	.show_options	= fat_show_options,
 };
 
 static struct export_operations fat_export_ops = {
-	decode_fh:	fat_decode_fh,
-	encode_fh:	fat_encode_fh,
-	get_dentry:	fat_get_dentry,
-	get_parent:	fat_get_parent,
+	.decode_fh	= fat_decode_fh,
+	.encode_fh	= fat_encode_fh,
+	.get_dentry	= fat_get_dentry,
+	.get_parent	= fat_get_parent,
 };
 
 /*
@@ -970,7 +970,7 @@
 	if (!root_inode)
 		goto out_fail;
 	root_inode->i_ino = MSDOS_ROOT_INO;
-	root_inode->i_version = 0;
+	root_inode->i_version = 1;
 	error = fat_read_root(root_inode);
 	if (error < 0)
 		goto out_fail;
@@ -1071,12 +1071,12 @@
 	return generic_block_bmap(mapping,block,fat_get_block);
 }
 static struct address_space_operations fat_aops = {
-	readpage: fat_readpage,
-	writepage: fat_writepage,
-	sync_page: block_sync_page,
-	prepare_write: fat_prepare_write,
-	commit_write: fat_commit_write,
-	bmap: _fat_bmap
+	.readpage = fat_readpage,
+	.writepage = fat_writepage,
+	.sync_page = block_sync_page,
+	.prepare_write = fat_prepare_write,
+	.commit_write = fat_commit_write,
+	.bmap = _fat_bmap
 };
 
 /* doesn't deal with root inode */
diff -Nru a/fs/fifo.c b/fs/fifo.c
--- a/fs/fifo.c	Sun Nov 10 19:28:39 2002
+++ b/fs/fifo.c	Sun Nov 10 19:28:39 2002
@@ -34,7 +34,6 @@
 	int ret;
 
 	ret = -ERESTARTSYS;
-	lock_kernel();
 	if (down_interruptible(PIPE_SEM(*inode)))
 		goto err_nolock_nocleanup;
 
@@ -117,7 +116,6 @@
 
 	/* Ok! */
 	up(PIPE_SEM(*inode));
-	unlock_kernel();
 	return 0;
 
 err_rd:
@@ -144,7 +142,6 @@
 	up(PIPE_SEM(*inode));
 
 err_nolock_nocleanup:
-	unlock_kernel();
 	return ret;
 }
 
diff -Nru a/fs/file_table.c b/fs/file_table.c
--- a/fs/file_table.c	Sun Nov 10 19:28:36 2002
+++ b/fs/file_table.c	Sun Nov 10 19:28:36 2002
@@ -25,9 +25,6 @@
 /* public *and* exported. Not pretty! */
 spinlock_t files_lock = SPIN_LOCK_UNLOCKED;
 
-/* file version */
-unsigned long event;
-
 /* Find an unused file structure and return a pointer to it.
  * Returns NULL, if there are no more free file structures or
  * we run out of memory.
@@ -54,7 +51,7 @@
 			return NULL;
 		}
 		atomic_set(&f->f_count,1);
-		f->f_version = ++event;
+		f->f_version = 0;
 		f->f_uid = current->fsuid;
 		f->f_gid = current->fsgid;
 		f->f_owner.lock = RW_LOCK_UNLOCKED;
diff -Nru a/fs/hpfs/dnode.c b/fs/hpfs/dnode.c
--- a/fs/hpfs/dnode.c	Sun Nov 10 19:28:39 2002
+++ b/fs/hpfs/dnode.c	Sun Nov 10 19:28:39 2002
@@ -403,7 +403,7 @@
 		c = 1;
 		goto ret;
 	}	
-	i->i_version = ++event;
+	i->i_version++;
 	c = hpfs_add_to_dnode(i, dno, name, namelen, new_de, 0);
 	ret:
 	if (!cdepth) hpfs_unlock_creation(i->i_sb);
@@ -710,7 +710,7 @@
 			return 2;
 		}
 	}
-	i->i_version = ++event;
+	i->i_version++;
 	for_all_poss(i, hpfs_pos_del, (t = get_pos(dnode, de)) + 1, 1);
 	hpfs_delete_de(i->i_sb, dnode, de);
 	hpfs_mark_4buffers_dirty(qbh);
diff -Nru a/fs/hpfs/inode.c b/fs/hpfs/inode.c
--- a/fs/hpfs/inode.c	Sun Nov 10 19:28:38 2002
+++ b/fs/hpfs/inode.c	Sun Nov 10 19:28:38 2002
@@ -84,7 +84,6 @@
 	hpfs_inode->i_ea_uid = 0;
 	hpfs_inode->i_ea_gid = 0;
 	hpfs_inode->i_ea_size = 0;
-	i->i_version = ++event;
 
 	hpfs_inode->i_rddir_off = NULL;
 	hpfs_inode->i_dirty = 0;
diff -Nru a/fs/hpfs/super.c b/fs/hpfs/super.c
--- a/fs/hpfs/super.c	Sun Nov 10 19:28:40 2002
+++ b/fs/hpfs/super.c	Sun Nov 10 19:28:40 2002
@@ -166,6 +166,7 @@
 	ei = (struct hpfs_inode_info *)kmem_cache_alloc(hpfs_inode_cachep, SLAB_KERNEL);
 	if (!ei)
 		return NULL;
+	ei->vfs_inode.i_version = 1;
 	return &ei->vfs_inode;
 }
 
diff -Nru a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
--- a/fs/hugetlbfs/inode.c	Sun Nov 10 19:28:41 2002
+++ b/fs/hugetlbfs/inode.c	Sun Nov 10 19:28:41 2002
@@ -443,36 +443,36 @@
 }
 
 static struct address_space_operations hugetlbfs_aops = {
-	readpage:	hugetlbfs_readpage,
-	writepage:	fail_writepage,
-	prepare_write:	hugetlbfs_prepare_write,
-	commit_write:	hugetlbfs_commit_write
+	.readpage	= hugetlbfs_readpage,
+	.writepage	= fail_writepage,
+	.prepare_write	= hugetlbfs_prepare_write,
+	.commit_write	= hugetlbfs_commit_write
 };
 
 struct file_operations hugetlbfs_file_operations = {
-	read:		generic_file_read,
-	write:		generic_file_write,
-	mmap:		hugetlbfs_file_mmap,
-	fsync:		simple_sync_file,
-	sendfile:	generic_file_sendfile,
+	.read		= generic_file_read,
+	.write		= generic_file_write,
+	.mmap		= hugetlbfs_file_mmap,
+	.fsync		= simple_sync_file,
+	.sendfile	= generic_file_sendfile,
 };
 
 static struct inode_operations hugetlbfs_dir_inode_operations = {
-	create:		hugetlbfs_create,
-	lookup:		simple_lookup,
-	link:		simple_link,
-	unlink:		simple_unlink,
-	symlink:	hugetlbfs_symlink,
-	mkdir:		hugetlbfs_mkdir,
-	rmdir:		simple_rmdir,
-	mknod:		hugetlbfs_mknod,
-	rename:		simple_rename,
-	setattr:	hugetlbfs_setattr,
+	.create		= hugetlbfs_create,
+	.lookup		= simple_lookup,
+	.link		= simple_link,
+	.unlink		= simple_unlink,
+	.symlink	= hugetlbfs_symlink,
+	.mkdir		= hugetlbfs_mkdir,
+	.rmdir		= simple_rmdir,
+	.mknod		= hugetlbfs_mknod,
+	.rename		= simple_rename,
+	.setattr	= hugetlbfs_setattr,
 };
 
 static struct super_operations hugetlbfs_ops = {
-	statfs:		simple_statfs,
-	drop_inode:	hugetlbfs_drop_inode,
+	.statfs		= simple_statfs,
+	.drop_inode	= hugetlbfs_drop_inode,
 };
 
 static int hugetlbfs_fill_super(struct super_block * sb, void * data, int silent)
@@ -504,9 +504,9 @@
 }
 
 static struct file_system_type hugetlbfs_fs_type = {
-	name:		"hugetlbfs",
-	get_sb:		hugetlbfs_get_sb,
-	kill_sb:	kill_litter_super,
+	.name		= "hugetlbfs",
+	.get_sb		= hugetlbfs_get_sb,
+	.kill_sb	= kill_litter_super,
 };
 
 static struct vfsmount *hugetlbfs_vfsmount;
diff -Nru a/fs/intermezzo/vfs.c b/fs/intermezzo/vfs.c
--- a/fs/intermezzo/vfs.c	Sun Nov 10 19:28:38 2002
+++ b/fs/intermezzo/vfs.c	Sun Nov 10 19:28:38 2002
@@ -74,7 +74,7 @@
 #ifdef CONFIG_FS_EXT_ATTR
 # include <linux/ext_attr.h>
 
-# ifdef CONFIG_FS_POSIX_ACL
+# if 0 /* was a broken check for Posix ACLs */
 #  include <linux/posix_acl.h>
 # endif
 #endif
@@ -466,7 +466,7 @@
         struct dentry *dentry;
         struct presto_file_set *fset;
         int error;
-#ifdef  CONFIG_FS_POSIX_ACL
+#if 0 /* was a broken check for Posix ACLs */
         int (*set_posix_acl)(struct inode *, int type, posix_acl_t *)=NULL;
 #endif
 
@@ -507,7 +507,7 @@
                                  (dentry->d_inode->i_mode & ~S_IALLUGO);
                 CDEBUG(D_PIOCTL, "chmod: orig %#o, set %#o, result %#o\n",
                        dentry->d_inode->i_mode, set_mode, iattr->ia_mode);
-#ifdef CONFIG_FS_POSIX_ACL
+#if 0 /* was a broken check for Posix ACLs */
                 /* ACl code interacts badly with setattr 
                  * since it tries to modify the ACL using 
                  * set_ext_attr which recurses back into presto.  
@@ -535,7 +535,7 @@
                 }
         }
 
-#ifdef CONFIG_FS_POSIX_ACL
+#if 0 /* was a broken check for Posix ACLs */
         /* restore the inode_operations if we changed them*/
         if (iattr->ia_valid & ATTR_MODE) 
                 dentry->d_inode->i_op->set_posix_acl=set_posix_acl;
@@ -2252,7 +2252,7 @@
 
 #ifdef CONFIG_FS_EXT_ATTR
 
-#ifdef CONFIG_FS_POSIX_ACL
+#if 0 /* was a broken check for Posix ACLs */
 /* Posix ACL code changes i_mode without using a notify_change (or
  * a mark_inode_dirty!). We need to duplicate this at the reintegrator
  * which is done by this function. This function also takes care of 
@@ -2395,7 +2395,7 @@
                 goto exit;
         }
 
-#ifdef CONFIG_FS_POSIX_ACL
+#if 0 /* was a broken check for Posix ACLs */
         /* Reset mode if specified*/
         /* XXX: when we do native acl support, move this code out! */
         if (mode != NULL) {
diff -Nru a/fs/jfs/inode.c b/fs/jfs/inode.c
--- a/fs/jfs/inode.c	Sun Nov 10 19:28:36 2002
+++ b/fs/jfs/inode.c	Sun Nov 10 19:28:36 2002
@@ -293,7 +293,7 @@
 	return mpage_readpage(page, jfs_get_block);
 }
 
-static int jfs_readpages(struct address_space *mapping,
+static int jfs_readpages(struct file *file, struct address_space *mapping,
 		struct list_head *pages, unsigned nr_pages)
 {
 	return mpage_readpages(mapping, pages, nr_pages, jfs_get_block);
diff -Nru a/fs/jfs/jfs_acl.h b/fs/jfs/jfs_acl.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/jfs/jfs_acl.h	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,33 @@
+/*
+ *   Copyright (c) International Business Machines  Corp., 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
+ */
+#ifndef _H_JFS_ACL
+#define _H_JFS_ACL
+
+#ifdef CONFIG_JFS_POSIX_ACL
+
+#include <linux/xattr_acl.h>
+
+struct posix_acl *jfs_get_acl(struct inode *, int);
+int jfs_set_acl(struct inode *, int, struct posix_acl *);
+int jfs_permission_have_sem(struct inode *, int);
+int jfs_permission(struct inode *, int);
+int jfs_init_acl(struct inode *, struct inode *);
+int jfs_setattr(struct dentry *, struct iattr *);
+
+#endif		/* CONFIG_JFS_POSIX_ACL */
+#endif		/* _H_JFS_ACL */
diff -Nru a/fs/locks.c b/fs/locks.c
--- a/fs/locks.c	Sun Nov 10 19:28:41 2002
+++ b/fs/locks.c	Sun Nov 10 19:28:41 2002
@@ -1401,6 +1401,7 @@
 
 	inode = filp->f_dentry->d_inode;
 
+#ifdef CONFIG_MMU
 	/* Don't allow mandatory locks on files that may be memory mapped
 	 * and shared.
 	 */
@@ -1413,6 +1414,7 @@
 			goto out;
 		}
 	}
+#endif
 
 	error = flock_to_posix_lock(filp, file_lock, &flock);
 	if (error)
diff -Nru a/fs/mbcache.c b/fs/mbcache.c
--- a/fs/mbcache.c	Sun Nov 10 19:28:41 2002
+++ b/fs/mbcache.c	Sun Nov 10 19:28:41 2002
@@ -324,14 +324,6 @@
 		goto fail;
 
 	spin_lock(&mb_cache_spinlock);
-	if (list_empty(&mb_cache_list)) {
-		if (mb_shrinker) {
-			printk(KERN_ERR "%s: already have a shrinker!\n",
-					__FUNCTION__);
-			remove_shrinker(mb_shrinker);
-		}
-		mb_shrinker = set_shrinker(DEFAULT_SEEKS, mb_cache_shrink_fn);
-	}
 	list_add(&cache->c_cache_list, &mb_cache_list);
 	spin_unlock(&mb_cache_spinlock);
 	return cache;
@@ -414,10 +406,6 @@
 		}
 	}
 	list_del(&cache->c_cache_list);
-	if (list_empty(&mb_cache_list) && mb_shrinker) {
-		remove_shrinker(mb_shrinker);
-		mb_shrinker = 0;
-	}
 	spin_unlock(&mb_cache_spinlock);
 
 	l = free_list.prev;
@@ -700,3 +688,18 @@
 }
 
 #endif  /* !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) */
+
+static int __init init_mbcache(void)
+{
+	mb_shrinker = set_shrinker(DEFAULT_SEEKS, mb_cache_shrink_fn);
+	return 0;
+}
+
+static void __exit exit_mbcache(void)
+{
+	remove_shrinker(mb_shrinker);
+}
+
+module_init(init_mbcache)
+module_exit(exit_mbcache)
+
diff -Nru a/fs/mpage.c b/fs/mpage.c
--- a/fs/mpage.c	Sun Nov 10 19:28:38 2002
+++ b/fs/mpage.c	Sun Nov 10 19:28:38 2002
@@ -14,6 +14,7 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/mm.h>
 #include <linux/kdev_t.h>
 #include <linux/bio.h>
 #include <linux/fs.h>
diff -Nru a/fs/nfs/Makefile b/fs/nfs/Makefile
--- a/fs/nfs/Makefile	Sun Nov 10 19:28:37 2002
+++ b/fs/nfs/Makefile	Sun Nov 10 19:28:37 2002
@@ -4,7 +4,7 @@
 
 obj-$(CONFIG_NFS_FS) += nfs.o
 
-nfs-y 			:= dir.o file.o flushd.o inode.o nfs2xdr.o pagelist.o \
+nfs-y 			:= dir.o file.o inode.o nfs2xdr.o pagelist.o \
 			   proc.o read.o symlink.o unlink.o write.o
 nfs-$(CONFIG_ROOT_NFS)	+= nfsroot.o mount_clnt.o      
 nfs-$(CONFIG_NFS_V3)	+= nfs3proc.o nfs3xdr.o
diff -Nru a/fs/nfs/file.c b/fs/nfs/file.c
--- a/fs/nfs/file.c	Sun Nov 10 19:28:40 2002
+++ b/fs/nfs/file.c	Sun Nov 10 19:28:40 2002
@@ -77,11 +77,6 @@
 
 	dfprintk(VFS, "nfs: flush(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino);
 
-	/* Make sure all async reads have been sent off. We don't bother
-	 * waiting on them though... */
-	if (file->f_mode & FMODE_READ)
-		nfs_pagein_inode(inode, 0, 0);
-
 	status = nfs_wb_file(inode, file);
 	if (!status) {
 		status = file->f_error;
@@ -170,36 +165,11 @@
 	return status;
 }
 
-/*
- * The following is used by wait_on_page_locked(), generic_file_readahead()
- * to initiate the completion of any page readahead operations.
- */
-static int nfs_sync_page(struct page *page)
-{
-	struct address_space *mapping;
-	struct inode	*inode;
-	unsigned long	index = page->index;
-	unsigned int	rpages;
-	int		result;
-
-	mapping = page->mapping;
-	if (!mapping)
-		return 0;
-	inode = mapping->host;
-	if (!inode)
-		return 0;
-
-	rpages = NFS_SERVER(inode)->rpages;
-	result = nfs_pagein_inode(inode, index, rpages);
-	if (result < 0)
-		return result;
-	return 0;
-}
-
 struct address_space_operations nfs_file_aops = {
 	.readpage = nfs_readpage,
-	.sync_page = nfs_sync_page,
+	.readpages = nfs_readpages,
 	.writepage = nfs_writepage,
+	.writepages = nfs_writepages,
 	.prepare_write = nfs_prepare_write,
 	.commit_write = nfs_commit_write,
 #ifdef CONFIG_NFS_DIRECTIO
diff -Nru a/fs/nfs/flushd.c b/fs/nfs/flushd.c
--- a/fs/nfs/flushd.c	Sun Nov 10 19:28:40 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,205 +0,0 @@
-/*
- * linux/fs/nfs/flushd.c
- *
- * For each NFS mount, there is a separate cache object that contains
- * a hash table of all clusters. With this cache, an async RPC task
- * (`flushd') is associated, which wakes up occasionally to inspect
- * its list of dirty buffers.
- * (Note that RPC tasks aren't kernel threads. Take a look at the
- * rpciod code to understand what they are).
- *
- * Inside the cache object, we also maintain a count of the current number
- * of dirty pages, which may not exceed a certain threshold.
- * (FIXME: This threshold should be configurable).
- *
- * The code is streamlined for what I think is the prevalent case for
- * NFS traffic, which is sequential write access without concurrent
- * access by different processes.
- *
- * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de>
- *
- * Rewritten 6/3/2000 by Trond Myklebust
- * Copyright (C) 1999, 2000, Trond Myklebust <trond.myklebust@fys.uio.no>
- */
-
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/pagemap.h>
-#include <linux/file.h>
-
-#include <linux/time.h>
-
-#include <linux/sunrpc/auth.h>
-#include <linux/sunrpc/clnt.h>
-#include <linux/sunrpc/sched.h>
-
-#include <linux/smp_lock.h>
-
-#include <linux/nfs.h>
-#include <linux/nfs_fs.h>
-#include <linux/nfs_page.h>
-#include <linux/nfs_fs_sb.h>
-#include <linux/nfs_flushd.h>
-
-/*
- * Various constants
- */
-#define NFSDBG_FACILITY         NFSDBG_PAGECACHE
-
-/*
- * This is the wait queue all cluster daemons sleep on
- */
-static RPC_WAITQ(flushd_queue, "nfs_flushd");
-
-/*
- * Local function declarations.
- */
-static void	nfs_flushd(struct rpc_task *);
-static void	nfs_flushd_exit(struct rpc_task *);
-
-
-int nfs_reqlist_init(struct nfs_server *server)
-{
-	struct nfs_reqlist	*cache;
-	struct rpc_task		*task;
-	int			status;
-
-	dprintk("NFS: writecache_init\n");
-
-	lock_kernel();
-	status = -ENOMEM;
-	/* Create the RPC task */
-	if (!(task = rpc_new_task(server->client, NULL, RPC_TASK_ASYNC)))
-		goto out_unlock;
-
-	cache = server->rw_requests;
-
-	status = 0;
-	if (cache->task)
-		goto out_unlock;
-
-	task->tk_calldata = server;
-
-	cache->task = task;
-
-	/* Run the task */
-	cache->runat = jiffies;
-
-	cache->auth = server->client->cl_auth;
-	task->tk_action   = nfs_flushd;
-	task->tk_exit   = nfs_flushd_exit;
-
-	rpc_execute(task);
-	unlock_kernel();
-	return 0;
- out_unlock:
-	if (task)
-		rpc_release_task(task);
-	unlock_kernel();
-	return status;
-}
-
-void nfs_reqlist_exit(struct nfs_server *server)
-{
-	struct nfs_reqlist      *cache;
-
-	lock_kernel();
-	cache = server->rw_requests;
-	if (!cache)
-		goto out;
-
-	dprintk("NFS: reqlist_exit (ptr %p rpc %p)\n", cache, cache->task);
-
-	while (cache->task) {
-		rpc_exit(cache->task, 0);
-		rpc_wake_up_task(cache->task);
-
-		interruptible_sleep_on_timeout(&cache->request_wait, 1 * HZ);
-	}
- out:
-	unlock_kernel();
-}
-
-int nfs_reqlist_alloc(struct nfs_server *server)
-{
-	struct nfs_reqlist	*cache;
-	if (server->rw_requests)
-		return 0;
-
-	cache = (struct nfs_reqlist *)kmalloc(sizeof(*cache), GFP_KERNEL);
-	if (!cache)
-		return -ENOMEM;
-
-	memset(cache, 0, sizeof(*cache));
-	atomic_set(&cache->nr_requests, 0);
-	init_waitqueue_head(&cache->request_wait);
-	server->rw_requests = cache;
-
-	return 0;
-}
-
-void nfs_reqlist_free(struct nfs_server *server)
-{
-	if (server->rw_requests) {
-		kfree(server->rw_requests);
-		server->rw_requests = NULL;
-	}
-}
-
-#define NFS_FLUSHD_TIMEOUT	(30*HZ)
-static void
-nfs_flushd(struct rpc_task *task)
-{
-	struct nfs_server	*server;
-	struct nfs_reqlist	*cache;
-	LIST_HEAD(head);
-
-        dprintk("NFS: %4d flushd starting\n", task->tk_pid);
-	server = (struct nfs_server *) task->tk_calldata;
-        cache = server->rw_requests;
-
-	for(;;) {
-		spin_lock(&nfs_wreq_lock);
-		if (nfs_scan_lru_dirty_timeout(server, &head)) {
-			spin_unlock(&nfs_wreq_lock);
-			nfs_flush_list(&head, server->wpages, FLUSH_AGING);
-			continue;
-		}
-		if (nfs_scan_lru_read_timeout(server, &head)) {
-			spin_unlock(&nfs_wreq_lock);
-			nfs_pagein_list(&head, server->rpages);
-			continue;
-		}
-#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-		if (nfs_scan_lru_commit_timeout(server, &head)) {
-			spin_unlock(&nfs_wreq_lock);
-			nfs_commit_list(&head, FLUSH_AGING);
-			continue;
-		}
-#endif
-		spin_unlock(&nfs_wreq_lock);
-		break;
-	}
-
-	dprintk("NFS: %4d flushd back to sleep\n", task->tk_pid);
-	if (task->tk_action) {
-		task->tk_timeout = NFS_FLUSHD_TIMEOUT;
-		cache->runat = jiffies + task->tk_timeout;
-		rpc_sleep_on(&flushd_queue, task, NULL, NULL);
-	}
-}
-
-static void
-nfs_flushd_exit(struct rpc_task *task)
-{
-	struct nfs_server	*server;
-	struct nfs_reqlist	*cache;
-	server = (struct nfs_server *) task->tk_calldata;
-	cache = server->rw_requests;
-
-	if (cache->task == task)
-		cache->task = NULL;
-	wake_up(&cache->request_wait);
-}
-
diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c	Sun Nov 10 19:28:40 2002
+++ b/fs/nfs/inode.c	Sun Nov 10 19:28:40 2002
@@ -29,7 +29,6 @@
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/nfs4_mount.h>
-#include <linux/nfs_flushd.h>
 #include <linux/lockd/bind.h>
 #include <linux/smp_lock.h>
 #include <linux/seq_file.h>
@@ -37,7 +36,6 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#define CONFIG_NFS_SNAPSHOT 1
 #define NFSDBG_FACILITY		NFSDBG_VFS
 #define NFS_PARANOIA 1
 
@@ -106,7 +104,7 @@
 {
 	int flags = sync ? FLUSH_WAIT : 0;
 
-	nfs_sync_file(inode, NULL, 0, 0, flags);
+	nfs_commit_file(inode, NULL, 0, 0, flags);
 }
 
 static void
@@ -117,7 +115,7 @@
 	/*
 	 * The following can never actually happen...
 	 */
-	if (nfs_have_writebacks(inode) || nfs_have_read(inode)) {
+	if (nfs_have_writebacks(inode)) {
 		printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
 	}
 
@@ -147,18 +145,9 @@
 	struct nfs_server *server = NFS_SB(sb);
 	struct rpc_clnt	*rpc;
 
-	/*
-	 * First get rid of the request flushing daemon.
-	 * Relies on rpc_shutdown_client() waiting on all
-	 * client tasks to finish.
-	 */
-	nfs_reqlist_exit(server);
-
 	if ((rpc = server->client) != NULL)
 		rpc_shutdown_client(rpc);
 
-	nfs_reqlist_free(server);
-
 	if (!(server->flags & NFS_MOUNT_NONLM))
 		lockd_down();	/* release rpc.lockd */
 	rpciod_down();		/* release rpciod */
@@ -262,10 +251,6 @@
 
 	sb->s_magic      = NFS_SUPER_MAGIC;
 	sb->s_op         = &nfs_sops;
-	INIT_LIST_HEAD(&server->lru_read);
-	INIT_LIST_HEAD(&server->lru_dirty);
-	INIT_LIST_HEAD(&server->lru_commit);
-	INIT_LIST_HEAD(&server->lru_busy);
 
 	/* Did getting the root inode fail? */
 	root_inode = nfs_get_root(sb, &server->fh);
@@ -327,27 +312,19 @@
 		server->acdirmin = server->acdirmax = 0;
 		sb->s_flags |= MS_SYNCHRONOUS;
 	}
+	server->backing_dev_info.ra_pages = server->rpages << 2;
 
 	sb->s_maxbytes = fsinfo.maxfilesize;
 	if (sb->s_maxbytes > MAX_LFS_FILESIZE) 
 		sb->s_maxbytes = MAX_LFS_FILESIZE; 
 
-	/* Fire up the writeback cache */
-	if (nfs_reqlist_alloc(server) < 0) {
-		printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n");
-		goto failure_kill_reqlist;
-	}
-
 	/* We're airborne Set socket buffersize */
 	rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
 	return 0;
 	/* Yargs. It didn't work out. */
-failure_kill_reqlist:
-	nfs_reqlist_exit(server);
 out_free_all:
 	if (root_inode)
 		iput(root_inode);
-	nfs_reqlist_free(server);
 	return -EINVAL;
 out_no_root:
 	printk("nfs_read_super: get root inode failed\n");
@@ -696,6 +673,7 @@
 		if (S_ISREG(inode->i_mode)) {
 			inode->i_fop = &nfs_file_operations;
 			inode->i_data.a_ops = &nfs_file_aops;
+			inode->i_data.backing_dev_info = &NFS_SB(sb)->backing_dev_info;
 		} else if (S_ISDIR(inode->i_mode)) {
 			inode->i_op = &nfs_dir_inode_operations;
 			inode->i_fop = &nfs_dir_operations;
@@ -1555,11 +1533,9 @@
 	if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
 	    SLAB_CTOR_CONSTRUCTOR) {
 		inode_init_once(&nfsi->vfs_inode);
-		INIT_LIST_HEAD(&nfsi->read);
 		INIT_LIST_HEAD(&nfsi->dirty);
 		INIT_LIST_HEAD(&nfsi->commit);
-		INIT_LIST_HEAD(&nfsi->writeback);
-		nfsi->nread = 0;
+		INIT_RADIX_TREE(&nfsi->nfs_page_tree, GFP_ATOMIC);
 		nfsi->ndirty = 0;
 		nfsi->ncommit = 0;
 		nfsi->npages = 0;
diff -Nru a/fs/nfs/mount_clnt.c b/fs/nfs/mount_clnt.c
--- a/fs/nfs/mount_clnt.c	Sun Nov 10 19:28:36 2002
+++ b/fs/nfs/mount_clnt.c	Sun Nov 10 19:28:36 2002
@@ -29,10 +29,9 @@
 #define MOUNT_UMNT		3
  */
 
-static int			nfs_gen_mount(struct sockaddr_in *,
-					      char *, struct nfs_fh *, int);
-static struct rpc_clnt *	mnt_create(char *, struct sockaddr_in *, int);
-extern struct rpc_program	mnt_program;
+static struct rpc_clnt *	mnt_create(char *, struct sockaddr_in *,
+								int, int);
+struct rpc_program		mnt_program;
 
 struct mnt_fhstatus {
 	unsigned int		status;
@@ -43,19 +42,8 @@
  * Obtain an NFS file handle for the given host and path
  */
 int
-nfs_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
-{
-	return nfs_gen_mount(addr, path, fh, NFS_MNT_VERSION);
-}
-
-int
-nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
-{
-	return nfs_gen_mount(addr, path, fh, NFS_MNT3_VERSION);
-}
-
-static int
-nfs_gen_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, int version)
+nfsroot_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh,
+		int version, int protocol)
 {
 	struct rpc_clnt		*mnt_clnt;
 	struct mnt_fhstatus	result = {
@@ -69,21 +57,22 @@
 			(unsigned)ntohl(addr->sin_addr.s_addr), path);
 
 	sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr->sin_addr.s_addr));
-	if (!(mnt_clnt = mnt_create(hostname, addr, version)))
+	if (!(mnt_clnt = mnt_create(hostname, addr, version, protocol)))
 		return -EACCES;
 
-	call = (version == 3) ? MOUNTPROC3_MNT : MNTPROC_MNT;
+	call = (version == NFS_MNT3_VERSION) ? MOUNTPROC3_MNT : MNTPROC_MNT;
 	status = rpc_call(mnt_clnt, call, path, &result, 0);
 	return status < 0? status : (result.status? -EACCES : 0);
 }
 
 static struct rpc_clnt *
-mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version)
+mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version,
+		int protocol)
 {
 	struct rpc_xprt	*xprt;
 	struct rpc_clnt	*clnt;
 
-	if (!(xprt = xprt_create_proto(IPPROTO_UDP, srvaddr, NULL)))
+	if (!(xprt = xprt_create_proto(protocol, srvaddr, NULL)))
 		return NULL;
 
 	clnt = rpc_create_client(xprt, hostname,
diff -Nru a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
--- a/fs/nfs/nfs2xdr.c	Sun Nov 10 19:28:39 2002
+++ b/fs/nfs/nfs2xdr.c	Sun Nov 10 19:28:39 2002
@@ -233,7 +233,6 @@
 static int
 nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
 {
-	struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
 	struct iovec *iov = req->rq_rvec;
 	int	status, count, recvd, hdrlen;
 
@@ -243,11 +242,6 @@
 
 	count = ntohl(*p++);
 	res->eof = 0;
-	if (rcvbuf->page_len) {
-		u32 end = page_offset(rcvbuf->pages[0]) + rcvbuf->page_base + count;
-		if (end >= res->fattr->size)
-			res->eof = 1;
-	}
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	if (iov->iov_len < hdrlen) {
 		printk(KERN_WARNING "NFS: READ reply header overflowed:"
@@ -263,7 +257,6 @@
 		printk(KERN_WARNING "NFS: server cheating in read reply: "
 			"count %d > recvd %d\n", count, recvd);
 		count = recvd;
-		res->eof = 0;
 	}
 
 	dprintk("RPC:      readres OK count %d\n", count);
@@ -361,13 +354,6 @@
 	struct rpc_auth	*auth = task->tk_auth;
 	unsigned int replen;
 	u32 count = args->count;
-
-	/*
-	 * Some servers (e.g. HP OS 9.5) seem to expect the buffer size
-	 * to be in longwords ... check whether to convert the size.
-	 */
-	if (task->tk_client->cl_flags & NFS_CLNTF_BUFSIZE)
-		count = count >> 2;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	*p++ = htonl(args->cookie);
diff -Nru a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
--- a/fs/nfs/nfs3proc.c	Sun Nov 10 19:28:39 2002
+++ b/fs/nfs/nfs3proc.c	Sun Nov 10 19:28:39 2002
@@ -811,7 +811,7 @@
 	rpc_init_task(task, NFS_CLIENT(inode), nfs3_commit_done, flags);
 	task->tk_calldata = data;
 	/* Release requests */
-	task->tk_release = nfs_writedata_release;
+	task->tk_release = nfs_commit_release;
 	
 	msg.rpc_proc = NFS3PROC_COMMIT;
 	msg.rpc_argp = &data->u.v3.args;
diff -Nru a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
--- a/fs/nfs/nfs4proc.c	Sun Nov 10 19:28:40 2002
+++ b/fs/nfs/nfs4proc.c	Sun Nov 10 19:28:40 2002
@@ -1481,7 +1481,7 @@
 	rpc_init_task(task, NFS_CLIENT(inode), nfs4_commit_done, flags);
 	task->tk_calldata = data;
 	/* Release requests */
-	task->tk_release = nfs_writedata_release;
+	task->tk_release = nfs_commit_release;
 	
 	rpc_call_setup(task, &msg, 0);	
 }
diff -Nru a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c
--- a/fs/nfs/nfsroot.c	Sun Nov 10 19:28:40 2002
+++ b/fs/nfs/nfsroot.c	Sun Nov 10 19:28:40 2002
@@ -64,6 +64,8 @@
  *	Trond Myklebust :	Add in preliminary support for NFSv3 and TCP.
  *				Fix bug in root_nfs_addr(). nfs_data.namlen
  *				is NOT for the length of the hostname.
+ *	Hua Qin		:	Support for mounting root file system via
+ *				NFS over TCP.
  */
 
 #include <linux/config.h>
@@ -440,12 +442,14 @@
 {
 	struct sockaddr_in sin;
 	int status;
+	int protocol = (nfs_data.flags & NFS_MOUNT_TCP) ?
+					IPPROTO_TCP : IPPROTO_UDP;
+	int version = (nfs_data.flags & NFS_MOUNT_VER3) ?
+					NFS_MNT3_VERSION : NFS_MNT_VERSION;
 
 	set_sockaddr(&sin, servaddr, mount_port);
-	if (nfs_data.flags & NFS_MOUNT_VER3)
-		status = nfs3_mount(&sin, nfs_path, &nfs_data.root);
-	else
-		status = nfs_mount(&sin, nfs_path, &nfs_data.root);
+	status = nfsroot_mount(&sin, nfs_path, &nfs_data.root,
+							version, protocol);
 	if (status < 0)
 		printk(KERN_ERR "Root-NFS: Server returned error %d "
 				"while mounting %s\n", status, nfs_path);
diff -Nru a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
--- a/fs/nfs/pagelist.c	Sun Nov 10 19:28:41 2002
+++ b/fs/nfs/pagelist.c	Sun Nov 10 19:28:41 2002
@@ -17,7 +17,6 @@
 #include <linux/nfs4.h>
 #include <linux/nfs_page.h>
 #include <linux/nfs_fs.h>
-#include <linux/nfs_flushd.h>
 #include <linux/nfs_mount.h>
 
 #define NFS_PARANOIA 1
@@ -36,9 +35,7 @@
 	p = kmem_cache_alloc(nfs_page_cachep, SLAB_NOFS);
 	if (p) {
 		memset(p, 0, sizeof(*p));
-		INIT_LIST_HEAD(&p->wb_hash);
 		INIT_LIST_HEAD(&p->wb_list);
-		INIT_LIST_HEAD(&p->wb_lru);
 		init_waitqueue_head(&p->wb_wait);
 	}
 	return p;
@@ -50,8 +47,6 @@
 	kmem_cache_free(nfs_page_cachep, p);
 }
 
-static int nfs_try_to_free_pages(struct nfs_server *);
-
 /**
  * nfs_create_request - Create an NFS read/write request.
  * @cred: RPC credential to use
@@ -72,29 +67,18 @@
 		   unsigned int offset, unsigned int count)
 {
 	struct nfs_server *server = NFS_SERVER(inode);
-	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
 	struct nfs_page		*req;
 
 	/* Deal with hard limits.  */
 	for (;;) {
-		/* Prevent races by incrementing *before* we test */
-		atomic_inc(&cache->nr_requests);
-
-		/* If we haven't reached the local hard limit yet,
-		 * try to allocate the request struct */
-		if (atomic_read(&cache->nr_requests) <= MAX_REQUEST_HARD) {
-			req = nfs_page_alloc();
-			if (req != NULL)
-				break;
-		}
-
-		atomic_dec(&cache->nr_requests);
+		/* try to allocate the request struct */
+		req = nfs_page_alloc();
+		if (req != NULL)
+			break;
 
 		/* Try to free up at least one request in order to stay
 		 * below the hard limit
 		 */
-		if (nfs_try_to_free_pages(server))
-			continue;
 		if (signalled() && (server->flags & NFS_MOUNT_INTR))
 			return ERR_PTR(-ERESTARTSYS);
 		yield();
@@ -138,7 +122,6 @@
 	if (req->wb_page) {
 		page_cache_release(req->wb_page);
 		req->wb_page = NULL;
-		atomic_dec(&NFS_REQUESTLIST(req->wb_inode)->nr_requests);
 	}
 }
 
@@ -157,18 +140,11 @@
 		spin_unlock(&nfs_wreq_lock);
 		return;
 	}
-	__nfs_del_lru(req);
 	spin_unlock(&nfs_wreq_lock);
 
 #ifdef NFS_PARANOIA
-	if (!list_empty(&req->wb_list))
-		BUG();
-	if (!list_empty(&req->wb_hash))
-		BUG();
-	if (NFS_WBACK_BUSY(req))
-		BUG();
-	if (atomic_read(&NFS_REQUESTLIST(req->wb_inode)->nr_requests) < 0)
-		BUG();
+	BUG_ON (!list_empty(&req->wb_list));
+	BUG_ON (NFS_WBACK_BUSY(req));
 #endif
 
 	/* Release struct file or cached credential */
@@ -316,104 +292,6 @@
 	return npages;
 }
 
-/*
- * nfs_scan_forward - Coalesce more requests
- * @req: First request to add
- * @dst: destination list
- * @nmax: maximum number of requests to coalesce
- *
- * Tries to coalesce more requests by traversing the request's wb_list.
- * Moves the resulting list into dst. Requests are guaranteed to be
- * contiguous, and have the same RPC credentials.
- */
-static int
-nfs_scan_forward(struct nfs_page *req, struct list_head *dst, int nmax)
-{
-	struct nfs_server *server = NFS_SERVER(req->wb_inode);
-	struct list_head *pos, *head = req->wb_list_head;
-	struct rpc_cred *cred = req->wb_cred;
-	unsigned long idx = req->wb_index + 1;
-	int npages = 0;
-
-	for (pos = req->wb_list.next; nfs_lock_request(req); pos = pos->next) {
-		nfs_list_remove_request(req);
-		nfs_list_add_request(req, dst);
-		__nfs_del_lru(req);
-		__nfs_add_lru(&server->lru_busy, req);
-		npages++;
-		if (npages == nmax)
-			break;
-		if (pos == head)
-			break;
-		if (req->wb_offset + req->wb_bytes != PAGE_CACHE_SIZE)
-			break;
-		req = nfs_list_entry(pos);
-		if (req->wb_index != idx++)
-			break;
-		if (req->wb_offset != 0)
-			break;
-		if (req->wb_cred != cred)
-			break;
-	}
-	return npages;
-}
-
-/**
- * nfs_scan_lru - Scan one of the least recently used list
- * @head: One of the NFS superblock lru lists
- * @dst: Destination list
- * @nmax: maximum number of requests to coalesce
- *
- * Scans one of the NFS superblock lru lists for upto nmax requests
- * and returns them on a list. The requests are all guaranteed to be
- * contiguous, originating from the same inode and the same file.
- */
-int
-nfs_scan_lru(struct list_head *head, struct list_head *dst, int nmax)
-{
-	struct list_head *pos;
-	struct nfs_page *req;
-	int npages = 0;
-
-	list_for_each(pos, head) {
-		req = nfs_lru_entry(pos);
-		npages = nfs_scan_forward(req, dst, nmax);
-		if (npages)
-			break;
-	}
-	return npages;
-}
-
-/**
- * nfs_scan_lru_timeout - Scan one of the superblock lru lists for timed out requests
- * @head: One of the NFS superblock lru lists
- * @dst: Destination list
- * @nmax: maximum number of requests to coalesce
- *
- * Scans one of the NFS superblock lru lists for upto nmax requests
- * and returns them on a list. The requests are all guaranteed to be
- * contiguous, originating from the same inode and the same file.
- * The first request on the destination list will be timed out, the
- * others are not guaranteed to be so.
- */
-int
-nfs_scan_lru_timeout(struct list_head *head, struct list_head *dst, int nmax)
-{
-	struct list_head *pos;
-	struct nfs_page *req;
-	int npages = 0;
-
-	list_for_each(pos, head) {
-		req = nfs_lru_entry(pos);
-		if (time_after(req->wb_timeout, jiffies))
-			break;
-		npages = nfs_scan_forward(req, dst, nmax);
-		if (npages)
-			break;
-	}
-	return npages;
-}
-
 /**
  * nfs_scan_list - Scan a list for matching requests
  * @head: One of the NFS inode request lists
@@ -460,81 +338,9 @@
 			continue;
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, dst);
-		__nfs_del_lru(req);
-		__nfs_add_lru(&NFS_SERVER(req->wb_inode)->lru_busy, req);
 		res++;
 	}
 	return res;
-}
-
-/*
- * nfs_try_to_free_pages - Free up NFS read/write requests
- * @server: The NFS superblock
- *
- * This function attempts to flush out NFS reads and writes in order
- * to keep the hard limit on the total number of pending requests
- * on a given NFS partition.
- * Note: we first try to commit unstable writes, then flush out pending
- *       reads, then finally the dirty pages.
- *       The assumption is that this reflects the ordering from the fastest
- *       to the slowest method for reclaiming requests.
- */
-static int
-nfs_try_to_free_pages(struct nfs_server *server)
-{
-	LIST_HEAD(head);
-	struct nfs_page *req = NULL;
-	int nreq;
-
-	for (;;) {
-		if (req) {
-			int status = nfs_wait_on_request(req);
-			nfs_release_request(req);
-			if (status)
-				break;
-			req = NULL;
-		}
-		nreq = atomic_read(&server->rw_requests->nr_requests);
-		if (nreq < MAX_REQUEST_HARD)
-			return 1;
-		spin_lock(&nfs_wreq_lock);
-		/* Are there any busy RPC calls that might free up requests? */
-		if (!list_empty(&server->lru_busy)) {
-			req = nfs_lru_entry(server->lru_busy.next);
-			req->wb_count++;
-			__nfs_del_lru(req);
-			spin_unlock(&nfs_wreq_lock);
-			continue;
-		}
-
-#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-		/* Let's try to free up some completed NFSv3 unstable writes */
-		nfs_scan_lru_commit(server, &head);
-		if (!list_empty(&head)) {
-			spin_unlock(&nfs_wreq_lock);
-			nfs_commit_list(&head, 0);
-			continue;
-		}
-#endif
-		/* OK, so we try to free up some pending readaheads */
-		nfs_scan_lru_read(server, &head);
-		if (!list_empty(&head)) {
-			spin_unlock(&nfs_wreq_lock);
-			nfs_pagein_list(&head, server->rpages);
-			continue;
-		}
-		/* Last resort: we try to flush out single requests */
-		nfs_scan_lru_dirty(server, &head);
-		if (!list_empty(&head)) {
-			spin_unlock(&nfs_wreq_lock);
-			nfs_flush_list(&head, server->wpages, FLUSH_STABLE);
-			continue;
-		}
-		spin_unlock(&nfs_wreq_lock);
-		break;
-	}
-	/* We failed to free up requests */
-	return 0;
 }
 
 int nfs_init_nfspagecache(void)
diff -Nru a/fs/nfs/read.c b/fs/nfs/read.c
--- a/fs/nfs/read.c	Sun Nov 10 19:28:36 2002
+++ b/fs/nfs/read.c	Sun Nov 10 19:28:36 2002
@@ -24,22 +24,27 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/pagemap.h>
+#include <linux/mempool.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_page.h>
-#include <linux/nfs_flushd.h>
 #include <linux/smp_lock.h>
 
 #include <asm/system.h>
 
 #define NFSDBG_FACILITY		NFSDBG_PAGECACHE
 
+static int nfs_pagein_one(struct list_head *, struct inode *);
+
 static kmem_cache_t *nfs_rdata_cachep;
+static mempool_t *nfs_rdata_mempool;
+
+#define MIN_POOL_READ	(32)
 
 static __inline__ struct nfs_read_data *nfs_readdata_alloc(void)
 {
 	struct nfs_read_data   *p;
-	p = kmem_cache_alloc(nfs_rdata_cachep, SLAB_NOFS);
+	p = (struct nfs_read_data *)mempool_alloc(nfs_rdata_mempool, SLAB_NOFS);
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
@@ -49,7 +54,7 @@
 
 static __inline__ void nfs_readdata_free(struct nfs_read_data *p)
 {
-	kmem_cache_free(nfs_rdata_cachep, p);
+	mempool_free(p, nfs_rdata_mempool);
 }
 
 void nfs_readdata_release(struct rpc_task *task)
@@ -129,36 +134,20 @@
 	return result;
 }
 
-/*
- * Add a request to the inode's asynchronous read list.
- */
-static inline void
-nfs_mark_request_read(struct nfs_page *req)
-{
-	struct inode *inode = req->wb_inode;
-	struct nfs_inode *nfsi = NFS_I(inode);
-
-	spin_lock(&nfs_wreq_lock);
-	nfs_list_add_request(req, &nfsi->read);
-	nfsi->nread++;
-	__nfs_add_lru(&NFS_SERVER(inode)->lru_read, req);
-	spin_unlock(&nfs_wreq_lock);
-}
-
 static int
 nfs_readpage_async(struct file *file, struct inode *inode, struct page *page)
 {
-	struct nfs_inode *nfsi = NFS_I(inode);
+	LIST_HEAD(one_request);
 	struct nfs_page	*new;
 
 	new = nfs_create_request(nfs_file_cred(file), inode, page, 0, PAGE_CACHE_SIZE);
-	if (IS_ERR(new))
+	if (IS_ERR(new)) {
+		unlock_page(page);
 		return PTR_ERR(new);
-	nfs_mark_request_read(new);
-
-	if (nfsi->nread >= NFS_SERVER(inode)->rpages ||
-	    page->index == (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT)
-		nfs_pagein_inode(inode, 0, 0);
+	}
+	nfs_lock_request(new);
+	nfs_list_add_request(new, &one_request);
+	nfs_pagein_one(&one_request, inode);
 	return 0;
 }
 
@@ -261,91 +250,6 @@
 	return error;
 }
 
-/**
- * nfs_scan_lru_read_timeout - Scan LRU list for timed out read requests
- * @server: NFS superblock data
- * @dst: destination list
- *
- * Moves a maximum of 'rpages' timed out requests from the NFS read LRU list.
- * The elements are checked to ensure that they form a contiguous set
- * of pages, and that they originated from the same file.
- */
-int
-nfs_scan_lru_read_timeout(struct nfs_server *server, struct list_head *dst)
-{
-	struct nfs_inode *nfsi;
-	int npages;
-
-	npages = nfs_scan_lru_timeout(&server->lru_read, dst, server->rpages);
-	if (npages) {
-		nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
-		nfsi->nread -= npages;
-	}
-	return npages;
-}
-
-/**
- * nfs_scan_lru_read - Scan LRU list for read requests
- * @server: NFS superblock data
- * @dst: destination list
- *
- * Moves a maximum of 'rpages' requests from the NFS read LRU list.
- * The elements are checked to ensure that they form a contiguous set
- * of pages, and that they originated from the same file.
- */
-int
-nfs_scan_lru_read(struct nfs_server *server, struct list_head *dst)
-{
-	struct nfs_inode *nfsi;
-	int npages;
-
-	npages = nfs_scan_lru(&server->lru_read, dst, server->rpages);
-	if (npages) {
-		nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
-		nfsi->nread -= npages;
-	}
-	return npages;
-}
-
-/*
- * nfs_scan_read - Scan an inode for read requests
- * @inode: NFS inode to scan
- * @dst: destination list
- * @idx_start: lower bound of page->index to scan
- * @npages: idx_start + npages sets the upper bound to scan
- *
- * Moves requests from the inode's read list.
- * The requests are *not* checked to ensure that they form a contiguous set.
- */
-static int
-nfs_scan_read(struct inode *inode, struct list_head *dst, unsigned long idx_start, unsigned int npages)
-{
-	struct nfs_inode *nfsi = NFS_I(inode);
-	int	res;
-	res = nfs_scan_list(&nfsi->read, dst, NULL, idx_start, npages);
-	nfsi->nread -= res;
-	if ((nfsi->nread == 0) != list_empty(&nfsi->read))
-		printk(KERN_ERR "NFS: desynchronized value of nfs_i.nread.\n");
-	return res;
-}
-
-int nfs_pagein_inode(struct inode *inode, unsigned long idx_start,
-		     unsigned int npages)
-{
-	LIST_HEAD(head);
-	int	res,
-		error = 0;
-
-	spin_lock(&nfs_wreq_lock);
-	res = nfs_scan_read(inode, &head, idx_start, npages);
-	spin_unlock(&nfs_wreq_lock);
-	if (res)
-		error = nfs_pagein_list(&head, NFS_SERVER(inode)->rpages);
-	if (error < 0)
-		return error;
-	return res;
-}
-
 /*
  * This is the callback from RPC telling us whether a reply was
  * received or some error occurred (timeout or socket shutdown).
@@ -355,11 +259,12 @@
 {
 	struct nfs_read_data	*data = (struct nfs_read_data *) task->tk_calldata;
 	struct inode		*inode = data->inode;
+	struct nfs_fattr	*fattr = &data->fattr;
 
 	dprintk("NFS: %4d nfs_readpage_result, (status %d)\n",
 		task->tk_pid, task->tk_status);
 
-	nfs_refresh_inode(inode, &data->fattr);
+	nfs_refresh_inode(inode, fattr);
 	while (!list_empty(&data->pages)) {
 		struct nfs_page *req = nfs_list_entry(data->pages.next);
 		struct page *page = req->wb_page;
@@ -368,13 +273,20 @@
 		if (task->tk_status >= 0) {
 			if (count < PAGE_CACHE_SIZE) {
 				char *p = kmap(page);
-				memset(p + count, 0, PAGE_CACHE_SIZE - count);
+
+				if (count < req->wb_bytes)
+					memset(p + req->wb_offset + count, 0,
+							req->wb_bytes - count);
 				kunmap(page);
-				count = 0;
-				if (eof)
+
+				if (eof ||
+				    ((fattr->valid & NFS_ATTR_FATTR) &&
+				     ((req_offset(req) + req->wb_offset + count) >= fattr->size)))
 					SetPageUptodate(page);
 				else
-					SetPageError(page);
+					if (count < req->wb_bytes)
+						SetPageError(page);
+				count = 0;
 			} else {
 				count -= PAGE_CACHE_SIZE;
 				SetPageUptodate(page);
@@ -439,6 +351,68 @@
 	goto out;
 }
 
+struct nfs_readdesc {
+	struct list_head *head;
+	struct file *filp;
+};
+
+static int
+readpage_sync_filler(void *data, struct page *page)
+{
+	struct nfs_readdesc *desc = (struct nfs_readdesc *)data;
+	return nfs_readpage_sync(desc->filp, page->mapping->host, page);
+}
+
+static int
+readpage_async_filler(void *data, struct page *page)
+{
+	struct nfs_readdesc *desc = (struct nfs_readdesc *)data;
+	struct inode *inode = page->mapping->host;
+	struct nfs_page *new;
+
+	nfs_wb_page(inode, page);
+	new = nfs_create_request(nfs_file_cred(desc->filp), inode, page,
+				0, PAGE_CACHE_SIZE);
+	if (IS_ERR(new)) {
+			SetPageError(page);
+			unlock_page(page);
+			return PTR_ERR(new);
+	}
+	nfs_lock_request(new);
+	nfs_list_add_request(new, desc->head);
+	return 0;
+}
+
+int
+nfs_readpages(struct file *filp, struct address_space *mapping,
+		struct list_head *pages, unsigned nr_pages)
+{
+	LIST_HEAD(head);
+	struct nfs_readdesc desc = {
+		.filp		= filp,
+		.head		= &head,
+	};
+	struct nfs_server *server = NFS_SERVER(mapping->host);
+	int is_sync = server->rsize < PAGE_CACHE_SIZE;
+	int ret;
+
+	ret = read_cache_pages(mapping, pages,
+			       is_sync ? readpage_sync_filler :
+					 readpage_async_filler,
+			       &desc);
+	while (!list_empty(pages)) {
+		struct page *page = list_entry(pages->prev, struct page, list);
+		list_del(&page->list);
+		page_cache_release(page);
+	}
+	if (!list_empty(&head)) {
+		int err = nfs_pagein_list(&head, server->rpages);
+		if (!ret)
+			ret = err;
+	}
+	return ret;
+}
+
 int nfs_init_readpagecache(void)
 {
 	nfs_rdata_cachep = kmem_cache_create("nfs_read_data",
@@ -448,11 +422,19 @@
 	if (nfs_rdata_cachep == NULL)
 		return -ENOMEM;
 
+	nfs_rdata_mempool = mempool_create(MIN_POOL_READ,
+					   mempool_alloc_slab,
+					   mempool_free_slab,
+					   nfs_rdata_cachep);
+	if (nfs_rdata_mempool == NULL)
+		return -ENOMEM;
+
 	return 0;
 }
 
 void nfs_destroy_readpagecache(void)
 {
+	mempool_destroy(nfs_rdata_mempool);
 	if (kmem_cache_destroy(nfs_rdata_cachep))
 		printk(KERN_INFO "nfs_read_data: not all structures were freed\n");
 }
diff -Nru a/fs/nfs/write.c b/fs/nfs/write.c
--- a/fs/nfs/write.c	Sun Nov 10 19:28:40 2002
+++ b/fs/nfs/write.c	Sun Nov 10 19:28:40 2002
@@ -52,17 +52,22 @@
 #include <linux/mm.h>
 #include <linux/pagemap.h>
 #include <linux/file.h>
+#include <linux/mpage.h>
+#include <linux/writeback.h>
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
-#include <linux/nfs_flushd.h>
 #include <linux/nfs_page.h>
 #include <asm/uaccess.h>
 #include <linux/smp_lock.h>
+#include <linux/mempool.h>
 
 #define NFSDBG_FACILITY		NFSDBG_PAGECACHE
 
+#define MIN_POOL_WRITE		(32)
+#define MIN_POOL_COMMIT		(4)
+
 /*
  * Local function declarations
  */
@@ -72,11 +77,13 @@
 static void	nfs_strategy(struct inode *inode);
 
 static kmem_cache_t *nfs_wdata_cachep;
+static mempool_t *nfs_wdata_mempool;
+static mempool_t *nfs_commit_mempool;
 
 static __inline__ struct nfs_write_data *nfs_writedata_alloc(void)
 {
 	struct nfs_write_data	*p;
-	p = kmem_cache_alloc(nfs_wdata_cachep, SLAB_NOFS);
+	p = (struct nfs_write_data *)mempool_alloc(nfs_wdata_mempool, SLAB_NOFS);
 	if (p) {
 		memset(p, 0, sizeof(*p));
 		INIT_LIST_HEAD(&p->pages);
@@ -86,7 +93,7 @@
 
 static __inline__ void nfs_writedata_free(struct nfs_write_data *p)
 {
-	kmem_cache_free(nfs_wdata_cachep, p);
+	mempool_free(p, nfs_wdata_mempool);
 }
 
 void nfs_writedata_release(struct rpc_task *task)
@@ -95,6 +102,28 @@
 	nfs_writedata_free(wdata);
 }
 
+static __inline__ struct nfs_write_data *nfs_commit_alloc(void)
+{
+	struct nfs_write_data	*p;
+	p = (struct nfs_write_data *)mempool_alloc(nfs_commit_mempool, SLAB_NOFS);
+	if (p) {
+		memset(p, 0, sizeof(*p));
+		INIT_LIST_HEAD(&p->pages);
+	}
+	return p;
+}
+
+static __inline__ void nfs_commit_free(struct nfs_write_data *p)
+{
+	mempool_free(p, nfs_commit_mempool);
+}
+
+void nfs_commit_release(struct rpc_task *task)
+{
+	struct nfs_write_data	*wdata = (struct nfs_write_data *)task->tk_calldata;
+	nfs_commit_free(wdata);
+}
+
 /*
  * This function will be used to simulate weak cache consistency
  * under NFSv2 when the NFSv3 attribute patch is included.
@@ -250,49 +279,43 @@
 	return err; 
 }
 
-/*
- * Check whether the file range we want to write to is locked by
- * us.
- */
-static int
-region_locked(struct inode *inode, struct nfs_page *req)
+int
+nfs_writepages(struct address_space *mapping, struct writeback_control *wbc)
 {
-	struct file_lock	*fl;
-	loff_t			rqstart, rqend;
-
-	/* Don't optimize writes if we don't use NLM */
-	if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)
-		return 0;
-
-	rqstart = req_offset(req) + req->wb_offset;
-	rqend = rqstart + req->wb_bytes;
-	for (fl = inode->i_flock; fl; fl = fl->fl_next) {
-		if (fl->fl_owner == current->files && (fl->fl_flags & FL_POSIX)
-		    && fl->fl_type == F_WRLCK
-		    && fl->fl_start <= rqstart && rqend <= fl->fl_end) {
-			return 1;
-		}
-	}
+	struct inode *inode = mapping->host;
+	int is_sync = !wbc->nonblocking;
+	int err;
 
-	return 0;
+	err = generic_writepages(mapping, wbc);
+	if (err)
+		goto out;
+	err = nfs_flush_file(inode, NULL, 0, 0, 0);
+	if (err < 0)
+		goto out;
+	if (is_sync)
+		err = nfs_wb_all(inode);
+out:
+	return err;
 }
 
 /*
  * Insert a write request into an inode
  */
-static inline void
+static inline int
 nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
-	if (!list_empty(&req->wb_hash))
-		return;
-	if (!NFS_WBACK_BUSY(req))
-		printk(KERN_ERR "NFS: unlocked request attempted hashed!\n");
-	if (list_empty(&nfsi->writeback))
+	int error;
+
+	error = radix_tree_insert(&nfsi->nfs_page_tree, req->wb_index, req);
+	BUG_ON(error == -EEXIST);
+	if (error)
+		return error;
+	if (!nfsi->npages)
 		igrab(inode);
 	nfsi->npages++;
-	list_add(&req->wb_hash, &nfsi->writeback);
 	req->wb_count++;
+	return 0;
 }
 
 /*
@@ -303,21 +326,14 @@
 {
 	struct nfs_inode *nfsi;
 	struct inode *inode;
+
+	BUG_ON (!NFS_WBACK_BUSY(req));
 	spin_lock(&nfs_wreq_lock);
-	if (list_empty(&req->wb_hash)) {
-		spin_unlock(&nfs_wreq_lock);
-		return;
-	}
-	if (!NFS_WBACK_BUSY(req))
-		printk(KERN_ERR "NFS: unlocked request attempted unhashed!\n");
 	inode = req->wb_inode;
-	list_del(&req->wb_hash);
-	INIT_LIST_HEAD(&req->wb_hash);
 	nfsi = NFS_I(inode);
+	radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
 	nfsi->npages--;
-	if ((nfsi->npages == 0) != list_empty(&nfsi->writeback))
-		printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n");
-	if (list_empty(&nfsi->writeback)) {
+	if (!nfsi->npages) {
 		spin_unlock(&nfs_wreq_lock);
 		iput(inode);
 	} else
@@ -333,19 +349,12 @@
 _nfs_find_request(struct inode *inode, unsigned long index)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
-	struct list_head	*head, *next;
+	struct nfs_page *req;
 
-	head = &nfsi->writeback;
-	next = head->next;
-	while (next != head) {
-		struct nfs_page *req = nfs_inode_wb_entry(next);
-		next = next->next;
-		if (req->wb_index != index)
-			continue;
+	req = (struct nfs_page*)radix_tree_lookup(&nfsi->nfs_page_tree, index);
+	if (req)
 		req->wb_count++;
-		return req;
-	}
-	return NULL;
+	return req;
 }
 
 static struct nfs_page *
@@ -371,8 +380,6 @@
 	spin_lock(&nfs_wreq_lock);
 	nfs_list_add_request(req, &nfsi->dirty);
 	nfsi->ndirty++;
-	__nfs_del_lru(req);
-	__nfs_add_lru(&NFS_SERVER(inode)->lru_dirty, req);
 	spin_unlock(&nfs_wreq_lock);
 	mark_inode_dirty(inode);
 }
@@ -400,8 +407,6 @@
 	spin_lock(&nfs_wreq_lock);
 	nfs_list_add_request(req, &nfsi->commit);
 	nfsi->ncommit++;
-	__nfs_del_lru(req);
-	__nfs_add_lru(&NFS_SERVER(inode)->lru_commit, req);
 	spin_unlock(&nfs_wreq_lock);
 	mark_inode_dirty(inode);
 }
@@ -416,8 +421,8 @@
 nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_start, unsigned int npages)
 {
 	struct nfs_inode *nfsi = NFS_I(inode);
-	struct list_head	*p, *head;
-	unsigned long		idx_end;
+	struct nfs_page *req;
+	unsigned long		idx_end, next;
 	unsigned int		res = 0;
 	int			error;
 
@@ -427,21 +432,17 @@
 		idx_end = idx_start + npages - 1;
 
 	spin_lock(&nfs_wreq_lock);
-	head = &nfsi->writeback;
-	p = head->next;
-	while (p != head) {
-		struct nfs_page *req = nfs_inode_wb_entry(p);
-
-		p = p->next;
+	next = idx_start;
+	while (radix_tree_gang_lookup(&nfsi->nfs_page_tree, (void **)&req, next, 1)) {
+		if (req->wb_index > idx_end)
+			break;
 
+		next = req->wb_index + 1;
 		if (file && req->wb_file != file)
 			continue;
-
-		if (req->wb_index < idx_start || req->wb_index > idx_end)
-			continue;
-
 		if (!NFS_WBACK_BUSY(req))
 			continue;
+
 		req->wb_count++;
 		spin_unlock(&nfs_wreq_lock);
 		error = nfs_wait_on_request(req);
@@ -449,59 +450,13 @@
 		if (error < 0)
 			return error;
 		spin_lock(&nfs_wreq_lock);
-		p = head->next;
+		next = idx_start;
 		res++;
 	}
 	spin_unlock(&nfs_wreq_lock);
 	return res;
 }
 
-/**
- * nfs_scan_lru_dirty_timeout - Scan LRU list for timed out dirty requests
- * @server: NFS superblock data
- * @dst: destination list
- *
- * Moves a maximum of 'wpages' requests from the NFS dirty page LRU list.
- * The elements are checked to ensure that they form a contiguous set
- * of pages, and that they originated from the same file.
- */
-int
-nfs_scan_lru_dirty_timeout(struct nfs_server *server, struct list_head *dst)
-{
-	struct nfs_inode *nfsi;
-	int npages;
-
-	npages = nfs_scan_lru_timeout(&server->lru_dirty, dst, server->wpages);
-	if (npages) {
-		nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
-		nfsi->ndirty -= npages;
-	}
-	return npages;
-}
-
-/**
- * nfs_scan_lru_dirty - Scan LRU list for dirty requests
- * @server: NFS superblock data
- * @dst: destination list
- *
- * Moves a maximum of 'wpages' requests from the NFS dirty page LRU list.
- * The elements are checked to ensure that they form a contiguous set
- * of pages, and that they originated from the same file.
- */
-int
-nfs_scan_lru_dirty(struct nfs_server *server, struct list_head *dst)
-{
-	struct nfs_inode *nfsi;
-	int npages;
-
-	npages = nfs_scan_lru(&server->lru_dirty, dst, server->wpages);
-	if (npages) {
-		nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
-		nfsi->ndirty -= npages;
-	}
-	return npages;
-}
-
 /*
  * nfs_scan_dirty - Scan an inode for dirty requests
  * @inode: NFS inode to scan
@@ -526,59 +481,6 @@
 }
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
-/**
- * nfs_scan_lru_commit_timeout - Scan LRU list for timed out commit requests
- * @server: NFS superblock data
- * @dst: destination list
- *
- * Finds the first a timed out request in the NFS commit LRU list and moves it
- * to the list dst. If such an element is found, we move all other commit
- * requests that apply to the same inode.
- * The assumption is that doing everything in a single commit-to-disk is
- * the cheaper alternative.
- */
-int
-nfs_scan_lru_commit_timeout(struct nfs_server *server, struct list_head *dst)
-{
-	struct nfs_inode *nfsi;
-	int npages;
-
-	npages = nfs_scan_lru_timeout(&server->lru_commit, dst, 1);
-	if (npages) {
-		nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
-		npages += nfs_scan_list(&nfsi->commit, dst, NULL, 0, 0);
-		nfsi->ncommit -= npages;
-	}
-	return npages;
-}
-
-
-/**
- * nfs_scan_lru_commit_timeout - Scan LRU list for timed out commit requests
- * @server: NFS superblock data
- * @dst: destination list
- *
- * Finds the first request in the NFS commit LRU list and moves it
- * to the list dst. If such an element is found, we move all other commit
- * requests that apply to the same inode.
- * The assumption is that doing everything in a single commit-to-disk is
- * the cheaper alternative.
- */
-int
-nfs_scan_lru_commit(struct nfs_server *server, struct list_head *dst)
-{
-	struct nfs_inode *nfsi;
-	int npages;
-
-	npages = nfs_scan_lru(&server->lru_commit, dst, 1);
-	if (npages) {
-		nfsi = NFS_I(nfs_list_entry(dst->next)->wb_inode);
-		npages += nfs_scan_list(&nfsi->commit, dst, NULL, 0, 0);
-		nfsi->ncommit -= npages;
-	}
-	return npages;
-}
-
 /*
  * nfs_scan_commit - Scan an inode for commit requests
  * @inode: NFS inode to scan
@@ -643,8 +545,14 @@
 		}
 
 		if (new) {
+			int error;
 			nfs_lock_request_dontget(new);
-			nfs_inode_add_request(inode, new);
+			error = nfs_inode_add_request(inode, new);
+			if (error) {
+				spin_unlock(&nfs_wreq_lock);
+				nfs_unlock_request(new);
+				return ERR_PTR(error);
+			}
 			spin_unlock(&nfs_wreq_lock);
 			nfs_mark_request_dirty(new);
 			return new;
@@ -658,11 +566,6 @@
 			new->wb_file = file;
 			get_file(file);
 		}
-		/* If the region is locked, adjust the timeout */
-		if (region_locked(inode, new))
-			new->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY;
-		else
-			new->wb_timeout = jiffies + NFS_WRITEBACK_DELAY;
 	}
 
 	/* We have a request for our page.
@@ -850,6 +753,7 @@
 		req = nfs_list_entry(head->next);
 		nfs_list_remove_request(req);
 		nfs_list_add_request(req, &data->pages);
+		SetPageWriteback(req->wb_page);
 		*pages++ = req->wb_page;
 		count += req->wb_bytes;
 	}
@@ -1005,10 +909,12 @@
 			SetPageError(page);
 			if (req->wb_file)
 				req->wb_file->f_error = task->tk_status;
+			end_page_writeback(page);
 			nfs_inode_remove_request(req);
 			dprintk(", error = %d\n", task->tk_status);
 			goto next;
 		}
+		end_page_writeback(page);
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 		if (stable != NFS_UNSTABLE || data->verf.committed == NFS_FILE_SYNC) {
@@ -1017,7 +923,6 @@
 			goto next;
 		}
 		memcpy(&req->wb_verf, &data->verf, sizeof(req->wb_verf));
-		req->wb_timeout = jiffies + NFS_COMMIT_DELAY;
 		nfs_mark_request_commit(req);
 		dprintk(" marked for commit\n");
 #else
@@ -1079,7 +984,7 @@
 	struct nfs_page         *req;
 	sigset_t		oldset;
 
-	data = nfs_writedata_alloc();
+	data = nfs_commit_alloc();
 
 	if (!data)
 		goto out_bad;
@@ -1223,11 +1128,27 @@
 	if (nfs_wdata_cachep == NULL)
 		return -ENOMEM;
 
+	nfs_wdata_mempool = mempool_create(MIN_POOL_WRITE,
+					   mempool_alloc_slab,
+					   mempool_free_slab,
+					   nfs_wdata_cachep);
+	if (nfs_wdata_mempool == NULL)
+		return -ENOMEM;
+
+	nfs_commit_mempool = mempool_create(MIN_POOL_COMMIT,
+					   mempool_alloc_slab,
+					   mempool_free_slab,
+					   nfs_wdata_cachep);
+	if (nfs_commit_mempool == NULL)
+		return -ENOMEM;
+
 	return 0;
 }
 
 void nfs_destroy_writepagecache(void)
 {
+	mempool_destroy(nfs_commit_mempool);
+	mempool_destroy(nfs_wdata_mempool);
 	if (kmem_cache_destroy(nfs_wdata_cachep))
 		printk(KERN_INFO "nfs_write_data: not all structures were freed\n");
 }
diff -Nru a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c
--- a/fs/nfsd/nfs3proc.c	Sun Nov 10 19:28:39 2002
+++ b/fs/nfsd/nfs3proc.c	Sun Nov 10 19:28:39 2002
@@ -41,16 +41,6 @@
 };
 
 /*
- * Reserve room in the send buffer
- */
-static inline void
-svcbuf_reserve(struct xdr_buf *buf, u32 **ptr, int *len, int nr)
-{
-	*ptr = (u32*)(buf->head[0].iov_base+buf->head[0].iov_len) + nr;
-	*len = ((PAGE_SIZE-buf->head[0].iov_len)>>2) - nr;
-}
-
-/*
  * NULL call.
  */
 static int
@@ -141,22 +131,17 @@
  * Read a symlink.
  */
 static int
-nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle     *argp,
+nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
 					   struct nfsd3_readlinkres *resp)
 {
-	u32		*path;
-	int		dummy, nfserr;
+	int nfserr;
 
 	dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
 
-	/* Reserve room for status, post_op_attr, and path length */
-	svcbuf_reserve(&rqstp->rq_res, &path, &dummy,
-				1 + NFS3_POST_OP_ATTR_WORDS + 1);
-
 	/* Read the symlink. */
 	fh_copy(&resp->fh, &argp->fh);
 	resp->len = NFS3_MAXPATHLEN;
-	nfserr = nfsd_readlink(rqstp, &resp->fh, (char *) path, &resp->len);
+	nfserr = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len);
 	RETURN_STATUS(nfserr);
 }
 
@@ -436,35 +421,28 @@
 nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
 					   struct nfsd3_readdirres  *resp)
 {
-	u32 *		buffer;
 	int		nfserr, count;
-	unsigned int	want;
 
 	dprintk("nfsd: READDIR(3)  %s %d bytes at %d\n",
 				SVCFH_fmt(&argp->fh),
 				argp->count, (u32) argp->cookie);
 
-	/* Reserve buffer space for status, attributes and verifier */
-	svcbuf_reserve(&rqstp->rq_res, &buffer, &count,
-				1 + NFS3_POST_OP_ATTR_WORDS + 2);
-
 	/* Make sure we've room for the NULL ptr & eof flag, and shrink to
 	 * client read size */
-	if ((count -= 2) > (want = (argp->count >> 2) - 2))
-		count = want;
+	count = (argp->count >> 2) - 2;
 
 	/* Read directory and encode entries on the fly */
 	fh_copy(&resp->fh, &argp->fh);
 
 	resp->buflen = count;
 	resp->common.err = nfs_ok;
-	resp->buffer = buffer;
+	resp->buffer = argp->buffer;
 	resp->offset = NULL;
 	resp->rqstp = rqstp;
 	nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie, 
 					&resp->common, nfs3svc_encode_entry);
 	memcpy(resp->verf, argp->verf, 8);
-	resp->count = resp->buffer - buffer;
+	resp->count = resp->buffer - argp->buffer;
 	if (resp->offset)
 		xdr_encode_hyper(resp->offset, argp->cookie);
 
@@ -479,35 +457,29 @@
 nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
 					       struct nfsd3_readdirres  *resp)
 {
-	u32 *	buffer;
-	int	nfserr, count, want;
+	int	nfserr, count;
 	loff_t	offset;
 
 	dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
 				SVCFH_fmt(&argp->fh),
 				argp->count, (u32) argp->cookie);
 
-	/* Reserve buffer space for status, attributes and verifier */
-	svcbuf_reserve(&rqstp->rq_res, &buffer, &count,
-				1 + NFS3_POST_OP_ATTR_WORDS + 2);
-
 	/* Make sure we've room for the NULL ptr & eof flag, and shrink to
 	 * client read size */
-	if ((count -= 2) > (want = argp->count >> 2))
-		count = want;
+	count = (argp->count >> 2) - 2;
 
 	/* Read directory and encode entries on the fly */
 	fh_copy(&resp->fh, &argp->fh);
 
 	resp->buflen = count;
 	resp->common.err = nfs_ok;
-	resp->buffer = buffer;
+	resp->buffer = argp->buffer;
 	resp->rqstp = rqstp;
 	offset = argp->cookie;
 	nfserr = nfsd_readdir(rqstp, &resp->fh, &offset, 
 			      &resp->common, nfs3svc_encode_entry_plus);
 	memcpy(resp->verf, argp->verf, 8);
-	resp->count = resp->buffer - buffer;
+	resp->count = resp->buffer - argp->buffer;
 	if (resp->offset)
 		xdr_encode_hyper(resp->offset, offset);
 
@@ -682,7 +654,7 @@
   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+NFS3_MAXPATHLEN/4),
+  PROC(readlink, readlink,	readlink,	fhandle,  RC_NOCACHE, ST+pAT+1+NFS3_MAXPATHLEN/4),
   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),
diff -Nru a/fs/nfsd/nfs3xdr.c b/fs/nfsd/nfs3xdr.c
--- a/fs/nfsd/nfs3xdr.c	Sun Nov 10 19:28:36 2002
+++ b/fs/nfsd/nfs3xdr.c	Sun Nov 10 19:28:36 2002
@@ -275,9 +275,9 @@
  * XDR decode functions
  */
 int
-nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+nfs3svc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args)
 {
-	if (!(p = decode_fh(p, fhp)))
+	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
 	return xdr_argsize_check(rqstp, p);
 }
@@ -338,7 +338,7 @@
 	v=0;
 	while (len > 0) {
 		pn = rqstp->rq_resused;
-		take_page(rqstp);
+		svc_take_page(rqstp);
 		args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
 		args->vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
 		v++;
@@ -468,6 +468,18 @@
 }
 
 int
+nfs3svc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p,
+					struct nfsd3_readlinkargs *args)
+{
+	if (!(p = decode_fh(p, &args->fh)))
+		return 0;
+	svc_take_page(rqstp);
+	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
 nfs3svc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_linkargs *args)
 {
@@ -490,6 +502,12 @@
 	args->dircount = ~0;
 	args->count  = ntohl(*p++);
 
+	if (args->count > PAGE_SIZE)
+		args->count = PAGE_SIZE;
+
+	svc_take_page(rqstp);
+	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+
 	return xdr_argsize_check(rqstp, p);
 }
 
@@ -504,6 +522,9 @@
 	args->dircount = ntohl(*p++);
 	args->count    = ntohl(*p++);
 
+	svc_take_page(rqstp);
+	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+
 	return xdr_argsize_check(rqstp, p);
 }
 
@@ -583,9 +604,17 @@
 	p = encode_post_op_attr(rqstp, p, &resp->fh);
 	if (resp->status == 0) {
 		*p++ = htonl(resp->len);
-		p += XDR_QUADLEN(resp->len);
-	}
-	return xdr_ressize_check(rqstp, p);
+		xdr_ressize_check(rqstp, p);
+		rqstp->rq_res.page_len = resp->len;
+		if (resp->len & 3) {
+			/* need to pad the tail */
+			rqstp->rq_res.tail[0].iov_base = p;
+			*p = 0;
+			rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
+		}
+		return 1;
+	} else
+		return xdr_ressize_check(rqstp, p);
 }
 
 /* READ */
@@ -600,18 +629,13 @@
 		*p++ = htonl(resp->count);	/* xdr opaque count */
 		xdr_ressize_check(rqstp, p);
 		/* now update rqstp->rq_res to reflect data aswell */
-		rqstp->rq_res.page_base = 0;
 		rqstp->rq_res.page_len = resp->count;
 		if (resp->count & 3) {
-			/* need to page with tail */
+			/* need to pad the tail */
 			rqstp->rq_res.tail[0].iov_base = p;
 			*p = 0;
 			rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
 		}
-		rqstp->rq_res.len =
-			rqstp->rq_res.head[0].iov_len+
-			rqstp->rq_res.page_len+
-			rqstp->rq_res.tail[0].iov_len;
 		return 1;
 	} else
 		return xdr_ressize_check(rqstp, p);
@@ -676,12 +700,14 @@
 	if (resp->status == 0) {
 		/* stupid readdir cookie */
 		memcpy(p, resp->verf, 8); p += 2;
+		xdr_ressize_check(rqstp, p);
 		p = resp->buffer;
 		*p++ = 0;		/* no more entries */
 		*p++ = htonl(resp->common.err == nfserr_eof);
-	}
-
-	return xdr_ressize_check(rqstp, p);
+		rqstp->rq_res.page_len = ((unsigned long)p & ~PAGE_MASK);
+		return 1;
+	} else
+		return xdr_ressize_check(rqstp, p);
 }
 
 /*
diff -Nru a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c
--- a/fs/nfsd/nfsproc.c	Sun Nov 10 19:28:38 2002
+++ b/fs/nfsd/nfsproc.c	Sun Nov 10 19:28:38 2002
@@ -30,13 +30,6 @@
 #define NFSDDBG_FACILITY		NFSDDBG_PROC
 
 
-static inline void
-svcbuf_reserve(struct xdr_buf *buf, u32 **ptr, int *len, int nr)
-{
-	*ptr = (u32*)(buf->head[0].iov_base+buf->head[0].iov_len) + nr;
-	*len = ((PAGE_SIZE-buf->head[0].iov_len)>>2) - nr;
-}
-
 static int
 nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 {
@@ -100,20 +93,16 @@
  * Read a symlink.
  */
 static int
-nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle     *argp,
+nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_readlinkargs *argp,
 					   struct nfsd_readlinkres *resp)
 {
-	u32		*path;
-	int		dummy, nfserr;
+	int	nfserr;
 
 	dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
 
-	/* Reserve room for status and path length */
-	svcbuf_reserve(&rqstp->rq_res, &path, &dummy, 2);
-
 	/* Read the symlink. */
 	resp->len = NFS_MAXPATHLEN;
-	nfserr = nfsd_readlink(rqstp, &argp->fh, (char *) path, &resp->len);
+	nfserr = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len);
 
 	fh_put(&argp->fh);
 	return nfserr;
@@ -467,7 +456,6 @@
 nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
 					  struct nfsd_readdirres  *resp)
 {
-	u32 *		buffer;
 	int		nfserr, count;
 	loff_t		offset;
 
@@ -475,19 +463,15 @@
 		SVCFH_fmt(&argp->fh),		
 		argp->count, argp->cookie);
 
-	/* Reserve buffer space for status */
-	svcbuf_reserve(&rqstp->rq_res, &buffer, &count, 1);
-
 	/* Shrink to the client read size */
-	if (count > (argp->count >> 2))
-		count = argp->count >> 2;
+	count = (argp->count >> 2) - 2;
 
 	/* Make sure we've room for the NULL ptr & eof flag */
 	count -= 2;
 	if (count < 0)
 		count = 0;
 
-	resp->buffer = buffer;
+	resp->buffer = argp->buffer;
 	resp->offset = NULL;
 	resp->buflen = count;
 	resp->common.err = nfs_ok;
@@ -496,7 +480,7 @@
 	nfserr = nfsd_readdir(rqstp, &argp->fh, &offset, 
 			      &resp->common, nfssvc_encode_entry);
 
-	resp->count = resp->buffer - buffer;
+	resp->count = resp->buffer - argp->buffer;
 	if (resp->offset)
 		*resp->offset = (u32)offset;
 
@@ -550,7 +534,7 @@
   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+NFS_MAXPATHLEN/4),
+  PROC(readlink, readlinkargs,	readlinkres,	none,		RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4),
   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),
diff -Nru a/fs/nfsd/nfsxdr.c b/fs/nfsd/nfsxdr.c
--- a/fs/nfsd/nfsxdr.c	Sun Nov 10 19:28:36 2002
+++ b/fs/nfsd/nfsxdr.c	Sun Nov 10 19:28:36 2002
@@ -188,9 +188,9 @@
 }
 
 int
-nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+nfssvc_decode_fhandle(struct svc_rqst *rqstp, u32 *p, struct nfsd_fhandle *args)
 {
-	if (!(p = decode_fh(p, fhp)))
+	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
 	return xdr_argsize_check(rqstp, p);
 }
@@ -239,7 +239,7 @@
 	v=0;
 	while (len > 0) {
 		pn=rqstp->rq_resused;
-		take_page(rqstp);
+		svc_take_page(rqstp);
 		args->vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
 		args->vec[v].iov_len = len < PAGE_SIZE?len:PAGE_SIZE;
 		v++;
@@ -305,6 +305,17 @@
 }
 
 int
+nfssvc_decode_readlinkargs(struct svc_rqst *rqstp, u32 *p, struct nfsd_readlinkargs *args)
+{
+	if (!(p = decode_fh(p, &args->fh)))
+		return 0;
+	svc_take_page(rqstp);
+	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
+
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
 nfssvc_decode_linkargs(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd_linkargs *args)
 {
@@ -337,6 +348,11 @@
 		return 0;
 	args->cookie = ntohl(*p++);
 	args->count  = ntohl(*p++);
+	if (args->count > PAGE_SIZE)
+		args->count = PAGE_SIZE;
+
+	svc_take_page(rqstp);
+	args->buffer = page_address(rqstp->rq_respages[rqstp->rq_resused-1]);
 
 	return xdr_argsize_check(rqstp, p);
 }
@@ -372,8 +388,15 @@
 					struct nfsd_readlinkres *resp)
 {
 	*p++ = htonl(resp->len);
-	p += XDR_QUADLEN(resp->len);
-	return xdr_ressize_check(rqstp, p);
+	xdr_ressize_check(rqstp, p);
+	rqstp->rq_res.page_len = resp->len;
+	if (resp->len & 3) {
+		/* need to pad the tail */
+		rqstp->rq_res.tail[0].iov_base = p;
+		*p = 0;
+		rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
+	}
+	return 1;
 }
 
 int
@@ -385,18 +408,13 @@
 	xdr_ressize_check(rqstp, p);
 
 	/* now update rqstp->rq_res to reflect data aswell */
-	rqstp->rq_res.page_base = 0;
 	rqstp->rq_res.page_len = resp->count;
 	if (resp->count & 3) {
-		/* need to pad with tail */
+		/* need to pad the tail */
 		rqstp->rq_res.tail[0].iov_base = p;
 		*p = 0;
 		rqstp->rq_res.tail[0].iov_len = 4 - (resp->count&3);
 	}
-	rqstp->rq_res.len = 
-		rqstp->rq_res.head[0].iov_len+
-		rqstp->rq_res.page_len+
-		rqstp->rq_res.tail[0].iov_len;
 	return 1;
 }
 
@@ -404,11 +422,13 @@
 nfssvc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd_readdirres *resp)
 {
+	xdr_ressize_check(rqstp, p);
 	p = resp->buffer;
 	*p++ = 0;			/* no more entries */
 	*p++ = htonl((resp->common.err == nfserr_eof));
+	rqstp->rq_res.page_len = ((unsigned long)p & ~PAGE_MASK);
 
-	return xdr_ressize_check(rqstp, p);
+	return 1;
 }
 
 int
diff -Nru a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
--- a/fs/nfsd/vfs.c	Sun Nov 10 19:28:39 2002
+++ b/fs/nfsd/vfs.c	Sun Nov 10 19:28:39 2002
@@ -13,6 +13,7 @@
  * dentry, don't worry--they have been taken care of.
  *
  * Copyright (C) 1995-1999 Olaf Kirch <okir@monad.swb.de>
+ * Zerocpy NFS support (C) 2002 Hirokazu Takahashi <taka@valinux.co.jp>
  */
 
 #include <linux/config.h>
@@ -28,6 +29,7 @@
 #include <linux/net.h>
 #include <linux/unistd.h>
 #include <linux/slab.h>
+#include <linux/pagemap.h>
 #include <linux/in.h>
 #include <linux/module.h>
 #include <linux/namei.h>
@@ -571,6 +573,38 @@
 }
 
 /*
+ * Grab and keep cached pages assosiated with a file in the svc_rqst
+ * so that they can be passed to the netowork sendmsg/sendpage routines
+ * directrly. They will be released after the sending has completed.
+ */
+static int
+nfsd_read_actor(read_descriptor_t *desc, struct page *page, unsigned long offset , unsigned long size)
+{
+	unsigned long count = desc->count;
+	struct svc_rqst *rqstp = (struct svc_rqst *)desc->buf;
+
+	if (size > count)
+		size = count;
+
+	if (rqstp->rq_res.page_len == 0) {
+		get_page(page);
+		rqstp->rq_respages[rqstp->rq_resused++] = page;
+		rqstp->rq_res.page_base = offset;
+		rqstp->rq_res.page_len = size;
+	} else if (page != rqstp->rq_respages[rqstp->rq_resused-1]) {
+		get_page(page);
+		rqstp->rq_respages[rqstp->rq_resused++] = page;
+		rqstp->rq_res.page_len += size;
+	} else {
+		rqstp->rq_res.page_len += size;
+	}
+
+	desc->count = count - size;
+	desc->written += size;
+	return size;
+}
+
+/*
  * Read data from a file. count must contain the requested read count
  * on entry. On return, *count contains the number of bytes actually read.
  * N.B. After this call fhp needs an fh_put
@@ -601,10 +635,16 @@
 	if (ra)
 		file.f_ra = ra->p_ra;
 
-	oldfs = get_fs();
-	set_fs(KERNEL_DS);
-	err = vfs_readv(&file, vec, vlen, *count, &offset);
-	set_fs(oldfs);
+	if (file.f_op->sendfile) {
+		svc_pushback_unused_pages(rqstp);
+		err = file.f_op->sendfile(&file, &offset, *count,
+						 nfsd_read_actor, rqstp);
+	} else {
+		oldfs = get_fs();
+		set_fs(KERNEL_DS);
+		err = vfs_readv(&file, vec, vlen, &offset);
+		set_fs(oldfs);
+	}
 
 	/* Write back readahead params */
 	if (ra)
@@ -678,7 +718,7 @@
 
 	/* Write the data. */
 	oldfs = get_fs(); set_fs(KERNEL_DS);
-	err = vfs_writev(&file, vec, vlen, cnt, &offset);
+	err = vfs_writev(&file, vec, vlen, &offset);
 	if (err >= 0)
 		nfsdstats.io_write += cnt;
 	set_fs(oldfs);
diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c
--- a/fs/ntfs/inode.c	Sun Nov 10 19:28:41 2002
+++ b/fs/ntfs/inode.c	Sun Nov 10 19:28:41 2002
@@ -495,7 +495,7 @@
 	 * This is for checking whether an inode has changed w.r.t. a file so
 	 * that the file can be updated if necessary (compare with f_version).
 	 */
-	vi->i_version = ++event;
+	vi->i_version = 1;
 
 	vi->i_uid = vol->uid;
 	vi->i_gid = vol->gid;
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	Sun Nov 10 19:28:41 2002
+++ b/fs/partitions/check.c	Sun Nov 10 19:28:41 2002
@@ -294,7 +294,7 @@
 	struct part_attribute * part_attr = container_of(attr,struct part_attribute,attr);
 	ssize_t ret = 0;
 	if (part_attr->show)
-		part_attr->show(p,page,count,off);
+		ret = part_attr->show(p,page,count,off);
 	return ret;
 }
 
diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
--- a/fs/proc/proc_misc.c	Sun Nov 10 19:28:37 2002
+++ b/fs/proc/proc_misc.c	Sun Nov 10 19:28:37 2002
@@ -40,7 +40,7 @@
 #include <linux/times.h>
 #include <linux/profile.h>
 #include <linux/blkdev.h>
-
+#include <linux/hugetlb.h>
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/io.h>
@@ -199,19 +199,8 @@
 		ps.nr_reverse_maps
 		);
 
-#ifdef CONFIG_HUGETLB_PAGE
-	{
-		extern unsigned long htlbpagemem, htlbzone_pages;
-		len += sprintf(page + len,
-				"HugePages_Total: %5lu\n"
-				"HugePages_Free:  %5lu\n"
-				"Hugepagesize:    %5lu kB\n",
-				htlbzone_pages,
-				htlbpagemem,
-				HPAGE_SIZE/1024);
-	}
+		len += hugetlb_report_meminfo(page + len);
 
-#endif
 	return proc_calc_metrics(page, start, off, count, eof, len);
 #undef K
 }
@@ -341,7 +330,6 @@
 	extern unsigned long total_forks;
 	unsigned long jif = jiffies;
 	unsigned int sum = 0, user = 0, nice = 0, system = 0, idle = 0, iowait = 0;
-	int major, disk;
 
 	for (i = 0 ; i < NR_CPUS; i++) {
 		int j;
@@ -372,7 +360,7 @@
 			jiffies_to_clock_t(kstat_cpu(i).cpustat.nice),
 			jiffies_to_clock_t(kstat_cpu(i).cpustat.system),
 			jiffies_to_clock_t(kstat_cpu(i).cpustat.idle),
-			jiffies_to_clock_t(kstat_cpu(i).cpustat.idle));
+			jiffies_to_clock_t(kstat_cpu(i).cpustat.iowait));
 	}
 	len += sprintf(page + len, "intr %u", sum);
 
@@ -381,37 +369,17 @@
 		len += sprintf(page + len, " %u", kstat_irqs(i));
 #endif
 
-	len += sprintf(page + len, "\ndisk_io: ");
-
-	for (major = 0; major < DK_MAX_MAJOR; major++) {
-		for (disk = 0; disk < DK_MAX_DISK; disk++) {
-			int active = dkstat.drive[major][disk] +
-				dkstat.drive_rblk[major][disk] +
-				dkstat.drive_wblk[major][disk];
-			if (active)
-				len += sprintf(page + len,
-					"(%u,%u):(%u,%u,%u,%u,%u) ",
-					major, disk,
-					dkstat.drive[major][disk],
-					dkstat.drive_rio[major][disk],
-					dkstat.drive_rblk[major][disk],
-					dkstat.drive_wio[major][disk],
-					dkstat.drive_wblk[major][disk]
-			);
-		}
-	}
-
 	len += sprintf(page + len,
 		"\nctxt %lu\n"
 		"btime %lu\n"
 		"processes %lu\n"
 		"procs_running %lu\n"
-		"procs_blocked %u\n",
+		"procs_blocked %lu\n",
 		nr_context_switches(),
 		xtime.tv_sec - jif / HZ,
 		total_forks,
 		nr_running(),
-		atomic_read(&nr_iowait_tasks));
+		nr_iowait());
 
 	return proc_calc_metrics(page, start, off, count, eof, len);
 }
diff -Nru a/fs/read_write.c b/fs/read_write.c
--- a/fs/read_write.c	Sun Nov 10 19:28:40 2002
+++ b/fs/read_write.c	Sun Nov 10 19:28:40 2002
@@ -40,7 +40,7 @@
 	if (offset>=0 && offset<=inode->i_sb->s_maxbytes) {
 		if (offset != file->f_pos) {
 			file->f_pos = offset;
-			file->f_version = ++event;
+			file->f_version = 0;
 		}
 		retval = offset;
 	}
@@ -64,7 +64,7 @@
 	if (offset>=0 && offset<=file->f_dentry->d_inode->i_sb->s_maxbytes) {
 		if (offset != file->f_pos) {
 			file->f_pos = offset;
-			file->f_version = ++event;
+			file->f_version = 0;
 		}
 		retval = offset;
 	}
@@ -93,7 +93,7 @@
 	if (offset >= 0) {
 		if (offset != file->f_pos) {
 			file->f_pos = offset;
-			file->f_version = ++event;
+			file->f_version = 0;
 		}
 		retval = offset;
 	}
@@ -207,53 +207,6 @@
 	return ret;
 }
 
-ssize_t vfs_readv(struct file *file, struct iovec *vec, int vlen, size_t count, loff_t *pos)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-	ssize_t ret;
-
-	if (!(file->f_mode & FMODE_READ))
-		return -EBADF;
-	if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
-		return -EINVAL;
-
-	ret = locks_verify_area(FLOCK_VERIFY_READ, inode, file, *pos, count);
-	if (!ret) {
-		ret = security_ops->file_permission (file, MAY_READ);
-		if (!ret) {
-			if (file->f_op->readv)
-				ret = file->f_op->readv(file, vec, vlen, pos);
-			else {
-				/* do it by hand */
-				struct iovec *vector = vec;
-				ret = 0;
-				while (vlen > 0) {
-					void * base =  vector->iov_base;
-					size_t len = vector->iov_len;
-					ssize_t nr;
-					vector++;
-					vlen--;
-					if (file->f_op->read)
-						nr = file->f_op->read(file, base, len, pos);
-					else
-						nr = do_sync_read(file, base, len, pos);
-					if (nr < 0) {
-						if (!ret) ret = nr;
-						break;
-					}
-					ret += nr;
-					if (nr != len)
-						break;
-				}
-			}
-			if (ret > 0)
-				dnotify_parent(file->f_dentry, DN_ACCESS);
-		}
-	}
-
-	return ret;
-}
-
 ssize_t do_sync_write(struct file *filp, const char *buf, size_t len, loff_t *ppos)
 {
 	struct kiocb kiocb;
@@ -294,53 +247,6 @@
 	return ret;
 }
 
-ssize_t vfs_writev(struct file *file, const struct iovec *vec, int vlen, size_t count, loff_t *pos)
-{
-	struct inode *inode = file->f_dentry->d_inode;
-	ssize_t ret;
-
-	if (!(file->f_mode & FMODE_WRITE))
-		return -EBADF;
-	if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
-		return -EINVAL;
-
-	ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, *pos, count);
-	if (!ret) {
-		ret = security_ops->file_permission (file, MAY_WRITE);
-		if (!ret) {
-			if (file->f_op->writev)
-				ret = file->f_op->writev(file, vec, vlen, pos);
-			else {
-				/* do it by hand */
-				const struct iovec *vector = vec;
-				ret = 0;
-				while (vlen > 0) {
-					void * base = vector->iov_base;
-					size_t len = vector->iov_len;
-					ssize_t nr;
-					vector++;
-					vlen--;
-					if (file->f_op->write)
-						nr = file->f_op->write(file, base, len, pos);
-					else
-						nr = do_sync_write(file, base, len, pos);
-					if (nr < 0) {
-						if (!ret) ret = nr;
-						break;
-					}
-					ret += nr;
-					if (nr != len)
-						break;
-				}
-			}
-			if (ret > 0)
-				dnotify_parent(file->f_dentry, DN_MODIFY);
-		}
-	}
-
-	return ret;
-}
-
 asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
 {
 	struct file *file;
@@ -427,7 +333,7 @@
 
 static ssize_t do_readv_writev(int type, struct file *file,
 			       const struct iovec * vector,
-			       unsigned long nr_segs)
+			       unsigned long nr_segs, loff_t *pos)
 {
 	typedef ssize_t (*io_fn_t)(struct file *, char *, size_t, loff_t *);
 	typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);
@@ -496,7 +402,7 @@
 	/* VERIFY_WRITE actually means a read, as we write to user space */
 	ret = locks_verify_area((type == READ 
 				 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
-				inode, file, file->f_pos, tot_len);
+				inode, file, *pos, tot_len);
 	if (ret)
 		goto out;
 
@@ -509,7 +415,7 @@
 		fnv = file->f_op->writev;
 	}
 	if (fnv) {
-		ret = fnv(file, iov, nr_segs, &file->f_pos);
+		ret = fnv(file, iov, nr_segs, pos);
 		goto out;
 	}
 
@@ -526,7 +432,7 @@
 		vector++;
 		nr_segs--;
 
-		nr = fn(file, base, len, &file->f_pos);
+		nr = fn(file, base, len, pos);
 
 		if (nr < 0) {
 			if (!ret) ret = nr;
@@ -545,50 +451,56 @@
 	return ret;
 }
 
+ssize_t vfs_readv(struct file *file, const struct iovec *vec,
+		  unsigned long vlen, loff_t *pos)
+{
+	if (!(file->f_mode & FMODE_READ))
+		return -EBADF;
+	if (!file->f_op || (!file->f_op->readv && !file->f_op->read))
+		return -EINVAL;
 
-asmlinkage ssize_t
-sys_readv(unsigned long fd, const struct iovec *vector, unsigned long nr_segs)
+	return do_readv_writev(READ, file, vec, vlen, pos);
+}
+
+ssize_t vfs_writev(struct file *file, const struct iovec *vec,
+		   unsigned long vlen, loff_t *pos)
 {
-	struct file * file;
-	ssize_t ret;
+	if (!(file->f_mode & FMODE_WRITE))
+		return -EBADF;
+	if (!file->f_op || (!file->f_op->writev && !file->f_op->write))
+		return -EINVAL;
+
+	return do_readv_writev(WRITE, file, vec, vlen, pos);
+}
+
 
+asmlinkage ssize_t
+sys_readv(unsigned long fd, const struct iovec *vec, unsigned long vlen)
+{
+	struct file *file;
+	ssize_t ret = -EBADF;
 
-	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 = security_ops->file_permission (file, MAY_READ);
-		if (!ret)
-			ret = do_readv_writev(READ, file, vector, nr_segs);
+	if (file) {
+		ret = vfs_readv(file, vec, vlen, &file->f_pos);
+		fput(file);
 	}
-	fput(file);
 
-bad_file:
 	return ret;
 }
 
 asmlinkage ssize_t
-sys_writev(unsigned long fd, const struct iovec * vector, unsigned long nr_segs)
+sys_writev(unsigned long fd, const struct iovec *vec, unsigned long vlen)
 {
-	struct file * file;
-	ssize_t ret;
-
+	struct file *file;
+	ssize_t ret = -EBADF;
 
-	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 = security_ops->file_permission (file, MAY_WRITE);
-		if (!ret)
-			ret = do_readv_writev(WRITE, file, vector, nr_segs);
+	if (file) {
+		ret = vfs_writev(file, vec, vlen, &file->f_pos);
+		fput(file);
 	}
-	fput(file);
 
-bad_file:
 	return ret;
 }
 
@@ -653,7 +565,7 @@
 		count = max - pos;
 	}
 
-	retval = in_file->f_op->sendfile(out_file, in_file, ppos, count);
+	retval = in_file->f_op->sendfile(in_file, ppos, count, file_send_actor, out_file);
 
 	if (*ppos > max)
 		retval = -EOVERFLOW;
diff -Nru a/fs/stat.c b/fs/stat.c
--- a/fs/stat.c	Sun Nov 10 19:28:37 2002
+++ b/fs/stat.c	Sun Nov 10 19:28:37 2002
@@ -28,7 +28,6 @@
 	stat->atime = inode->i_atime;
 	stat->mtime = inode->i_mtime;
 	stat->ctime = inode->i_ctime;
-	stat->ctime = inode->i_ctime;
 	stat->size = inode->i_size;
 	stat->blocks = inode->i_blocks;
 	stat->blksize = inode->i_blksize;
@@ -96,8 +95,8 @@
 }
 
 #if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) \
- && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) \
- && !defined(__arm__)
+  && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__) \
+  && !defined(__arm__) && !defined(CONFIG_V850)
 
 /*
  * For backward compatibility?  Maybe this should be moved
diff -Nru a/fs/ufs/dir.c b/fs/ufs/dir.c
--- a/fs/ufs/dir.c	Sun Nov 10 19:28:41 2002
+++ b/fs/ufs/dir.c	Sun Nov 10 19:28:41 2002
@@ -353,7 +353,7 @@
 void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de,
 		struct buffer_head *bh, struct inode *inode)
 {
-	dir->i_version = ++event;
+	dir->i_version++;
 	de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino);
 	mark_buffer_dirty(bh);
 	if (IS_DIRSYNC(dir)) {
@@ -463,7 +463,7 @@
 	}
 	brelse (bh);
 	dir->i_mtime = dir->i_ctime = CURRENT_TIME;
-	dir->i_version = ++event;
+	dir->i_version++;
 	mark_inode_dirty(dir);
 
 	UFSD(("EXIT\n"))
@@ -504,7 +504,7 @@
 				fs16_add(sb, &pde->d_reclen,
 					fs16_to_cpu(sb, dir->d_reclen));
 			dir->d_ino = 0;
-			inode->i_version = ++event;
+			inode->i_version++;
 			inode->i_ctime = inode->i_mtime = CURRENT_TIME;
 			mark_inode_dirty(inode);
 			mark_buffer_dirty(bh);
diff -Nru a/fs/ufs/inode.c b/fs/ufs/inode.c
--- a/fs/ufs/inode.c	Sun Nov 10 19:28:37 2002
+++ b/fs/ufs/inode.c	Sun Nov 10 19:28:37 2002
@@ -519,7 +519,7 @@
 	inode->i_mtime = fs32_to_cpu(sb, ufs_inode->ui_mtime.tv_sec);
 	inode->i_blocks = fs32_to_cpu(sb, ufs_inode->ui_blocks);
 	inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size (for stat) */
-	inode->i_version = ++event;
+	inode->i_version++;
 	ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags);
 	ufsi->i_gen = fs32_to_cpu(sb, ufs_inode->ui_gen);
 	ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
diff -Nru a/fs/ufs/super.c b/fs/ufs/super.c
--- a/fs/ufs/super.c	Sun Nov 10 19:28:36 2002
+++ b/fs/ufs/super.c	Sun Nov 10 19:28:36 2002
@@ -1006,6 +1006,7 @@
 	ei = (struct ufs_inode_info *)kmem_cache_alloc(ufs_inode_cachep, SLAB_KERNEL);
 	if (!ei)
 		return NULL;
+	ei->vfs_inode.i_version = 1;
 	return &ei->vfs_inode;
 }
 
diff -Nru a/fs/umsdos/dir.c b/fs/umsdos/dir.c
--- a/fs/umsdos/dir.c	Sun Nov 10 19:28:39 2002
+++ b/fs/umsdos/dir.c	Sun Nov 10 19:28:39 2002
@@ -48,8 +48,8 @@
 
 struct dentry_operations umsdos_dentry_operations =
 {
-	d_revalidate:	umsdos_dentry_validate,
-	d_delete:	umsdos_dentry_dput,
+	.d_revalidate	= umsdos_dentry_validate,
+	.d_delete	= umsdos_dentry_dput,
 };
 
 struct UMSDOS_DIR_ONCE {
@@ -790,21 +790,21 @@
 
 struct file_operations umsdos_dir_operations =
 {
-	read:		generic_read_dir,
-	readdir:	UMSDOS_readdir,
-	ioctl:		UMSDOS_ioctl_dir,
+	.read		= generic_read_dir,
+	.readdir	= UMSDOS_readdir,
+	.ioctl		= UMSDOS_ioctl_dir,
 };
 
 struct inode_operations umsdos_dir_inode_operations =
 {
-	create:		UMSDOS_create,
-	lookup:		UMSDOS_lookup,
-	link:		UMSDOS_link,
-	unlink:		UMSDOS_unlink,
-	symlink:	UMSDOS_symlink,
-	mkdir:		UMSDOS_mkdir,
-	rmdir:		UMSDOS_rmdir,
-	mknod:		UMSDOS_mknod,
-	rename:		UMSDOS_rename,
-	setattr:	UMSDOS_notify_change,
+	.create		= UMSDOS_create,
+	.lookup		= UMSDOS_lookup,
+	.link		= UMSDOS_link,
+	.unlink		= UMSDOS_unlink,
+	.symlink	= UMSDOS_symlink,
+	.mkdir		= UMSDOS_mkdir,
+	.rmdir		= UMSDOS_rmdir,
+	.mknod		= UMSDOS_mknod,
+	.rename		= UMSDOS_rename,
+	.setattr	= UMSDOS_notify_change,
 };
diff -Nru a/fs/umsdos/inode.c b/fs/umsdos/inode.c
--- a/fs/umsdos/inode.c	Sun Nov 10 19:28:37 2002
+++ b/fs/umsdos/inode.c	Sun Nov 10 19:28:37 2002
@@ -108,14 +108,14 @@
 }
 
 static struct inode_operations umsdos_file_inode_operations = {
-	truncate:	fat_truncate,
-	setattr:	UMSDOS_notify_change,
+	.truncate	= fat_truncate,
+	.setattr	= UMSDOS_notify_change,
 };
 
 static struct inode_operations umsdos_symlink_inode_operations = {
-	readlink:	page_readlink,
-	follow_link:	page_follow_link,
-	setattr:	UMSDOS_notify_change,
+	.readlink	= page_readlink,
+	.follow_link	= page_follow_link,
+	.setattr	= UMSDOS_notify_change,
 };
 
 /*
@@ -335,12 +335,12 @@
 
 static struct super_operations umsdos_sops =
 {
-	write_inode:	UMSDOS_write_inode,
-	put_inode:	UMSDOS_put_inode,
-	delete_inode:	fat_delete_inode,
-	put_super:	UMSDOS_put_super,
-	statfs:		UMSDOS_statfs,
-	clear_inode:	fat_clear_inode,
+	.write_inode	= UMSDOS_write_inode,
+	.put_inode	= UMSDOS_put_inode,
+	.delete_inode	= fat_delete_inode,
+	.put_super	= UMSDOS_put_super,
+	.statfs		= UMSDOS_statfs,
+	.clear_inode	= fat_clear_inode,
 };
 
 int UMSDOS_statfs(struct super_block *sb,struct statfs *buf)
diff -Nru a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c
--- a/fs/umsdos/rdir.c	Sun Nov 10 19:28:37 2002
+++ b/fs/umsdos/rdir.c	Sun Nov 10 19:28:37 2002
@@ -231,18 +231,18 @@
  */
 struct file_operations umsdos_rdir_operations =
 {
-	read:		generic_read_dir,
-	readdir:	UMSDOS_rreaddir,
-	ioctl:		UMSDOS_ioctl_dir,
+	.read		= generic_read_dir,
+	.readdir	= UMSDOS_rreaddir,
+	.ioctl		= UMSDOS_ioctl_dir,
 };
 
 struct inode_operations umsdos_rdir_inode_operations =
 {
-	create:		msdos_create,
-	lookup:		UMSDOS_rlookup,
-	unlink:		msdos_unlink,
-	mkdir:		msdos_mkdir,
-	rmdir:		UMSDOS_rrmdir,
-	rename:		msdos_rename,
-	setattr:	UMSDOS_notify_change,
+	.create		= msdos_create,
+	.lookup		= UMSDOS_rlookup,
+	.unlink		= msdos_unlink,
+	.mkdir		= msdos_mkdir,
+	.rmdir		= UMSDOS_rrmdir,
+	.rename		= msdos_rename,
+	.setattr	= UMSDOS_notify_change,
 };
diff -Nru a/fs/xfs/Makefile b/fs/xfs/Makefile
--- a/fs/xfs/Makefile	Sun Nov 10 19:28:40 2002
+++ b/fs/xfs/Makefile	Sun Nov 10 19:28:40 2002
@@ -59,7 +59,7 @@
 				   xfs_qm_syscalls.o \
 				   xfs_qm.o
 
-xfs-obj-$(CONFIG_FS_POSIX_ACL)	+= xfs_acl.o
+xfs-obj-$(CONFIG_XFS_POSIX_ACL)	+= xfs_acl.o
 xfs-obj-$(CONFIG_FS_POSIX_CAP)	+= xfs_cap.o
 xfs-obj-$(CONFIG_FS_POSIX_MAC)	+= xfs_mac.o
 xfs-obj-$(CONFIG_PROC_FS)	+= linux/xfs_stats.o
@@ -127,6 +127,7 @@
 				   xfs_fs_subr.o \
 				   xfs_globals.o \
 				   xfs_ioctl.o \
+				   xfs_iomap.o \
 				   xfs_iops.o \
 				   xfs_lrw.o \
 				   xfs_super.o \
diff -Nru a/fs/xfs/linux/xfs_aops.c b/fs/xfs/linux/xfs_aops.c
--- a/fs/xfs/linux/xfs_aops.c	Sun Nov 10 19:28:41 2002
+++ b/fs/xfs/linux/xfs_aops.c	Sun Nov 10 19:28:41 2002
@@ -350,8 +350,22 @@
 /*
  * Calling this without startio set means we are being asked to make a dirty
  * page ready for freeing it's buffers.  When called with startio set then
- * we are coming from writepage.
+ * we are coming from writepage. 
+ *
+ * When called with startio e.g. from
+ * write page it is important that we write WHOLE page if possible. The
+ * bh->b_state's can not know of any of the blocks or which block for
+ * that matter are dirty due to map writes, and therefore bh uptodate is
+ * only vaild if the pagei itself isn't completely uptodate. Some layers
+ * may clear the page dirty flag prior to calling write page under the
+ * assumption the entire page will be written out, by not writing out the
+ * whole page the page can be reused before all vaild dirty data is
+ * written out. Note: in the case of a page that has been dirty'd by
+ * mapwrite and but partially setup by block_prepare_write the
+ * bh->b_states's will not agree and only ones setup by BPW/BCW will have
+ * valid state, thus the whole page must be written out thing.
  */
+
 STATIC int
 delalloc_convert(
 	struct page		*page,
@@ -414,7 +428,9 @@
 					unlock_buffer(bh);
 				}
 			}
-		} else if (!buffer_mapped(bh) && allocate_space) {
+		} else if (!buffer_mapped(bh) && 
+			   (buffer_uptodate(bh) || PageUptodate(page))
+			   && (allocate_space || startio)) {
 			int	size;
 
 			/* Getting here implies an unmapped buffer was found,
@@ -442,7 +458,7 @@
 				}
 			}
 		} else if (startio && buffer_mapped(bh)) {
-			if (buffer_dirty(bh) || allocate_space) {
+			if(buffer_uptodate(bh) && allocate_space) {
 				lock_buffer(bh);
 				bh_arr[cnt++] = bh;
 			}
@@ -644,6 +660,7 @@
 
 STATIC int
 linvfs_readpages(
+	struct file		*unused,
 	struct address_space	*mapping,
 	struct list_head	*pages,
 	unsigned		nr_pages)
diff -Nru a/fs/xfs/linux/xfs_iomap.c b/fs/xfs/linux/xfs_iomap.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/xfs/linux/xfs_iomap.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,892 @@
+/*
+ * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.	 Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+/*
+ *  fs/xfs/linux/xfs_lrw.c (Linux Read Write stuff)
+ *
+ */
+
+#include <xfs.h>
+#include <linux/pagemap.h>
+#include <linux/capability.h>
+
+
+#define XFS_WRITEIO_ALIGN(mp,off)	(((off) >> mp->m_writeio_log) \
+						<< mp->m_writeio_log)
+#define XFS_STRAT_WRITE_IMAPS	2
+
+STATIC int xfs_iomap_read(xfs_iocore_t *, loff_t, size_t, int, page_buf_bmap_t *,
+			int *);
+STATIC int xfs_iomap_write(xfs_iocore_t *, loff_t, size_t, page_buf_bmap_t *,
+			int *, int);
+STATIC int xfs_iomap_write_delay(xfs_iocore_t *, loff_t, size_t, page_buf_bmap_t *,
+			int *, int, int);
+STATIC int xfs_iomap_write_direct(xfs_iocore_t *, loff_t, size_t, page_buf_bmap_t *,
+			int *, int, int);
+STATIC int _xfs_imap_to_bmap(xfs_iocore_t *, xfs_off_t, xfs_bmbt_irec_t *,
+			page_buf_bmap_t *, int, int);
+
+
+int
+xfs_strategy(xfs_inode_t *ip,
+	xfs_off_t	offset,
+	ssize_t		count,
+	int		flags,
+	page_buf_bmap_t	*pbmapp,
+	int		*npbmaps)
+{
+	xfs_iocore_t	*io;
+	xfs_mount_t	*mp;
+	int		error;
+	xfs_fileoff_t	offset_fsb;
+	xfs_fileoff_t	end_fsb;
+	xfs_fileoff_t	map_start_fsb;
+	xfs_fileoff_t	last_block;
+	xfs_fsblock_t	first_block;
+	xfs_bmap_free_t free_list;
+	xfs_filblks_t	count_fsb;
+	int		committed, i, loops, nimaps;
+	int		is_xfs = 1; /* This will be a variable at some point */
+	xfs_bmbt_irec_t imap[XFS_MAX_RW_NBMAPS];
+	xfs_trans_t	*tp;
+
+	io = &ip->i_iocore;
+	mp = ip->i_mount;
+	/* is_xfs = IO_IS_XFS(io); */
+	ASSERT((ip->i_d.di_mode & IFMT) == IFREG);
+	ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) ==
+	       ((io->io_flags & XFS_IOCORE_RT) != 0));
+
+	if (XFS_FORCED_SHUTDOWN(mp))
+		return XFS_ERROR(EIO);
+
+	offset_fsb = XFS_B_TO_FSBT(mp, offset);
+	nimaps = min(XFS_MAX_RW_NBMAPS, *npbmaps);
+	end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
+	first_block = NULLFSBLOCK;
+
+	XFS_ILOCK(mp, io, XFS_ILOCK_SHARED | XFS_EXTSIZE_RD);
+	error = XFS_BMAPI(mp, NULL, io, offset_fsb,
+			(xfs_filblks_t)(end_fsb - offset_fsb),
+			XFS_BMAPI_ENTIRE, &first_block, 0, imap,
+			&nimaps, NULL);
+	XFS_IUNLOCK(mp, io, XFS_ILOCK_SHARED | XFS_EXTSIZE_RD);
+	if (error) {
+		return XFS_ERROR(error);
+	}
+
+	if (nimaps && !ISNULLSTARTBLOCK(imap[0].br_startblock)) {
+		*npbmaps = _xfs_imap_to_bmap(&ip->i_iocore, offset, imap,
+				pbmapp, nimaps, *npbmaps);
+		return 0;
+	}
+
+	/*
+	 * Make sure that the dquots are there.
+	 */
+
+	if (XFS_IS_QUOTA_ON(mp)) {
+		if (XFS_NOT_DQATTACHED(mp, ip)) {
+			if ((error = xfs_qm_dqattach(ip, 0))) {
+				return XFS_ERROR(error);
+			}
+		}
+	}
+	XFS_STATS_ADD(xfsstats.xs_xstrat_bytes,
+		XFS_FSB_TO_B(mp, imap[0].br_blockcount));
+
+	offset_fsb = imap[0].br_startoff;
+	count_fsb = imap[0].br_blockcount;
+	map_start_fsb = offset_fsb;
+	while (count_fsb != 0) {
+		/*
+		 * Set up a transaction with which to allocate the
+		 * backing store for the file.	Do allocations in a
+		 * loop until we get some space in the range we are
+		 * interested in.  The other space that might be allocated
+		 * is in the delayed allocation extent on which we sit
+		 * but before our buffer starts.
+		 */
+		nimaps = 0;
+		loops = 0;
+		while (nimaps == 0) {
+			if (is_xfs) {
+				tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
+				error = xfs_trans_reserve(tp, 0,
+						XFS_WRITE_LOG_RES(mp),
+						0, XFS_TRANS_PERM_LOG_RES,
+						XFS_WRITE_LOG_COUNT);
+				if (error) {
+					xfs_trans_cancel(tp, 0);
+					goto error0;
+				}
+				xfs_ilock(ip, XFS_ILOCK_EXCL);
+				xfs_trans_ijoin(tp, ip,
+						XFS_ILOCK_EXCL);
+				xfs_trans_ihold(tp, ip);
+			} else {
+				tp = NULL;
+				XFS_ILOCK(mp, io, XFS_ILOCK_EXCL |
+						XFS_EXTSIZE_WR);
+			}
+
+
+			/*
+			 * Allocate the backing store for the file.
+			 */
+			XFS_BMAP_INIT(&(free_list),
+					&(first_block));
+			nimaps = XFS_STRAT_WRITE_IMAPS;
+
+			/*
+			 * Ensure we don't go beyond eof - it is possible
+			 * the extents changed since we did the read call,
+			 * we dropped the ilock in the interim.
+			 */
+
+			end_fsb = XFS_B_TO_FSB(mp, XFS_SIZE(mp, io));
+			xfs_bmap_last_offset(NULL, ip, &last_block,
+				XFS_DATA_FORK);
+			last_block = XFS_FILEOFF_MAX(last_block, end_fsb);
+			if ((map_start_fsb + count_fsb) > last_block) {
+				count_fsb = last_block - map_start_fsb;
+				if (count_fsb == 0) {
+					if (is_xfs) {
+						xfs_bmap_cancel(&free_list);
+						xfs_trans_cancel(tp,
+						  (XFS_TRANS_RELEASE_LOG_RES |
+							 XFS_TRANS_ABORT));
+					}
+					XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL |
+							    XFS_EXTSIZE_WR);
+					return XFS_ERROR(EAGAIN);
+				}
+			}
+
+			error = XFS_BMAPI(mp, tp, io, map_start_fsb, count_fsb,
+					XFS_BMAPI_WRITE, &first_block, 1,
+					imap, &nimaps, &free_list);
+			if (error) {
+				xfs_bmap_cancel(&free_list);
+				xfs_trans_cancel(tp,
+					(XFS_TRANS_RELEASE_LOG_RES |
+					 XFS_TRANS_ABORT));
+				XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL |
+						    XFS_EXTSIZE_WR);
+
+				goto error0;
+			}
+
+			if (is_xfs) {
+				error = xfs_bmap_finish(&(tp), &(free_list),
+						first_block, &committed);
+				if (error) {
+					xfs_bmap_cancel(&free_list);
+					xfs_trans_cancel(tp,
+						(XFS_TRANS_RELEASE_LOG_RES |
+						XFS_TRANS_ABORT));
+					xfs_iunlock(ip, XFS_ILOCK_EXCL);
+					goto error0;
+				}
+
+				error = xfs_trans_commit(tp,
+						XFS_TRANS_RELEASE_LOG_RES,
+						NULL);
+				if (error) {
+					xfs_iunlock(ip, XFS_ILOCK_EXCL);
+					goto error0;
+				}
+			}
+
+			if (nimaps == 0) {
+				XFS_IUNLOCK(mp, io,
+						XFS_ILOCK_EXCL|XFS_EXTSIZE_WR);
+			} /* else hold 'till we maybe loop again below */
+		}
+
+		/*
+		 * See if we were able to allocate an extent that
+		 * covers at least part of the user's requested size.
+		 */
+
+		offset_fsb = XFS_B_TO_FSBT(mp, offset);
+		for(i = 0; i < nimaps; i++) {
+			int maps;
+			if (offset_fsb >= imap[i].br_startoff &&
+				(offset_fsb < (imap[i].br_startoff + imap[i].br_blockcount))) {
+				XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL | XFS_EXTSIZE_WR);
+				maps = min(nimaps, *npbmaps);
+				*npbmaps = _xfs_imap_to_bmap(io, offset, &imap[i],
+					pbmapp, maps, *npbmaps);
+				XFS_STATS_INC(xfsstats.xs_xstrat_quick);
+				return 0;
+			}
+			count_fsb -= imap[i].br_blockcount; /* for next bmapi,
+								if needed. */
+		}
+
+		/*
+		 * We didn't get an extent the caller can write into so
+		 * loop around and try starting after the last imap we got back.
+		 */
+
+		nimaps--; /* Index of last entry  */
+		ASSERT(nimaps >= 0);
+		ASSERT(offset_fsb >= imap[nimaps].br_startoff + imap[nimaps].br_blockcount);
+		ASSERT(count_fsb);
+		offset_fsb = imap[nimaps].br_startoff + imap[nimaps].br_blockcount;
+		map_start_fsb = offset_fsb;
+		XFS_STATS_INC(xfsstats.xs_xstrat_split);
+		XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_WR);
+	}
+
+	ASSERT(0);	/* Should never get here */
+
+ error0:
+	if (error) {
+		ASSERT(count_fsb != 0);
+		ASSERT(is_xfs || XFS_FORCED_SHUTDOWN(mp));
+	}
+
+	return XFS_ERROR(error);
+}
+
+
+/*
+ * xfs_bmap() is the same as the irix xfs_bmap from xfs_rw.c
+ * execpt for slight changes to the params
+ */
+int
+xfs_bmap(bhv_desc_t	*bdp,
+	xfs_off_t	offset,
+	ssize_t		count,
+	int		flags,
+	page_buf_bmap_t	*pbmapp,
+	int		*npbmaps)
+{
+	xfs_inode_t	*ip;
+	int		error;
+	int		lockmode;
+	int		fsynced = 0;
+	vnode_t		*vp;
+
+	ip = XFS_BHVTOI(bdp);
+	ASSERT((ip->i_d.di_mode & IFMT) == IFREG);
+	ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) ==
+	       ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0));
+
+	if (XFS_FORCED_SHUTDOWN(ip->i_iocore.io_mount))
+		return XFS_ERROR(EIO);
+
+	if (flags & PBF_READ) {
+		lockmode = xfs_ilock_map_shared(ip);
+		error = xfs_iomap_read(&ip->i_iocore, offset, count,
+				 XFS_BMAPI_ENTIRE, pbmapp, npbmaps);
+		xfs_iunlock_map_shared(ip, lockmode);
+	} else if (flags & PBF_FILE_ALLOCATE) {
+		error = xfs_strategy(ip, offset, count, flags,
+				pbmapp, npbmaps);
+	} else { /* PBF_WRITE */
+		ASSERT(flags & PBF_WRITE);
+		vp = BHV_TO_VNODE(bdp);
+		xfs_ilock(ip, XFS_ILOCK_EXCL);
+
+		/*
+		 * Make sure that the dquots are there. This doesn't hold
+		 * the ilock across a disk read.
+		 */
+
+		if (XFS_IS_QUOTA_ON(ip->i_mount)) {
+			if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
+				if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) {
+					xfs_iunlock(ip, XFS_ILOCK_EXCL);
+					return XFS_ERROR(error);
+				}
+			}
+		}
+retry:
+		error = xfs_iomap_write(&ip->i_iocore, offset, count,
+					pbmapp, npbmaps, flags);
+		/* xfs_iomap_write unlocks/locks/unlocks */
+
+		if (error == ENOSPC) {
+			switch (fsynced) {
+			case 0:
+				if (ip->i_delayed_blks) {
+					filemap_fdatawrite(LINVFS_GET_IP(vp)->i_mapping);
+					fsynced = 1;
+				} else {
+					fsynced = 2;
+					flags |= PBF_SYNC;
+				}
+				error = 0;
+				xfs_ilock(ip, XFS_ILOCK_EXCL);
+				goto retry;
+			case 1:
+				fsynced = 2;
+				if (!(flags & PBF_SYNC)) {
+					flags |= PBF_SYNC;
+					error = 0;
+					xfs_ilock(ip, XFS_ILOCK_EXCL);
+					goto retry;
+				}
+			case 2:
+				sync_blockdev(vp->v_vfsp->vfs_super->s_bdev);
+				xfs_log_force(ip->i_mount, (xfs_lsn_t)0,
+						XFS_LOG_FORCE|XFS_LOG_SYNC);
+
+				error = 0;
+/**
+				delay(HZ);
+**/
+				fsynced++;
+				xfs_ilock(ip, XFS_ILOCK_EXCL);
+				goto retry;
+			}
+		}
+	}
+
+	return XFS_ERROR(error);
+}
+
+
+STATIC int
+_xfs_imap_to_bmap(
+	xfs_iocore_t	*io,
+	xfs_off_t	offset,
+	xfs_bmbt_irec_t *imap,
+	page_buf_bmap_t	*pbmapp,
+	int		imaps,			/* Number of imap entries */
+	int		pbmaps)			/* Number of pbmap entries */
+{
+	xfs_mount_t	*mp;
+	xfs_fsize_t	nisize;
+	int		im, pbm;
+	xfs_fsblock_t	start_block;
+
+	mp = io->io_mount;
+	nisize = XFS_SIZE(mp, io);
+	if (io->io_new_size > nisize)
+		nisize = io->io_new_size;
+
+	for (im=0, pbm=0; im < imaps && pbm < pbmaps; im++,pbmapp++,imap++,pbm++) {
+		pbmapp->pbm_target = io->io_flags & XFS_IOCORE_RT ?
+			mp->m_rtdev_targp :
+			mp->m_ddev_targp;
+		pbmapp->pbm_offset = XFS_FSB_TO_B(mp, imap->br_startoff);
+		pbmapp->pbm_delta = offset - pbmapp->pbm_offset;
+		pbmapp->pbm_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount);
+		pbmapp->pbm_flags = 0;
+
+		start_block = imap->br_startblock;
+		if (start_block == HOLESTARTBLOCK) {
+			pbmapp->pbm_bn = PAGE_BUF_DADDR_NULL;
+			pbmapp->pbm_flags = PBMF_HOLE;
+		} else if (start_block == DELAYSTARTBLOCK) {
+			pbmapp->pbm_bn = PAGE_BUF_DADDR_NULL;
+			pbmapp->pbm_flags = PBMF_DELAY;
+		} else {
+			pbmapp->pbm_bn = XFS_FSB_TO_DB_IO(io, start_block);
+			if (imap->br_state == XFS_EXT_UNWRITTEN)
+				pbmapp->pbm_flags |= PBMF_UNWRITTEN;
+		}
+
+		if ((pbmapp->pbm_offset + pbmapp->pbm_bsize) >= nisize) {
+			pbmapp->pbm_flags |= PBMF_EOF;
+		}
+
+		offset += pbmapp->pbm_bsize - pbmapp->pbm_delta;
+	}
+	return(pbm);	/* Return the number filled */
+}
+
+STATIC int
+xfs_iomap_read(
+	xfs_iocore_t	*io,
+	loff_t		offset,
+	size_t		count,
+	int		flags,
+	page_buf_bmap_t	*pbmapp,
+	int		*npbmaps)
+{
+	xfs_fileoff_t	offset_fsb;
+	xfs_fileoff_t	end_fsb;
+	int		nimaps;
+	int		error;
+	xfs_mount_t	*mp;
+	xfs_bmbt_irec_t imap[XFS_MAX_RW_NBMAPS];
+
+	ASSERT(ismrlocked(io->io_lock, MR_UPDATE | MR_ACCESS) != 0);
+
+	mp = io->io_mount;
+	offset_fsb = XFS_B_TO_FSBT(mp, offset);
+	nimaps = sizeof(imap) / sizeof(imap[0]);
+	nimaps = min(nimaps, *npbmaps); /* Don't ask for more than caller has */
+	end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
+	error = XFS_BMAPI(mp, NULL, io, offset_fsb,
+				(xfs_filblks_t)(end_fsb - offset_fsb),
+				flags, NULL, 0, imap,
+				&nimaps, NULL);
+	if (error) {
+		return XFS_ERROR(error);
+	}
+
+	if(nimaps) {
+		*npbmaps = _xfs_imap_to_bmap(io, offset, imap, pbmapp, nimaps,
+			*npbmaps);
+	} else
+		*npbmaps = 0;
+	return XFS_ERROR(error);
+}
+
+/*
+ * xfs_iomap_write: return pagebuf_bmap_t's telling higher layers
+ *	where to write.
+ * There are 2 main cases:
+ *	1 the extents already exist
+ *	2 must allocate.
+ *	There are 3 cases when we allocate:
+ *		delay allocation (doesn't really allocate or use transactions)
+ *		direct allocation (no previous delay allocation
+ *		convert delay to real allocations
+ */
+
+STATIC int
+xfs_iomap_write(
+	xfs_iocore_t	*io,
+	loff_t		offset,
+	size_t		count,
+	page_buf_bmap_t	*pbmapp,
+	int		*npbmaps,
+	int		ioflag)
+{
+	int		maps;
+	int		error = 0;
+	int		found;
+	int		flags = 0;
+
+	maps = *npbmaps;
+	if (!maps)
+		goto out;
+
+	/*
+	 * If we have extents that are allocated for this range,
+	 * return them.
+	 */
+
+	found = 0;
+	error = xfs_iomap_read(io, offset, count, flags, pbmapp, npbmaps);
+	if (error)
+		goto out;
+
+	/*
+	 * If we found mappings and they can just have data written
+	 * without conversion,
+	 * let the caller write these and call us again.
+	 *
+	 * If we have a HOLE or UNWRITTEN, proceed down lower to
+	 * get the space or to convert to written.
+	 */
+
+	if (*npbmaps) {
+		if (!(pbmapp->pbm_flags & PBMF_HOLE)) {
+			*npbmaps = 1; /* Only checked the first one. */
+					/* We could check more, ... */
+			goto out;
+		}
+	}
+	found = *npbmaps;
+	*npbmaps = maps; /* Restore to original requested */
+
+	if (ioflag & PBF_DIRECT) {
+		error = xfs_iomap_write_direct(io, offset, count, pbmapp,
+					npbmaps, ioflag, found);
+	} else {
+		error = xfs_iomap_write_delay(io, offset, count, pbmapp,
+				npbmaps, ioflag, found);
+	}
+
+out:
+	XFS_IUNLOCK(io->io_mount, io, XFS_ILOCK_EXCL);
+	return XFS_ERROR(error);
+}
+
+STATIC int
+xfs_iomap_write_delay(
+	xfs_iocore_t	*io,
+	loff_t		offset,
+	size_t		count,
+	page_buf_bmap_t	*pbmapp,
+	int		*npbmaps,
+	int		ioflag,
+	int		found)
+{
+	xfs_fileoff_t	offset_fsb;
+	xfs_fileoff_t	ioalign;
+	xfs_fileoff_t	last_fsb;
+	xfs_fileoff_t	start_fsb;
+	xfs_filblks_t	count_fsb;
+	xfs_off_t	aligned_offset;
+	xfs_fsize_t	isize;
+	xfs_fsblock_t	firstblock;
+	int		nimaps;
+	int		error;
+	int		n;
+	unsigned int	iosize;
+	xfs_mount_t	*mp;
+#define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP
+	xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS];
+	int		aeof;
+
+	ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0);
+
+	mp = io->io_mount;
+
+	isize = XFS_SIZE(mp, io);
+	if (io->io_new_size > isize) {
+		isize = io->io_new_size;
+	}
+
+	aeof = 0;
+	offset_fsb = XFS_B_TO_FSBT(mp, offset);
+	last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
+	/*
+	 * If the caller is doing a write at the end of the file,
+	 * then extend the allocation (and the buffer used for the write)
+	 * out to the file system's write iosize.  We clean up any extra
+	 * space left over when the file is closed in xfs_inactive().
+	 * We can only do this if we are sure that we will create buffers
+	 * over all of the space we allocate beyond the end of the file.
+	 * Not doing so would allow us to create delalloc blocks with
+	 * no pages in memory covering them.  So, we need to check that
+	 * there are not any real blocks in the area beyond the end of
+	 * the file which we are optimistically going to preallocate. If
+	 * there are then our buffers will stop when they encounter them
+	 * and we may accidentally create delalloc blocks beyond them
+	 * that we never cover with a buffer.  All of this is because
+	 * we are not actually going to write the extra blocks preallocated
+	 * at this point.
+	 *
+	 * We don't bother with this for sync writes, because we need
+	 * to minimize the amount we write for good performance.
+	 */
+	if (!(ioflag & PBF_SYNC) && ((offset + count) > XFS_SIZE(mp, io))) {
+		start_fsb = XFS_B_TO_FSBT(mp,
+				  ((xfs_ufsize_t)(offset + count - 1)));
+		count_fsb = mp->m_writeio_blocks;
+		while (count_fsb > 0) {
+			nimaps = XFS_WRITE_IMAPS;
+			error = XFS_BMAPI(mp, NULL, io, start_fsb, count_fsb,
+					  0, NULL, 0, imap, &nimaps,
+					  NULL);
+			if (error) {
+				return error;
+			}
+			for (n = 0; n < nimaps; n++) {
+				if ((imap[n].br_startblock != HOLESTARTBLOCK) &&
+				    (imap[n].br_startblock != DELAYSTARTBLOCK)) {
+					goto write_map;
+				}
+				start_fsb += imap[n].br_blockcount;
+				count_fsb -= imap[n].br_blockcount;
+				ASSERT(count_fsb < 0xffff000);
+			}
+		}
+		iosize = mp->m_writeio_blocks;
+		aligned_offset = XFS_WRITEIO_ALIGN(mp, (offset + count - 1));
+		ioalign = XFS_B_TO_FSBT(mp, aligned_offset);
+		last_fsb = ioalign + iosize;
+		aeof = 1;
+	}
+ write_map:
+	nimaps = XFS_WRITE_IMAPS;
+	firstblock = NULLFSBLOCK;
+
+	/*
+	 * roundup the allocation request to m_dalign boundary if file size
+	 * is greater that 512K and we are allocating past the allocation eof
+	 */
+	if (mp->m_dalign && (XFS_SIZE(mp, io) >= mp->m_dalign) && aeof) {
+		int eof;
+		xfs_fileoff_t new_last_fsb;
+		new_last_fsb = roundup_64(last_fsb, mp->m_dalign);
+		error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof);
+		if (error) {
+			return error;
+		}
+		if (eof) {
+			last_fsb = new_last_fsb;
+		}
+	}
+
+	error = XFS_BMAPI(mp, NULL, io, offset_fsb,
+			  (xfs_filblks_t)(last_fsb - offset_fsb),
+			  XFS_BMAPI_DELAY | XFS_BMAPI_WRITE |
+			  XFS_BMAPI_ENTIRE, &firstblock, 1, imap,
+			  &nimaps, NULL);
+	/*
+	 * This can be EDQUOT, if nimaps == 0
+	 */
+	if (error) {
+		return XFS_ERROR(error);
+	}
+	/*
+	 * If bmapi returned us nothing, and if we didn't get back EDQUOT,
+	 * then we must have run out of space.
+	 */
+	if (nimaps == 0) {
+		return XFS_ERROR(ENOSPC);
+	}
+
+	/*
+	 * Now map our desired I/O size and alignment over the
+	 * extents returned by xfs_bmapi().
+	 */
+	*npbmaps = _xfs_imap_to_bmap(io, offset, imap, pbmapp,
+						nimaps, *npbmaps);
+	return 0;
+}
+
+STATIC int
+xfs_iomap_write_direct(
+	xfs_iocore_t	*io,
+	loff_t		offset,
+	size_t		count,
+	page_buf_bmap_t	*pbmapp,
+	int		*npbmaps,
+	int		ioflag,
+	int		found)
+{
+	xfs_inode_t	*ip = XFS_IO_INODE(io);
+	xfs_mount_t	*mp;
+	xfs_fileoff_t	offset_fsb;
+	xfs_fileoff_t	last_fsb;
+	xfs_filblks_t	count_fsb;
+	xfs_fsize_t	isize;
+	xfs_fsblock_t	firstfsb;
+	int		nimaps, maps;
+	int		error;
+	xfs_trans_t	*tp;
+
+#define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP
+	xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS], *imapp;
+	xfs_bmap_free_t free_list;
+	int		aeof;
+	int		bmapi_flags;
+	xfs_filblks_t	datablocks;
+	int		rt;
+	int		committed;
+	int		numrtextents;
+	uint		resblks;
+	int		rtextsize;
+
+	maps = min(XFS_WRITE_IMAPS, *npbmaps);
+	nimaps = maps;
+
+	mp = io->io_mount;
+	isize = XFS_SIZE(mp, io);
+	if (io->io_new_size > isize)
+		isize = io->io_new_size;
+
+	if ((offset + count) > isize) {
+		aeof = 1;
+	} else {
+		aeof = 0;
+	}
+
+	offset_fsb = XFS_B_TO_FSBT(mp, offset);
+	last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
+	count_fsb = last_fsb - offset_fsb;
+	if (found && (pbmapp->pbm_flags & PBMF_HOLE)) {
+		xfs_fileoff_t	map_last_fsb;
+		map_last_fsb = XFS_B_TO_FSB(mp,
+			(pbmapp->pbm_bsize + pbmapp->pbm_offset));
+
+		if (map_last_fsb < last_fsb) {
+			last_fsb = map_last_fsb;
+			count_fsb = last_fsb - offset_fsb;
+		}
+		ASSERT(count_fsb > 0);
+	}
+
+	/*
+	 * roundup the allocation request to m_dalign boundary if file size
+	 * is greater that 512K and we are allocating past the allocation eof
+	 */
+	if (!found && mp->m_dalign && (isize >= 524288) && aeof) {
+		int eof;
+		xfs_fileoff_t new_last_fsb;
+		new_last_fsb = roundup_64(last_fsb, mp->m_dalign);
+		printk("xfs_iomap_write_direct: about to XFS_BMAP_EOF %Ld\n",
+			new_last_fsb);
+		error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof);
+		if (error) {
+			goto error_out;
+		}
+		if (eof)
+			last_fsb = new_last_fsb;
+	}
+
+	bmapi_flags = XFS_BMAPI_WRITE|XFS_BMAPI_DIRECT_IO|XFS_BMAPI_ENTIRE;
+	bmapi_flags &= ~XFS_BMAPI_DIRECT_IO;
+
+	/*
+	 * determine if this is a realtime file
+	 */
+	if ((rt = (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) != 0) {
+		rtextsize = mp->m_sb.sb_rextsize;
+	} else
+		rtextsize = 0;
+
+	error = 0;
+
+	/*
+	 * allocate file space for the bmapp entries passed in.
+	 */
+
+	/*
+	 * determine if reserving space on
+	 * the data or realtime partition.
+	 */
+	if (rt) {
+		numrtextents = (count_fsb + rtextsize - 1);
+		do_div(numrtextents, rtextsize);
+		datablocks = 0;
+	} else {
+		datablocks = count_fsb;
+		numrtextents = 0;
+	}
+
+	/*
+	 * allocate and setup the transaction
+	 */
+	tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
+	resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks);
+
+	xfs_iunlock(ip, XFS_ILOCK_EXCL);
+
+	error = xfs_trans_reserve(tp,
+				  resblks,
+				  XFS_WRITE_LOG_RES(mp),
+				  numrtextents,
+				  XFS_TRANS_PERM_LOG_RES,
+				  XFS_WRITE_LOG_COUNT);
+
+	/*
+	 * check for running out of space
+	 */
+	if (error) {
+		/*
+		 * Free the transaction structure.
+		 */
+		xfs_trans_cancel(tp, 0);
+	}
+
+	xfs_ilock(ip, XFS_ILOCK_EXCL);
+
+	if (error)  {
+		goto error_out; /* Don't return in above if .. trans ..,
+					need lock to return */
+	}
+
+	if (XFS_IS_QUOTA_ON(mp)) {
+		if (xfs_trans_reserve_quota(tp,
+					    ip->i_udquot,
+					    ip->i_gdquot,
+					    resblks, 0, 0)) {
+			error = (EDQUOT);
+			goto error1;
+		}
+		nimaps = 1;
+	} else {
+		nimaps = 2;
+	}
+
+	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
+	xfs_trans_ihold(tp, ip);
+
+	/*
+	 * issue the bmapi() call to allocate the blocks
+	 */
+	XFS_BMAP_INIT(&free_list, &firstfsb);
+	imapp = &imap[0];
+	error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb,
+		bmapi_flags, &firstfsb, 1, imapp, &nimaps, &free_list);
+	if (error) {
+		goto error0;
+	}
+
+	/*
+	 * complete the transaction
+	 */
+
+	error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed);
+	if (error) {
+		goto error0;
+	}
+
+	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
+	if (error) {
+		goto error_out;
+	}
+
+	/* copy any maps to caller's array and return any error. */
+	if (nimaps == 0) {
+		error = (ENOSPC);
+		goto error_out;
+	}
+
+	maps = min(nimaps, maps);
+	*npbmaps = _xfs_imap_to_bmap(io, offset, &imap[0], pbmapp, maps,
+								*npbmaps);
+	if(*npbmaps) {
+		/*
+		 * this is new since xfs_iomap_read
+		 * didn't find it.
+		 */
+		if (*npbmaps != 1) {
+			printk("NEED MORE WORK FOR MULTIPLE BMAPS (which are new)\n");
+		}
+	}
+	goto out;
+
+ error0:	/* Cancel bmap, unlock inode, and cancel trans */
+	xfs_bmap_cancel(&free_list);
+
+ error1:	/* Just cancel transaction */
+	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
+	*npbmaps = 0;	/* nothing set-up here */
+
+error_out:
+out:	/* Just return error and any tracing at end of routine */
+	return XFS_ERROR(error);
+}
+
diff -Nru a/fs/xfs/linux/xfs_iops.c b/fs/xfs/linux/xfs_iops.c
--- a/fs/xfs/linux/xfs_iops.c	Sun Nov 10 19:28:38 2002
+++ b/fs/xfs/linux/xfs_iops.c	Sun Nov 10 19:28:38 2002
@@ -52,17 +52,17 @@
 	ip->i_blocks = va.va_nblocks;
 }
 
-#ifdef CONFIG_FS_POSIX_ACL
 /*
  * Determine whether a process has a valid fs_struct (kernel daemons
  * like knfsd don't have an fs_struct).
+ *
+ * XXX(hch):  nfsd is broken, better fix it instead.
  */
 STATIC int inline
 has_fs_struct(struct task_struct *task)
 {
 	return (task->fs != init_task.fs);
 }
-#endif
 
 STATIC int
 linvfs_mknod(
@@ -81,15 +81,8 @@
 	if (test_default_acl)
 		have_default_acl = test_default_acl(dvp);
 
-#ifdef CONFIG_FS_POSIX_ACL
-	/*
-	 * Conditionally compiled so that the ACL base kernel changes can be
-	 * split out into separate patches - remove this once MS_POSIXACL is
-	 * accepted, or some other way to implement this exists.
-	 */
 	if (IS_POSIXACL(dir) && !have_default_acl && has_fs_struct(current))
 		mode &= ~current->fs->umask;
-#endif
 
 	memset(&va, 0, sizeof(va));
 	va.va_mask = AT_TYPE|AT_MODE;
diff -Nru a/fs/xfs/linux/xfs_linux.h b/fs/xfs/linux/xfs_linux.h
--- a/fs/xfs/linux/xfs_linux.h	Sun Nov 10 19:28:36 2002
+++ b/fs/xfs/linux/xfs_linux.h	Sun Nov 10 19:28:36 2002
@@ -60,6 +60,7 @@
 #include <linux/xfs_super.h>
 #include <linux/xfs_globals.h>
 #include <linux/xfs_fs_subr.h>
+#include <linux/xfs_lrw.h>
 
 #include <pagebuf/page_buf.h>
 
@@ -152,11 +153,8 @@
 #define EFSCORRUPTED	990		/* Filesystem is corrupted */
 
 #define SYNCHRONIZE()	barrier()
-#define lbolt		jiffies
 #define rootdev		ROOT_DEV
 #define __return_address __builtin_return_address(0)
-#define LONGLONG_MAX	9223372036854775807LL	/* max "long long int" */
-#define nopkg()		( ENOSYS )
 
 /* IRIX uses a dynamic sizing algorithm (ndquot = 200 + numprocs*2) */
 /* we may well need to fine-tune this if it ever becomes an issue.  */
diff -Nru a/fs/xfs/linux/xfs_lrw.c b/fs/xfs/linux/xfs_lrw.c
--- a/fs/xfs/linux/xfs_lrw.c	Sun Nov 10 19:28:36 2002
+++ b/fs/xfs/linux/xfs_lrw.c	Sun Nov 10 19:28:36 2002
@@ -39,22 +39,6 @@
 #include <linux/capability.h>
 
 
-#define XFS_WRITEIO_ALIGN(mp,off)	(((off) >> mp->m_writeio_log) \
-						<< mp->m_writeio_log)
-#define XFS_STRAT_WRITE_IMAPS	2
-
-STATIC int xfs_iomap_read(xfs_iocore_t *, loff_t, size_t, int, page_buf_bmap_t *,
-			int *);
-STATIC int xfs_iomap_write(xfs_iocore_t *, loff_t, size_t, page_buf_bmap_t *,
-			int *, int);
-STATIC int xfs_iomap_write_delay(xfs_iocore_t *, loff_t, size_t, page_buf_bmap_t *,
-			int *, int, int);
-STATIC int xfs_iomap_write_direct(xfs_iocore_t *, loff_t, size_t, page_buf_bmap_t *,
-			int *, int, int);
-STATIC int _xfs_imap_to_bmap(xfs_iocore_t *, xfs_off_t, xfs_bmbt_irec_t *,
-			page_buf_bmap_t *, int, int);
-
-
 /*
  *	xfs_iozero
  *
@@ -743,999 +727,11 @@
 		}
 	} /* (ioflags & O_SYNC) */
 
-	/*
-	 * If we are coming from an nfsd thread then insert into the
-	 * reference cache.
-	 */
-
-	if (!strcmp(current->comm, "nfsd"))
-		xfs_refcache_insert(xip);
-
-	/* Drop lock this way - the old refcache release is in here */
 	xfs_rwunlock(bdp, locktype);
-
 	return(ret);
 }
 
 
-int
-xfs_strategy(xfs_inode_t *ip,
-	xfs_off_t	offset,
-	ssize_t		count,
-	int		flags,
-	page_buf_bmap_t	*pbmapp,
-	int		*npbmaps)
-{
-	xfs_iocore_t	*io;
-	xfs_mount_t	*mp;
-	int		error;
-	xfs_fileoff_t	offset_fsb;
-	xfs_fileoff_t	end_fsb;
-	xfs_fileoff_t	map_start_fsb;
-	xfs_fileoff_t	last_block;
-	xfs_fsblock_t	first_block;
-	xfs_bmap_free_t free_list;
-	xfs_filblks_t	count_fsb;
-	int		committed, i, loops, nimaps;
-	int		is_xfs = 1; /* This will be a variable at some point */
-	xfs_bmbt_irec_t imap[XFS_MAX_RW_NBMAPS];
-	xfs_trans_t	*tp;
-
-	io = &ip->i_iocore;
-	mp = ip->i_mount;
-	/* is_xfs = IO_IS_XFS(io); */
-	ASSERT((ip->i_d.di_mode & IFMT) == IFREG);
-	ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) ==
-	       ((io->io_flags & XFS_IOCORE_RT) != 0));
-
-	if (XFS_FORCED_SHUTDOWN(mp))
-		return XFS_ERROR(EIO);
-
-	offset_fsb = XFS_B_TO_FSBT(mp, offset);
-	nimaps = min(XFS_MAX_RW_NBMAPS, *npbmaps);
-	end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
-	first_block = NULLFSBLOCK;
-
-	XFS_ILOCK(mp, io, XFS_ILOCK_SHARED | XFS_EXTSIZE_RD);
-	error = XFS_BMAPI(mp, NULL, io, offset_fsb,
-			(xfs_filblks_t)(end_fsb - offset_fsb),
-			XFS_BMAPI_ENTIRE, &first_block, 0, imap,
-			&nimaps, NULL);
-	XFS_IUNLOCK(mp, io, XFS_ILOCK_SHARED | XFS_EXTSIZE_RD);
-	if (error) {
-		return XFS_ERROR(error);
-	}
-
-	if (nimaps && !ISNULLSTARTBLOCK(imap[0].br_startblock)) {
-		*npbmaps = _xfs_imap_to_bmap(&ip->i_iocore, offset, imap,
-				pbmapp, nimaps, *npbmaps);
-		return 0;
-	}
-
-	/*
-	 * Make sure that the dquots are there.
-	 */
-
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if (XFS_NOT_DQATTACHED(mp, ip)) {
-			if ((error = xfs_qm_dqattach(ip, 0))) {
-				return XFS_ERROR(error);
-			}
-		}
-	}
-	XFS_STATS_ADD(xfsstats.xs_xstrat_bytes,
-		XFS_FSB_TO_B(mp, imap[0].br_blockcount));
-
-	offset_fsb = imap[0].br_startoff;
-	count_fsb = imap[0].br_blockcount;
-	map_start_fsb = offset_fsb;
-	while (count_fsb != 0) {
-		/*
-		 * Set up a transaction with which to allocate the
-		 * backing store for the file.	Do allocations in a
-		 * loop until we get some space in the range we are
-		 * interested in.  The other space that might be allocated
-		 * is in the delayed allocation extent on which we sit
-		 * but before our buffer starts.
-		 */
-		nimaps = 0;
-		loops = 0;
-		while (nimaps == 0) {
-			if (is_xfs) {
-				tp = xfs_trans_alloc(mp, XFS_TRANS_STRAT_WRITE);
-				error = xfs_trans_reserve(tp, 0,
-						XFS_WRITE_LOG_RES(mp),
-						0, XFS_TRANS_PERM_LOG_RES,
-						XFS_WRITE_LOG_COUNT);
-				if (error) {
-					xfs_trans_cancel(tp, 0);
-					goto error0;
-				}
-				xfs_ilock(ip, XFS_ILOCK_EXCL);
-				xfs_trans_ijoin(tp, ip,
-						XFS_ILOCK_EXCL);
-				xfs_trans_ihold(tp, ip);
-			} else {
-				tp = NULL;
-				XFS_ILOCK(mp, io, XFS_ILOCK_EXCL |
-						XFS_EXTSIZE_WR);
-			}
-
-
-			/*
-			 * Allocate the backing store for the file.
-			 */
-			XFS_BMAP_INIT(&(free_list),
-					&(first_block));
-			nimaps = XFS_STRAT_WRITE_IMAPS;
-
-			/*
-			 * Ensure we don't go beyond eof - it is possible
-			 * the extents changed since we did the read call,
-			 * we dropped the ilock in the interim.
-			 */
-
-			end_fsb = XFS_B_TO_FSB(mp, XFS_SIZE(mp, io));
-			xfs_bmap_last_offset(NULL, ip, &last_block,
-				XFS_DATA_FORK);
-			last_block = XFS_FILEOFF_MAX(last_block, end_fsb);
-			if ((map_start_fsb + count_fsb) > last_block) {
-				count_fsb = last_block - map_start_fsb;
-				if (count_fsb == 0) {
-					if (is_xfs) {
-						xfs_bmap_cancel(&free_list);
-						xfs_trans_cancel(tp,
-						  (XFS_TRANS_RELEASE_LOG_RES |
-							 XFS_TRANS_ABORT));
-					}
-					XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL |
-							    XFS_EXTSIZE_WR);
-					return XFS_ERROR(EAGAIN);
-				}
-			}
-
-			error = XFS_BMAPI(mp, tp, io, map_start_fsb, count_fsb,
-					XFS_BMAPI_WRITE, &first_block, 1,
-					imap, &nimaps, &free_list);
-			if (error) {
-				xfs_bmap_cancel(&free_list);
-				xfs_trans_cancel(tp,
-					(XFS_TRANS_RELEASE_LOG_RES |
-					 XFS_TRANS_ABORT));
-				XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL |
-						    XFS_EXTSIZE_WR);
-
-				goto error0;
-			}
-
-			if (is_xfs) {
-				error = xfs_bmap_finish(&(tp), &(free_list),
-						first_block, &committed);
-				if (error) {
-					xfs_bmap_cancel(&free_list);
-					xfs_trans_cancel(tp,
-						(XFS_TRANS_RELEASE_LOG_RES |
-						XFS_TRANS_ABORT));
-					xfs_iunlock(ip, XFS_ILOCK_EXCL);
-					goto error0;
-				}
-
-				error = xfs_trans_commit(tp,
-						XFS_TRANS_RELEASE_LOG_RES,
-						NULL);
-				if (error) {
-					xfs_iunlock(ip, XFS_ILOCK_EXCL);
-					goto error0;
-				}
-			}
-
-			if (nimaps == 0) {
-				XFS_IUNLOCK(mp, io,
-						XFS_ILOCK_EXCL|XFS_EXTSIZE_WR);
-			} /* else hold 'till we maybe loop again below */
-		}
-
-		/*
-		 * See if we were able to allocate an extent that
-		 * covers at least part of the user's requested size.
-		 */
-
-		offset_fsb = XFS_B_TO_FSBT(mp, offset);
-		for(i = 0; i < nimaps; i++) {
-			int maps;
-			if (offset_fsb >= imap[i].br_startoff &&
-				(offset_fsb < (imap[i].br_startoff + imap[i].br_blockcount))) {
-				XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL | XFS_EXTSIZE_WR);
-				maps = min(nimaps, *npbmaps);
-				*npbmaps = _xfs_imap_to_bmap(io, offset, &imap[i],
-					pbmapp, maps, *npbmaps);
-				XFS_STATS_INC(xfsstats.xs_xstrat_quick);
-				return 0;
-			}
-			count_fsb -= imap[i].br_blockcount; /* for next bmapi,
-								if needed. */
-		}
-
-		/*
-		 * We didn't get an extent the caller can write into so
-		 * loop around and try starting after the last imap we got back.
-		 */
-
-		nimaps--; /* Index of last entry  */
-		ASSERT(nimaps >= 0);
-		ASSERT(offset_fsb >= imap[nimaps].br_startoff + imap[nimaps].br_blockcount);
-		ASSERT(count_fsb);
-		offset_fsb = imap[nimaps].br_startoff + imap[nimaps].br_blockcount;
-		map_start_fsb = offset_fsb;
-		XFS_STATS_INC(xfsstats.xs_xstrat_split);
-		XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_WR);
-	}
-
-	ASSERT(0);	/* Should never get here */
-
- error0:
-	if (error) {
-		ASSERT(count_fsb != 0);
-		ASSERT(is_xfs || XFS_FORCED_SHUTDOWN(mp));
-	}
-
-	return XFS_ERROR(error);
-}
-
-
-/*
- * xfs_bmap() is the same as the irix xfs_bmap from xfs_rw.c
- * execpt for slight changes to the params
- */
-int
-xfs_bmap(bhv_desc_t	*bdp,
-	xfs_off_t	offset,
-	ssize_t		count,
-	int		flags,
-	page_buf_bmap_t	*pbmapp,
-	int		*npbmaps)
-{
-	xfs_inode_t	*ip;
-	int		error;
-	int		lockmode;
-	int		fsynced = 0;
-	vnode_t		*vp;
-
-	ip = XFS_BHVTOI(bdp);
-	ASSERT((ip->i_d.di_mode & IFMT) == IFREG);
-	ASSERT(((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) != 0) ==
-	       ((ip->i_iocore.io_flags & XFS_IOCORE_RT) != 0));
-
-	if (XFS_FORCED_SHUTDOWN(ip->i_iocore.io_mount))
-		return XFS_ERROR(EIO);
-
-	if (flags & PBF_READ) {
-		lockmode = xfs_ilock_map_shared(ip);
-		error = xfs_iomap_read(&ip->i_iocore, offset, count,
-				 XFS_BMAPI_ENTIRE, pbmapp, npbmaps);
-		xfs_iunlock_map_shared(ip, lockmode);
-	} else if (flags & PBF_FILE_ALLOCATE) {
-		error = xfs_strategy(ip, offset, count, flags,
-				pbmapp, npbmaps);
-	} else { /* PBF_WRITE */
-		ASSERT(flags & PBF_WRITE);
-		vp = BHV_TO_VNODE(bdp);
-		xfs_ilock(ip, XFS_ILOCK_EXCL);
-
-		/*
-		 * Make sure that the dquots are there. This doesn't hold
-		 * the ilock across a disk read.
-		 */
-
-		if (XFS_IS_QUOTA_ON(ip->i_mount)) {
-			if (XFS_NOT_DQATTACHED(ip->i_mount, ip)) {
-				if ((error = xfs_qm_dqattach(ip, XFS_QMOPT_ILOCKED))) {
-					xfs_iunlock(ip, XFS_ILOCK_EXCL);
-					return XFS_ERROR(error);
-				}
-			}
-		}
-retry:
-		error = xfs_iomap_write(&ip->i_iocore, offset, count,
-					pbmapp, npbmaps, flags);
-		/* xfs_iomap_write unlocks/locks/unlocks */
-
-		if (error == ENOSPC) {
-			switch (fsynced) {
-			case 0:
-				if (ip->i_delayed_blks) {
-					filemap_fdatawrite(LINVFS_GET_IP(vp)->i_mapping);
-					fsynced = 1;
-				} else {
-					fsynced = 2;
-					flags |= PBF_SYNC;
-				}
-				error = 0;
-				xfs_ilock(ip, XFS_ILOCK_EXCL);
-				goto retry;
-			case 1:
-				fsynced = 2;
-				if (!(flags & PBF_SYNC)) {
-					flags |= PBF_SYNC;
-					error = 0;
-					xfs_ilock(ip, XFS_ILOCK_EXCL);
-					goto retry;
-				}
-			case 2:
-				sync_blockdev(vp->v_vfsp->vfs_super->s_bdev);
-				xfs_log_force(ip->i_mount, (xfs_lsn_t)0,
-						XFS_LOG_FORCE|XFS_LOG_SYNC);
-
-				error = 0;
-/**
-				delay(HZ);
-**/
-				fsynced++;
-				xfs_ilock(ip, XFS_ILOCK_EXCL);
-				goto retry;
-			}
-		}
-	}
-
-	return XFS_ERROR(error);
-}
-
-
-STATIC int
-_xfs_imap_to_bmap(
-	xfs_iocore_t	*io,
-	xfs_off_t	offset,
-	xfs_bmbt_irec_t *imap,
-	page_buf_bmap_t	*pbmapp,
-	int		imaps,			/* Number of imap entries */
-	int		pbmaps)			/* Number of pbmap entries */
-{
-	xfs_mount_t	*mp;
-	xfs_fsize_t	nisize;
-	int		im, pbm;
-	xfs_fsblock_t	start_block;
-
-	mp = io->io_mount;
-	nisize = XFS_SIZE(mp, io);
-	if (io->io_new_size > nisize)
-		nisize = io->io_new_size;
-
-	for (im=0, pbm=0; im < imaps && pbm < pbmaps; im++,pbmapp++,imap++,pbm++) {
-		pbmapp->pbm_target = io->io_flags & XFS_IOCORE_RT ?
-			mp->m_rtdev_targp :
-			mp->m_ddev_targp;
-		pbmapp->pbm_offset = XFS_FSB_TO_B(mp, imap->br_startoff);
-		pbmapp->pbm_delta = offset - pbmapp->pbm_offset;
-		pbmapp->pbm_bsize = XFS_FSB_TO_B(mp, imap->br_blockcount);
-		pbmapp->pbm_flags = 0;
-
-		start_block = imap->br_startblock;
-		if (start_block == HOLESTARTBLOCK) {
-			pbmapp->pbm_bn = PAGE_BUF_DADDR_NULL;
-			pbmapp->pbm_flags = PBMF_HOLE;
-		} else if (start_block == DELAYSTARTBLOCK) {
-			pbmapp->pbm_bn = PAGE_BUF_DADDR_NULL;
-			pbmapp->pbm_flags = PBMF_DELAY;
-		} else {
-			pbmapp->pbm_bn = XFS_FSB_TO_DB_IO(io, start_block);
-			if (imap->br_state == XFS_EXT_UNWRITTEN)
-				pbmapp->pbm_flags |= PBMF_UNWRITTEN;
-		}
-
-		if ((pbmapp->pbm_offset + pbmapp->pbm_bsize) >= nisize) {
-			pbmapp->pbm_flags |= PBMF_EOF;
-		}
-
-		offset += pbmapp->pbm_bsize - pbmapp->pbm_delta;
-	}
-	return(pbm);	/* Return the number filled */
-}
-
-STATIC int
-xfs_iomap_read(
-	xfs_iocore_t	*io,
-	loff_t		offset,
-	size_t		count,
-	int		flags,
-	page_buf_bmap_t	*pbmapp,
-	int		*npbmaps)
-{
-	xfs_fileoff_t	offset_fsb;
-	xfs_fileoff_t	end_fsb;
-	int		nimaps;
-	int		error;
-	xfs_mount_t	*mp;
-	xfs_bmbt_irec_t imap[XFS_MAX_RW_NBMAPS];
-
-	ASSERT(ismrlocked(io->io_lock, MR_UPDATE | MR_ACCESS) != 0);
-/**	ASSERT(ismrlocked(io->io_iolock, MR_UPDATE | MR_ACCESS) != 0); **/
-/*	xfs_iomap_enter_trace(XFS_IOMAP_READ_ENTER, io, offset, count); */
-
-	mp = io->io_mount;
-	offset_fsb = XFS_B_TO_FSBT(mp, offset);
-	nimaps = sizeof(imap) / sizeof(imap[0]);
-	nimaps = min(nimaps, *npbmaps); /* Don't ask for more than caller has */
-	end_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
-	error = XFS_BMAPI(mp, NULL, io, offset_fsb,
-				(xfs_filblks_t)(end_fsb - offset_fsb),
-				flags, NULL, 0, imap,
-				&nimaps, NULL);
-	if (error) {
-		return XFS_ERROR(error);
-	}
-
-	if(nimaps) {
-		*npbmaps = _xfs_imap_to_bmap(io, offset, imap, pbmapp, nimaps,
-			*npbmaps);
-	} else
-		*npbmaps = 0;
-	return XFS_ERROR(error);
-}
-
-/*
- * xfs_iomap_write: return pagebuf_bmap_t's telling higher layers
- *	where to write.
- * There are 2 main cases:
- *	1 the extents already exist
- *	2 must allocate.
- *	There are 3 cases when we allocate:
- *		delay allocation (doesn't really allocate or use transactions)
- *		direct allocation (no previous delay allocation
- *		convert delay to real allocations
- */
-
-STATIC int
-xfs_iomap_write(
-	xfs_iocore_t	*io,
-	loff_t		offset,
-	size_t		count,
-	page_buf_bmap_t	*pbmapp,
-	int		*npbmaps,
-	int		ioflag)
-{
-	int		maps;
-	int		error = 0;
-	int		found;
-	int		flags = 0;
-
-	maps = *npbmaps;
-	if (!maps)
-		goto out;
-
-	/*
-	 * If we have extents that are allocated for this range,
-	 * return them.
-	 */
-
-	found = 0;
-	error = xfs_iomap_read(io, offset, count, flags, pbmapp, npbmaps);
-	if (error)
-		goto out;
-
-	/*
-	 * If we found mappings and they can just have data written
-	 * without conversion,
-	 * let the caller write these and call us again.
-	 *
-	 * If we have a HOLE or UNWRITTEN, proceed down lower to
-	 * get the space or to convert to written.
-	 */
-
-	if (*npbmaps) {
-		if (!(pbmapp->pbm_flags & PBMF_HOLE)) {
-			*npbmaps = 1; /* Only checked the first one. */
-					/* We could check more, ... */
-			goto out;
-		}
-	}
-	found = *npbmaps;
-	*npbmaps = maps; /* Restore to original requested */
-
-	if (ioflag & PBF_DIRECT) {
-		error = xfs_iomap_write_direct(io, offset, count, pbmapp,
-					npbmaps, ioflag, found);
-	} else {
-		error = xfs_iomap_write_delay(io, offset, count, pbmapp,
-				npbmaps, ioflag, found);
-	}
-
-out:
-	XFS_IUNLOCK(io->io_mount, io, XFS_ILOCK_EXCL);
-	return XFS_ERROR(error);
-}
-
-/*
- * Map the given I/O size and I/O alignment over the given extent.
- * If we're at the end of the file and the underlying extent is
- * delayed alloc, make sure we extend out to the
- * next i_writeio_blocks boundary.  Otherwise make sure that we
- * are confined to the given extent.
- */
-/*ARGSUSED*/
-STATIC void
-xfs_write_bmap(
-	xfs_mount_t	*mp,
-	xfs_iocore_t	*io,
-	xfs_bmbt_irec_t *imapp,
-	page_buf_bmap_t	*pbmapp,
-	int		iosize,
-	xfs_fileoff_t	ioalign,
-	xfs_fsize_t	isize)
-{
-	__int64_t	extra_blocks;
-	xfs_fileoff_t	size_diff;
-	xfs_fileoff_t	ext_offset;
-	xfs_fsblock_t	start_block;
-	int		length;		/* length of this mapping in blocks */
-	xfs_off_t	offset;		/* logical block offset of this mapping */
-
-	if (ioalign < imapp->br_startoff) {
-		/*
-		 * The desired alignment doesn't end up on this
-		 * extent.  Move up to the beginning of the extent.
-		 * Subtract whatever we drop from the iosize so that
-		 * we stay aligned on iosize boundaries.
-		 */
-		size_diff = imapp->br_startoff - ioalign;
-		iosize -= (int)size_diff;
-		ASSERT(iosize > 0);
-		ext_offset = 0;
-		offset = imapp->br_startoff;
-		pbmapp->pbm_offset = XFS_FSB_TO_B(mp, imapp->br_startoff);
-	} else {
-		/*
-		 * The alignment requested fits on this extent,
-		 * so use it.
-		 */
-		ext_offset = ioalign - imapp->br_startoff;
-		offset = ioalign;
-		pbmapp->pbm_offset = XFS_FSB_TO_B(mp, ioalign);
-	}
-	start_block = imapp->br_startblock;
-	ASSERT(start_block != HOLESTARTBLOCK);
-	if (start_block != DELAYSTARTBLOCK) {
-		pbmapp->pbm_bn = XFS_FSB_TO_DB_IO(io, start_block + ext_offset);
-		if (imapp->br_state == XFS_EXT_UNWRITTEN) {
-			pbmapp->pbm_flags = PBMF_UNWRITTEN;
-		}
-	} else {
-		pbmapp->pbm_bn = PAGE_BUF_DADDR_NULL;
-		pbmapp->pbm_flags = PBMF_DELAY;
-	}
-	pbmapp->pbm_target = io->io_flags & XFS_IOCORE_RT ?
-		mp->m_rtdev_targp :
-		mp->m_ddev_targp;
-	length = iosize;
-
-	/*
-	 * If the iosize from our offset extends beyond the end of
-	 * the extent, then trim down length to match that of the extent.
-	 */
-	extra_blocks = (xfs_off_t)(offset + length) -
-		       (__uint64_t)(imapp->br_startoff +
-				    imapp->br_blockcount);
-	if (extra_blocks > 0) {
-		length -= extra_blocks;
-		ASSERT(length > 0);
-	}
-
-	pbmapp->pbm_bsize = XFS_FSB_TO_B(mp, length);
-}
-
-STATIC int
-xfs_iomap_write_delay(
-	xfs_iocore_t	*io,
-	loff_t		offset,
-	size_t		count,
-	page_buf_bmap_t	*pbmapp,
-	int		*npbmaps,
-	int		ioflag,
-	int		found)
-{
-	xfs_fileoff_t	offset_fsb;
-	xfs_fileoff_t	ioalign;
-	xfs_fileoff_t	last_fsb;
-	xfs_fileoff_t	start_fsb;
-	xfs_filblks_t	count_fsb;
-	xfs_off_t	aligned_offset;
-	xfs_fsize_t	isize;
-	xfs_fsblock_t	firstblock;
-	__uint64_t	last_page_offset;
-	int		nimaps;
-	int		error;
-	int		n;
-	unsigned int	iosize;
-	short		small_write;
-	xfs_mount_t	*mp;
-#define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP
-	xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS];
-	int		aeof;
-
-	ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0);
-
-/*	xfs_iomap_enter_trace(XFS_IOMAP_WRITE_ENTER, io, offset, count); */
-
-	mp = io->io_mount;
-/***
-	ASSERT(! XFS_NOT_DQATTACHED(mp, ip));
-***/
-
-	isize = XFS_SIZE(mp, io);
-	if (io->io_new_size > isize) {
-		isize = io->io_new_size;
-	}
-
-	aeof = 0;
-	offset_fsb = XFS_B_TO_FSBT(mp, offset);
-	last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
-	/*
-	 * If the caller is doing a write at the end of the file,
-	 * then extend the allocation (and the buffer used for the write)
-	 * out to the file system's write iosize.  We clean up any extra
-	 * space left over when the file is closed in xfs_inactive().
-	 * We can only do this if we are sure that we will create buffers
-	 * over all of the space we allocate beyond the end of the file.
-	 * Not doing so would allow us to create delalloc blocks with
-	 * no pages in memory covering them.  So, we need to check that
-	 * there are not any real blocks in the area beyond the end of
-	 * the file which we are optimistically going to preallocate. If
-	 * there are then our buffers will stop when they encounter them
-	 * and we may accidentally create delalloc blocks beyond them
-	 * that we never cover with a buffer.  All of this is because
-	 * we are not actually going to write the extra blocks preallocated
-	 * at this point.
-	 *
-	 * We don't bother with this for sync writes, because we need
-	 * to minimize the amount we write for good performance.
-	 */
-	if (!(ioflag & PBF_SYNC) && ((offset + count) > XFS_SIZE(mp, io))) {
-		start_fsb = XFS_B_TO_FSBT(mp,
-				  ((xfs_ufsize_t)(offset + count - 1)));
-		count_fsb = mp->m_writeio_blocks;
-		while (count_fsb > 0) {
-			nimaps = XFS_WRITE_IMAPS;
-			error = XFS_BMAPI(mp, NULL, io, start_fsb, count_fsb,
-					  0, NULL, 0, imap, &nimaps,
-					  NULL);
-			if (error) {
-				return error;
-			}
-			for (n = 0; n < nimaps; n++) {
-				if ((imap[n].br_startblock != HOLESTARTBLOCK) &&
-				    (imap[n].br_startblock != DELAYSTARTBLOCK)) {
-					goto write_map;
-				}
-				start_fsb += imap[n].br_blockcount;
-				count_fsb -= imap[n].br_blockcount;
-				ASSERT(count_fsb < 0xffff000);
-			}
-		}
-		iosize = mp->m_writeio_blocks;
-		aligned_offset = XFS_WRITEIO_ALIGN(mp, (offset + count - 1));
-		ioalign = XFS_B_TO_FSBT(mp, aligned_offset);
-		last_fsb = ioalign + iosize;
-		aeof = 1;
-	}
- write_map:
-	nimaps = XFS_WRITE_IMAPS;
-	firstblock = NULLFSBLOCK;
-
-	/*
-	 * roundup the allocation request to m_dalign boundary if file size
-	 * is greater that 512K and we are allocating past the allocation eof
-	 */
-	if (mp->m_dalign && (XFS_SIZE(mp, io) >= mp->m_dalign) && aeof) {
-		int eof;
-		xfs_fileoff_t new_last_fsb;
-		new_last_fsb = roundup_64(last_fsb, mp->m_dalign);
-		error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof);
-		if (error) {
-			return error;
-		}
-		if (eof) {
-			last_fsb = new_last_fsb;
-		}
-	}
-
-	error = XFS_BMAPI(mp, NULL, io, offset_fsb,
-			  (xfs_filblks_t)(last_fsb - offset_fsb),
-			  XFS_BMAPI_DELAY | XFS_BMAPI_WRITE |
-			  XFS_BMAPI_ENTIRE, &firstblock, 1, imap,
-			  &nimaps, NULL);
-	/*
-	 * This can be EDQUOT, if nimaps == 0
-	 */
-	if (error) {
-		return XFS_ERROR(error);
-	}
-	/*
-	 * If bmapi returned us nothing, and if we didn't get back EDQUOT,
-	 * then we must have run out of space.
-	 */
-	if (nimaps == 0) {
-/*		xfs_iomap_enter_trace(XFS_IOMAP_WRITE_NOSPACE,
-				      io, offset, count); */
-		return XFS_ERROR(ENOSPC);
-	}
-
-	if (!(ioflag & PBF_SYNC) ||
-	    ((last_fsb - offset_fsb) >= mp->m_writeio_blocks)) {
-		/*
-		 * For normal or large sync writes, align everything
-		 * into i_writeio_blocks sized chunks.
-		 */
-		iosize = mp->m_writeio_blocks;
-		aligned_offset = XFS_WRITEIO_ALIGN(mp, offset);
-		ioalign = XFS_B_TO_FSBT(mp, aligned_offset);
-		small_write = 0;
-		/* XXX - Are we shrinking? XXXXX  */
-	} else {
-		/*
-		 * For small sync writes try to minimize the amount
-		 * of I/O we do.  Round down and up to the larger of
-		 * page or block boundaries.  Set the small_write
-		 * variable to 1 to indicate to the code below that
-		 * we are not using the normal buffer alignment scheme.
-		 */
-		if (NBPP > mp->m_sb.sb_blocksize) {
-			aligned_offset = ctooff(offtoct(offset));
-			ioalign = XFS_B_TO_FSBT(mp, aligned_offset);
-			last_page_offset = ctob64(btoc64(offset + count));
-			iosize = XFS_B_TO_FSBT(mp, last_page_offset -
-					       aligned_offset);
-		} else {
-			ioalign = offset_fsb;
-			iosize = last_fsb - offset_fsb;
-		}
-		small_write = 1;
-		/* XXX - Are we shrinking? XXXXX  */
-	}
-
-	/*
-	 * Now map our desired I/O size and alignment over the
-	 * extents returned by xfs_bmapi().
-	 */
-	xfs_write_bmap(mp, io, imap, pbmapp, iosize, ioalign, isize);
-	pbmapp->pbm_delta = offset - pbmapp->pbm_offset;
-
-	ASSERT((pbmapp->pbm_bsize > 0)
-		&& (pbmapp->pbm_bsize - pbmapp->pbm_delta > 0));
-
-	/*
-	 * A bmap is the EOF bmap when it reaches to or beyond the new
-	 * inode size.
-	 */
-	if ((pbmapp->pbm_offset + pbmapp->pbm_bsize ) >= isize) {
-		pbmapp->pbm_flags |= PBMF_EOF;
-	}
-
-/*	xfs_iomap_map_trace(XFS_IOMAP_WRITE_MAP,
-			    io, offset, count, bmapp, imap);	     */
-
-	/* On IRIX, we walk more imaps filling in more bmaps. On Linux
-		just handle one for now. To find the code on IRIX,
-		look in xfs_iomap_write() in xfs_rw.c. */
-
-	*npbmaps = 1;
-	return 0;
-}
-
-STATIC int
-xfs_iomap_write_direct(
-	xfs_iocore_t	*io,
-	loff_t		offset,
-	size_t		count,
-	page_buf_bmap_t	*pbmapp,
-	int		*npbmaps,
-	int		ioflag,
-	int		found)
-{
-	xfs_inode_t	*ip = XFS_IO_INODE(io);
-	xfs_mount_t	*mp;
-	xfs_fileoff_t	offset_fsb;
-	xfs_fileoff_t	last_fsb;
-	xfs_filblks_t	count_fsb;
-	xfs_fsize_t	isize;
-	xfs_fsblock_t	firstfsb;
-	int		nimaps, maps;
-	int		error;
-	xfs_trans_t	*tp;
-
-#define XFS_WRITE_IMAPS XFS_BMAP_MAX_NMAP
-	xfs_bmbt_irec_t imap[XFS_WRITE_IMAPS], *imapp;
-	xfs_bmap_free_t free_list;
-	int		aeof;
-	int		bmapi_flags;
-	xfs_filblks_t	datablocks;
-	int		rt;
-	int		committed;
-	int		numrtextents;
-	uint		resblks;
-	int		rtextsize;
-
-	maps = min(XFS_WRITE_IMAPS, *npbmaps);
-	nimaps = maps;
-
-	mp = io->io_mount;
-	isize = XFS_SIZE(mp, io);
-	if (io->io_new_size > isize)
-		isize = io->io_new_size;
-
-	if ((offset + count) > isize) {
-		aeof = 1;
-	} else {
-		aeof = 0;
-	}
-
-	offset_fsb = XFS_B_TO_FSBT(mp, offset);
-	last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count)));
-	count_fsb = last_fsb - offset_fsb;
-	if (found && (pbmapp->pbm_flags & PBMF_HOLE)) {
-		xfs_fileoff_t	map_last_fsb;
-		map_last_fsb = XFS_B_TO_FSB(mp,
-			(pbmapp->pbm_bsize + pbmapp->pbm_offset));
-
-		if (map_last_fsb < last_fsb) {
-			last_fsb = map_last_fsb;
-			count_fsb = last_fsb - offset_fsb;
-		}
-		ASSERT(count_fsb > 0);
-	}
-
-	/*
-	 * roundup the allocation request to m_dalign boundary if file size
-	 * is greater that 512K and we are allocating past the allocation eof
-	 */
-	if (!found && mp->m_dalign && (isize >= 524288) && aeof) {
-		int eof;
-		xfs_fileoff_t new_last_fsb;
-		new_last_fsb = roundup_64(last_fsb, mp->m_dalign);
-		printk("xfs_iomap_write_direct: about to XFS_BMAP_EOF %Ld\n",
-			new_last_fsb);
-		error = XFS_BMAP_EOF(mp, io, new_last_fsb, XFS_DATA_FORK, &eof);
-		if (error) {
-			goto error_out;
-		}
-		if (eof)
-			last_fsb = new_last_fsb;
-	}
-
-	bmapi_flags = XFS_BMAPI_WRITE|XFS_BMAPI_DIRECT_IO|XFS_BMAPI_ENTIRE;
-	bmapi_flags &= ~XFS_BMAPI_DIRECT_IO;
-
-	/*
-	 * determine if this is a realtime file
-	 */
-	if ((rt = (ip->i_d.di_flags & XFS_DIFLAG_REALTIME)) != 0) {
-		rtextsize = mp->m_sb.sb_rextsize;
-	} else
-		rtextsize = 0;
-
-	error = 0;
-
-	/*
-	 * allocate file space for the bmapp entries passed in.
-	 */
-
-	/*
-	 * determine if reserving space on
-	 * the data or realtime partition.
-	 */
-	if (rt) {
-		numrtextents = (count_fsb + rtextsize - 1);
-		do_div(numrtextents, rtextsize);
-		datablocks = 0;
-	} else {
-		datablocks = count_fsb;
-		numrtextents = 0;
-	}
-
-	/*
-	 * allocate and setup the transaction
-	 */
-	tp = xfs_trans_alloc(mp, XFS_TRANS_DIOSTRAT);
-	resblks = XFS_DIOSTRAT_SPACE_RES(mp, datablocks);
-
-	xfs_iunlock(ip, XFS_ILOCK_EXCL);
-
-	error = xfs_trans_reserve(tp,
-				  resblks,
-				  XFS_WRITE_LOG_RES(mp),
-				  numrtextents,
-				  XFS_TRANS_PERM_LOG_RES,
-				  XFS_WRITE_LOG_COUNT);
-
-	/*
-	 * check for running out of space
-	 */
-	if (error) {
-		/*
-		 * Free the transaction structure.
-		 */
-		xfs_trans_cancel(tp, 0);
-	}
-
-	xfs_ilock(ip, XFS_ILOCK_EXCL);
-
-	if (error)  {
-		goto error_out; /* Don't return in above if .. trans ..,
-					need lock to return */
-	}
-
-	if (XFS_IS_QUOTA_ON(mp)) {
-		if (xfs_trans_reserve_quota(tp,
-					    ip->i_udquot,
-					    ip->i_gdquot,
-					    resblks, 0, 0)) {
-			error = (EDQUOT);
-			goto error1;
-		}
-		nimaps = 1;
-	} else {
-		nimaps = 2;
-	}
-
-	xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
-	xfs_trans_ihold(tp, ip);
-
-	/*
-	 * issue the bmapi() call to allocate the blocks
-	 */
-	XFS_BMAP_INIT(&free_list, &firstfsb);
-	imapp = &imap[0];
-	error = XFS_BMAPI(mp, tp, io, offset_fsb, count_fsb,
-		bmapi_flags, &firstfsb, 1, imapp, &nimaps, &free_list);
-	if (error) {
-		goto error0;
-	}
-
-	/*
-	 * complete the transaction
-	 */
-
-	error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed);
-	if (error) {
-		goto error0;
-	}
-
-	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
-	if (error) {
-		goto error_out;
-	}
-
-	/* copy any maps to caller's array and return any error. */
-	if (nimaps == 0) {
-		error = (ENOSPC);
-		goto error_out;
-	}
-
-	maps = min(nimaps, maps);
-	*npbmaps = _xfs_imap_to_bmap(io, offset, &imap[0], pbmapp, maps,
-								*npbmaps);
-	if(*npbmaps) {
-		/*
-		 * this is new since xfs_iomap_read
-		 * didn't find it.
-		 */
-		if (*npbmaps != 1) {
-			printk("NEED MORE WORK FOR MULTIPLE BMAPS (which are new)\n");
-		}
-	}
-	goto out;
-
- error0:	/* Cancel bmap, unlock inode, and cancel trans */
-	xfs_bmap_cancel(&free_list);
-
- error1:	/* Just cancel transaction */
-	xfs_trans_cancel(tp, XFS_TRANS_RELEASE_LOG_RES | XFS_TRANS_ABORT);
-	*npbmaps = 0;	/* nothing set-up here */
-
-error_out:
-out:	/* Just return error and any tracing at end of routine */
-	return XFS_ERROR(error);
-}
-
-
 /*
  * All xfs metadata buffers except log state machine buffers
  * get this attached as their b_bdstrat callback function.
@@ -1810,7 +806,6 @@
 	int error;
 
 	mp = XFS_BHVTOM(bdp);
-	xfs_refcache_purge_mp(mp);
 	xfs_binval(mp->m_ddev_targp);
 
 	do {
diff -Nru a/fs/xfs/linux/xfs_lrw.h b/fs/xfs/linux/xfs_lrw.h
--- a/fs/xfs/linux/xfs_lrw.h	Sun Nov 10 19:28:36 2002
+++ b/fs/xfs/linux/xfs_lrw.h	Sun Nov 10 19:28:36 2002
@@ -29,41 +29,39 @@
  *
  * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  */
-
 #ifndef __XFS_LRW_H__
 #define __XFS_LRW_H__
 
+struct vnode;
+struct bhv_desc;
+struct xfs_mount;
+struct xfs_iocore;
+struct page_buf_s;
+struct page_buf_bmap_s;
+
 #define XFS_IOMAP_READ_ENTER	3
 /*
  * Maximum count of bmaps used by read and write paths.
  */
 #define XFS_MAX_RW_NBMAPS	4
 
-extern int xfs_bmap (bhv_desc_t *, xfs_off_t, ssize_t, int, page_buf_bmap_t *, int *);
-extern int xfsbdstrat (struct xfs_mount *, struct xfs_buf *);
-extern int xfs_bdstrat_cb (struct xfs_buf *);
+extern int xfs_bmap (struct bhv_desc *, xfs_off_t, ssize_t, int,
+			struct page_buf_bmap_s *, int *);
+extern int xfsbdstrat (struct xfs_mount *, struct page_buf_s *);
+extern int xfs_bdstrat_cb (struct page_buf_s *);
 
-extern int xfs_zero_eof (vnode_t *, struct xfs_iocore *, xfs_off_t,
+extern int xfs_zero_eof (struct vnode *, struct xfs_iocore *, xfs_off_t,
 				xfs_fsize_t, xfs_fsize_t);
-extern ssize_t xfs_read (
-	struct bhv_desc		*bdp,
-	struct file		*filp,
-	const struct iovec	*iovp,
-	unsigned long		segs,
-	loff_t			*offp,
-	struct cred		*credp);
-
-extern ssize_t xfs_write (
-	struct bhv_desc		*bdp,
-	struct file		*filp,
-	const struct iovec	*iovp,
-	unsigned long		segs,
-	loff_t			*offp,
-	struct cred		*credp);
+extern ssize_t xfs_read (struct bhv_desc *, struct file *,
+				const struct iovec *, unsigned long,
+				loff_t *, struct cred *);
+extern ssize_t xfs_write (struct bhv_desc *, struct file *,
+				const struct iovec *, unsigned long,
+				loff_t *, struct cred *);
 
-extern int xfs_dev_is_read_only(xfs_mount_t *, char *);
+extern int xfs_dev_is_read_only (struct xfs_mount *, char *);
 
-extern void XFS_log_write_unmount_ro (bhv_desc_t *);
+extern void XFS_log_write_unmount_ro (struct bhv_desc *);
 
 #define XFS_FSB_TO_DB_IO(io,fsb) \
 		(((io)->io_flags & XFS_IOCORE_RT) ? \
diff -Nru a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c
--- a/fs/xfs/linux/xfs_super.c	Sun Nov 10 19:28:41 2002
+++ b/fs/xfs/linux/xfs_super.c	Sun Nov 10 19:28:41 2002
@@ -34,6 +34,8 @@
 #include <linux/bitops.h>
 #include <linux/blkdev.h>
 #include <linux/namei.h>
+#include <linux/pagemap.h>
+#include <linux/major.h>
 #include <linux/init.h>
 #include <linux/ctype.h>
 #include <linux/seq_file.h>
@@ -43,6 +45,10 @@
 extern int  xfs_init(void);
 extern void xfs_cleanup(void);
 
+#ifndef EVMS_MAJOR
+# define EVMS_MAJOR		117
+#endif
+
 /* For kernels which have the s_maxbytes field - set it */
 #ifdef MAX_NON_LFS
 # define set_max_bytes(sb)	((sb)->s_maxbytes = XFS_MAX_FILE_OFFSET)
@@ -50,7 +56,7 @@
 # define set_max_bytes(sb)	do { } while (0)
 #endif
 
-#ifdef CONFIG_FS_POSIX_ACL
+#ifdef CONFIG_XFS_POSIX_ACL
 # define set_posix_acl(sb)	((sb)->s_flags |= MS_POSIXACL)
 #else
 # define set_posix_acl(sb)	do { } while (0)
@@ -113,13 +119,9 @@
 	struct xfs_mount_args	*args)
 {
 	char			*this_char, *value, *eov;
-	int			logbufs = -1;
-	int			logbufsize = -1;
 	int			dsunit, dswidth, vol_dsunit, vol_dswidth;
+	int			logbufs, logbufsize;
 	int			iosize;
-	int			rval = 1;	/* failure is default */
-
-	iosize = dsunit = dswidth = vol_dsunit = vol_dswidth = 0;
 
 	/* Default to 32 bit inodes on linux all the time */
 	args->flags |= XFSMNT_32BITINODES;
@@ -129,11 +131,13 @@
 		args->flags |= XFSMNT_NOATIME;
 
 	if (!options) {
-		args->logbufs = logbufs;
-		args->logbufsize = logbufsize;
+		args->logbufs = args->logbufsize = -1;
 		return 0;
 	}
 
+	logbufs = logbufsize = -1;
+	iosize = dsunit = dswidth = vol_dsunit = vol_dswidth = 0;
+
 	while ((this_char = strsep(&options, ",")) != NULL) {
 		if (!*this_char)
 			continue;
@@ -141,10 +145,20 @@
 			*value++ = 0;
 
 		if (!strcmp(this_char, MNTOPT_LOGBUFS)) {
+			if (!value || !*value) {
+				printk("XFS: %s option requires an argument\n",
+					MNTOPT_LOGBUFS);
+				return -EINVAL;
+			}
 			logbufs = simple_strtoul(value, &eov, 10);
 		} else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) {
-			int in_kilobytes = 0;
+			int	in_kilobytes = 0;
 
+			if (!value || !*value) {
+				printk("XFS: %s option requires an argument\n",
+					MNTOPT_LOGBSIZE);
+				return -EINVAL;
+			}
 			if (toupper(value[strlen(value)-1]) == 'K') {
 				in_kilobytes = 1;
 				value[strlen(value)-1] = '\0';
@@ -153,8 +167,18 @@
 			if (in_kilobytes)
 				logbufsize = logbufsize * 1024;
 		} else if (!strcmp(this_char, MNTOPT_LOGDEV)) {
+			if (!value || !*value) {
+				printk("XFS: %s option requires an argument\n",
+					MNTOPT_LOGDEV);
+				return -EINVAL;
+			}
 			strncpy(args->logname, value, MAXNAMELEN);
 		} else if (!strcmp(this_char, MNTOPT_MTPT)) {
+			if (!value || !*value) {
+				printk("XFS: %s option requires an argument\n",
+					MNTOPT_MTPT);
+				return -EINVAL;
+			}
 			strncpy(args->mtpt, value, MAXNAMELEN);
 #if CONFIG_XFS_DMAPI
 		} else if (!strcmp(this_char, MNTOPT_DMAPI)) {
@@ -165,11 +189,21 @@
 		} else if (!strcmp(this_char, MNTOPT_DMAPI) ||
 			   !strcmp(this_char, MNTOPT_XDSM)) {
 			printk("XFS: this kernel does not support dmapi/xdsm.\n");
-			return rval;
+			return -EINVAL;
 #endif
 		} else if (!strcmp(this_char, MNTOPT_RTDEV)) {
+			if (!value || !*value) {
+				printk("XFS: %s option requires an argument\n",
+					MNTOPT_RTDEV);
+				return -EINVAL;
+			}
 			strncpy(args->rtname, value, MAXNAMELEN);
 		} else if (!strcmp(this_char, MNTOPT_BIOSIZE)) {
+			if (!value || !*value) {
+				printk("XFS: %s option requires an argument\n",
+					MNTOPT_BIOSIZE); 
+				return -EINVAL;
+			}
 			iosize = simple_strtoul(value, &eov, 10);
 			args->flags |= XFSMNT_IOSIZE;
 			args->iosizelog = (uint8_t) iosize;
@@ -183,8 +217,9 @@
 #ifdef XFS_BIG_FILESYSTEMS
 			args->flags |= XFSMNT_INO64;
 #else
-			printk("XFS: ino64 option not allowed on this system\n");
-			return rval;
+			printk("XFS: %s option not allowed on this system\n",
+				MNTOPT_INO64);
+			return -EINVAL;
 #endif
 		} else if (!strcmp(this_char, MNTOPT_UQUOTA)) {
 			args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF;
@@ -204,8 +239,18 @@
 		} else if (!strcmp(this_char, MNTOPT_NOALIGN)) {
 			args->flags |= XFSMNT_NOALIGN;
 		} else if (!strcmp(this_char, MNTOPT_SUNIT)) {
+			if (!value || !*value) {
+				printk("XFS: %s option requires an argument\n",
+					MNTOPT_SUNIT);
+				return -EINVAL;
+			}
 			dsunit = simple_strtoul(value, &eov, 10);
 		} else if (!strcmp(this_char, MNTOPT_SWIDTH)) {
+			if (!value || !*value) {
+				printk("XFS: %s option requires an argument\n",
+					MNTOPT_SWIDTH);
+				return -EINVAL;
+			}
 			dswidth = simple_strtoul(value, &eov, 10);
 		} else if (!strcmp(this_char, MNTOPT_NOUUID)) {
 			args->flags |= XFSMNT_NOUUID;
@@ -218,33 +263,33 @@
 printk("XFS: irixsgid is now a sysctl(2) variable, option is deprecated.\n");
 		} else {
 			printk("XFS: unknown mount option [%s].\n", this_char);
-			return rval;
+			return -EINVAL;
 		}
 	}
 
 	if (args->flags & XFSMNT_NORECOVERY) {
 		if ((flags & MS_RDONLY) == 0) {
 			printk("XFS: no-recovery mounts must be read-only.\n");
-			return rval;
+			return -EINVAL;
 		}
 	}
 
 	if ((args->flags & XFSMNT_NOALIGN) && (dsunit || dswidth)) {
 		printk(
 	"XFS: sunit and swidth options incompatible with the noalign option\n");
-		return rval;
+		return -EINVAL;
 	}
 
 	if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
 		printk("XFS: sunit and swidth must be specified together\n");
-		return rval;
+		return -EINVAL;
 	}
 
 	if (dsunit && (dswidth % dsunit != 0)) {
 		printk(
 	"XFS: stripe width (%d) must be a multiple of the stripe unit (%d)\n",
 			dswidth, dsunit);
-		return rval;
+		return -EINVAL;
 	}
 
 	if ((args->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) {
@@ -332,6 +377,160 @@
 	return 0;
 }
 
+STATIC __inline__ void
+xfs_set_inodeops(
+	struct inode		*inode)
+{
+	vnode_t			*vp = LINVFS_GET_VP(inode);
+
+	if (vp->v_type == VNON) {
+		make_bad_inode(inode);
+	} else if (S_ISREG(inode->i_mode)) {
+		inode->i_op = &linvfs_file_inode_operations;
+		inode->i_fop = &linvfs_file_operations;
+		inode->i_mapping->a_ops = &linvfs_aops;
+	} else if (S_ISDIR(inode->i_mode)) {
+		inode->i_op = &linvfs_dir_inode_operations;
+		inode->i_fop = &linvfs_dir_operations;
+	} else if (S_ISLNK(inode->i_mode)) {
+		inode->i_op = &linvfs_symlink_inode_operations;
+		if (inode->i_blocks)
+			inode->i_mapping->a_ops = &linvfs_aops;
+	} else {
+		inode->i_op = &linvfs_file_inode_operations;
+		init_special_inode(inode, inode->i_mode,
+					kdev_t_to_nr(inode->i_rdev));
+	}
+}
+
+STATIC __inline__ void
+xfs_revalidate_inode(
+	xfs_mount_t	*mp,
+	vnode_t		*vp,
+	xfs_inode_t	*ip)
+{
+	struct inode	*inode = LINVFS_GET_IP(vp);
+
+	inode->i_mode	= (ip->i_d.di_mode & MODEMASK) | VTTOIF(vp->v_type);
+	inode->i_nlink	= ip->i_d.di_nlink;
+	inode->i_uid	= ip->i_d.di_uid;
+	inode->i_gid 	= ip->i_d.di_gid;
+	if (((1 << vp->v_type) & ((1<<VBLK) | (1<<VCHR))) == 0) {
+		inode->i_rdev	= NODEV;
+	} else {
+		xfs_dev_t dev = ip->i_df.if_u2.if_rdev;
+		inode->i_rdev	= XFS_DEV_TO_KDEVT(dev);
+	}
+	inode->i_blksize = PAGE_CACHE_SIZE;
+	inode->i_generation = ip->i_d.di_gen;
+	inode->i_size	= ip->i_d.di_size;
+	inode->i_blocks =
+		XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks);
+	inode->i_atime	= ip->i_d.di_atime.t_sec;
+	inode->i_mtime	= ip->i_d.di_mtime.t_sec;
+	inode->i_ctime	= ip->i_d.di_ctime.t_sec;
+
+	vp->v_flag &= ~VMODIFIED;
+}
+
+void
+xfs_initialize_vnode(
+	bhv_desc_t	*bdp,
+	vnode_t		*vp,
+	bhv_desc_t	*inode_bhv,
+	int		unlock)
+{
+	xfs_inode_t	*ip = XFS_BHVTOI(inode_bhv);
+	struct inode	*inode = LINVFS_GET_IP(vp);
+
+	if (vp->v_fbhv == NULL) {
+		vp->v_vfsp = bhvtovfs(bdp);
+		bhv_desc_init(&(ip->i_bhv_desc), ip, vp, &xfs_vnodeops);
+		bhv_insert_initial(VN_BHV_HEAD(vp), &(ip->i_bhv_desc));
+	}
+
+	vp->v_type = IFTOVT(ip->i_d.di_mode);
+	/* Have we been called during the new inode create process,
+	 * in which case we are too early to fill in the linux inode.
+	 */
+	if (vp->v_type == VNON)
+		return;
+
+	xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);
+
+	/* For new inodes we need to set the ops vectors,
+	 * and unlock the inode.
+	 */
+	if (unlock && (inode->i_state & I_NEW)) {
+		xfs_set_inodeops(inode);
+		unlock_new_inode(inode);
+	}
+}
+
+int
+xfs_blkdev_get(
+	const char		*name,
+	struct block_device	**bdevp)
+{
+	struct nameidata	nd;
+	int			error;
+
+	error = path_lookup(name, LOOKUP_FOLLOW, &nd);
+	if (error) {
+		printk("XFS: Invalid device [%s], error=%d\n", name, error);
+		return -error;
+	}
+
+	/* I think we actually want bd_acquire here..  --hch */
+	*bdevp = bdget(kdev_t_to_nr(nd.dentry->d_inode->i_rdev));
+	if (*bdevp) {
+		error = blkdev_get(*bdevp, FMODE_READ|FMODE_WRITE, 0, BDEV_FS);
+	} else {
+		error = -ENOMEM;
+	}
+
+	path_release(&nd);
+	return -error;
+}
+
+void
+xfs_blkdev_put(
+	struct block_device	*bdev)
+{
+	if (bdev)
+		blkdev_put(bdev, BDEV_FS);
+}
+
+void
+xfs_free_buftarg(
+	xfs_buftarg_t		*btp)
+{
+	pagebuf_delwri_flush(btp, PBDF_WAIT, NULL);
+	kfree(btp);
+}
+
+xfs_buftarg_t *
+xfs_alloc_buftarg(
+	struct block_device	*bdev)
+{
+	xfs_buftarg_t		*btp;
+
+	btp = kmem_zalloc(sizeof(*btp), KM_SLEEP);
+
+	btp->pbr_dev =  bdev->bd_dev;
+	btp->pbr_bdev = bdev;
+	btp->pbr_mapping = bdev->bd_inode->i_mapping;
+	btp->pbr_blocksize = PAGE_CACHE_SIZE;
+
+	switch (MAJOR(btp->pbr_dev)) {
+	case MD_MAJOR:
+	case EVMS_MAJOR:
+		btp->pbr_flags = PBR_ALIGNED_ONLY;
+		break;
+	}
+
+	return btp;
+}
 
 STATIC kmem_cache_t * linvfs_inode_cachep;
 
@@ -452,6 +651,7 @@
 	sb->s_dirt = 1;
 	sb->s_blocksize = statvfs.f_bsize;
 	sb->s_blocksize_bits = ffs(statvfs.f_bsize) - 1;
+	set_posix_acl(sb);
 
 	VFS_ROOT(vfsp, &rootvp, error);
 	if (error)
@@ -479,9 +679,8 @@
 			goto fail_vnrele;
 		}
 	}
-	set_posix_acl(sb);
 
-	vn_trace_exit(rootvp, "linvfs_read_super", (inst_t *)__return_address);
+	vn_trace_exit(rootvp, __FUNCTION__, (inst_t *)__return_address);
 
 	kfree(args);
 	return 0;
@@ -505,38 +704,12 @@
 	return -error;
 }
 
-void
-linvfs_set_inode_ops(
-	struct inode		*inode)
-{
-	vnode_t			*vp = LINVFS_GET_VP(inode);
-
-	if (vp->v_type == VNON) {
-		make_bad_inode(inode);
-	} else if (S_ISREG(inode->i_mode)) {
-		inode->i_op = &linvfs_file_inode_operations;
-		inode->i_fop = &linvfs_file_operations;
-		inode->i_mapping->a_ops = &linvfs_aops;
-	} else if (S_ISDIR(inode->i_mode)) {
-		inode->i_op = &linvfs_dir_inode_operations;
-		inode->i_fop = &linvfs_dir_operations;
-	} else if (S_ISLNK(inode->i_mode)) {
-		inode->i_op = &linvfs_symlink_inode_operations;
-		if (inode->i_blocks)
-			inode->i_mapping->a_ops = &linvfs_aops;
-	} else {
-		inode->i_op = &linvfs_file_inode_operations;
-		init_special_inode(inode, inode->i_mode,
-					kdev_t_to_nr(inode->i_rdev));
-	}
-}
-
 /*
  * We do not actually write the inode here, just mark the
  * super block dirty so that sync_supers calls us and
  * forces the flush.
  */
-void
+STATIC void
 linvfs_write_inode(
 	struct inode		*inode,
 	int			sync)
@@ -545,9 +718,7 @@
 	int			error, flags = FLUSH_INODE;
 
 	if (vp) {
-		vn_trace_entry(vp, "linvfs_write_inode",
-					(inst_t *)__return_address);
-
+		vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
 		if (sync)
 			flags |= FLUSH_SYNC;
 		VOP_IFLUSH(vp, flags, error);
@@ -556,7 +727,7 @@
 	}
 }
 
-void
+STATIC void
 linvfs_clear_inode(
 	struct inode		*inode)
 {
@@ -564,17 +735,15 @@
 
 	if (vp) {
 		vn_rele(vp);
-		vn_trace_entry(vp, "linvfs_clear_inode",
-					(inst_t *)__return_address);
+		vn_trace_entry(vp, __FUNCTION__, (inst_t *)__return_address);
 		/*
 		 * Do all our cleanup, and remove this vnode.
 		 */
-		vp->v_flag |= VPURGE;
 		vn_remove(vp);
 	}
 }
 
-void
+STATIC void
 linvfs_put_inode(
 	struct inode		*ip)
 {
@@ -585,7 +754,7 @@
 		VOP_RELEASE(vp, error);
 }
 
-void
+STATIC void
 linvfs_put_super(
 	struct super_block	*sb)
 {
@@ -595,14 +764,14 @@
 	VFS_DOUNMOUNT(vfsp, 0, NULL, NULL, error);
 	if (error) {
 		printk("XFS unmount got error %d\n", error);
-		printk("linvfs_put_super: vfsp/0x%p left dangling!\n", vfsp);
+		printk("%s: vfsp/0x%p left dangling!\n", __FUNCTION__, vfsp);
 		return;
 	}
 
 	vfs_deallocate(vfsp);
 }
 
-void
+STATIC void
 linvfs_write_super(
 	struct super_block	*sb)
 {
@@ -616,7 +785,7 @@
 		NULL, error);
 }
 
-int
+STATIC int
 linvfs_statfs(
 	struct super_block	*sb,
 	struct statfs		*statp)
@@ -625,11 +794,10 @@
 	int			error;
 
 	VFS_STATVFS(vfsp, statp, NULL, error);
-
 	return error;
 }
 
-int
+STATIC int
 linvfs_remount(
 	struct super_block	*sb,
 	int			*flags,
@@ -677,7 +845,7 @@
 	return error;
 }
 
-void
+STATIC void
 linvfs_freeze_fs(
 	struct super_block	*sb)
 {
@@ -693,7 +861,7 @@
 	VN_RELE(vp);
 }
 
-void
+STATIC void
 linvfs_unfreeze_fs(
 	struct super_block	*sb)
 {
@@ -707,7 +875,6 @@
 	VN_RELE(vp);
 }
 
-
 STATIC struct dentry *
 linvfs_get_parent(
 	struct dentry		*child)
@@ -744,6 +911,37 @@
 	return parent;
 }
 
+STATIC struct dentry *
+linvfs_get_dentry(
+	struct super_block	*sb,
+	void			*data)
+{
+	vnode_t			*vp;
+	struct inode		*inode;
+	struct dentry		*result;
+	xfs_fid2_t		xfid;
+	vfs_t			*vfsp = LINVFS_GET_VFS(sb);
+	int			error;
+
+	xfid.fid_len = sizeof(xfs_fid2_t) - sizeof(xfid.fid_len);
+	xfid.fid_pad = 0;
+	xfid.fid_gen = ((__u32 *)data)[1];
+	xfid.fid_ino = ((__u32 *)data)[0];
+
+	VFS_VGET(vfsp, &vp, (fid_t *)&xfid, error);
+	if (error || vp == NULL)
+		return ERR_PTR(-ESTALE) ;
+
+	inode = LINVFS_GET_IP(vp);
+	result = d_alloc_anon(inode);
+        if (!result) {
+		iput(inode);
+		return ERR_PTR(-ENOMEM);
+	}
+	result->d_vfs_flags |= DCACHE_REFERENCED;
+	return result;
+}
+
 STATIC struct super_block *
 linvfs_get_sb(
 	struct file_system_type	*fs_type,
@@ -754,10 +952,6 @@
 	return get_sb_bdev(fs_type, flags, dev_name, data, linvfs_fill_super);
 }
 
-STATIC struct export_operations linvfs_export_ops = {
-	.get_parent		= linvfs_get_parent,
-};
-
 STATIC int
 linvfs_show_options(
 	struct seq_file		*m,
@@ -767,6 +961,11 @@
 
 	return xfs_showargs(vfsp, m);
 }
+
+STATIC struct export_operations linvfs_export_ops = {
+	.get_parent		= linvfs_get_parent,
+	.get_dentry		= linvfs_get_dentry,
+};
 
 STATIC struct super_operations linvfs_sops = {
 	.alloc_inode		= linvfs_alloc_inode,
diff -Nru a/fs/xfs/linux/xfs_super.h b/fs/xfs/linux/xfs_super.h
--- a/fs/xfs/linux/xfs_super.h	Sun Nov 10 19:28:38 2002
+++ b/fs/xfs/linux/xfs_super.h	Sun Nov 10 19:28:38 2002
@@ -32,7 +32,7 @@
 #ifndef __XFS_SUPER_H__
 #define __XFS_SUPER_H__
 
-#ifdef CONFIG_FS_POSIX_ACL
+#ifdef CONFIG_XFS_POSIX_ACL
 # define XFS_ACL_STRING		"ACLs, "
 #else
 # define XFS_ACL_STRING
@@ -73,15 +73,20 @@
 				XFS_QUOTA_STRING XFS_VNTRACE_STRING \
 				XFS_DBG_STRING /* DBG must be last */
 
-
 #define LINVFS_GET_VFS(s) \
 	(vfs_t *)((s)->s_fs_info)
 #define LINVFS_SET_VFS(s, vfsp) \
 	((s)->s_fs_info = vfsp)
 
+struct pb_target;
+struct block_device;
+
+extern void xfs_initialize_vnode (bhv_desc_t *, vnode_t *, bhv_desc_t *, int);
+
+extern int  xfs_blkdev_get (const char *, struct block_device **);
+extern void xfs_blkdev_put (struct block_device *);
 
-extern void
-linvfs_set_inode_ops(
-	struct inode	*inode);
+extern struct pb_target *xfs_alloc_buftarg (struct block_device *);
+extern void xfs_free_buftarg (struct pb_target *);
 
 #endif	/* __XFS_SUPER_H__ */
diff -Nru a/fs/xfs/linux/xfs_sysctl.c b/fs/xfs/linux/xfs_sysctl.c
--- a/fs/xfs/linux/xfs_sysctl.c	Sun Nov 10 19:28:41 2002
+++ b/fs/xfs/linux/xfs_sysctl.c	Sun Nov 10 19:28:41 2002
@@ -40,43 +40,14 @@
 
 extern struct xfsstats xfsstats;
 
-STATIC ulong xfs_min[XFS_PARAM] = { \
-			    0,			    0, 0, 0, 0, 0 };
-STATIC ulong xfs_max[XFS_PARAM] = { \
-	XFS_REFCACHE_SIZE_MAX,  XFS_REFCACHE_SIZE_MAX, 1, 1, 1, 1 };
+STATIC ulong xfs_min[XFS_PARAM] = { 0, 0, 0, 0 };
+STATIC ulong xfs_max[XFS_PARAM] = { 1, 1, 1, 1 };
 
-xfs_param_t xfs_params = { 128, 32, 0, 1, 0, 0 };
+xfs_param_t xfs_params = { 0, 1, 0, 0 };
 
 static struct ctl_table_header *xfs_table_header;
 
 
-/* Custom proc handlers */
-
-STATIC int
-xfs_refcache_resize_proc_handler(
-	ctl_table	*ctl,
-	int		write,
-	struct file	*filp,
-	void		*buffer,
-	size_t		*lenp)
-{
-	int		ret, *valp = ctl->data;
-	int		xfs_refcache_new_size;
-	int		xfs_refcache_old_size = *valp;
-
-	ret = proc_doulongvec_minmax(ctl, write, filp, buffer, lenp);
-	xfs_refcache_new_size = *valp;
-
-	if (!ret && write && xfs_refcache_new_size != xfs_refcache_old_size) {
-		xfs_refcache_resize(xfs_refcache_new_size);
-		/* Don't purge more than size of the cache */
-		if (xfs_refcache_new_size < xfs_params.refcache_purge)
-			xfs_params.refcache_purge = xfs_refcache_new_size;
-	}
-
-	return ret;
-}
-
 STATIC int
 xfs_stats_clear_proc_handler(
 	ctl_table	*ctl,
@@ -103,14 +74,6 @@
 }
 
 STATIC ctl_table xfs_table[] = {
-	{XFS_REFCACHE_SIZE, "refcache_size", &xfs_params.refcache_size,
-	sizeof(ulong), 0644, NULL, &xfs_refcache_resize_proc_handler,
-	&sysctl_intvec, NULL, &xfs_min[0], &xfs_max[0]},
-
-	{XFS_REFCACHE_PURGE, "refcache_purge", &xfs_params.refcache_purge,
-	sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax,
-	&sysctl_intvec, NULL, &xfs_min[1], &xfs_params.refcache_size},
-
 	{XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear,
 	sizeof(ulong), 0644, NULL, &xfs_stats_clear_proc_handler,
 	&sysctl_intvec, NULL, &xfs_min[2], &xfs_max[2]},
diff -Nru a/fs/xfs/linux/xfs_sysctl.h b/fs/xfs/linux/xfs_sysctl.h
--- a/fs/xfs/linux/xfs_sysctl.h	Sun Nov 10 19:28:36 2002
+++ b/fs/xfs/linux/xfs_sysctl.h	Sun Nov 10 19:28:36 2002
@@ -42,8 +42,6 @@
 #define XFS_PARAM	(sizeof(struct xfs_param) / sizeof(ulong))
 
 typedef struct xfs_param {
-	ulong	refcache_size;	/* Size of NFS reference cache.          */
-	ulong	refcache_purge;	/* # of entries to purge each time.      */
 	ulong	stats_clear;	/* Reset all XFS statistics to zero.     */
 	ulong	restrict_chown;	/* Root/non-root can give away files.    */
 	ulong	sgid_inherit;	/* Inherit ISGID bit if process' GID is  */
@@ -52,12 +50,10 @@
 } xfs_param_t;
 
 enum {
-	XFS_REFCACHE_SIZE = 1,
-	XFS_REFCACHE_PURGE = 2,
-	XFS_STATS_CLEAR = 3,
-	XFS_RESTRICT_CHOWN = 4,
-	XFS_SGID_INHERIT = 5,
-	XFS_SYMLINK_MODE = 6,
+	XFS_STATS_CLEAR = 1,
+	XFS_RESTRICT_CHOWN = 2,
+	XFS_SGID_INHERIT = 3,
+	XFS_SYMLINK_MODE = 4,
 };
 
 extern xfs_param_t	xfs_params;
diff -Nru a/fs/xfs/linux/xfs_vnode.c b/fs/xfs/linux/xfs_vnode.c
--- a/fs/xfs/linux/xfs_vnode.c	Sun Nov 10 19:28:38 2002
+++ b/fs/xfs/linux/xfs_vnode.c	Sun Nov 10 19:28:38 2002
@@ -184,7 +184,6 @@
 		return NULL;
 
 	vn_trace_exit(vp, "vn_get", (inst_t *)__return_address);
-	ASSERT((vp->v_flag & VPURGE) == 0);
 
 	return vp;
 }
@@ -237,8 +236,6 @@
 vn_purge(struct vnode *vp, vmap_t *vmap)
 {
 	vn_trace_entry(vp, "vn_purge", (inst_t *)__return_address);
-
-	ASSERT(vp->v_flag & VPURGE);
 
 again:
 	/*
diff -Nru a/fs/xfs/linux/xfs_vnode.h b/fs/xfs/linux/xfs_vnode.h
--- a/fs/xfs/linux/xfs_vnode.h	Sun Nov 10 19:28:41 2002
+++ b/fs/xfs/linux/xfs_vnode.h	Sun Nov 10 19:28:41 2002
@@ -119,7 +119,6 @@
 #define VFRLOCKS	 0x8000000	/* vnode has FR locks applied	*/
 #define VENF_LOCKING	0x10000000	/* enf. mode FR locking in effect */
 #define VOPLOCK		0x20000000	/* oplock set on the vnode	*/
-#define VPURGE		0x40000000	/* In the linux 'put' thread	*/
 
 typedef enum vrwlock	{ VRWLOCK_NONE, VRWLOCK_READ,
 			  VRWLOCK_WRITE, VRWLOCK_WRITE_DIRECT,
diff -Nru a/fs/xfs/pagebuf/page_buf.c b/fs/xfs/pagebuf/page_buf.c
--- a/fs/xfs/pagebuf/page_buf.c	Sun Nov 10 19:28:36 2002
+++ b/fs/xfs/pagebuf/page_buf.c	Sun Nov 10 19:28:36 2002
@@ -341,7 +341,7 @@
 _pagebuf_get_pages(
 	page_buf_t		*pb,
 	int			page_count,
-	int			flags)
+	page_buf_flags_t	flags)
 {
 	int			gpf_mask = pb_to_gfp(flags);
 
@@ -392,10 +392,10 @@
  */
 void
 _pagebuf_free_object(
-	pb_hash_t	*hash,	/* hash bucket for buffer	*/
-	page_buf_t	*pb)	/* buffer to deallocate		*/
+	pb_hash_t		*hash,	/* hash bucket for buffer */
+	page_buf_t		*pb)	/* buffer to deallocate	*/
 {
-	int		pb_flags = pb->pb_flags;
+	page_buf_flags_t	pb_flags = pb->pb_flags;
 
 	PB_TRACE(pb, PB_TRACE_REC(free_obj), 0);
 	pb->pb_flags |= PBF_FREED;
@@ -571,7 +571,8 @@
 
 	if (!pb->pb_locked) {
 		for (pi = 0; pi < page_count; pi++) {
-			unlock_page(pb->pb_pages[pi]);
+			if (pb->pb_pages[pi])
+				unlock_page(pb->pb_pages[pi]);
 		}
 	}
 
@@ -827,7 +828,7 @@
 	struct inode		*inode,
 	loff_t			ioff,
 	size_t			isize,
-	int			flags)
+	page_buf_flags_t	flags)
 {
 	page_buf_t		*pb = NULL;
 
@@ -848,7 +849,7 @@
 	pb_target_t		*target,
 	loff_t			ioff,
 	size_t			isize,
-	int			flags)
+	page_buf_flags_t	flags)
 {
 	flags |= (PBF_TRYLOCK|PBF_READ|PBF_ASYNC|PBF_MAPPABLE|PBF_READ_AHEAD);
 	pagebuf_get(target, ioff, isize, flags);
@@ -936,7 +937,7 @@
 {
 	int			rval;
 	void			*rmem = NULL;
-	int			flags = _PBF_LOCKABLE | PBF_FORCEIO;
+	page_buf_flags_t	flags = _PBF_LOCKABLE | PBF_FORCEIO;
 	page_buf_t		*pb;
 	size_t			tlen = 0;
 
@@ -1229,10 +1230,8 @@
 pagebuf_iostart(			/* start I/O on a buffer	  */
 	page_buf_t		*pb,	/* buffer to start		  */
 	page_buf_flags_t	flags)	/* PBF_LOCK, PBF_ASYNC, PBF_READ, */
-					/* PBF_WRITE, PBF_ALLOCATE,	  */
-					/* PBF_DELWRI, 			  */
+					/* PBF_WRITE, PBF_DELWRI,	  */
 					/* PBF_SYNC, PBF_DONT_BLOCK	  */
-					/* PBF_RELEASE			  */
 {
 	int			status = 0;
 
@@ -1671,7 +1670,7 @@
 	page_buf_t		*pb;
 	struct list_head	*curr, *next, tmp;
 	struct timer_list	pb_daemon_timer =
-		{ .function = (timeout_fn)pagebuf_daemon_wakeup };
+		TIMER_INITIALIZER((timeout_fn)pagebuf_daemon_wakeup, 0, 0);
 
 	/*  Set up the thread  */
 	daemonize();
diff -Nru a/fs/xfs/pagebuf/page_buf.h b/fs/xfs/pagebuf/page_buf.h
--- a/fs/xfs/pagebuf/page_buf.h	Sun Nov 10 19:28:40 2002
+++ b/fs/xfs/pagebuf/page_buf.h	Sun Nov 10 19:28:40 2002
@@ -240,15 +240,16 @@
 		struct pb_target *,	/* inode for buffer		*/
 		loff_t,			/* starting offset of range	*/
 		size_t,			/* length of range		*/
-		page_buf_flags_t);	/* PBF_LOCK, PBF_READ, PBF_ALLOCATE, */
-					/* PBF_ASYNC,			*/	
+		page_buf_flags_t);	/* PBF_LOCK, PBF_READ,		*/
+					/* PBF_ASYNC			*/	
 
 extern page_buf_t *pagebuf_lookup(
 		struct pb_target *,
 		struct inode *,
 		loff_t,			/* starting offset of range	*/
 		size_t,			/* length of range		*/
-		int);			/* PBF_ENTER_PAGES		*/
+		page_buf_flags_t);	/* PBF_READ, PBF_WRITE,		*/
+					/* PBF_FORCEIO, _PBF_LOCKABLE	*/
 
 extern page_buf_t *pagebuf_get_empty(	/* allocate pagebuf struct with */
 					/*  no memory or disk address	*/
@@ -272,7 +273,7 @@
 		struct pb_target  *,	/* target for buffer (or NULL)	*/
 		loff_t,			/* starting offset of range	*/
 		size_t,			/* length of range		*/
-		int);			/* additional read flags	*/
+		page_buf_flags_t);	/* additional read flags	*/
 
 /* Writing and Releasing Buffers */
 
@@ -314,10 +315,9 @@
 
 extern int pagebuf_iostart(		/* start I/O on a buffer	*/
 		page_buf_t *,		/* buffer to start		*/
-		page_buf_flags_t);	/* PBF_LOCK, PBF_ASYNC, PBF_READ, */
-					/* PBF_WRITE, PBF_ALLOCATE,	*/
-					/* PBF_DELWRI, 			*/
-					/* PBF_SYNC			*/
+		page_buf_flags_t);	/* PBF_LOCK, PBF_ASYNC,		*/
+					/* PBF_READ, PBF_WRITE,		*/
+					/* PBF_DELWRI, PBF_SYNC		*/
 
 extern int pagebuf_iorequest(		/* start real I/O		*/
 		page_buf_t *);		/* buffer to convey to device	*/
diff -Nru a/fs/xfs/xfs.h b/fs/xfs/xfs.h
--- a/fs/xfs/xfs.h	Sun Nov 10 19:28:37 2002
+++ b/fs/xfs/xfs.h	Sun Nov 10 19:28:37 2002
@@ -109,6 +109,4 @@
 #include <xfs_utils.h>
 #include <xfs_dmapi.h>
 
-#include <linux/xfs_lrw.h>
-
 #endif	/* __XFS_H__ */
diff -Nru a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
--- a/fs/xfs/xfs_acl.c	Sun Nov 10 19:28:39 2002
+++ b/fs/xfs/xfs_acl.c	Sun Nov 10 19:28:39 2002
@@ -33,7 +33,7 @@
 #include <xfs.h>
 #include <linux/posix_acl_xattr.h>
 
-STATIC int	xfs_acl_setmode(vnode_t *, xfs_acl_t *);
+STATIC int	xfs_acl_setmode(vnode_t *, xfs_acl_t *, int *);
 STATIC void	xfs_acl_filter_mode(mode_t, xfs_acl_t *);
 STATIC void	xfs_acl_get_endian(xfs_acl_t *);
 STATIC int	xfs_acl_access(uid_t, gid_t, xfs_acl_t *, mode_t, cred_t *);
@@ -279,6 +279,7 @@
 	posix_acl_xattr_header	*ext_acl = acl;
 	xfs_acl_t		*xfs_acl;
 	int			error;
+	int			basicperms = 0; /* more than std unix perms? */
 
 	if (!acl)
 		return -EINVAL;
@@ -303,8 +304,21 @@
 
 	/* Incoming ACL exists, set file mode based on its value */
 	if (kind == _ACL_TYPE_ACCESS)
-		xfs_acl_setmode(vp, xfs_acl);
-	xfs_acl_set_attr(vp, xfs_acl, kind, &error);
+		xfs_acl_setmode(vp, xfs_acl, &basicperms);
+
+	/*
+	 * If we have more than std unix permissions, set up the actual attr.
+	 * Otherwise, delete any existing attr.  This prevents us from
+	 * having actual attrs for permissions that can be stored in the
+	 * standard permission bits.
+	 */
+	if (!basicperms) {
+		xfs_acl_set_attr(vp, xfs_acl, kind, &error);
+	} else {
+		xfs_acl_vremove(vp, _ACL_TYPE_ACCESS);
+	}
+		
+
 out:
 	VN_RELE(vp);
 	_ACL_FREE(xfs_acl);
@@ -368,6 +382,38 @@
 }
 
 /*
+ * Look for any effective exec access, to allow CAP_DAC_OVERRIDE for exec.
+ * Ignore checking for exec in USER_OBJ when there is no mask, because
+ * in this "minimal acl" case we don't have any actual acls, and we
+ * won't even be here.
+ */
+STATIC int
+xfs_acl_find_any_exec(
+	xfs_acl_t	*fap)
+{
+	int		i;
+	int		masked_aces = 0;
+	int		mask = 0;
+
+	for (i = 0; i < fap->acl_cnt; i++) {
+		if (fap->acl_entry[i].ae_perm & ACL_EXECUTE) {
+			if (fap->acl_entry[i].ae_tag & (ACL_USER_OBJ|ACL_OTHER))
+				return 1;
+
+			if (fap->acl_entry[i].ae_tag == ACL_MASK)
+				mask = fap->acl_entry[i].ae_perm;
+			else
+				masked_aces |= fap->acl_entry[i].ae_perm;
+
+			if ((mask & masked_aces) & ACL_EXECUTE)
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
+/*
  * The access control process to determine the access permission:
  *	if uid == file owner id, use the file owner bits.
  *	if gid == file owner group id, use the file group bits.
@@ -376,19 +422,25 @@
  *	until all acl entries are exhausted. The final permission produced
  *	by matching acl entry or entries needs to be & with group permission.
  *	if not owner, owning group, or matching entry in ACL, use file
- *	other bits.
+ *	other bits.  Don't allow CAP_DAC_OVERRIDE on exec access unless
+ *	there is some effective exec access somewhere.
  */
 STATIC int
 xfs_acl_capability_check(
 	mode_t		mode,
-	cred_t		*cr)
+	cred_t		*cr,
+	xfs_acl_t	*fap)
 {
 	if ((mode & ACL_READ) && !capable_cred(cr, CAP_DAC_READ_SEARCH))
 		return EACCES;
 	if ((mode & ACL_WRITE) && !capable_cred(cr, CAP_DAC_OVERRIDE))
 		return EACCES;
-	if ((mode & ACL_EXECUTE) && !capable_cred(cr, CAP_DAC_OVERRIDE))
+	if ((mode & ACL_EXECUTE) &&
+	    (!capable_cred(cr, CAP_DAC_OVERRIDE) ||
+             !xfs_acl_find_any_exec(fap))) {
 		return EACCES;
+	}
+
 	return 0;
 }
 
@@ -493,7 +545,8 @@
 	case 0:
 		break;
 	}
-	return xfs_acl_capability_check(md, cr);
+
+	return xfs_acl_capability_check(md, cr, fap);
 }
 
 /*
@@ -679,6 +732,7 @@
 {
 	xfs_acl_t	*cacl;
 	int		error = 0;
+	int		basicperms = 0;
 
 	/*
 	 * If the parent does not have a default ACL, or it's an
@@ -702,7 +756,7 @@
 
 	memcpy(cacl, pdaclp, sizeof(xfs_acl_t));
 	xfs_acl_filter_mode(vap->va_mode, cacl);
-	xfs_acl_setmode(vp, cacl);
+	xfs_acl_setmode(vp, cacl, &basicperms);
 
 	/*
 	 * Set the Default and Access ACL on the file.	The mode is already
@@ -713,7 +767,7 @@
 	 */
 	if (vp->v_type == VDIR)
 		xfs_acl_set_attr(vp, pdaclp, _ACL_TYPE_DEFAULT, &error);
-	if (!error)
+	if (!error && !basicperms)
 		xfs_acl_set_attr(vp, cacl, _ACL_TYPE_ACCESS, &error);
 	_ACL_FREE(cacl);
 	return error;
@@ -729,13 +783,16 @@
 STATIC int
 xfs_acl_setmode(
 	vnode_t		*vp,
-	xfs_acl_t	*acl)
+	xfs_acl_t	*acl,
+	int		*basicperms)
 {
 	vattr_t		va;
 	xfs_acl_entry_t *ap;
 	xfs_acl_entry_t *gap = NULL;
 	int		i, error, nomask = 1;
 
+	*basicperms = 1;
+
 	if (acl->acl_cnt == XFS_ACL_NOT_PRESENT)
 		return 0;
 
@@ -759,14 +816,16 @@
 		case ACL_GROUP_OBJ:
 			gap = ap;
 			break;
-		case ACL_MASK:
+		case ACL_MASK:	/* more than just standard modes */
 			nomask = 0;
 			va.va_mode |= ap->ae_perm << 3;
+			*basicperms = 0;
 			break;
 		case ACL_OTHER:
 			va.va_mode |= ap->ae_perm;
 			break;
-		default:
+		default:	/* more than just standard modes */
+			*basicperms = 0;
 			break;
 		}
 		ap++;
diff -Nru a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h
--- a/fs/xfs/xfs_acl.h	Sun Nov 10 19:28:39 2002
+++ b/fs/xfs/xfs_acl.h	Sun Nov 10 19:28:39 2002
@@ -63,7 +63,7 @@
 
 #ifdef __KERNEL__
 
-#ifdef CONFIG_FS_POSIX_ACL
+#ifdef CONFIG_XFS_POSIX_ACL
 
 struct vattr;
 struct vnode;
diff -Nru a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
--- a/fs/xfs/xfs_attr.c	Sun Nov 10 19:28:40 2002
+++ b/fs/xfs/xfs_attr.c	Sun Nov 10 19:28:40 2002
@@ -1170,6 +1170,7 @@
 	state->args = args;
 	state->mp = mp;
 	state->blocksize = state->mp->m_sb.sb_blocksize;
+	state->node_ents = state->mp->m_attr_node_ents;
 
 	/*
 	 * Search to see if name already exists, and get back a pointer
@@ -1337,6 +1338,7 @@
 		state->args = args;
 		state->mp = mp;
 		state->blocksize = state->mp->m_sb.sb_blocksize;
+		state->node_ents = state->mp->m_attr_node_ents;
 		state->inleaf = 0;
 		error = xfs_da_node_lookup_int(state, &retval);
 		if (error)
@@ -1428,6 +1430,7 @@
 	state->args = args;
 	state->mp = dp->i_mount;
 	state->blocksize = state->mp->m_sb.sb_blocksize;
+	state->node_ents = state->mp->m_attr_node_ents;
 
 	/*
 	 * Search to see if name exists, and get back a pointer to it.
@@ -1695,6 +1698,7 @@
 	state->args = args;
 	state->mp = args->dp->i_mount;
 	state->blocksize = state->mp->m_sb.sb_blocksize;
+	state->node_ents = state->mp->m_attr_node_ents;
 
 	/*
 	 * Search to see if name exists, and get back a pointer to it.
diff -Nru a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c
--- a/fs/xfs/xfs_bmap_btree.c	Sun Nov 10 19:28:40 2002
+++ b/fs/xfs/xfs_bmap_btree.c	Sun Nov 10 19:28:40 2002
@@ -1874,7 +1874,7 @@
  * xfs_bmbt_get_startblock, xfs_bmbt_get_blockcount and xfs_bmbt_get_state.
  */
 
-static __inline__ void
+STATIC __inline__ void
 __xfs_bmbt_get_all(
 		__uint64_t l0,
 		__uint64_t l1,
@@ -2514,10 +2514,10 @@
 #if XFS_BIG_FILESYSTEMS
 	r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
 		((xfs_bmbt_rec_base_t)o << 9) |
-		((xfs_bmbt_rec_base_t)b >> 43));
+		((xfs_bmbt_rec_base_t)b >> 43);
 	r->l1 = ((xfs_bmbt_rec_base_t)b << 21) |
 		((xfs_bmbt_rec_base_t)c &
-		(xfs_bmbt_rec_base_t)XFS_MASK64LO(21)));
+		(xfs_bmbt_rec_base_t)XFS_MASK64LO(21));
 #else	/* !XFS_BIG_FILESYSTEMS */
 	if (ISNULLSTARTBLOCK(b)) {
 		r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) |
diff -Nru a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
--- a/fs/xfs/xfs_buf.h	Sun Nov 10 19:28:41 2002
+++ b/fs/xfs/xfs_buf.h	Sun Nov 10 19:28:41 2002
@@ -203,7 +203,6 @@
 
 static inline int	xfs_bawrite(void *mp, page_buf_t *bp)
 {
-	extern int	xfs_bdstrat_cb(struct xfs_buf *);
 	int ret;
 
 	bp->pb_fspriv3 = mp;
@@ -278,8 +277,6 @@
 
 static inline int xfs_bdwrite(void *mp, page_buf_t *bp)
 {
-	extern int	xfs_bdstrat_cb(struct xfs_buf *);
-
 	bp->pb_strat = xfs_bdstrat_cb;
 	bp->pb_fspriv3 = mp;
 
diff -Nru a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c
--- a/fs/xfs/xfs_buf_item.c	Sun Nov 10 19:28:36 2002
+++ b/fs/xfs/xfs_buf_item.c	Sun Nov 10 19:28:36 2002
@@ -331,6 +331,7 @@
 			vecp++;
 			first_bit = next_bit;
 			last_bit = next_bit;
+			nbits = 1;
 		} else {
 			last_bit++;
 			nbits++;
@@ -1029,12 +1030,12 @@
 		}
 
 		if ((XFS_BUF_TARGET_DEV(bp) != lastdev) ||
-		    ((lbolt - lasttime) > 500)) {
+		    (time_after(jiffies, (lasttime + 5*HZ)))) {
+			lasttime = jiffies;
 			prdev("XFS write error in file system meta-data "
 			      "block 0x%Lx in %s",
 			      XFS_BUF_TARGET_DEV(bp),
 			      XFS_BUF_ADDR(bp), mp->m_fsname);
-			lasttime = lbolt;
 		}
 		lastdev = XFS_BUF_TARGET_DEV(bp);
 
diff -Nru a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c
--- a/fs/xfs/xfs_da_btree.c	Sun Nov 10 19:28:40 2002
+++ b/fs/xfs/xfs_da_btree.c	Sun Nov 10 19:28:40 2002
@@ -381,12 +381,16 @@
 	INT_SET(node->btree[1].hashval, ARCH_CONVERT, blk2->hashval);
 	INT_SET(node->btree[1].before, ARCH_CONVERT, blk2->blkno);
 	INT_SET(node->hdr.count, ARCH_CONVERT, 2);
-	if (XFS_DIR_IS_V2(mp)) {
+
+#ifdef DEBUG
+	if (INT_GET(oldroot->hdr.info.magic, ARCH_CONVERT) == XFS_DIR2_LEAFN_MAGIC) {
 		ASSERT(blk1->blkno >= mp->m_dirleafblk &&
 		       blk1->blkno < mp->m_dirfreeblk);
 		ASSERT(blk2->blkno >= mp->m_dirleafblk &&
 		       blk2->blkno < mp->m_dirfreeblk);
 	}
+#endif
+
 	/* Header is already logged by xfs_da_node_create */
 	xfs_da_log_buf(tp, bp,
 		XFS_DA_LOGRANGE(node, node->btree,
@@ -421,7 +425,7 @@
 	/*
 	 * Do we have to split the node?
 	 */
-	if ((INT_GET(node->hdr.count, ARCH_CONVERT) + newcount) > XFS_DA_NODE_ENTRIES(state->mp)) {
+	if ((INT_GET(node->hdr.count, ARCH_CONVERT) + newcount) > state->node_ents) {
 		/*
 		 * Allocate a new node, add to the doubly linked chain of
 		 * nodes, then move some of our excess entries into it.
@@ -825,7 +829,7 @@
 	ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
 	node = (xfs_da_intnode_t *)info;
 	count = INT_GET(node->hdr.count, ARCH_CONVERT);
-	if (count > (XFS_DA_NODE_ENTRIES(state->mp) >> 1)) {
+	if (count > (state->node_ents >> 1)) {
 		*action = 0;	/* blk over 50%, dont try to join */
 		return(0);	/* blk over 50%, dont try to join */
 	}
@@ -879,8 +883,8 @@
 		ASSERT(bp != NULL);
 
 		node = (xfs_da_intnode_t *)info;
-		count  = XFS_DA_NODE_ENTRIES(state->mp);
-		count -= XFS_DA_NODE_ENTRIES(state->mp) >> 2;
+		count  = state->node_ents;
+		count -= state->node_ents >> 2;
 		count -= INT_GET(node->hdr.count, ARCH_CONVERT);
 		node = bp->data;
 		ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC);
diff -Nru a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h
--- a/fs/xfs/xfs_da_btree.h	Sun Nov 10 19:28:39 2002
+++ b/fs/xfs/xfs_da_btree.h	Sun Nov 10 19:28:39 2002
@@ -90,15 +90,6 @@
 typedef struct xfs_da_node_hdr xfs_da_node_hdr_t;
 typedef struct xfs_da_node_entry xfs_da_node_entry_t;
 
-#define XFS_DA_NODE_ENTSIZE_BYNAME	/* space a name uses */ \
-	(sizeof(xfs_da_node_entry_t))
-#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_DA_NODE_ENTRIES)
-int xfs_da_node_entries(struct xfs_mount *mp);
-#define XFS_DA_NODE_ENTRIES(mp)		xfs_da_node_entries(mp)
-#else
-#define XFS_DA_NODE_ENTRIES(mp)		((mp)->m_da_node_ents)
-#endif
-
 #define XFS_DA_MAXHASH	((xfs_dahash_t)-1) /* largest valid hash value */
 
 /*
@@ -243,7 +234,7 @@
 typedef struct xfs_da_state_blk {
 	xfs_dabuf_t	*bp;		/* buffer containing block */
 	xfs_dablk_t	blkno;		/* filesystem blkno of buffer */
-	xfs_daddr_t		disk_blkno;	/* on-disk blkno (in BBs) of buffer */
+	xfs_daddr_t	disk_blkno;	/* on-disk blkno (in BBs) of buffer */
 	int		index;		/* relevant index into block */
 	xfs_dahash_t	hashval;	/* last hash value in block */
 	int		magic;		/* blk's magic number, ie: blk type */
@@ -257,12 +248,13 @@
 typedef struct xfs_da_state {
 	xfs_da_args_t		*args;		/* filename arguments */
 	struct xfs_mount	*mp;		/* filesystem mount point */
-	int			blocksize;	/* logical block size */
-	int			inleaf;		/* insert into 1->lf, 0->splf */
+	unsigned int		blocksize;	/* logical block size */
+	unsigned int		node_ents;	/* how many entries in danode */
 	xfs_da_state_path_t	path;		/* search/split paths */
 	xfs_da_state_path_t	altpath;	/* alternate path for join */
-	int			extravalid;	/* T/F: extrablk is in use */
-	int			extraafter;	/* T/F: extrablk is after new */
+	unsigned int		inleaf     : 1;	/* insert into 1->lf, 0->splf */
+	unsigned int		extravalid : 1;	/* T/F: extrablk is in use */
+	unsigned int		extraafter : 1;	/* T/F: extrablk is after new */
 	xfs_da_state_blk_t	extrablk;	/* for double-splits on leafs */
 						/* for dirv2 extrablk is data */
 } xfs_da_state_t;
diff -Nru a/fs/xfs/xfs_dir.c b/fs/xfs/xfs_dir.c
--- a/fs/xfs/xfs_dir.c	Sun Nov 10 19:28:38 2002
+++ b/fs/xfs/xfs_dir.c	Sun Nov 10 19:28:38 2002
@@ -176,7 +176,7 @@
 	count = shortcount > leafcount ? shortcount : leafcount;
 	mp->m_dircook_elog = xfs_da_log2_roundup(count + 1);
 	ASSERT(mp->m_dircook_elog <= mp->m_sb.sb_blocklog);
-	mp->m_da_node_ents =
+	mp->m_dir_node_ents = mp->m_attr_node_ents =
 		(XFS_LBSIZE(mp) - (uint)sizeof(xfs_da_node_hdr_t)) /
 		(uint)sizeof(xfs_da_node_entry_t);
 	mp->m_dir_magicpct = (XFS_LBSIZE(mp) * 37) / 100;
@@ -734,6 +734,7 @@
 	state->args = args;
 	state->mp = args->dp->i_mount;
 	state->blocksize = state->mp->m_sb.sb_blocksize;
+	state->node_ents = state->mp->m_dir_node_ents;
 
 	/*
 	 * Search to see if name already exists, and get back a pointer
@@ -787,6 +788,7 @@
 	state->args = args;
 	state->mp = args->dp->i_mount;
 	state->blocksize = state->mp->m_sb.sb_blocksize;
+	state->node_ents = state->mp->m_dir_node_ents;
 
 	/*
 	 * Search to see if name exists, and get back a pointer to it.
@@ -835,6 +837,7 @@
 	state->args = args;
 	state->mp = args->dp->i_mount;
 	state->blocksize = state->mp->m_sb.sb_blocksize;
+	state->node_ents = state->mp->m_dir_node_ents;
 
 	/*
 	 * Search to see if name exists,
@@ -1019,6 +1022,7 @@
 	state->args = args;
 	state->mp = args->dp->i_mount;
 	state->blocksize = state->mp->m_sb.sb_blocksize;
+	state->node_ents = state->mp->m_dir_node_ents;
 	inum = args->inumber;
 
 	/*
diff -Nru a/fs/xfs/xfs_dir2.c b/fs/xfs/xfs_dir2.c
--- a/fs/xfs/xfs_dir2.c	Sun Nov 10 19:28:41 2002
+++ b/fs/xfs/xfs_dir2.c	Sun Nov 10 19:28:41 2002
@@ -107,7 +107,10 @@
 	mp->m_dirdatablk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_DATA_FIRSTDB(mp));
 	mp->m_dirleafblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_LEAF_FIRSTDB(mp));
 	mp->m_dirfreeblk = XFS_DIR2_DB_TO_DA(mp, XFS_DIR2_FREE_FIRSTDB(mp));
-	mp->m_da_node_ents =
+	mp->m_attr_node_ents =
+		(mp->m_sb.sb_blocksize - (uint)sizeof(xfs_da_node_hdr_t)) /
+		(uint)sizeof(xfs_da_node_entry_t);
+	mp->m_dir_node_ents =
 		(mp->m_dirblksize - (uint)sizeof(xfs_da_node_hdr_t)) /
 		(uint)sizeof(xfs_da_node_entry_t);
 	mp->m_dir_magicpct = (mp->m_dirblksize * 37) / 100;
diff -Nru a/fs/xfs/xfs_dir2_node.c b/fs/xfs/xfs_dir2_node.c
--- a/fs/xfs/xfs_dir2_node.c	Sun Nov 10 19:28:36 2002
+++ b/fs/xfs/xfs_dir2_node.c	Sun Nov 10 19:28:36 2002
@@ -1274,6 +1274,7 @@
 	state->args = args;
 	state->mp = args->dp->i_mount;
 	state->blocksize = state->mp->m_dirblksize;
+	state->node_ents = state->mp->m_dir_node_ents;
 	/*
 	 * Look up the name.  We're not supposed to find it, but
 	 * this gives us the insertion point.
@@ -1747,6 +1748,7 @@
 	state->args = args;
 	state->mp = args->dp->i_mount;
 	state->blocksize = state->mp->m_dirblksize;
+	state->node_ents = state->mp->m_dir_node_ents;
 	/*
 	 * Fill in the path to the entry in the cursor.
 	 */
@@ -1791,6 +1793,7 @@
 	state->args = args;
 	state->mp = args->dp->i_mount;
 	state->blocksize = state->mp->m_dirblksize;
+	state->node_ents = state->mp->m_dir_node_ents;
 	/*
 	 * Look up the entry we're deleting, set up the cursor.
 	 */
@@ -1861,6 +1864,7 @@
 	state->args = args;
 	state->mp = args->dp->i_mount;
 	state->blocksize = state->mp->m_dirblksize;
+	state->node_ents = state->mp->m_dir_node_ents;
 	inum = args->inumber;
 	/*
 	 * Lookup the entry to change in the btree.
diff -Nru a/fs/xfs/xfs_dmapi.h b/fs/xfs/xfs_dmapi.h
--- a/fs/xfs/xfs_dmapi.h	Sun Nov 10 19:28:41 2002
+++ b/fs/xfs/xfs_dmapi.h	Sun Nov 10 19:28:41 2002
@@ -268,7 +268,7 @@
 	int		flags,
 	vrwlock_t	*locktype)
 {
-	return nopkg();
+	return ENOSYS;
 }
 
 static __inline int
@@ -288,7 +288,7 @@
 	bhv_desc_t	*bdp,
 	dm_right_t	vp_right)
 {
-	return nopkg();
+	return ENOSYS;
 }
 
 static __inline int
@@ -304,7 +304,7 @@
 	int		retcode,
 	int		flags)
 {
-	return nopkg();
+	return ENOSYS;
 }
 
 static __inline void
diff -Nru a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c
--- a/fs/xfs/xfs_fsops.c	Sun Nov 10 19:28:41 2002
+++ b/fs/xfs/xfs_fsops.c	Sun Nov 10 19:28:41 2002
@@ -563,9 +563,6 @@
 	/* Stop new writers */
 	xfs_start_freeze(mp, XFS_FREEZE_WRITE);
 
-	/* Flush the refcache */
-	xfs_refcache_purge_mp(mp);
-
 	/* Flush delalloc and delwri data */
 	VFS_SYNC(vfsp, SYNC_DELWRI|SYNC_WAIT, NULL, error);
 
diff -Nru a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
--- a/fs/xfs/xfs_iget.c	Sun Nov 10 19:28:39 2002
+++ b/fs/xfs/xfs_iget.c	Sun Nov 10 19:28:39 2002
@@ -31,8 +31,6 @@
  */
 
 #include <xfs.h>
-#include <linux/pagemap.h>
-
 
 /*
  * Initialize the inode hash table for the newly mounted file system.
@@ -108,36 +106,6 @@
 
 	kmem_free(mp->m_chash, mp->m_chsize*sizeof(xfs_chash_t));
 	mp->m_chash = NULL;
-}
-
-void
-xfs_revalidate_inode(
-	xfs_mount_t	*mp,
-	vnode_t		*vp,
-	xfs_inode_t	*ip)
-{
-	struct inode	*inode = LINVFS_GET_IP(vp);
-
-	inode->i_mode	= (ip->i_d.di_mode & MODEMASK) | VTTOIF(vp->v_type);
-	inode->i_nlink	= ip->i_d.di_nlink;
-	inode->i_uid	= ip->i_d.di_uid;
-	inode->i_gid 	= ip->i_d.di_gid;
-	if (((1 << vp->v_type) & ((1<<VBLK) | (1<<VCHR))) == 0) {
-		inode->i_rdev	= NODEV;
-	} else {
-		xfs_dev_t dev = ip->i_df.if_u2.if_rdev;
-		inode->i_rdev	= XFS_DEV_TO_KDEVT(dev);
-	}
-	inode->i_blksize = PAGE_CACHE_SIZE;
-	inode->i_generation = ip->i_d.di_gen;
-	inode->i_size	= ip->i_d.di_size;
-	inode->i_blocks =
-		XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks);
-	inode->i_atime	= ip->i_d.di_atime.t_sec;
-	inode->i_mtime	= ip->i_d.di_mtime.t_sec;
-	inode->i_ctime	= ip->i_d.di_ctime.t_sec;
-
-	vp->v_flag &= ~VMODIFIED;
 }
 
 /*
diff -Nru a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
--- a/fs/xfs/xfs_inode.c	Sun Nov 10 19:28:39 2002
+++ b/fs/xfs/xfs_inode.c	Sun Nov 10 19:28:39 2002
@@ -3384,7 +3384,6 @@
 			 * whether we reached the end or not.
 			 */
 			VMAP(vp, vmap);
-			vp->v_flag |= VPURGE;		/* OK for vn_purge */
 			XFS_MOUNT_IUNLOCK(mp);
 
 			vn_purge(vp, &vmap);
diff -Nru a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
--- a/fs/xfs/xfs_inode.h	Sun Nov 10 19:28:40 2002
+++ b/fs/xfs/xfs_inode.h	Sun Nov 10 19:28:40 2002
@@ -269,8 +269,6 @@
 	sema_t			i_flock;	/* inode flush lock */
 	atomic_t		i_pincount;	/* inode pin count */
 	wait_queue_head_t	i_ipin_wait;	/* inode pinning wait queue */
-	struct xfs_inode	**i_refcache;	/* ptr to entry in ref cache */
-	struct xfs_inode	*i_release;	/* inode to unref */
 
 	/* I/O state */
 	xfs_iocore_t		i_iocore;	/* I/O core */
@@ -531,8 +529,6 @@
 void		xfs_lock_inodes(xfs_inode_t **, int, int, uint);
 
 #define xfs_ipincount(ip)	((unsigned int) atomic_read(&ip->i_pincount))
-
-void xfs_revalidate_inode(struct xfs_mount *, vnode_t *vp, xfs_inode_t *);
 
 #ifdef DEBUG
 void		xfs_isize_check(struct xfs_mount *, xfs_inode_t *, xfs_fsize_t);
diff -Nru a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
--- a/fs/xfs/xfs_log.c	Sun Nov 10 19:28:41 2002
+++ b/fs/xfs/xfs_log.c	Sun Nov 10 19:28:41 2002
@@ -480,9 +480,17 @@
 	 * just worked.
 	 */
 	if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) {
-		int    error;
+		int	error;
+		vfs_t	*vfsp = XFS_MTOVFS(mp);
+		int	readonly = (vfsp->vfs_flag & VFS_RDONLY);
 
-		error = xlog_recover(log,XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY);
+		if (readonly)
+			vfsp->vfs_flag &= ~VFS_RDONLY;
+
+		error = xlog_recover(log, readonly);
+
+		if (readonly)
+			vfsp->vfs_flag |= VFS_RDONLY;
 		if (error) {
 			cmn_err(CE_WARN, "XFS: log mount/recovery failed");
 			xlog_unalloc_log(log);
diff -Nru a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
--- a/fs/xfs/xfs_log_recover.c	Sun Nov 10 19:28:40 2002
+++ b/fs/xfs/xfs_log_recover.c	Sun Nov 10 19:28:40 2002
@@ -145,7 +145,7 @@
     printk("xlog_header_check_dump:\n	 SB : uuid = ");
     for (b=0;b<16;b++) printk("%02x",((unsigned char *)&mp->m_sb.sb_uuid)[b]);
     printk(", fmt = %d\n",XLOG_FMT);
-    printk("	log: uuid = ");
+    printk("    log: uuid = ");
     for (b=0;b<16;b++) printk("%02x",((unsigned char *)&head->h_fs_uuid)[b]);
     printk(", fmt = %d\n", INT_GET(head->h_fmt, ARCH_CONVERT));
 }
@@ -1802,7 +1802,7 @@
 		 */
 		error = 0;
 		if (buf_f->blf_flags & (XFS_BLI_UDQUOT_BUF|XFS_BLI_GDQUOT_BUF)) {
-			/* OK, if this returns nopkg() */
+			/* OK, if this returns ENOSYS */
 			error = xfs_qm_dqcheck((xfs_disk_dquot_t *)
 					       item->ri_buf[i].i_addr,
 					       -1, 0, XFS_QMOPT_DOWARN,
@@ -2315,7 +2315,7 @@
 	 * of looking at the SB quota bits.
 	 *
 	 * The other possibility, of course, is that the quota subsystem was
-	 * removed since the last mount - nopkg().
+	 * removed since the last mount - ENOSYS.
 	 */
 	dq_f = (xfs_dq_logformat_t *)item->ri_buf[0].i_addr;
 	ASSERT(dq_f);
@@ -2323,7 +2323,7 @@
 			   dq_f->qlf_id,
 			   0, XFS_QMOPT_DOWARN,
 			   "xlog_recover_do_dquot_trans (log copy)"))) {
-	  if ((error == nopkg()))
+	  if (error == ENOSYS)
 			return (0);
 		return XFS_ERROR(EIO);
 	}
diff -Nru a/fs/xfs/xfs_macros.c b/fs/xfs/xfs_macros.c
--- a/fs/xfs/xfs_macros.c	Sun Nov 10 19:28:38 2002
+++ b/fs/xfs/xfs_macros.c	Sun Nov 10 19:28:38 2002
@@ -854,14 +854,6 @@
 }
 #endif
 
-#if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DA_NODE_ENTRIES)
-int
-xfs_da_node_entries(xfs_mount_t *mp)
-{
-	return XFS_DA_NODE_ENTRIES(mp);
-}
-#endif
-
 #if XFS_WANT_FUNCS_C || (XFS_WANT_SPACE_C && XFSSO_XFS_DADDR_TO_AGBNO)
 xfs_agblock_t
 xfs_daddr_to_agbno(xfs_mount_t *mp, xfs_daddr_t d)
diff -Nru a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
--- a/fs/xfs/xfs_mount.c	Sun Nov 10 19:28:38 2002
+++ b/fs/xfs/xfs_mount.c	Sun Nov 10 19:28:38 2002
@@ -31,13 +31,6 @@
  */
 
 #include <xfs.h>
-#include <linux/major.h>
-#include <linux/namei.h>
-#include <linux/pagemap.h>
-
-#ifndef EVMS_MAJOR
-#define EVMS_MAJOR	117
-#endif
 
 STATIC void	xfs_mount_reset_sbqflags(xfs_mount_t *);
 STATIC void	xfs_mount_log_sbunit(xfs_mount_t *, __int64_t);
@@ -537,8 +530,6 @@
 	mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog;
 }
 
-extern void xfs_refcache_sbdirty(struct super_block*);
-
 /*
  * xfs_mountfs
  *
@@ -570,6 +561,7 @@
 	extern xfs_ioops_t xfs_iocore_xfs;	/* from xfs_iocore.c */
 	__uint64_t	ret64;
 	uint		quotaflags, quotaondisk, rootqcheck, needquotacheck;
+	uint		uquotaondisk = 0, gquotaondisk = 0;
 	boolean_t	needquotamount;
 	__int64_t	update_flags;
 	int		agno, noio;
@@ -810,12 +802,6 @@
 		return(0);
 	}
 
-	/*
-	 * Set up timer list structure for nfs refcache
-	 */
-	init_timer(&mp->m_sbdirty_timer);
-	mp->m_sbdirty_timer.function = (void (*)(unsigned long)) xfs_refcache_sbdirty;
-
 	/* Initialize the I/O function vector with XFS functions */
 	mp->m_io_ops = xfs_iocore_xfs;
 
@@ -914,7 +900,6 @@
 		VMAP(rvp, vmap);
 		prdev("Root inode %llu is not a directory",
 		      mp->m_dev, (unsigned long long)rip->i_ino);
-		rvp->v_flag |= VPURGE;
 		xfs_iunlock(rip, XFS_ILOCK_EXCL);
 		VN_RELE(rvp);
 		vn_purge(rvp, &vmap);
@@ -928,6 +913,11 @@
 	quotaondisk = XFS_SB_VERSION_HASQUOTA(&mp->m_sb) &&
 		mp->m_sb.sb_qflags & (XFS_UQUOTA_ACCT|XFS_GQUOTA_ACCT);
 
+	if (quotaondisk) {
+		uquotaondisk = mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT;
+		gquotaondisk = mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT;
+	}
+
 	/*
 	 * If the device itself is read-only, we can't allow
 	 * the user to change the state of quota on the mount -
@@ -935,14 +925,16 @@
 	 * which would lead to an I/O error and shutdown
 	 */
 
-	if (((quotaondisk && !XFS_IS_QUOTA_ON(mp)) ||
-	      (!quotaondisk && XFS_IS_QUOTA_ON(mp))) &&
-	      xfs_dev_is_read_only(mp, "changing quota state")) {
+	if (((uquotaondisk && !XFS_IS_UQUOTA_ON(mp)) ||
+	    (!uquotaondisk &&  XFS_IS_UQUOTA_ON(mp)) ||
+	     (gquotaondisk && !XFS_IS_GQUOTA_ON(mp)) ||
+	    (!gquotaondisk &&  XFS_IS_GQUOTA_ON(mp)))  &&
+	    xfs_dev_is_read_only(mp, "changing quota state")) {
 		cmn_err(CE_WARN,
-			"XFS: device %s is read-only, cannot change "
-			"quota state.  Please mount with%s quota option.",
-			mp->m_fsname, quotaondisk ? "" : "out");
-		rvp->v_flag |= VPURGE;
+			"XFS: please mount with%s%s%s.",
+			(!quotaondisk ? "out quota" : ""),
+			(uquotaondisk ? " usrquota" : ""),
+			(gquotaondisk ? " grpquota" : ""));
 		VN_RELE(rvp);
 		vn_remove(rvp);
 		error = XFS_ERROR(EPERM);
@@ -957,7 +949,6 @@
 		 * Free up the root inode.
 		 */
 		cmn_err(CE_WARN, "XFS: failed to read RT inodes");
-		rvp->v_flag |= VPURGE;
 		VMAP(rvp, vmap);
 		VN_RELE(rvp);
 		vn_purge(rvp, &vmap);
@@ -1730,69 +1721,4 @@
 
 	if (level == XFS_FREEZE_TRANS)
 		atomic_inc(&mp->m_active_trans);
-}
-
-int
-xfs_blkdev_get(
-	const char		*name,
-	struct block_device	**bdevp)
-{
-	struct nameidata	nd;
-	int			error = 0;
-
-	error = path_lookup(name, LOOKUP_FOLLOW, &nd);
-	if (error) {
-		printk("XFS: Invalid device [%s], error=%d\n",
-				name, error);
-		return error;
-	}
-
-	/* I think we actually want bd_acquire here..  --hch */
-	*bdevp = bdget(kdev_t_to_nr(nd.dentry->d_inode->i_rdev));
-	if (*bdevp) {
-		error = blkdev_get(*bdevp, FMODE_READ|FMODE_WRITE, 0, BDEV_FS);
-	} else {
-		error = -ENOMEM;
-	}
-
-	path_release(&nd);
-	return -error;
-}
-
-void
-xfs_blkdev_put(
-	struct block_device	*bdev)
-{
-	blkdev_put(bdev, BDEV_FS);
-}
-
-void
-xfs_free_buftarg(
-	xfs_buftarg_t		*btp)
-{
-	pagebuf_delwri_flush(btp, PBDF_WAIT, NULL);
-	kfree(btp);
-}
-
-xfs_buftarg_t *
-xfs_alloc_buftarg(
-	struct block_device	*bdev)
-{
-	xfs_buftarg_t		*btp;
-
-	btp = kmem_zalloc(sizeof(*btp), KM_SLEEP);
-
-	btp->pbr_dev =  bdev->bd_dev;
-	btp->pbr_bdev = bdev;
-	btp->pbr_mapping = bdev->bd_inode->i_mapping;
-	btp->pbr_blocksize = PAGE_CACHE_SIZE;
-
-	switch (MAJOR(btp->pbr_dev)) {
-	case MD_MAJOR:
-	case EVMS_MAJOR:
-		btp->pbr_flags = PBR_ALIGNED_ONLY;
-		break;
-	}
-
-	return btp;
 }
diff -Nru a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
--- a/fs/xfs/xfs_mount.h	Sun Nov 10 19:28:36 2002
+++ b/fs/xfs/xfs_mount.h	Sun Nov 10 19:28:36 2002
@@ -209,7 +209,8 @@
 	uint			m_dmevmask;	/* DMI events for this FS */
 	uint			m_flags;	/* global mount flags */
 	uint			m_attroffset;	/* inode attribute offset */
-	int			m_da_node_ents; /* how many entries in danode */
+	uint			m_dir_node_ents; /* #entries in a dir danode */
+	uint			m_attr_node_ents; /* #entries in attr danode */
 	int			m_ialloc_inos;	/* inodes in inode allocation */
 	int			m_ialloc_blks;	/* blocks in inode allocation */
 	int			m_litino;	/* size of inode union area */
@@ -253,8 +254,6 @@
 						 * snapshot */
 	sv_t			m_wait_unfreeze;/* waiting to unfreeze */
 	atomic_t		m_active_trans; /* number trans frozen */
-	struct timer_list	m_sbdirty_timer;/* superblock dirty timer
-						 * for nfs refcache */
 } xfs_mount_t;
 
 /*
diff -Nru a/fs/xfs/xfs_qm.c b/fs/xfs/xfs_qm.c
--- a/fs/xfs/xfs_qm.c	Sun Nov 10 19:28:36 2002
+++ b/fs/xfs/xfs_qm.c	Sun Nov 10 19:28:36 2002
@@ -1998,16 +1998,11 @@
 	int		error;
 	__int64_t	sbflags;
 	uint		flags;
-	int		readonly;
-	vfs_t		*vfsp;
 
 	ASSERT(mp->m_quotainfo);
 	uip = gip = NULL;
-	error = 0;
 	sbflags = 0;
 	flags = 0;
-	vfsp = XFS_MTOVFS(mp);
-	readonly = vfsp->vfs_flag & VFS_RDONLY;
 
 	/*
 	 * Get the uquota and gquota inodes
@@ -2046,7 +2041,7 @@
 		if ((error = xfs_qm_qino_alloc(mp, &uip,
 					      sbflags | XFS_SB_UQUOTINO,
 					      flags | XFS_QMOPT_UQUOTA)))
-			goto error;
+			return XFS_ERROR(error);
 
 		flags &= ~XFS_QMOPT_SBVERSION;
 	}
@@ -2057,18 +2052,14 @@
 			if (uip)
 				VN_RELE(XFS_ITOV(uip));
 
-			goto error;
+			return XFS_ERROR(error);
 		}
 	}
 
 	XFS_QI_UQIP(mp) = uip;
 	XFS_QI_GQIP(mp) = gip;
 
-error:
-	if (readonly)
-		vfsp->vfs_flag |= VFS_RDONLY;
-
-	return XFS_ERROR(error);
+	return (0);
 }
 
 
diff -Nru a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c
--- a/fs/xfs/xfs_rename.c	Sun Nov 10 19:28:39 2002
+++ b/fs/xfs/xfs_rename.c	Sun Nov 10 19:28:39 2002
@@ -627,7 +627,6 @@
 	 */
 	error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
 	if (target_ip != NULL) {
-		xfs_refcache_purge_ip(target_ip);
 		IRELE(target_ip);
 	}
 	/*
diff -Nru a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c
--- a/fs/xfs/xfs_rtalloc.c	Sun Nov 10 19:28:37 2002
+++ b/fs/xfs/xfs_rtalloc.c	Sun Nov 10 19:28:37 2002
@@ -2264,9 +2264,9 @@
 	sbp = &mp->m_sb;
 	if (sbp->sb_rblocks == 0)
 		return 0;
-	if (mp->m_rtdev_targp != NULL) {
-		printk(KERN_WARNING
-		"XFS: This FS has an RT subvol - specify -o rtdev on mount\n");
+	if (mp->m_rtdev_targp == NULL) {
+		cmn_err(CE_WARN,
+	"XFS: This filesystem has a realtime volume, use rtdev=device option");
 		return XFS_ERROR(ENODEV);
 	}
 	mp->m_rsumlevels = sbp->sb_rextslog + 1;
@@ -2280,15 +2280,15 @@
 	 */
 	d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
 	if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_rblocks) {
-		printk(KERN_WARNING "XFS: RT mount - %llu != %llu\n",
+		cmn_err(CE_WARN, "XFS: realtime mount -- %llu != %llu",
 			(unsigned long long) XFS_BB_TO_FSB(mp, d),
 			(unsigned long long) mp->m_sb.sb_rblocks);
 		return XFS_ERROR(E2BIG);
 	}
 	error = xfs_read_buf(mp, mp->m_rtdev_targp, d - 1, 1, 0, &bp);
 	if (error) {
-		printk(KERN_WARNING
-			"XFS: RT mount - xfs_read_buf returned %d\n", error);
+		cmn_err(CE_WARN,
+	"XFS: realtime mount -- xfs_read_buf failed, returned %d", error);
 		if (error == ENOSPC)
 			return XFS_ERROR(E2BIG);
 		return error;
diff -Nru a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c
--- a/fs/xfs/xfs_rw.c	Sun Nov 10 19:28:41 2002
+++ b/fs/xfs/xfs_rw.c	Sun Nov 10 19:28:41 2002
@@ -231,7 +231,7 @@
 {
 	cmn_err(CE_ALERT,
  "I/O error in filesystem (\"%s\") meta-data dev 0x%x block 0x%llx"
- "	 (\"%s\") error %d buf count %u",
+ "       (\"%s\") error %d buf count %u",
 		(!mp || !mp->m_fsname) ? "(fs name not set)" : mp->m_fsname,
 		XFS_BUF_TARGET_DEV(bp),
 		(__uint64_t)blkno,
@@ -370,384 +370,5 @@
 	VOP_FLUSHINVAL_PAGES(vp, ctooff(offtoct(offset)), -1, FI_REMAPF_LOCKED);
 	if (relock) {
 		XFS_ILOCK_DEMOTE(mp, io, XFS_IOLOCK_EXCL);
-	}
-}
-
-
-
-spinlock_t	xfs_refcache_lock = SPIN_LOCK_UNLOCKED;
-xfs_inode_t	**xfs_refcache;
-int		xfs_refcache_size;
-int		xfs_refcache_index;
-int		xfs_refcache_busy;
-int		xfs_refcache_count;
-
-/*
- * Timer callback to mark SB dirty, make sure we keep purging refcache
- */
-void
-xfs_refcache_sbdirty(struct super_block *sb)
-{
-	sb->s_dirt = 1;
-}
-
-/*
- * Insert the given inode into the reference cache.
- */
-void
-xfs_refcache_insert(
-	xfs_inode_t	*ip)
-{
-	vnode_t		*vp;
-	xfs_inode_t	*release_ip;
-	xfs_inode_t	**refcache;
-
-	ASSERT(ismrlocked(&(ip->i_iolock), MR_UPDATE));
-
-	/*
-	 * If an unmount is busy blowing entries out of the cache,
-	 * then don't bother.
-	 */
-	if (xfs_refcache_busy) {
-		return;
-	}
-
-	/*
-	 * If we tuned the refcache down to zero, don't do anything.
-	 */
-	 if (!xfs_refcache_size) {
-		return;
-	}
-
-	/*
-	 * The inode is already in the refcache, so don't bother
-	 * with it.
-	 */
-	if (ip->i_refcache != NULL) {
-		return;
-	}
-
-	vp = XFS_ITOV(ip);
-	/* ASSERT(vp->v_count > 0); */
-	VN_HOLD(vp);
-
-	/*
-	 * We allocate the reference cache on use so that we don't
-	 * waste the memory on systems not being used as NFS servers.
-	 */
-	if (xfs_refcache == NULL) {
-		refcache = (xfs_inode_t **)kmem_zalloc(XFS_REFCACHE_SIZE_MAX *
-						       sizeof(xfs_inode_t *),
-						       KM_SLEEP);
-	} else {
-		refcache = NULL;
-	}
-
-	spin_lock(&xfs_refcache_lock);
-
-	/*
-	 * If we allocated memory for the refcache above and it still
-	 * needs it, then use the memory we allocated.	Otherwise we'll
-	 * free the memory below.
-	 */
-	if (refcache != NULL) {
-		if (xfs_refcache == NULL) {
-			xfs_refcache = refcache;
-			refcache = NULL;
-		}
-	}
-
-	/*
-	 * If an unmount is busy clearing out the cache, don't add new
-	 * entries to it.
-	 */
-	if (xfs_refcache_busy) {
-		spin_unlock(&xfs_refcache_lock);
-		VN_RELE(vp);
-		/*
-		 * If we allocated memory for the refcache above but someone
-		 * else beat us to using it, then free the memory now.
-		 */
-		if (refcache != NULL) {
-			kmem_free(refcache,
-				  XFS_REFCACHE_SIZE_MAX * sizeof(xfs_inode_t *));
-		}
-		return;
-	}
-	release_ip = xfs_refcache[xfs_refcache_index];
-	if (release_ip != NULL) {
-		release_ip->i_refcache = NULL;
-		xfs_refcache_count--;
-		ASSERT(xfs_refcache_count >= 0);
-	}
-	xfs_refcache[xfs_refcache_index] = ip;
-	ASSERT(ip->i_refcache == NULL);
-	ip->i_refcache = &(xfs_refcache[xfs_refcache_index]);
-	xfs_refcache_count++;
-	ASSERT(xfs_refcache_count <= xfs_refcache_size);
-	xfs_refcache_index++;
-	if (xfs_refcache_index == xfs_refcache_size) {
-		xfs_refcache_index = 0;
-	}
-	spin_unlock(&xfs_refcache_lock);
-
-	/*
-	 * Save the pointer to the inode to be released so that we can
-	 * VN_RELE it once we've dropped our inode locks in xfs_rwunlock().
-	 * The pointer may be NULL, but that's OK.
-	 */
-	ip->i_release = release_ip;
-
-	/*
-	 * If we allocated memory for the refcache above but someone
-	 * else beat us to using it, then free the memory now.
-	 */
-	if (refcache != NULL) {
-		kmem_free(refcache,
-			  XFS_REFCACHE_SIZE_MAX * sizeof(xfs_inode_t *));
-	}
-	return;
-}
-
-
-/*
- * If the given inode is in the reference cache, purge its entry and
- * release the reference on the vnode.
- */
-void
-xfs_refcache_purge_ip(
-	xfs_inode_t	*ip)
-{
-	vnode_t *vp;
-	int	error;
-
-	/*
-	 * If we're not pointing to our entry in the cache, then
-	 * we must not be in the cache.
-	 */
-	if (ip->i_refcache == NULL) {
-		return;
-	}
-
-	spin_lock(&xfs_refcache_lock);
-	if (ip->i_refcache == NULL) {
-		spin_unlock(&xfs_refcache_lock);
-		return;
-	}
-
-	/*
-	 * Clear both our pointer to the cache entry and its pointer
-	 * back to us.
-	 */
-	ASSERT(*(ip->i_refcache) == ip);
-	*(ip->i_refcache) = NULL;
-	ip->i_refcache = NULL;
-	xfs_refcache_count--;
-	ASSERT(xfs_refcache_count >= 0);
-	spin_unlock(&xfs_refcache_lock);
-
-	vp = XFS_ITOV(ip);
-	/* ASSERT(vp->v_count > 1); */
-	VOP_RELEASE(vp, error);
-	VN_RELE(vp);
-
-	return;
-}
-
-
-/*
- * This is called from the XFS unmount code to purge all entries for the
- * given mount from the cache.	It uses the refcache busy counter to
- * make sure that new entries are not added to the cache as we purge them.
- */
-void
-xfs_refcache_purge_mp(
-	xfs_mount_t	*mp)
-{
-	vnode_t		*vp;
-	int		error, i;
-	xfs_inode_t	*ip;
-
-	if (xfs_refcache == NULL) {
-		return;
-	}
-
-	spin_lock(&xfs_refcache_lock);
-	/*
-	 * Bumping the busy counter keeps new entries from being added
-	 * to the cache.  We use a counter since multiple unmounts could
-	 * be in here simultaneously.
-	 */
-	xfs_refcache_busy++;
-
-	for (i = 0; i < xfs_refcache_size; i++) {
-		ip = xfs_refcache[i];
-		if ((ip != NULL) && (ip->i_mount == mp)) {
-			xfs_refcache[i] = NULL;
-			ip->i_refcache = NULL;
-			xfs_refcache_count--;
-			ASSERT(xfs_refcache_count >= 0);
-			spin_unlock(&xfs_refcache_lock);
-			vp = XFS_ITOV(ip);
-			VOP_RELEASE(vp, error);
-			VN_RELE(vp);
-			spin_lock(&xfs_refcache_lock);
-		}
-	}
-
-	xfs_refcache_busy--;
-	ASSERT(xfs_refcache_busy >= 0);
-	spin_unlock(&xfs_refcache_lock);
-}
-
-
-/*
- * This is called from the XFS sync code to ensure that the refcache
- * is emptied out over time.  We purge a small number of entries with
- * each call.
- */
-void
-xfs_refcache_purge_some(xfs_mount_t *mp)
-{
-	int		error, i;
-	xfs_inode_t	*ip;
-	int		iplist_index;
-	xfs_inode_t	**iplist;
-	int		purge_count;
-
-	if ((xfs_refcache == NULL) || (xfs_refcache_count == 0)) {
-		return;
-	}
-
-	iplist_index = 0;
-	purge_count = xfs_params.refcache_purge;
-	iplist = (xfs_inode_t **)kmem_zalloc(purge_count *
-					  sizeof(xfs_inode_t *), KM_SLEEP);
-
-	spin_lock(&xfs_refcache_lock);
-
-	/*
-	 * Store any inodes we find in the next several entries
-	 * into the iplist array to be released after dropping
-	 * the spinlock.  We always start looking from the currently
-	 * oldest place in the cache.  We move the refcache index
-	 * forward as we go so that we are sure to eventually clear
-	 * out the entire cache when the system goes idle.
-	 */
-	for (i = 0; i < purge_count; i++) {
-		ip = xfs_refcache[xfs_refcache_index];
-		if (ip != NULL) {
-			xfs_refcache[xfs_refcache_index] = NULL;
-			ip->i_refcache = NULL;
-			xfs_refcache_count--;
-			ASSERT(xfs_refcache_count >= 0);
-			iplist[iplist_index] = ip;
-			iplist_index++;
-		}
-		xfs_refcache_index++;
-		if (xfs_refcache_index == xfs_refcache_size) {
-			xfs_refcache_index = 0;
-		}
-	}
-
-	spin_unlock(&xfs_refcache_lock);
-
-	/*
-	 * If there are still entries in the refcache,
-	 * set timer to mark the SB dirty to make sure that
-	 * we hit sync even if filesystem is idle, so that we'll
-	 * purge some more later.
-	 */
-	if (xfs_refcache_count) {
-		del_timer_sync(&mp->m_sbdirty_timer);
-		mp->m_sbdirty_timer.data =
-		    (unsigned long)LINVFS_GET_IP(XFS_ITOV(mp->m_rootip))->i_sb;
-		mp->m_sbdirty_timer.expires = jiffies + 2*HZ;
-		add_timer(&mp->m_sbdirty_timer);
-	}
-
-	/*
-	 * Now drop the inodes we collected.
-	 */
-	for (i = 0; i < iplist_index; i++) {
-		VOP_RELEASE(XFS_ITOV(iplist[i]), error);
-		VN_RELE(XFS_ITOV(iplist[i]));
-	}
-
-	kmem_free(iplist, purge_count *
-			  sizeof(xfs_inode_t *));
-}
-
-/*
- * This is called when the refcache is dynamically resized
- * via a sysctl.
- *
- * If the new size is smaller than the old size, purge all
- * entries in slots greater than the new size, and move
- * the index if necessary.
- *
- * If the refcache hasn't even been allocated yet, or the
- * new size is larger than the old size, just set the value
- * of xfs_refcache_size.
- */
-
-void
-xfs_refcache_resize(int xfs_refcache_new_size)
-{
-	int		i;
-	xfs_inode_t	*ip;
-	int		iplist_index = 0;
-	xfs_inode_t	**iplist;
-	int		error;
-
-	/*
-	 * If the new size is smaller than the current size,
-	 * purge entries to create smaller cache, and
-	 * reposition index if necessary.
-	 * Don't bother if no refcache yet.
-	 */
-	if (xfs_refcache && (xfs_refcache_new_size < xfs_refcache_size)) {
-
-		iplist = (xfs_inode_t **)kmem_zalloc(XFS_REFCACHE_SIZE_MAX *
-				sizeof(xfs_inode_t *), KM_SLEEP);
-
-		spin_lock(&xfs_refcache_lock);
-
-		for (i = xfs_refcache_new_size; i < xfs_refcache_size; i++) {
-			ip = xfs_refcache[i];
-			if (ip != NULL) {
-				xfs_refcache[i] = NULL;
-				ip->i_refcache = NULL;
-				xfs_refcache_count--;
-				ASSERT(xfs_refcache_count >= 0);
-				iplist[iplist_index] = ip;
-				iplist_index++;
-			}
-		}
-
-		xfs_refcache_size = xfs_refcache_new_size;
-
-		/*
-		 * Move index to beginning of cache if it's now past the end
-		 */
-		if (xfs_refcache_index >= xfs_refcache_new_size)
-			xfs_refcache_index = 0;
-
-		spin_unlock(&xfs_refcache_lock);
-
-		/*
-		 * Now drop the inodes we collected.
-		 */
-		for (i = 0; i < iplist_index; i++) {
-			VOP_RELEASE(XFS_ITOV(iplist[i]), error);
-			VN_RELE(XFS_ITOV(iplist[i]));
-		}
-
-		kmem_free(iplist, XFS_REFCACHE_SIZE_MAX *
-				  sizeof(xfs_inode_t *));
-	} else {
-		spin_lock(&xfs_refcache_lock);
-		xfs_refcache_size = xfs_refcache_new_size;
-		spin_unlock(&xfs_refcache_lock);
 	}
 }
diff -Nru a/fs/xfs/xfs_rw.h b/fs/xfs/xfs_rw.h
--- a/fs/xfs/xfs_rw.h	Sun Nov 10 19:28:37 2002
+++ b/fs/xfs/xfs_rw.h	Sun Nov 10 19:28:37 2002
@@ -70,12 +70,6 @@
 #define XFS_MAX_BMAP_LEN_BYTES	524288
 
 /*
- * Maximum size (in inodes) for the nfs refcache
- */
-#define XFS_REFCACHE_SIZE_MAX	512
-
-
-/*
  * Convert the given file system block to a disk block.
  * We have to treat it differently based on whether the
  * file is a real time file or not, because the bmap code
@@ -154,26 +148,6 @@
 	xfs_off_t		offset,
 	int			write,
 	int			relock);
-
-void
-xfs_refcache_insert(
-	struct xfs_inode	*ip);
-
-void
-xfs_refcache_purge_ip(
-	struct xfs_inode	*ip);
-
-void
-xfs_refcache_purge_mp(
-	struct xfs_mount	*mp);
-
-void
-xfs_refcache_purge_some(
-	struct xfs_mount	*mp);
-
-void
-xfs_refcache_resize(
-	int			xfs_refcache_new_size);
 
 int
 xfs_bioerror(
diff -Nru a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
--- a/fs/xfs/xfs_vfsops.c	Sun Nov 10 19:28:37 2002
+++ b/fs/xfs/xfs_vfsops.c	Sun Nov 10 19:28:37 2002
@@ -63,7 +63,6 @@
 #ifdef XFS_DABUF_DEBUG
 	extern lock_t		xfs_dabuf_global_lock;
 #endif
-	extern int		xfs_refcache_size;
 
 #ifdef XFS_DABUF_DEBUG
 	spinlock_init(&xfs_dabuf_global_lock, "xfsda");
@@ -144,14 +143,6 @@
 
 	xfs_init_procfs();
 	xfs_sysctl_register();
-
-	xfs_refcache_size = xfs_params.refcache_size;
-
-	/*
-	 * The inode hash table is created on a per mounted
-	 * file system bases.
-	 */
-
 	return 0;
 }
 
@@ -168,14 +159,9 @@
 	extern kmem_zone_t	*xfs_efi_zone;
 	extern kmem_zone_t	*xfs_buf_item_zone;
 	extern kmem_zone_t	*xfs_chashlist_zone;
-	extern xfs_inode_t	**xfs_refcache;
 
 	xfs_cleanup_procfs();
 	xfs_sysctl_unregister();
-	if (xfs_refcache) {
-		kmem_free(xfs_refcache,
-			XFS_REFCACHE_SIZE_MAX * sizeof(xfs_inode_t *));
-	}
 
 	kmem_cache_destroy(xfs_bmap_free_item_zone);
 	kmem_cache_destroy(xfs_btree_cur_zone);
@@ -584,13 +570,6 @@
 	}
 
 	/*
-	 * First blow any referenced inode from this file system
-	 * out of the reference cache, and delete the timer.
-	 */
-	xfs_refcache_purge_mp(mp);
-	del_timer_sync(&mp->m_sbdirty_timer);
-
-	/*
 	 * Make sure there are no active users.
 	 */
 	if (xfs_ibusy(mp)) {
@@ -607,14 +586,10 @@
 	ASSERT(vn_count(rvp) == 1);
 
 	/*
-	 * Drop the reference count, and then
-	 * run the vnode through vn_remove.
+	 * Drop the reference count
 	 */
-	rvp->v_flag |= VPURGE;			/* OK for vn_purge */
 	VN_RELE(rvp);
 
-	vn_remove(rvp);
-
 	/*
 	 * If we're forcing a shutdown, typically because of a media error,
 	 * we want to make sure we invalidate dirty pages that belong to
@@ -1433,7 +1408,7 @@
 		ASSERT(ipointer_in == B_FALSE);
 		ip = ip->i_mnext;
 
-	} while (ip->i_mnext != mp->m_inodes);
+	} while (ip != mp->m_inodes);
 
 	XFS_MOUNT_IUNLOCK(mp);
 
@@ -1514,15 +1489,6 @@
 	}
 
 	/*
-	 * If this is the 30 second sync, then kick some entries out of
-	 * the reference cache.	 This ensures that idle entries are
-	 * eventually kicked out of the cache.
-	 */
-	if (flags & SYNC_BDFLUSH) {
-		xfs_refcache_purge_some(mp);
-	}
-
-	/*
 	 * Now check to see if the log needs a "dummy" transaction.
 	 */
 
@@ -1567,40 +1533,6 @@
 	return XFS_ERROR(last_error);
 }
 
-STATIC void
-xfs_initialize_vnode(
-	bhv_desc_t	*bdp,
-	vnode_t		*vp,
-	bhv_desc_t	*inode_bhv,
-	int		unlock)
-{
-	xfs_inode_t	*ip = XFS_BHVTOI(inode_bhv);
-	struct inode	*inode = LINVFS_GET_IP(vp);
-
-	if (vp->v_fbhv == NULL) {
-		vp->v_vfsp = bhvtovfs(bdp);
-		bhv_desc_init(&(ip->i_bhv_desc), ip, vp, &xfs_vnodeops);
-		bhv_insert_initial(VN_BHV_HEAD(vp), &(ip->i_bhv_desc));
-	}
-
-	vp->v_type = IFTOVT(ip->i_d.di_mode);
-	/* Have we been called during the new inode create process,
-	 * in which case we are too early to fill in the linux inode.
-	 */
-	if (vp->v_type == VNON)
-		return;
-
-	xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip);
-
-	/* For new inodes we need to set the ops vectors,
-	 * and unlock the inode.
-	 */
-	if (unlock && (inode->i_state & I_NEW)) {
-		linvfs_set_inode_ops(inode);
-		unlock_new_inode(inode);
-	}
-}
-
 /*
  * xfs_vget - called by DMAPI to get vnode from file handle
  */
@@ -1616,10 +1548,8 @@
 	xfs_ino_t	ino;
 	unsigned int	igen;
 	xfs_mount_t	*mp;
-	struct inode	*inode = NULL;
 
 	xfid  = (struct xfs_fid *)fidp;
-
 	if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) {
 		ino  = xfid->xfs_fid_ino;
 		igen = xfid->xfs_fid_gen;
@@ -1649,9 +1579,7 @@
 	}
 
 	*vpp = XFS_ITOV(ip);
-	inode = LINVFS_GET_IP((*vpp));
 	xfs_iunlock(ip, XFS_ILOCK_SHARED);
-
 	return 0;
 }
 
diff -Nru a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
--- a/fs/xfs/xfs_vnodeops.c	Sun Nov 10 19:28:41 2002
+++ b/fs/xfs/xfs_vnodeops.c	Sun Nov 10 19:28:41 2002
@@ -1625,8 +1625,8 @@
 		return 0;
 	}
 
-	/* If we are in the NFS reference cache then don't do this now */
-	if (ip->i_refcache)
+	/* If this is a read-only mount, don't do this (would generate I/O) */
+	if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
 		return 0;
 
 	mp = ip->i_mount;
@@ -1704,6 +1704,11 @@
 	}
 
 	error = 0;
+
+	/* If this is a read-only mount, don't do this (would generate I/O) */
+	if (vp->v_vfsp->vfs_flag & VFS_RDONLY)
+		goto out;
+
 	if (ip->i_d.di_nlink != 0) {
 		if ((((ip->i_d.di_mode & IFMT) == IFREG) &&
 		     ((ip->i_d.di_size > 0) || (VN_CACHED(vp) > 0)) &&
@@ -2694,14 +2699,6 @@
 		goto std_return;
 	}
 
-	/*
-	 * Before we drop our extra reference to the inode, purge it
-	 * from the refcache if it is there.  By waiting until afterwards
-	 * to do the IRELE, we ensure that we won't go inactive in the
-	 * xfs_refcache_purge_ip routine (although that would be OK).
-	 */
-	xfs_refcache_purge_ip(ip);
-
 	vn_trace_exit(XFS_ITOV(ip), "xfs_remove",
 						(inst_t *)__return_address);
 
@@ -2743,14 +2740,6 @@
 	cancel_flags |= XFS_TRANS_ABORT;
 	xfs_trans_cancel(tp, cancel_flags);
 
-	/*
-	 * Before we drop our extra reference to the inode, purge it
-	 * from the refcache if it is there.  By waiting until afterwards
-	 * to do the IRELE, we ensure that we won't go inactive in the
-	 * xfs_refcache_purge_ip routine (although that would be OK).
-	 */
-	xfs_refcache_purge_ip(ip);
-
 	IRELE(ip);
 
 	goto std_return;
@@ -3909,30 +3898,14 @@
 	vrwlock_t	locktype)
 {
 	xfs_inode_t	*ip;
-	xfs_inode_t	*release_ip;
 	vnode_t		*vp;
-	int		error;
 
 	vp = BHV_TO_VNODE(bdp);
 	if (vp->v_type == VDIR)
 		return;
 	ip = XFS_BHVTOI(bdp);
 	if (locktype == VRWLOCK_WRITE) {
-		/*
-		 * In the write case, we may have added a new entry to
-		 * the reference cache.	 This might store a pointer to
-		 * an inode to be released in this inode.  If it is there,
-		 * clear the pointer and release the inode after unlocking
-		 * this one.
-		 */
-		release_ip = ip->i_release;
-		ip->i_release = NULL;
 		xfs_iunlock (ip, XFS_IOLOCK_EXCL);
-
-		if (release_ip != NULL) {
-			VOP_RELEASE(XFS_ITOV(release_ip), error);
-			VN_RELE(XFS_ITOV(release_ip));
-		}
 	} else {
 		ASSERT((locktype == VRWLOCK_READ) ||
 		       (locktype == VRWLOCK_WRITE_DIRECT));
diff -Nru a/fs/xfs/xfsidbg.c b/fs/xfs/xfsidbg.c
--- a/fs/xfs/xfsidbg.c	Sun Nov 10 19:28:40 2002
+++ b/fs/xfs/xfsidbg.c	Sun Nov 10 19:28:40 2002
@@ -3725,8 +3725,8 @@
 {
 	xfs_da_state_blk_t *eblk;
 
-	kdb_printf("args 0x%p mp 0x%p blocksize %d inleaf %d\n",
-		s->args, s->mp, s->blocksize, s->inleaf);
+	kdb_printf("args 0x%p mp 0x%p blocksize %u node_ents %u inleaf %u\n",
+		s->args, s->mp, s->blocksize, s->node_ents, s->inleaf);
 	if (s->args)
 		xfsidbg_xdaargs(s->args);
 
@@ -4637,9 +4637,10 @@
 	printflags(mp->m_flags, xmount_flags,"flags");
 	kdb_printf("ialloc_inos %d ialloc_blks %d litino %d\n",
 		mp->m_ialloc_inos, mp->m_ialloc_blks, mp->m_litino);
-	kdb_printf("attroffset %d da_node_ents %d maxicount %Ld inoalign_mask %d\n",
-		mp->m_attroffset, mp->m_da_node_ents, mp->m_maxicount,
-		mp->m_inoalign_mask);
+	kdb_printf("dir_node_ents %u attr_node_ents %u\n",
+		mp->m_dir_node_ents, mp->m_attr_node_ents);
+	kdb_printf("attroffset %d maxicount %Ld inoalign_mask %d\n",
+		mp->m_attroffset, mp->m_maxicount, mp->m_inoalign_mask);
 	kdb_printf("resblks %Ld resblks_avail %Ld\n", mp->m_resblks,
 		mp->m_resblks_avail);
 #if XFS_BIG_FILESYSTEMS
diff -Nru a/include/asm-arm/arch-sa1100/SA-1101.h b/include/asm-arm/arch-sa1100/SA-1101.h
--- a/include/asm-arm/arch-sa1100/SA-1101.h	Sun Nov 10 19:28:37 2002
+++ b/include/asm-arm/arch-sa1100/SA-1101.h	Sun Nov 10 19:28:37 2002
@@ -26,6 +26,14 @@
 # endif
 #endif
 
+/*
+ * We have mapped the sa1101 depending on the value of SA1101_BASE.
+ * It then appears from 0xf4000000.
+ */
+
+#define SA1101_p2v( x )         ((x) - SA1101_BASE + 0xf4000000)
+#define SA1101_v2p( x )         ((x) - 0xf4000000  + SA1101_BASE)
+
 #ifndef SA1101_p2v
 #define SA1101_p2v(PhAdd)  (PhAdd)
 #endif
diff -Nru a/include/asm-arm/arch-sa1100/hardware.h b/include/asm-arm/arch-sa1100/hardware.h
--- a/include/asm-arm/arch-sa1100/hardware.h	Sun Nov 10 19:28:39 2002
+++ b/include/asm-arm/arch-sa1100/hardware.h	Sun Nov 10 19:28:39 2002
@@ -76,112 +76,8 @@
 
 #include "SA-1100.h"
 
-/*
- * Implementation specifics.
- *
- * *** NOTE ***
- * Any definitions in these files should be prefixed by an identifier -
- * eg, ASSABET_UCB1300_IRQ  This will allow us to eleminate these
- * ifdefs, and lots of other preprocessor gunk elsewhere.
- */
-
-#include "badge4.h"
-
-#ifdef CONFIG_SA1100_PANGOLIN
-#include "pangolin.h"
-#endif
-
-#ifdef CONFIG_SA1100_HUW_WEBPANEL
-#include "huw_webpanel.h"
-#endif
-
-#ifdef CONFIG_SA1100_PFS168
-#include "pfs168.h"
-#endif
-
-
-#ifdef CONFIG_SA1100_YOPY
-#include "yopy.h"
-#endif
-
-#ifdef CONFIG_SA1100_FREEBIRD
-#include "freebird.h"
-#endif
-
-#ifdef CONFIG_SA1100_CERF
-#include "cerf.h"
-#endif
-
-#ifdef CONFIG_SA1100_EMPEG
-#include "empeg.h"
-#endif
-
-#include "h3600.h"
-
-#ifdef CONFIG_SA1100_ITSY
-#include "itsy.h"
-#endif
-
-#if defined(CONFIG_SA1100_GRAPHICSCLIENT)
-#include "graphicsclient.h"
-#endif
-
-#if defined(CONFIG_SA1100_OMNIMETER)
-#include "omnimeter.h"
-#endif
-
-#if defined(CONFIG_SA1100_JORNADA720)
-#include "jornada720.h"
-#endif
-
-#if defined(CONFIG_SA1100_PLEB)
-#include "pleb.h"
-#endif
-
-#if defined(CONFIG_SA1100_LART)
-#include "lart.h"
-#endif
-
-#ifdef CONFIG_SA1100_SIMPAD
-#include "simpad.h"
-#endif
-
-#if defined(CONFIG_SA1100_GRAPHICSMASTER)
-#include "graphicsmaster.h"
-#endif
-
-#if defined(CONFIG_SA1100_ADSBITSY)
-#include "adsbitsy.h"
-#endif
-
-#include "stork.h"
-
-#include "system3.h"
-
 #ifdef CONFIG_SA1101
-
-/*
- * We have mapped the sa1101 depending on the value of SA1101_BASE.
- * It then appears from 0xf4000000.
- */
-
-#define SA1101_p2v( x )         ((x) - SA1101_BASE + 0xf4000000)
-#define SA1101_v2p( x )         ((x) - 0xf4000000  + SA1101_BASE)
-
 #include "SA-1101.h"
-
-#endif
-
-#if defined(CONFIG_SA1100_OMNIMETER)
-#include "omnimeter.h"
-#endif
-
-#if defined(CONFIG_SA1100_JORNADA720)
-#include "jornada720.h"
-#endif
-
-#if defined(CONFIG_SA1100_FLEXANET)
-#include "flexanet.h"
 #endif
 
 #endif  /* _ASM_ARCH_HARDWARE_H */
diff -Nru a/include/asm-generic/xor.h b/include/asm-generic/xor.h
--- a/include/asm-generic/xor.h	Sun Nov 10 19:28:41 2002
+++ b/include/asm-generic/xor.h	Sun Nov 10 19:28:41 2002
@@ -13,6 +13,8 @@
  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include <asm/processor.h>
+
 static void
 xor_8regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
 {
@@ -121,7 +123,7 @@
 		d5 ^= p2[5];
 		d6 ^= p2[6];
 		d7 ^= p2[7];
-		p1[0] = d0;	/* Store the result (in burts)		*/
+		p1[0] = d0;	/* Store the result (in bursts)		*/
 		p1[1] = d1;
 		p1[2] = d2;
 		p1[3] = d3;
@@ -166,7 +168,7 @@
 		d5 ^= p3[5];
 		d6 ^= p3[6];
 		d7 ^= p3[7];
-		p1[0] = d0;	/* Store the result (in burts)		*/
+		p1[0] = d0;	/* Store the result (in bursts)		*/
 		p1[1] = d1;
 		p1[2] = d2;
 		p1[3] = d3;
@@ -220,7 +222,7 @@
 		d5 ^= p4[5];
 		d6 ^= p4[6];
 		d7 ^= p4[7];
-		p1[0] = d0;	/* Store the result (in burts)		*/
+		p1[0] = d0;	/* Store the result (in bursts)		*/
 		p1[1] = d1;
 		p1[2] = d2;
 		p1[3] = d3;
@@ -283,7 +285,7 @@
 		d5 ^= p5[5];
 		d6 ^= p5[6];
 		d7 ^= p5[7];
-		p1[0] = d0;	/* Store the result (in burts)		*/
+		p1[0] = d0;	/* Store the result (in bursts)		*/
 		p1[1] = d1;
 		p1[2] = d2;
 		p1[3] = d3;
@@ -299,6 +301,382 @@
 	} while (--lines > 0);
 }
 
+static void
+xor_8regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+	long lines = bytes / (sizeof (long)) / 8 - 1;
+	prefetchw(p1);
+	prefetch(p2);
+
+	do {
+		prefetchw(p1+8);
+		prefetch(p2+8);
+ once_more:
+		p1[0] ^= p2[0];
+		p1[1] ^= p2[1];
+		p1[2] ^= p2[2];
+		p1[3] ^= p2[3];
+		p1[4] ^= p2[4];
+		p1[5] ^= p2[5];
+		p1[6] ^= p2[6];
+		p1[7] ^= p2[7];
+		p1 += 8;
+		p2 += 8;
+	} while (--lines > 0);
+	if (lines == 0)
+		goto once_more;
+}
+
+static void
+xor_8regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3)
+{
+	long lines = bytes / (sizeof (long)) / 8 - 1;
+	prefetchw(p1);
+	prefetch(p2);
+	prefetch(p3);
+
+	do {
+		prefetchw(p1+8);
+		prefetch(p2+8);
+		prefetch(p3+8);
+ once_more:
+		p1[0] ^= p2[0] ^ p3[0];
+		p1[1] ^= p2[1] ^ p3[1];
+		p1[2] ^= p2[2] ^ p3[2];
+		p1[3] ^= p2[3] ^ p3[3];
+		p1[4] ^= p2[4] ^ p3[4];
+		p1[5] ^= p2[5] ^ p3[5];
+		p1[6] ^= p2[6] ^ p3[6];
+		p1[7] ^= p2[7] ^ p3[7];
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+	} while (--lines > 0);
+	if (lines == 0)
+		goto once_more;
+}
+
+static void
+xor_8regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3, unsigned long *p4)
+{
+	long lines = bytes / (sizeof (long)) / 8 - 1;
+
+	prefetchw(p1);
+	prefetch(p2);
+	prefetch(p3);
+	prefetch(p4);
+
+	do {
+		prefetchw(p1+8);
+		prefetch(p2+8);
+		prefetch(p3+8);
+		prefetch(p4+8);
+ once_more:
+		p1[0] ^= p2[0] ^ p3[0] ^ p4[0];
+		p1[1] ^= p2[1] ^ p3[1] ^ p4[1];
+		p1[2] ^= p2[2] ^ p3[2] ^ p4[2];
+		p1[3] ^= p2[3] ^ p3[3] ^ p4[3];
+		p1[4] ^= p2[4] ^ p3[4] ^ p4[4];
+		p1[5] ^= p2[5] ^ p3[5] ^ p4[5];
+		p1[6] ^= p2[6] ^ p3[6] ^ p4[6];
+		p1[7] ^= p2[7] ^ p3[7] ^ p4[7];
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+		p4 += 8;
+	} while (--lines > 0);
+	if (lines == 0)
+		goto once_more;
+}
+
+static void
+xor_8regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+	long lines = bytes / (sizeof (long)) / 8 - 1;
+
+	prefetchw(p1);
+	prefetch(p2);
+	prefetch(p3);
+	prefetch(p4);
+	prefetch(p5);
+
+	do {
+		prefetchw(p1+8);
+		prefetch(p2+8);
+		prefetch(p3+8);
+		prefetch(p4+8);
+		prefetch(p5+8);
+ once_more:
+		p1[0] ^= p2[0] ^ p3[0] ^ p4[0] ^ p5[0];
+		p1[1] ^= p2[1] ^ p3[1] ^ p4[1] ^ p5[1];
+		p1[2] ^= p2[2] ^ p3[2] ^ p4[2] ^ p5[2];
+		p1[3] ^= p2[3] ^ p3[3] ^ p4[3] ^ p5[3];
+		p1[4] ^= p2[4] ^ p3[4] ^ p4[4] ^ p5[4];
+		p1[5] ^= p2[5] ^ p3[5] ^ p4[5] ^ p5[5];
+		p1[6] ^= p2[6] ^ p3[6] ^ p4[6] ^ p5[6];
+		p1[7] ^= p2[7] ^ p3[7] ^ p4[7] ^ p5[7];
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+		p4 += 8;
+		p5 += 8;
+	} while (--lines > 0);
+	if (lines == 0)
+		goto once_more;
+}
+
+static void
+xor_32regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2)
+{
+	long lines = bytes / (sizeof (long)) / 8 - 1;
+
+	prefetchw(p1);
+	prefetch(p2);
+
+	do {
+		register long d0, d1, d2, d3, d4, d5, d6, d7;
+
+		prefetchw(p1+8);
+		prefetch(p2+8);
+ once_more:
+		d0 = p1[0];	/* Pull the stuff into registers	*/
+		d1 = p1[1];	/*  ... in bursts, if possible.		*/
+		d2 = p1[2];
+		d3 = p1[3];
+		d4 = p1[4];
+		d5 = p1[5];
+		d6 = p1[6];
+		d7 = p1[7];
+		d0 ^= p2[0];
+		d1 ^= p2[1];
+		d2 ^= p2[2];
+		d3 ^= p2[3];
+		d4 ^= p2[4];
+		d5 ^= p2[5];
+		d6 ^= p2[6];
+		d7 ^= p2[7];
+		p1[0] = d0;	/* Store the result (in bursts)		*/
+		p1[1] = d1;
+		p1[2] = d2;
+		p1[3] = d3;
+		p1[4] = d4;
+		p1[5] = d5;
+		p1[6] = d6;
+		p1[7] = d7;
+		p1 += 8;
+		p2 += 8;
+	} while (--lines > 0);
+	if (lines == 0)
+		goto once_more;
+}
+
+static void
+xor_32regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3)
+{
+	long lines = bytes / (sizeof (long)) / 8 - 1;
+
+	prefetchw(p1);
+	prefetch(p2);
+	prefetch(p3);
+
+	do {
+		register long d0, d1, d2, d3, d4, d5, d6, d7;
+
+		prefetchw(p1+8);
+		prefetch(p2+8);
+		prefetch(p3+8);
+ once_more:
+		d0 = p1[0];	/* Pull the stuff into registers	*/
+		d1 = p1[1];	/*  ... in bursts, if possible.		*/
+		d2 = p1[2];
+		d3 = p1[3];
+		d4 = p1[4];
+		d5 = p1[5];
+		d6 = p1[6];
+		d7 = p1[7];
+		d0 ^= p2[0];
+		d1 ^= p2[1];
+		d2 ^= p2[2];
+		d3 ^= p2[3];
+		d4 ^= p2[4];
+		d5 ^= p2[5];
+		d6 ^= p2[6];
+		d7 ^= p2[7];
+		d0 ^= p3[0];
+		d1 ^= p3[1];
+		d2 ^= p3[2];
+		d3 ^= p3[3];
+		d4 ^= p3[4];
+		d5 ^= p3[5];
+		d6 ^= p3[6];
+		d7 ^= p3[7];
+		p1[0] = d0;	/* Store the result (in bursts)		*/
+		p1[1] = d1;
+		p1[2] = d2;
+		p1[3] = d3;
+		p1[4] = d4;
+		p1[5] = d5;
+		p1[6] = d6;
+		p1[7] = d7;
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+	} while (--lines > 0);
+	if (lines == 0)
+		goto once_more;
+}
+
+static void
+xor_32regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3, unsigned long *p4)
+{
+	long lines = bytes / (sizeof (long)) / 8 - 1;
+
+	prefetchw(p1);
+	prefetch(p2);
+	prefetch(p3);
+	prefetch(p4);
+
+	do {
+		register long d0, d1, d2, d3, d4, d5, d6, d7;
+
+		prefetchw(p1+8);
+		prefetch(p2+8);
+		prefetch(p3+8);
+		prefetch(p4+8);
+ once_more:
+		d0 = p1[0];	/* Pull the stuff into registers	*/
+		d1 = p1[1];	/*  ... in bursts, if possible.		*/
+		d2 = p1[2];
+		d3 = p1[3];
+		d4 = p1[4];
+		d5 = p1[5];
+		d6 = p1[6];
+		d7 = p1[7];
+		d0 ^= p2[0];
+		d1 ^= p2[1];
+		d2 ^= p2[2];
+		d3 ^= p2[3];
+		d4 ^= p2[4];
+		d5 ^= p2[5];
+		d6 ^= p2[6];
+		d7 ^= p2[7];
+		d0 ^= p3[0];
+		d1 ^= p3[1];
+		d2 ^= p3[2];
+		d3 ^= p3[3];
+		d4 ^= p3[4];
+		d5 ^= p3[5];
+		d6 ^= p3[6];
+		d7 ^= p3[7];
+		d0 ^= p4[0];
+		d1 ^= p4[1];
+		d2 ^= p4[2];
+		d3 ^= p4[3];
+		d4 ^= p4[4];
+		d5 ^= p4[5];
+		d6 ^= p4[6];
+		d7 ^= p4[7];
+		p1[0] = d0;	/* Store the result (in bursts)		*/
+		p1[1] = d1;
+		p1[2] = d2;
+		p1[3] = d3;
+		p1[4] = d4;
+		p1[5] = d5;
+		p1[6] = d6;
+		p1[7] = d7;
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+		p4 += 8;
+	} while (--lines > 0);
+	if (lines == 0)
+		goto once_more;
+}
+
+static void
+xor_32regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
+	    unsigned long *p3, unsigned long *p4, unsigned long *p5)
+{
+	long lines = bytes / (sizeof (long)) / 8 - 1;
+
+	prefetchw(p1);
+	prefetch(p2);
+	prefetch(p3);
+	prefetch(p4);
+	prefetch(p5);
+
+	do {
+		register long d0, d1, d2, d3, d4, d5, d6, d7;
+
+		prefetchw(p1+8);
+		prefetch(p2+8);
+		prefetch(p3+8);
+		prefetch(p4+8);
+		prefetch(p5+8);
+ once_more:
+		d0 = p1[0];	/* Pull the stuff into registers	*/
+		d1 = p1[1];	/*  ... in bursts, if possible.		*/
+		d2 = p1[2];
+		d3 = p1[3];
+		d4 = p1[4];
+		d5 = p1[5];
+		d6 = p1[6];
+		d7 = p1[7];
+		d0 ^= p2[0];
+		d1 ^= p2[1];
+		d2 ^= p2[2];
+		d3 ^= p2[3];
+		d4 ^= p2[4];
+		d5 ^= p2[5];
+		d6 ^= p2[6];
+		d7 ^= p2[7];
+		d0 ^= p3[0];
+		d1 ^= p3[1];
+		d2 ^= p3[2];
+		d3 ^= p3[3];
+		d4 ^= p3[4];
+		d5 ^= p3[5];
+		d6 ^= p3[6];
+		d7 ^= p3[7];
+		d0 ^= p4[0];
+		d1 ^= p4[1];
+		d2 ^= p4[2];
+		d3 ^= p4[3];
+		d4 ^= p4[4];
+		d5 ^= p4[5];
+		d6 ^= p4[6];
+		d7 ^= p4[7];
+		d0 ^= p5[0];
+		d1 ^= p5[1];
+		d2 ^= p5[2];
+		d3 ^= p5[3];
+		d4 ^= p5[4];
+		d5 ^= p5[5];
+		d6 ^= p5[6];
+		d7 ^= p5[7];
+		p1[0] = d0;	/* Store the result (in bursts)		*/
+		p1[1] = d1;
+		p1[2] = d2;
+		p1[3] = d3;
+		p1[4] = d4;
+		p1[5] = d5;
+		p1[6] = d6;
+		p1[7] = d7;
+		p1 += 8;
+		p2 += 8;
+		p3 += 8;
+		p4 += 8;
+		p5 += 8;
+	} while (--lines > 0);
+	if (lines == 0)
+		goto once_more;
+}
+
 static struct xor_block_template xor_block_8regs = {
 	name: "8regs",
 	do_2: xor_8regs_2,
@@ -315,8 +693,26 @@
 	do_5: xor_32regs_5,
 };
 
+static struct xor_block_template xor_block_8regs_p = {
+	name: "8regs_prefetch",
+	do_2: xor_8regs_p_2,
+	do_3: xor_8regs_p_3,
+	do_4: xor_8regs_p_4,
+	do_5: xor_8regs_p_5,
+};
+
+static struct xor_block_template xor_block_32regs_p = {
+	name: "32regs_prefetch",
+	do_2: xor_32regs_p_2,
+	do_3: xor_32regs_p_3,
+	do_4: xor_32regs_p_4,
+	do_5: xor_32regs_p_5,
+};
+
 #define XOR_TRY_TEMPLATES			\
 	do {					\
 		xor_speed(&xor_block_8regs);	\
+		xor_speed(&xor_block_8regs_p);	\
 		xor_speed(&xor_block_32regs);	\
+		xor_speed(&xor_block_32regs_p);	\
 	} while (0)
diff -Nru a/include/asm-i386/bitops.h b/include/asm-i386/bitops.h
--- a/include/asm-i386/bitops.h	Sun Nov 10 19:28:40 2002
+++ b/include/asm-i386/bitops.h	Sun Nov 10 19:28:40 2002
@@ -89,7 +89,7 @@
 
 /**
  * __change_bit - Toggle a bit in memory
- * @nr: the bit to set
+ * @nr: the bit to change
  * @addr: the address to start counting from
  *
  * Unlike change_bit(), this function is non-atomic and may be reordered.
@@ -106,7 +106,7 @@
 
 /**
  * change_bit - Toggle a bit in memory
- * @nr: Bit to clear
+ * @nr: Bit to change
  * @addr: Address to start counting from
  *
  * change_bit() is atomic and may not be reordered.
@@ -162,7 +162,7 @@
 
 /**
  * test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to set
+ * @nr: Bit to clear
  * @addr: Address to count from
  *
  * This operation is atomic and cannot be reordered.  
@@ -181,7 +181,7 @@
 
 /**
  * __test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to set
+ * @nr: Bit to clear
  * @addr: Address to count from
  *
  * This operation is non-atomic and can be reordered.  
@@ -213,7 +213,7 @@
 
 /**
  * test_and_change_bit - Change a bit and return its new value
- * @nr: Bit to set
+ * @nr: Bit to change
  * @addr: Address to count from
  *
  * This operation is atomic and cannot be reordered.  
diff -Nru a/include/asm-i386/elf.h b/include/asm-i386/elf.h
--- a/include/asm-i386/elf.h	Sun Nov 10 19:28:40 2002
+++ b/include/asm-i386/elf.h	Sun Nov 10 19:28:40 2002
@@ -7,6 +7,7 @@
 
 #include <asm/ptrace.h>
 #include <asm/user.h>
+#include <asm/processor.h>
 
 #include <linux/utsname.h>
 
@@ -59,6 +60,9 @@
 
 /* Wow, the "main" arch needs arch dependent functions too.. :) */
 
+#define savesegment(seg,value) \
+	asm volatile("movl %%" #seg ",%0":"=m" (*(int *)&(value)))
+
 /* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
    now struct_user_regs, they are different) */
 
@@ -72,9 +76,8 @@
 	pr_reg[6] = regs->eax;				\
 	pr_reg[7] = regs->xds;				\
 	pr_reg[8] = regs->xes;				\
-	/* fake once used fs and gs selectors? */	\
-	pr_reg[9] = regs->xds;	/* was fs and __fs */	\
-	pr_reg[10] = regs->xds;	/* was gs and __gs */	\
+	savesegment(fs,pr_reg[9]);			\
+	savesegment(gs,pr_reg[10]);			\
 	pr_reg[11] = regs->orig_eax;			\
 	pr_reg[12] = regs->eip;				\
 	pr_reg[13] = regs->xcs;				\
@@ -99,6 +102,20 @@
 
 #ifdef __KERNEL__
 #define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX)
+
+extern int dump_task_regs (struct task_struct *, elf_gregset_t *);
+extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *);
+extern int dump_task_extended_fpu (struct task_struct *, struct user_fxsr_struct *);
+
+#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs)
+#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
+#define ELF_CORE_COPY_XFPREGS(tsk, elf_xfpregs) dump_task_extended_fpu(tsk, elf_xfpregs)
+
+#ifdef CONFIG_SMP
+extern void dump_smp_unlazy_fpu(void);
+#define ELF_CORE_SYNC dump_smp_unlazy_fpu
+#endif
+
 #endif
 
 #endif
diff -Nru a/include/asm-i386/hardirq.h b/include/asm-i386/hardirq.h
--- a/include/asm-i386/hardirq.h	Sun Nov 10 19:28:40 2002
+++ b/include/asm-i386/hardirq.h	Sun Nov 10 19:28:40 2002
@@ -76,6 +76,8 @@
 #define hardirq_endlock()	do { } while (0)
 
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
+#define nmi_enter()		(irq_enter())
+#define nmi_exit()		(preempt_count() -= HARDIRQ_OFFSET)
 
 #if CONFIG_PREEMPT
 # define in_atomic()	((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
diff -Nru a/include/asm-i386/timer.h b/include/asm-i386/timer.h
--- a/include/asm-i386/timer.h	Sun Nov 10 19:28:38 2002
+++ b/include/asm-i386/timer.h	Sun Nov 10 19:28:38 2002
@@ -19,4 +19,8 @@
 #define TICK_SIZE (tick_nsec / 1000)
 
 extern struct timer_opts* select_timer(void);
+
+/* Modifiers for buggy PIT handling */
+
+extern int pit_latch_buggy;
 #endif
diff -Nru a/include/asm-ia64/elf.h b/include/asm-ia64/elf.h
--- a/include/asm-ia64/elf.h	Sun Nov 10 19:28:40 2002
+++ b/include/asm-ia64/elf.h	Sun Nov 10 19:28:40 2002
@@ -65,12 +65,16 @@
 #define ELF_NGREG	128	/* we really need just 72 but let's leave some headroom... */
 #define ELF_NFPREG	128	/* f0 and f1 could be omitted, but so what... */
 
+typedef unsigned long elf_fpxregset_t;
+
 typedef unsigned long elf_greg_t;
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
 typedef struct ia64_fpreg elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
+
+
 struct pt_regs;	/* forward declaration... */
 extern void ia64_elf_core_copy_regs (struct pt_regs *src, elf_gregset_t dst);
 #define ELF_CORE_COPY_REGS(_dest,_regs)	ia64_elf_core_copy_regs(_regs, _dest);
@@ -88,6 +92,14 @@
 struct elf64_hdr;
 extern void ia64_set_personality (struct elf64_hdr *elf_ex, int ibcs2_interpreter);
 #define SET_PERSONALITY(ex, ibcs2)	ia64_set_personality(&(ex), ibcs2)
+
+extern int dump_task_regs(struct task_struct *, elf_gregset_t *);
+extern int dump_task_fpu (struct task_struct *, elf_fpregset_t *);
+
+#define ELF_CORE_COPY_TASK_REGS(tsk, elf_gregs) dump_task_regs(tsk, elf_gregs)
+#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs)
+
+
 #endif
 
 #endif /* _ASM_IA64_ELF_H */
diff -Nru a/include/asm-parisc/mman.h b/include/asm-parisc/mman.h
--- a/include/asm-parisc/mman.h	Sun Nov 10 19:28:40 2002
+++ b/include/asm-parisc/mman.h	Sun Nov 10 19:28:40 2002
@@ -18,6 +18,8 @@
 #define MAP_LOCKED	0x2000		/* pages are locked */
 #define MAP_NORESERVE	0x4000		/* don't check for reservations */
 #define MAP_GROWSDOWN	0x8000		/* stack-like segment */
+#define MAP_POPULATE	0x10000		/* populate (prefault) pagetables */
+#define MAP_NONBLOCK	0x20000		/* do not block on IO */
 
 #define MS_SYNC		1		/* synchronous memory sync */
 #define MS_ASYNC	2		/* sync memory asynchronously */
diff -Nru a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h
--- a/include/asm-parisc/pgtable.h	Sun Nov 10 19:28:41 2002
+++ b/include/asm-parisc/pgtable.h	Sun Nov 10 19:28:41 2002
@@ -13,8 +13,6 @@
 #include <asm/cache.h>
 #include <asm/bitops.h>
 
-#define ARCH_STACK_GROWSUP
-
 /*
  * kern_addr_valid(ADDR) tests if ADDR is pointing to valid kernel
  * memory.  For the return value to be meaningful, ADDR must be >=
diff -Nru a/include/asm-ppc/cacheflush.h b/include/asm-ppc/cacheflush.h
--- a/include/asm-ppc/cacheflush.h	Sun Nov 10 19:28:40 2002
+++ b/include/asm-ppc/cacheflush.h	Sun Nov 10 19:28:40 2002
@@ -24,9 +24,9 @@
 #define flush_cache_range(vma, a, b)	do { } while (0)
 #define flush_cache_page(vma, p)	do { } while (0)
 #define flush_page_to_ram(page)		do { } while (0)
+#define flush_icache_page(vma, page)	do { } while (0)
 
 extern void flush_dcache_page(struct page *page);
-extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
 extern void flush_icache_range(unsigned long, unsigned long);
 extern void flush_icache_user_range(struct vm_area_struct *vma,
 		struct page *page, unsigned long addr, int len);
diff -Nru a/include/asm-ppc/highmem.h b/include/asm-ppc/highmem.h
--- a/include/asm-ppc/highmem.h	Sun Nov 10 19:28:39 2002
+++ b/include/asm-ppc/highmem.h	Sun Nov 10 19:28:39 2002
@@ -41,11 +41,7 @@
  * easily, subsequent pte tables have to be allocated in one physical
  * chunk of RAM.
  */
-#ifdef CONFIG_HIGHMEM_START_BOOL
 #define PKMAP_BASE CONFIG_HIGHMEM_START
-#else
-#define PKMAP_BASE (0xfe000000UL)
-#endif /* CONFIG_HIGHMEM_START_BOOL */
 #define LAST_PKMAP 1024
 #define LAST_PKMAP_MASK (LAST_PKMAP-1)
 #define PKMAP_NR(virt)  ((virt-PKMAP_BASE) >> PAGE_SHIFT)
diff -Nru a/include/asm-ppc/ibm4xx.h b/include/asm-ppc/ibm4xx.h
--- a/include/asm-ppc/ibm4xx.h	Sun Nov 10 19:28:40 2002
+++ b/include/asm-ppc/ibm4xx.h	Sun Nov 10 19:28:40 2002
@@ -19,35 +19,35 @@
 #ifdef CONFIG_40x
 
 #if defined(CONFIG_ASH)
-#include <platforms/ash.h>
+#include <platforms/4xx/ash.h>
 #endif
 
 #if defined (CONFIG_CEDER)
-#include <platforms/ceder.h>
+#include <platforms/4xx/ceder.h>
 #endif
 
 #if defined(CONFIG_CPCI405)
-#include <platforms/cpci405.h>
+#include <platforms/4xx/cpci405.h>
 #endif
 
 #if defined(CONFIG_EP405)
-#include <platforms/ep405.h>
+#include <platforms/4xx/ep405.h>
 #endif
 
 #if defined(CONFIG_OAK)
-#include <platforms/oak.h>
+#include <platforms/4xx/oak.h>
 #endif
 
 #if defined(CONFIG_REDWOOD_4)
-#include <platforms/redwood.h>
+#include <platforms/4xx/redwood.h>
 #endif
 
 #if defined(CONFIG_REDWOOD_5)
-#include <platforms/redwood5.h>
+#include <platforms/4xx/redwood5.h>
 #endif
 
 #if defined(CONFIG_WALNUT)
-#include <platforms/walnut.h>
+#include <platforms/4xx/walnut.h>
 #endif
 
 #ifndef PPC4xx_MACHINE_NAME
diff -Nru a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
--- a/include/asm-ppc/machdep.h	Sun Nov 10 19:28:38 2002
+++ b/include/asm-ppc/machdep.h	Sun Nov 10 19:28:38 2002
@@ -37,6 +37,9 @@
 	void		(*power_off)(void);
 	void		(*halt)(void);
 
+	void		(*idle)(void);
+	void		(*power_save)(void);
+
 	long		(*time_init)(void); /* Optional, may be NULL */
 	int		(*set_rtc_time)(unsigned long nowtime);
 	unsigned long	(*get_rtc_time)(void);
diff -Nru a/include/asm-ppc/mman.h b/include/asm-ppc/mman.h
--- a/include/asm-ppc/mman.h	Sun Nov 10 19:28:41 2002
+++ b/include/asm-ppc/mman.h	Sun Nov 10 19:28:41 2002
@@ -19,6 +19,8 @@
 #define MAP_GROWSDOWN	0x0100		/* stack-like segment */
 #define MAP_DENYWRITE	0x0800		/* ETXTBSY */
 #define MAP_EXECUTABLE	0x1000		/* mark it as an executable */
+#define MAP_POPULATE	0x8000		/* populate (prefault) pagetables */
+#define MAP_NONBLOCK	0x10000		/* do not block on IO */
 
 #define MS_ASYNC	1		/* sync memory asynchronously */
 #define MS_INVALIDATE	2		/* invalidate the caches */
diff -Nru a/include/asm-ppc/page.h b/include/asm-ppc/page.h
--- a/include/asm-ppc/page.h	Sun Nov 10 19:28:38 2002
+++ b/include/asm-ppc/page.h	Sun Nov 10 19:28:38 2002
@@ -9,12 +9,8 @@
 #ifdef __KERNEL__
 #include <linux/config.h>
 
-/* Be sure to change arch/ppc/Makefile to match */
-#ifdef CONFIG_KERNEL_START_BOOL
+/* This must match what is in arch/ppc/Makefile */
 #define PAGE_OFFSET	CONFIG_KERNEL_START
-#else
-#define PAGE_OFFSET	0xc0000000
-#endif /* CONFIG_KERNEL_START_BOOL */
 #define KERNELBASE	PAGE_OFFSET
 
 #ifndef __ASSEMBLY__
diff -Nru a/include/asm-ppc/poll.h b/include/asm-ppc/poll.h
--- a/include/asm-ppc/poll.h	Sun Nov 10 19:28:39 2002
+++ b/include/asm-ppc/poll.h	Sun Nov 10 19:28:39 2002
@@ -12,6 +12,7 @@
 #define POLLWRNORM	0x0100
 #define POLLWRBAND	0x0200
 #define POLLMSG		0x0400
+#define POLLREMOVE	0x1000
 
 struct pollfd {
 	int fd;
diff -Nru a/include/asm-ppc/tlbflush.h b/include/asm-ppc/tlbflush.h
--- a/include/asm-ppc/tlbflush.h	Sun Nov 10 19:28:37 2002
+++ b/include/asm-ppc/tlbflush.h	Sun Nov 10 19:28:37 2002
@@ -30,7 +30,6 @@
 static inline void flush_tlb_kernel_range(unsigned long start,
 				unsigned long end)
 	{ _tlbia(); }
-#define update_mmu_cache(vma, addr, pte)	do { } while (0)
 
 #elif defined(CONFIG_8xx)
 #define __tlbia()	asm volatile ("tlbia; sync" : : : "memory")
@@ -46,7 +45,6 @@
 static inline void flush_tlb_kernel_range(unsigned long start,
 				unsigned long end)
 	{ __tlbia(); }
-#define update_mmu_cache(vma, addr, pte)	do { } while (0)
 
 #else	/* 6xx, 7xx, 7xxx cpus */
 struct mm_struct;
@@ -56,15 +54,6 @@
 extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 			    unsigned long end);
 extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
-
-/*
- * This gets called at the end of handling a page fault, when
- * the kernel has put a new PTE into the page table for the process.
- * We use it to put a corresponding HPTE into the hash table
- * ahead of time, instead of waiting for the inevitable extra
- * hash-table miss exception.
- */
-extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
 #endif
 
 /*
@@ -76,6 +65,17 @@
 				      unsigned long start, unsigned long end)
 {
 }
+
+/*
+ * This gets called at the end of handling a page fault, when
+ * the kernel has put a new PTE into the page table for the process.
+ * We use it to ensure coherency between the i-cache and d-cache
+ * for the page which has just been mapped in.
+ * On machines which use an MMU hash table, we use this to put a
+ * corresponding HPTE into the hash table ahead of time, instead of
+ * waiting for the inevitable extra hash-table miss exception.
+ */
+extern void update_mmu_cache(struct vm_area_struct *, unsigned long, pte_t);
 
 #endif /* _PPC_TLBFLUSH_H */
 #endif /*__KERNEL__ */
diff -Nru a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
--- a/include/asm-ppc/unistd.h	Sun Nov 10 19:28:37 2002
+++ b/include/asm-ppc/unistd.h	Sun Nov 10 19:28:37 2002
@@ -239,6 +239,11 @@
 #define __NR_alloc_hugepages	232
 #define __NR_free_hugepages	233
 #define __NR_exit_group		234
+#define __NR_lookup_dcookie	235
+#define __NR_sys_epoll_create	236
+#define __NR_sys_epoll_ctl	237
+#define __NR_sys_epoll_wait	238
+#define __NR_remap_file_pages	239
 
 #define __NR(n)	#n
 
diff -Nru a/include/asm-ppc64/elf.h b/include/asm-ppc64/elf.h
--- a/include/asm-ppc64/elf.h	Sun Nov 10 19:28:40 2002
+++ b/include/asm-ppc64/elf.h	Sun Nov 10 19:28:40 2002
@@ -57,9 +57,9 @@
 #define ELF_ET_DYN_BASE         (0x08000000)
 
 /* Common routine for both 32-bit and 64-bit processes */
-#define ELF_CORE_COPY_REGS(gregs, regs) elf_core_copy_regs(gregs, regs);
+#define ELF_CORE_COPY_REGS(gregs, regs) ppc64_elf_core_copy_regs(gregs, regs);
 static inline void
-elf_core_copy_regs(elf_gregset_t dstRegs, struct pt_regs* srcRegs)
+ppc64_elf_core_copy_regs(elf_gregset_t dstRegs, struct pt_regs* srcRegs)
 {
 	int i;
 
diff -Nru a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h
--- a/include/asm-ppc64/machdep.h	Sun Nov 10 19:28:38 2002
+++ b/include/asm-ppc64/machdep.h	Sun Nov 10 19:28:38 2002
@@ -37,25 +37,21 @@
 	long		(*hpte_updatepp)(unsigned long slot, 
 					 unsigned long newpp, 
 					 unsigned long va,
-					 int large);
+					 int large,
+					 int local);
 	void            (*hpte_updateboltedpp)(unsigned long newpp, 
 					       unsigned long ea);
-	long		(*insert_hpte)(unsigned long hpte_group,
-				       unsigned long vpn,
+	long		(*hpte_insert)(unsigned long hpte_group,
+				       unsigned long va,
 				       unsigned long prpn,
 				       int secondary, 
 				       unsigned long hpteflags, 
 				       int bolted,
 				       int large);
-	long		(*remove_hpte)(unsigned long hpte_group);
+	long		(*hpte_remove)(unsigned long hpte_group);
 	void		(*flush_hash_range)(unsigned long context,
 					    unsigned long number,
 					    int local);
-	void		(*make_pte)(void *htab, unsigned long va,
-				    unsigned long pa,
-				    int mode,
-				    unsigned long hash_mask,
-				    int large);
 
 	void		(*tce_build)(struct TceTable * tbl,
 				     long tcenum,
diff -Nru a/include/asm-ppc64/mman.h b/include/asm-ppc64/mman.h
--- a/include/asm-ppc64/mman.h	Sun Nov 10 19:28:39 2002
+++ b/include/asm-ppc64/mman.h	Sun Nov 10 19:28:39 2002
@@ -34,6 +34,9 @@
 #define MCL_CURRENT     0x2000          /* lock all currently mapped pages */
 #define MCL_FUTURE      0x4000          /* lock all additions to address space */
 
+#define MAP_POPULATE	0x8000		/* populate (prefault) pagetables */
+#define MAP_NONBLOCK	0x10000		/* do not block on IO */
+
 #define MADV_NORMAL	0x0		/* default page-in behavior */
 #define MADV_RANDOM	0x1		/* page-in minimum required */
 #define MADV_SEQUENTIAL	0x2		/* read-ahead aggressively */
diff -Nru a/include/asm-ppc64/poll.h b/include/asm-ppc64/poll.h
--- a/include/asm-ppc64/poll.h	Sun Nov 10 19:28:36 2002
+++ b/include/asm-ppc64/poll.h	Sun Nov 10 19:28:36 2002
@@ -21,6 +21,7 @@
 #define POLLWRNORM	0x0100
 #define POLLWRBAND	0x0200
 #define POLLMSG		0x0400
+#define POLLREMOVE	0x1000
 
 struct pollfd {
 	int fd;
diff -Nru a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h
--- a/include/asm-ppc64/processor.h	Sun Nov 10 19:28:37 2002
+++ b/include/asm-ppc64/processor.h	Sun Nov 10 19:28:37 2002
@@ -636,8 +636,8 @@
 /* This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
-#define TASK_UNMAPPED_BASE_USER32 (STACK_TOP_USER32 / 4)
-#define TASK_UNMAPPED_BASE_USER64 (STACK_TOP_USER64 / 4)
+#define TASK_UNMAPPED_BASE_USER32 (PAGE_ALIGN(STACK_TOP_USER32 / 4))
+#define TASK_UNMAPPED_BASE_USER64 (PAGE_ALIGN(STACK_TOP_USER64 / 4))
 
 #define TASK_UNMAPPED_BASE ((test_thread_flag(TIF_32BIT)||(ppcdebugset(PPCDBG_BINFMT_32ADDR))) ? \
 		TASK_UNMAPPED_BASE_USER32 : TASK_UNMAPPED_BASE_USER64 )
diff -Nru a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h
--- a/include/asm-ppc64/unistd.h	Sun Nov 10 19:28:36 2002
+++ b/include/asm-ppc64/unistd.h	Sun Nov 10 19:28:36 2002
@@ -450,6 +450,6 @@
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
-#define cond_syscall(x) asm(".weak\t." #x "\n\t.set\t." #x ",sys_ni_syscall");
+#define cond_syscall(x) asm(".weak\t." #x "\n\t.set\t." #x ",.sys_ni_syscall");
 
 #endif /* _ASM_PPC_UNISTD_H_ */
diff -Nru a/include/asm-sparc/poll.h b/include/asm-sparc/poll.h
--- a/include/asm-sparc/poll.h	Sun Nov 10 19:28:41 2002
+++ b/include/asm-sparc/poll.h	Sun Nov 10 19:28:41 2002
@@ -12,6 +12,7 @@
 #define POLLRDBAND	128
 #define POLLWRBAND	256
 #define POLLMSG		512
+#define POLLREMOVE	1024
 
 struct pollfd {
 	int fd;
diff -Nru a/include/asm-sparc/system.h b/include/asm-sparc/system.h
--- a/include/asm-sparc/system.h	Sun Nov 10 19:28:40 2002
+++ b/include/asm-sparc/system.h	Sun Nov 10 19:28:40 2002
@@ -135,7 +135,7 @@
 	 * clobber every non-fixed-usage register besides l2/l3/o4/o5.  -DaveM
 	 *
 	 * Hey Dave, that do not touch sign is too much of an incentive
-	 * - Anton
+	 * - Anton & Pete
 	 */
 #define switch_to(prev, next, last) do {						\
 	__label__ here;									\
@@ -160,6 +160,7 @@
 	"wr	%%g4, 0x20, %%psr\n\t"							\
 	"nop\n\t"									\
 	"nop\n\t"									\
+	"nop\n\t"	/* LEON needs this: load to %sp depends on CWP. */		\
 	"ldd	[%%g6 + %4], %%sp\n\t"							\
 	"wr	%%g5, 0x0, %%wim\n\t"							\
 	"ldd	[%%sp + 0x00], %%l0\n\t"						\
diff -Nru a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
--- a/include/asm-sparc/unistd.h	Sun Nov 10 19:28:37 2002
+++ b/include/asm-sparc/unistd.h	Sun Nov 10 19:28:37 2002
@@ -207,7 +207,7 @@
 #define __NR_uname              189 /* Linux Specific                              */
 #define __NR_init_module        190 /* Linux Specific                              */
 #define __NR_personality        191 /* Linux Specific                              */
-/* #define __NR_prof            192    Linux Specific                              */
+#define __NR_remap_file_pages   192 /* Linux Specific                              */
 /* #define __NR_break           193    Linux Specific                              */
 /* #define __NR_lock            194    Linux Specific                              */
 /* #define __NR_mpx             195    Linux Specific                              */
diff -Nru a/include/asm-sparc/vac-ops.h b/include/asm-sparc/vac-ops.h
--- a/include/asm-sparc/vac-ops.h	Sun Nov 10 19:28:38 2002
+++ b/include/asm-sparc/vac-ops.h	Sun Nov 10 19:28:38 2002
@@ -98,8 +98,8 @@
 	unsigned int num_bytes;     /* Size of the cache */
 	unsigned int num_lines;     /* Number of cache lines */
 	unsigned int do_hwflushes;  /* Hardware flushing available? */
-	enum { NONE, WRITE_THROUGH,
-	    WRITE_BACK } type;      /* What type of VAC? */
+	enum { VAC_NONE, VAC_WRITE_THROUGH,
+	    VAC_WRITE_BACK } type;  /* What type of VAC? */
 	unsigned int linesize;      /* Size of each line in bytes */
 	unsigned int log2lsize;     /* log2(linesize) */
 	unsigned int on;            /* VAC is enabled */
diff -Nru a/include/asm-sparc64/elf.h b/include/asm-sparc64/elf.h
--- a/include/asm-sparc64/elf.h	Sun Nov 10 19:28:38 2002
+++ b/include/asm-sparc64/elf.h	Sun Nov 10 19:28:38 2002
@@ -9,6 +9,7 @@
 #include <asm/ptrace.h>
 #ifdef __KERNEL__
 #include <asm/processor.h>
+#include <asm/uaccess.h>
 #endif
 
 /*
diff -Nru a/include/asm-sparc64/poll.h b/include/asm-sparc64/poll.h
--- a/include/asm-sparc64/poll.h	Sun Nov 10 19:28:41 2002
+++ b/include/asm-sparc64/poll.h	Sun Nov 10 19:28:41 2002
@@ -12,6 +12,7 @@
 #define POLLRDBAND	128
 #define POLLWRBAND	256
 #define POLLMSG		512
+#define POLLREMOVE	1024
 
 struct pollfd {
 	int fd;
diff -Nru a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
--- a/include/asm-sparc64/unistd.h	Sun Nov 10 19:28:37 2002
+++ b/include/asm-sparc64/unistd.h	Sun Nov 10 19:28:37 2002
@@ -207,7 +207,7 @@
 #define __NR_uname              189 /* Linux Specific                              */
 #define __NR_init_module        190 /* Linux Specific                              */
 #define __NR_personality        191 /* Linux Specific                              */
-/* #define __NR_prof            192    Linux Specific                              */
+#define __NR_remap_file_pages   192 /* Linux Specific                              */
 /* #define __NR_break           193    Linux Specific                              */
 /* #define __NR_lock            194    Linux Specific                              */
 /* #define __NR_mpx             195    Linux Specific                              */
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Sun Nov 10 19:28:37 2002
+++ b/include/linux/blkdev.h	Sun Nov 10 19:28:37 2002
@@ -11,22 +11,6 @@
 
 #include <asm/scatterlist.h>
 
-/*
- * Disk stats ...
- */
-
-#define DK_MAX_MAJOR 16
-#define DK_MAX_DISK 16
- 
-struct disk_stat {
-        unsigned int drive[DK_MAX_MAJOR][DK_MAX_DISK];
-        unsigned int drive_rio[DK_MAX_MAJOR][DK_MAX_DISK];
-        unsigned int drive_wio[DK_MAX_MAJOR][DK_MAX_DISK];
-        unsigned int drive_rblk[DK_MAX_MAJOR][DK_MAX_DISK];
-        unsigned int drive_wblk[DK_MAX_MAJOR][DK_MAX_DISK];
-};
-extern struct disk_stat dkstat;
-
 struct request_queue;
 typedef struct request_queue request_queue_t;
 struct elevator_s;
@@ -110,7 +94,8 @@
 enum rq_flag_bits {
 	__REQ_RW,	/* not set, read. set, write */
 	__REQ_RW_AHEAD,	/* READA */
-	__REQ_BARRIER,	/* may not be passed */
+	__REQ_SOFTBARRIER,	/* may not be passed by ioscheduler */
+	__REQ_HARDBARRIER,	/* may not be passed by drive either */
 	__REQ_CMD,	/* is a regular fs rw request */
 	__REQ_NOMERGE,	/* don't touch this for merging */
 	__REQ_STARTED,	/* drive already may have started this one */
@@ -134,7 +119,8 @@
 
 #define REQ_RW		(1 << __REQ_RW)
 #define REQ_RW_AHEAD	(1 << __REQ_RW_AHEAD)
-#define REQ_BARRIER	(1 << __REQ_BARRIER)
+#define REQ_SOFTBARRIER	(1 << __REQ_SOFTBARRIER)
+#define REQ_HARDBARRIER	(1 << __REQ_HARDBARRIER)
 #define REQ_CMD		(1 << __REQ_CMD)
 #define REQ_NOMERGE	(1 << __REQ_NOMERGE)
 #define REQ_STARTED	(1 << __REQ_STARTED)
@@ -275,9 +261,10 @@
  * mergeable request must not have _NOMERGE or _BARRIER bit set, nor may
  * it already be started by driver.
  */
+#define RQ_NOMERGE_FLAGS	\
+	(REQ_NOMERGE | REQ_STARTED | REQ_HARDBARRIER | REQ_SOFTBARRIER)
 #define rq_mergeable(rq)	\
-	(!((rq)->flags & (REQ_NOMERGE | REQ_STARTED | REQ_BARRIER))	\
-	&& ((rq)->flags & REQ_CMD))
+	(!((rq)->flags & RQ_NOMERGE_FLAGS) && blk_fs_request((rq)))
 
 /*
  * noop, requests are automagically marked as active/inactive by I/O
@@ -466,10 +453,5 @@
 )
 #endif 
  
-
-
-extern atomic_t nr_iowait_tasks;
-void io_schedule(void);
-void io_schedule_timeout(long timeout);
 
 #endif
diff -Nru a/include/linux/cpufreq.h b/include/linux/cpufreq.h
--- a/include/linux/cpufreq.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/cpufreq.h	Sun Nov 10 19:28:40 2002
@@ -206,41 +206,41 @@
 };
 
 #define CTL_CPU_VARS_SPEED_MAX { \
-                ctl_name: CPU_NR_FREQ_MAX, \
-                data: &cpu_max_freq, \
-                procname: "speed-max", \
-                maxlen:	sizeof(cpu_max_freq),\
-                mode: 0444, \
-                proc_handler: proc_dointvec, }
+                .ctl_name	= CPU_NR_FREQ_MAX, \
+                .data		= &cpu_max_freq, \
+                .procname	= "speed-max", \
+                .maxlen		= sizeof(cpu_max_freq),\
+                .mode		= 0444, \
+                .proc_handler	= proc_dointvec, }
 
 #define CTL_CPU_VARS_SPEED_MIN { \
-                ctl_name: CPU_NR_FREQ_MIN, \
-                data: &cpu_min_freq, \
-                procname: "speed-min", \
-                maxlen:	sizeof(cpu_min_freq),\
-                mode: 0444, \
-                proc_handler: proc_dointvec, }
+                .ctl_name	= CPU_NR_FREQ_MIN, \
+                .data		= &cpu_min_freq, \
+                .procname	= "speed-min", \
+                .maxlen		= sizeof(cpu_min_freq),\
+                .mode		= 0444, \
+                .proc_handler	= proc_dointvec, }
 
 #define CTL_CPU_VARS_SPEED(cpunr) { \
-                ctl_name: CPU_NR_FREQ, \
-                procname: "speed", \
-                mode: 0644, \
-                proc_handler: cpufreq_procctl, \
-                strategy: cpufreq_sysctl, \
-                extra1: (void*) (cpunr), }
+                .ctl_name	= CPU_NR_FREQ, \
+                .procname	= "speed", \
+                .mode		= 0644, \
+                .proc_handler	= cpufreq_procctl, \
+                .strategy	= cpufreq_sysctl, \
+                .extra1		= (void*) (cpunr), }
 
 #define CTL_TABLE_CPU_VARS(cpunr) static ctl_table ctl_cpu_vars_##cpunr[] = {\
                 CTL_CPU_VARS_SPEED_MAX, \
                 CTL_CPU_VARS_SPEED_MIN, \
                 CTL_CPU_VARS_SPEED(cpunr),  \
-                { ctl_name: 0, }, }
+                { .ctl_name = 0, }, }
 
 /* the ctl_table entry for each CPU */
 #define CPU_ENUM(s) { \
-                ctl_name: (CPU_NR + s), \
-                procname: #s, \
-                mode: 0555, \
-                child: ctl_cpu_vars_##s }
+                .ctl_name	= (CPU_NR + s), \
+                .procname	= #s, \
+                .mode		= 0555, \
+                .child		= ctl_cpu_vars_##s }
 
 #endif /* CONFIG_CPU_FREQ_24_API */
 
diff -Nru a/include/linux/crypto.h b/include/linux/crypto.h
--- a/include/linux/crypto.h	Sun Nov 10 19:28:38 2002
+++ b/include/linux/crypto.h	Sun Nov 10 19:28:38 2002
@@ -17,9 +17,11 @@
 #define _LINUX_CRYPTO_H
 
 #include <linux/module.h>
+#include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/string.h>
+#include <asm/page.h>
 
 /*
  * Algorithm masks and types.
@@ -65,7 +67,8 @@
  * via crypto_register_alg() and crypto_unregister_alg().
  */
 struct cipher_alg {
-	unsigned int cia_keysize;
+	unsigned int cia_min_keysize;
+	unsigned int cia_max_keysize;
 	unsigned int cia_ivsize;
 	int (*cia_setkey)(void *ctx, const u8 *key,
 	                  unsigned int keylen, u32 *flags);
@@ -112,6 +115,11 @@
 int crypto_unregister_alg(struct crypto_alg *alg);
 
 /*
+ * Algorithm query interface.
+ */
+int crypto_alg_available(const char *name, u32 flags);
+
+/*
  * Transforms: user-instantiated objects which encapsulate algorithms
  * and core processing logic.  Managed via crypto_alloc_tfm() and
  * crypto_free_tfm(), as well as the various helpers below.
@@ -136,9 +144,6 @@
 	void (*dit_final)(struct crypto_tfm *tfm, u8 *out);
 	void (*dit_digest)(struct crypto_tfm *tfm, struct scatterlist *sg,
 	                   unsigned int nsg, u8 *out);
-	void (*dit_hmac)(struct crypto_tfm *tfm, u8 *key,
-	                 unsigned int keylen, struct scatterlist *sg,
-	                 unsigned int nsg, u8 *out);
 };
 
 struct compress_tfm {
@@ -153,6 +158,7 @@
 struct crypto_tfm {
 
 	void *crt_ctx;
+	void *crt_work_block;
 	u32 crt_flags;
 	
 	union {
@@ -203,9 +209,14 @@
 	return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK;
 }
 
-static inline unsigned int crypto_tfm_alg_keysize(struct crypto_tfm *tfm)
+static inline unsigned int crypto_tfm_alg_min_keysize(struct crypto_tfm *tfm)
 {
-	return tfm->__crt_alg->cra_cipher.cia_keysize;
+	return tfm->__crt_alg->cra_cipher.cia_min_keysize;
+}
+
+static inline unsigned int crypto_tfm_alg_max_keysize(struct crypto_tfm *tfm)
+{
+	return tfm->__crt_alg->cra_cipher.cia_max_keysize;
 }
 
 static inline unsigned int crypto_tfm_alg_ivsize(struct crypto_tfm *tfm)
@@ -254,16 +265,6 @@
 	tfm->crt_digest.dit_digest(tfm, sg, nsg, out);
 }
 
-static inline void crypto_digest_hmac(struct crypto_tfm *tfm,
-                                      u8 *key, unsigned int keylen,
-                                      struct scatterlist *sg,
-                                      unsigned int nsg, u8 *out)
-                                      
-{
-	BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_DIGEST);
-	tfm->crt_digest.dit_hmac(tfm, key, keylen, sg, nsg, out);
-}
-
 static inline int crypto_cipher_setkey(struct crypto_tfm *tfm,
                                        const u8 *key, unsigned int keylen)
 {
@@ -313,4 +314,18 @@
 	tfm->crt_compress.cot_decompress(tfm);
 }
 
+/*
+ * HMAC support.
+ */
+#ifdef CONFIG_CRYPTO_HMAC
+void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen);
+void crypto_hmac_update(struct crypto_tfm *tfm,
+                        struct scatterlist *sg, unsigned int nsg);
+void crypto_hmac_final(struct crypto_tfm *tfm, u8 *key,
+                       unsigned int *keylen, u8 *out);
+void crypto_hmac(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen,
+                 struct scatterlist *sg, unsigned int nsg, u8 *out);
+#endif	/* CONFIG_CRYPTO_HMAC */
+
 #endif	/* _LINUX_CRYPTO_H */
+
diff -Nru a/include/linux/devfs_fs_kernel.h b/include/linux/devfs_fs_kernel.h
--- a/include/linux/devfs_fs_kernel.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/devfs_fs_kernel.h	Sun Nov 10 19:28:40 2002
@@ -23,21 +23,14 @@
 
 #define DEVFS_FL_NONE           0x000 /* This helps to make code more readable
 				       */
-#define DEVFS_FL_AUTO_OWNER     0x001 /* When a closed inode is opened the
-					 ownerships are set to the opening
-					 process and the protection is set to
-					 that given in <<mode>>. When the inode
-					 is closed, ownership reverts back to
-					 <<uid>> and <<gid>> and the protection
-					 is set to read-write for all        */
-#define DEVFS_FL_HIDE           0x002 /* Do not show entry in directory list */
-#define DEVFS_FL_AUTO_DEVNUM    0x004 /* Automatically generate device number
+#define DEVFS_FL_HIDE           0x001 /* Do not show entry in directory list */
+#define DEVFS_FL_AUTO_DEVNUM    0x002 /* Automatically generate device number
 				       */
-#define DEVFS_FL_AOPEN_NOTIFY   0x008 /* Asynchronously notify devfsd on open
+#define DEVFS_FL_AOPEN_NOTIFY   0x004 /* Asynchronously notify devfsd on open
 				       */
-#define DEVFS_FL_REMOVABLE      0x010 /* This is a removable media device    */
-#define DEVFS_FL_WAIT           0x020 /* Wait for devfsd to finish           */
-#define DEVFS_FL_CURRENT_OWNER  0x040 /* Set initial ownership to current    */
+#define DEVFS_FL_REMOVABLE      0x008 /* This is a removable media device    */
+#define DEVFS_FL_WAIT           0x010 /* Wait for devfsd to finish           */
+#define DEVFS_FL_CURRENT_OWNER  0x020 /* Set initial ownership to current    */
 #define DEVFS_FL_DEFAULT        DEVFS_FL_NONE
 
 
diff -Nru a/include/linux/elf.h b/include/linux/elf.h
--- a/include/linux/elf.h	Sun Nov 10 19:28:37 2002
+++ b/include/linux/elf.h	Sun Nov 10 19:28:37 2002
@@ -1,6 +1,7 @@
 #ifndef _LINUX_ELF_H
 #define _LINUX_ELF_H
 
+#include <linux/sched.h>
 #include <linux/types.h>
 #include <asm/elf.h>
 
@@ -578,7 +579,8 @@
 #define NT_PRFPREG	2
 #define NT_PRPSINFO	3
 #define NT_TASKSTRUCT	4
-#define NT_PRFPXREG	20
+#define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */
+
 
 /* Note header in a PT_NOTE section */
 typedef struct elf32_note {
diff -Nru a/include/linux/elfcore.h b/include/linux/elfcore.h
--- a/include/linux/elfcore.h	Sun Nov 10 19:28:41 2002
+++ b/include/linux/elfcore.h	Sun Nov 10 19:28:41 2002
@@ -85,4 +85,45 @@
 #define PRARGSZ ELF_PRARGSZ 
 #endif
 
+#ifdef __KERNEL__
+static inline void elf_core_copy_regs(elf_gregset_t *elfregs, struct pt_regs *regs)
+{
+#ifdef ELF_CORE_COPY_REGS
+	ELF_CORE_COPY_REGS((*elfregs), regs)
+#else
+	BUG_ON(sizeof(*elfregs) != sizeof(*regs));
+	*(struct pt_regs *)elfregs = *regs;
+#endif
+}
+
+static inline int elf_core_copy_task_regs(struct task_struct *t, elf_gregset_t* elfregs)
+{
+#ifdef ELF_CORE_COPY_TASK_REGS
+	
+	return ELF_CORE_COPY_TASK_REGS(t, elfregs);
+#endif
+	return 0;
+}
+
+extern int dump_fpu (struct pt_regs *, elf_fpregset_t *);
+
+static inline int elf_core_copy_task_fpregs(struct task_struct *t, elf_fpregset_t *fpu)
+{
+#ifdef ELF_CORE_COPY_FPREGS
+	return ELF_CORE_COPY_FPREGS(t, fpu);
+#else
+	return dump_fpu(NULL, fpu);
+#endif
+}
+
+#ifdef ELF_CORE_COPY_XFPREGS
+static inline int elf_core_copy_task_xfpregs(struct task_struct *t, elf_fpxregset_t *xfpu)
+{
+	return ELF_CORE_COPY_XFPREGS(t, xfpu);
+}
+#endif
+
+#endif /* __KERNEL__ */
+
+
 #endif /* _LINUX_ELFCORE_H */
diff -Nru a/include/linux/eventpoll.h b/include/linux/eventpoll.h
--- a/include/linux/eventpoll.h	Sun Nov 10 19:28:39 2002
+++ b/include/linux/eventpoll.h	Sun Nov 10 19:28:39 2002
@@ -14,10 +14,6 @@
 #ifndef _LINUX_EVENTPOLL_H
 #define _LINUX_EVENTPOLL_H
 
-/* Forward declarations to avoid compiler errors */
-struct file;
-struct pollfd;
-
 
 /* Valid opcodes to issue to sys_epoll_ctl() */
 #define EP_CTL_ADD 1
@@ -25,6 +21,13 @@
 #define EP_CTL_MOD 3
 
 
+#ifdef __KERNEL__
+
+/* Forward declarations to avoid compiler errors */
+struct file;
+struct pollfd;
+
+
 /* Kernel space functions implementing the user space "epoll" API */
 asmlinkage int sys_epoll_create(int size);
 asmlinkage int sys_epoll_ctl(int epfd, int op, int fd, unsigned int events);
@@ -34,6 +37,7 @@
 /* Used in fs/file_table.c:__fput() to unlink files from the eventpoll interface */
 void ep_notify_file_close(struct file *file);
 
+#endif /* #ifdef __KERNEL__ */
 
-#endif
+#endif /* #ifndef _LINUX_EVENTPOLL_H */
 
diff -Nru a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
--- a/include/linux/ext3_fs.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/ext3_fs.h	Sun Nov 10 19:28:40 2002
@@ -513,10 +513,9 @@
 #define EXT3_FEATURE_INCOMPAT_META_BG		0x0010
 
 #define EXT3_FEATURE_COMPAT_SUPP	EXT2_FEATURE_COMPAT_EXT_ATTR
-#define EXT2_FEATURE_INCOMPAT_SUPP	(EXT2_FEATURE_INCOMPAT_FILETYPE| \
-					 EXT2_FEATURE_INCOMPAT_META_BG)
 #define EXT3_FEATURE_INCOMPAT_SUPP	(EXT3_FEATURE_INCOMPAT_FILETYPE| \
-					 EXT3_FEATURE_INCOMPAT_RECOVER)
+					 EXT3_FEATURE_INCOMPAT_RECOVER| \
+					 EXT3_FEATURE_INCOMPAT_META_BG)
 #define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
 					 EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
 					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
@@ -689,7 +688,7 @@
 extern int ext3_check_dir_entry(const char *, struct inode *,
 				struct ext3_dir_entry_2 *,
 				struct buffer_head *, unsigned long);
-extern void ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
+extern int ext3_htree_store_dirent(struct file *dir_file, __u32 hash,
 				    __u32 minor_hash,
 				    struct ext3_dir_entry_2 *dirent);
 extern void ext3_htree_free_dir_info(struct dir_private_info *p);
diff -Nru a/include/linux/flat.h b/include/linux/flat.h
--- a/include/linux/flat.h	Sun Nov 10 19:28:37 2002
+++ b/include/linux/flat.h	Sun Nov 10 19:28:37 2002
@@ -2,6 +2,9 @@
 /* Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>
  *                     The Silver Hammer Group, Ltd.
  * Copyright (C) 2002  David McCullough <davidm@snapgear.com>
+ *
+ * This file provides the definitions and structures needed to
+ * support uClinux flat-format executables.
  */
 
 #ifndef _LINUX_FLAT_H
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Sun Nov 10 19:28:38 2002
+++ b/include/linux/fs.h	Sun Nov 10 19:28:38 2002
@@ -297,7 +297,7 @@
 	/* Set a page dirty */
 	int (*set_page_dirty)(struct page *page);
 
-	int (*readpages)(struct address_space *mapping,
+	int (*readpages)(struct file *filp, struct address_space *mapping,
 			struct list_head *pages, unsigned nr_pages);
 
 	/*
@@ -736,6 +736,24 @@
 };
 
 /*
+ * "descriptor" for what we're up to with a read for sendfile().
+ * This allows us to use the same read code yet
+ * have multiple different users of the data that
+ * we read from a file.
+ *
+ * The simplest case just copies the data to user
+ * mode.
+ */
+typedef struct {
+	size_t written;
+	size_t count;
+	char * buf;
+	int error;
+} read_descriptor_t;
+
+typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long);
+
+/*
  * NOTE:
  * read, write, poll, fsync, readv, writev can be called
  *   without the big kernel lock held in all filesystems.
@@ -761,7 +779,7 @@
 	int (*lock) (struct file *, int, struct file_lock *);
 	ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
 	ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
-	ssize_t (*sendfile) (struct file *, struct file *, loff_t *, size_t);
+	ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
 	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
 	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 };
@@ -793,8 +811,10 @@
 
 extern ssize_t vfs_read(struct file *, char *, size_t, loff_t *);
 extern ssize_t vfs_write(struct file *, const char *, size_t, loff_t *);
-extern ssize_t vfs_readv(struct file *, struct iovec *, int, size_t, loff_t *);
-extern ssize_t vfs_writev(struct file *, const struct iovec *, int, size_t, loff_t *);
+extern ssize_t vfs_readv(struct file *, const struct iovec *,
+		unsigned long, loff_t *);
+extern ssize_t vfs_writev(struct file *, const struct iovec *,
+		unsigned long, loff_t *);
 
 /*
  * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called
@@ -1174,24 +1194,6 @@
 
 #include <linux/err.h>
 
-/*
- * "descriptor" for what we're up to with a read for sendfile().
- * This allows us to use the same read code yet
- * have multiple different users of the data that
- * we read from a file.
- *
- * The simplest case just copies the data to user
- * mode.
- */
-typedef struct {
-	size_t written;
-	size_t count;
-	char * buf;
-	int error;
-} read_descriptor_t;
-
-typedef int (*read_actor_t)(read_descriptor_t *, struct page *, unsigned long, unsigned long);
-
 /* needed for stackable file system support */
 extern loff_t default_llseek(struct file *file, loff_t offset, int origin);
 
@@ -1254,7 +1256,7 @@
 extern ssize_t do_sync_write(struct file *filp, const char *buf, size_t len, loff_t *ppos);
 ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov,
 				unsigned long nr_segs, loff_t *ppos);
-extern ssize_t generic_file_sendfile(struct file *, struct file *, loff_t *, size_t);
+extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
 extern void do_generic_mapping_read(struct address_space *, struct file_ra_state *, struct file *,
 				    loff_t *, read_descriptor_t *, read_actor_t);
 extern void
diff -Nru a/include/linux/hugetlb.h b/include/linux/hugetlb.h
--- a/include/linux/hugetlb.h	Sun Nov 10 19:28:39 2002
+++ b/include/linux/hugetlb.h	Sun Nov 10 19:28:39 2002
@@ -2,17 +2,25 @@
 #define _LINUX_HUGETLB_H
 
 #ifdef CONFIG_HUGETLB_PAGE
+
+struct ctl_table;
+
 static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
 {
 	return vma->vm_flags & VM_HUGETLB;
 }
 
+int hugetlb_sysctl_handler(struct ctl_table *, int, struct file *, void *, size_t *);
 int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *);
 int follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *, struct page **, struct vm_area_struct **, unsigned long *, int *, int);
 void zap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long);
 void unmap_hugepage_range(struct vm_area_struct *, unsigned long, unsigned long);
 int hugetlb_prefault(struct address_space *, struct vm_area_struct *);
 void huge_page_release(struct page *);
+int hugetlb_report_meminfo(char *);
+
+extern int htlbpage_max;
+
 #else /* !CONFIG_HUGETLB_PAGE */
 static inline int is_vm_hugetlb_page(struct vm_area_struct *vma)
 {
@@ -25,6 +33,7 @@
 #define zap_hugepage_range(vma, start, len)	BUG()
 #define unmap_hugepage_range(vma, start, end)	BUG()
 #define huge_page_release(page)			BUG()
+#define hugetlb_report_meminfo(buf)		0
 
 #endif /* !CONFIG_HUGETLB_PAGE */
 
diff -Nru a/include/linux/ide.h b/include/linux/ide.h
--- a/include/linux/ide.h	Sun Nov 10 19:28:39 2002
+++ b/include/linux/ide.h	Sun Nov 10 19:28:39 2002
@@ -96,6 +96,14 @@
 #define ERROR_RECAL	1	/* Recalibrate every 2nd retry */
 
 /*
+ * Tune flags
+ */
+#define IDE_TUNE_BIOS		3
+#define IDE_TUNE_NOAUTO		2
+#define IDE_TUNE_AUTO		1
+#define IDE_TUNE_DEFAULT	0
+
+/*
  * state flags
  */
 #define DMA_PIO_RETRY	1	/* retrying in PIO */
@@ -743,7 +751,8 @@
 	unsigned nice0		: 1;	/* give obvious excess bandwidth */
 	unsigned nice2		: 1;	/* give a share in our own bandwidth */
 	unsigned doorlocking	: 1;	/* for removable only: door lock/unlock works */
-	unsigned autotune	: 2;	/* 1=autotune, 2=noautotune, 0=default */
+	unsigned autotune	: 3;	/* 1=autotune, 2=noautotune, 
+					   3=biostimings, 0=default */
 	unsigned remap_0_to_1	: 2;	/* 0=remap if ezdrive, 1=remap, 2=noremap */
 	unsigned ata_flash	: 1;	/* 1=present, 0=default */
 	unsigned blocked        : 1;	/* 1=powermanagment told us not to do anything, so sleep nicely */
diff -Nru a/include/linux/in.h b/include/linux/in.h
--- a/include/linux/in.h	Sun Nov 10 19:28:39 2002
+++ b/include/linux/in.h	Sun Nov 10 19:28:39 2002
@@ -69,6 +69,7 @@
 #define	IP_RECVTOS	13
 #define IP_MTU		14
 #define IP_FREEBIND	15
+#define IP_IPSEC_POLICY	16
 
 /* BSD compatibility */
 #define IP_RECVRETOPTS	IP_RETOPTS
diff -Nru a/include/linux/inetdevice.h b/include/linux/inetdevice.h
--- a/include/linux/inetdevice.h	Sun Nov 10 19:28:37 2002
+++ b/include/linux/inetdevice.h	Sun Nov 10 19:28:37 2002
@@ -19,6 +19,8 @@
 	int	tag;
 	int     arp_filter;
 	int	medium_id;
+	int	no_xfrm;
+	int	no_policy;
 	void	*sysctl;
 };
 
diff -Nru a/include/linux/ipsec.h b/include/linux/ipsec.h
--- a/include/linux/ipsec.h	Sun Nov 10 19:28:37 2002
+++ b/include/linux/ipsec.h	Sun Nov 10 19:28:37 2002
@@ -1,69 +1,46 @@
-/*
- *	Definitions for the SECurity layer
- *
- *	Author:
- *		Robert Muchsel <muchsel@acm.org>
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License
- *	as published by the Free Software Foundation; either version
- *	2 of the License, or (at your option) any later version.
- */
- 
 #ifndef _LINUX_IPSEC_H
 #define _LINUX_IPSEC_H
 
-#include <linux/config.h>
-#include <linux/socket.h>
-#include <net/sock.h>
-#include <linux/skbuff.h>
-
-/* Values for the set/getsockopt calls */
-
-/* These defines are compatible with NRL IPv6, however their semantics
-   is different */
-
-#define IPSEC_LEVEL_NONE	-1	/* send plaintext, accept any */
-#define IPSEC_LEVEL_DEFAULT	0	/* encrypt/authenticate if possible */
-					/* the default MUST be 0, because a */
-					/* socket is initialized with 0's */
-#define IPSEC_LEVEL_USE		1	/* use outbound, don't require inbound */
-#define IPSEC_LEVEL_REQUIRE	2	/* require both directions */
-#define IPSEC_LEVEL_UNIQUE	2	/* for compatibility only */
-
-#ifdef __KERNEL__
-
-/* skb bit flags set on packet input processing */
-
-#define RCV_SEC			0x0f	/* options on receive */
-#define RCV_AUTH		0x01	/* was authenticated */
-#define RCV_CRYPT		0x02	/* was encrypted */
-#define RCV_TUNNEL		0x04	/* was tunneled */
-#define SND_SEC			0xf0	/* options on send, these are */
-#define SND_AUTH		0x10	/* currently unused */
-#define SND_CRYPT		0x20
-#define SND_TUNNEL		0x40
-
-/*
- *	FIXME: ignores network encryption for now..
- */
- 
-#ifdef CONFIG_NET_SECURITY
-static __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
-{
-	return ((sk->authentication < IPSEC_LEVEL_REQUIRE) ||
-		(skb->security & RCV_AUTH)) &&
-		((sk->encryption < IPSEC_LEVEL_REQUIRE) ||
-		(skb->security & RCV_CRYPT));
-}
-
-#else
-
-static __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
-{
-	return 1;
-}
-#endif /* CONFIG */
+/* The definitions, required to talk to KAME racoon IKE. */
+
+#include <linux/pfkeyv2.h>
+
+#define IPSEC_PORT_ANY		0
+#define IPSEC_ULPROTO_ANY	255
+#define IPSEC_PROTO_ANY		255
+
+enum {
+	IPSEC_MODE_ANY		= 0,	/* We do not support this for SA */
+	IPSEC_MODE_TRANSPORT	= 1,
+	IPSEC_MODE_TUNNEL	= 2
+};
+
+enum {
+	IPSEC_DIR_ANY		= 0,
+	IPSEC_DIR_INBOUND	= 1,
+	IPSEC_DIR_OUTBOUND	= 2,
+	IPSEC_DIR_FWD		= 3,	/* It is our own */
+	IPSEC_DIR_MAX		= 4,
+	IPSEC_DIR_INVALID	= 5
+};
+
+enum {
+	IPSEC_POLICY_DISCARD	= 0,
+	IPSEC_POLICY_NONE	= 1,
+	IPSEC_POLICY_IPSEC	= 2,
+	IPSEC_POLICY_ENTRUST	= 3,
+	IPSEC_POLICY_BYPASS	= 4
+};
+
+enum {
+	IPSEC_LEVEL_DEFAULT	= 0,
+	IPSEC_LEVEL_USE		= 1,
+	IPSEC_LEVEL_REQUIRE	= 2,
+	IPSEC_LEVEL_UNIQUE	= 3
+};
+
+#define IPSEC_MANUAL_REQID_MAX	0x3fff
+
+#define IPSEC_REPLAYWSIZE  32
 
-#endif	/* __KERNEL__ */
 #endif	/* _LINUX_IPSEC_H */
diff -Nru a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h	Sun Nov 10 19:28:36 2002
+++ b/include/linux/mm.h	Sun Nov 10 19:28:36 2002
@@ -106,7 +106,11 @@
 #define VM_ACCOUNT	0x00100000	/* Is a VM accounted object */
 #define VM_HUGETLB	0x00400000	/* Huge TLB Page VM */
 
-#define VM_STACK_FLAGS	(0x00000100 | VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT)
+#ifdef CONFIG_STACK_GROWSUP
+#define VM_STACK_FLAGS	(VM_GROWSUP | VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT)
+#else
+#define VM_STACK_FLAGS	(VM_GROWSDOWN | VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT)
+#endif
 
 #define VM_READHINTMASK			(VM_SEQ_READ | VM_RAND_READ)
 #define VM_ClearReadHint(v)		(v)->vm_flags &= ~VM_READHINTMASK
diff -Nru a/include/linux/module.h b/include/linux/module.h
--- a/include/linux/module.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/module.h	Sun Nov 10 19:28:40 2002
@@ -311,7 +311,7 @@
  */
 #define MODULE_GENERIC_TABLE(gtype,name) \
 static const struct gtype##_id * __module_##gtype##_table \
-  __attribute__ ((unused, __section__(".data.exit"))) = name
+  __attribute__ ((unused, __section__(".exit.data"))) = name
 
 #ifndef __GENKSYMS__
 
diff -Nru a/include/linux/mtd/ftl.h b/include/linux/mtd/ftl.h
--- a/include/linux/mtd/ftl.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/mtd/ftl.h	Sun Nov 10 19:28:40 2002
@@ -15,7 +15,7 @@
  * limitations under the License. 
  *
  * The initial developer of the original code is David A. Hinds
- * <dhinds@pcmcia.sourceforge.org>.  Portions created by David A. Hinds
+ * <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
diff -Nru a/include/linux/nfs_flushd.h b/include/linux/nfs_flushd.h
--- a/include/linux/nfs_flushd.h	Sun Nov 10 19:28:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,61 +0,0 @@
-#ifndef NFS_CLUSTER_H
-#define NFS_CLUSTER_H
-
-
-
-#ifdef __KERNEL__
-#include <asm/atomic.h>
-#include <linux/nfs_fs_sb.h>
-
-/*
- * Counters of total number and pending number of requests.
- * When the total number of requests exceeds the hard limit, we stall
- * until it drops again.
- */
-#define MAX_REQUEST_HARD        256
-
-/*
- * Maximum number of requests per write cluster.
- * 32 requests per cluster account for 128K of data on an intel box.
- * Note: it's a good idea to make this number smaller than MAX_REQUEST_SOFT.
- *
- * For 100Mbps Ethernet, 128 pages (i.e. 256K) per cluster gives much
- * better performance.
- */
-#define REQUEST_HASH_SIZE	16
-#define REQUEST_NR(off)		((off) >> PAGE_CACHE_SHIFT)
-#define REQUEST_HASH(ino, off)	(((ino) ^ REQUEST_NR(off)) & (REQUEST_HASH_SIZE - 1))
-
-
-/*
- * Functions
- */
-extern int		nfs_reqlist_alloc(struct nfs_server *);
-extern void		nfs_reqlist_free(struct nfs_server *);
-extern int		nfs_reqlist_init(struct nfs_server *);
-extern void		nfs_reqlist_exit(struct nfs_server *);
-extern void		nfs_wake_flushd(void);
-
-/*
- * This is the per-mount writeback cache.
- */
-struct nfs_reqlist {
-	atomic_t		nr_requests;
-	unsigned long		runat;
-	wait_queue_head_t	request_wait;
-
-	/* The async RPC task that is responsible for scanning the
-	 * requests.
-	 */
-	struct rpc_task		*task;		/* request flush task */
-
-	/* Authentication flavor handle for this NFS client */
-	struct rpc_auth		*auth;
-
-	/* The list of all inodes with pending writebacks.  */
-	struct inode		*inodes;
-};
-
-#endif
-
-#endif
diff -Nru a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
--- a/include/linux/nfs_fs.h	Sun Nov 10 19:28:39 2002
+++ b/include/linux/nfs_fs.h	Sun Nov 10 19:28:39 2002
@@ -37,35 +37,17 @@
 # define NFS_DEBUG
 #endif
 
-/*
- * NFS_MAX_DIRCACHE controls the number of simultaneously cached
- * directory chunks. Each chunk holds the list of nfs_entry's returned
- * in a single readdir call in a memory region of size PAGE_SIZE.
- *
- * Note that at most server->rsize bytes of the cache memory are used.
- */
-#define NFS_MAX_DIRCACHE		16
-
 #define NFS_MAX_FILE_IO_BUFFER_SIZE	32768
 #define NFS_DEF_FILE_IO_BUFFER_SIZE	4096
 
 /*
  * The upper limit on timeouts for the exponential backoff algorithm.
  */
-#define NFS_MAX_RPC_TIMEOUT		(6*HZ)
-#define NFS_READ_DELAY			(2*HZ)
 #define NFS_WRITEBACK_DELAY		(5*HZ)
 #define NFS_WRITEBACK_LOCKDELAY		(60*HZ)
 #define NFS_COMMIT_DELAY		(5*HZ)
 
 /*
- * Size of the lookup cache in units of number of entries cached.
- * It is better not to make this too large although the optimum
- * depends on a usage and environment.
- */
-#define NFS_LOOKUP_CACHE_SIZE		64
-
-/*
  * superblock magic number for NFS
  */
 #define NFS_SUPER_MAGIC			0x6969
@@ -75,9 +57,6 @@
  */
 #define NFS_RPC_SWAPFLAGS		(RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS)
 
-/* Flags in the RPC client structure */
-#define NFS_CLNTF_BUFSIZE	0x0001	/* readdir buffer in longwords */
-
 #define NFS_RW_SYNC		0x0001	/* O_SYNC handling */
 #define NFS_RW_SWAP		0x0002	/* This is a swap request */
 
@@ -163,13 +142,11 @@
 	/*
 	 * This is the list of dirty unwritten pages.
 	 */
-	struct list_head	read;
 	struct list_head	dirty;
 	struct list_head	commit;
-	struct list_head	writeback;
+	struct radix_tree_root	nfs_page_tree;
 
-	unsigned int		nread,
-				ndirty,
+	unsigned int		ndirty,
 				ncommit,
 				npages;
 
@@ -187,8 +164,7 @@
 #define NFS_INO_STALE		0x0001		/* possible stale inode */
 #define NFS_INO_ADVISE_RDPLUS   0x0002          /* advise readdirplus */
 #define NFS_INO_REVALIDATING	0x0004		/* revalidating attrs */
-#define NFS_IS_SNAPSHOT		0x0010		/* a snapshot file */
-#define NFS_INO_FLUSH		0x0020		/* inode is due for flushing */
+#define NFS_INO_FLUSH		0x0008		/* inode is due for flushing */
 
 static inline struct nfs_inode *NFS_I(struct inode *inode)
 {
@@ -200,9 +176,7 @@
 #define NFS_SERVER(inode)		(NFS_SB(inode->i_sb))
 #define NFS_CLIENT(inode)		(NFS_SERVER(inode)->client)
 #define NFS_PROTO(inode)		(NFS_SERVER(inode)->rpc_ops)
-#define NFS_REQUESTLIST(inode)		(NFS_SERVER(inode)->rw_requests)
 #define NFS_ADDR(inode)			(RPC_PEERADDR(NFS_CLIENT(inode)))
-#define NFS_CONGESTED(inode)		(RPC_CONGESTED(NFS_CLIENT(inode)))
 #define NFS_COOKIEVERF(inode)		(NFS_I(inode)->cookieverf)
 #define NFS_READTIME(inode)		(NFS_I(inode)->read_cache_jiffies)
 #define NFS_MTIME_UPDATE(inode)		(NFS_I(inode)->cache_mtime_jiffies)
@@ -210,7 +184,6 @@
 #define NFS_CACHE_MTIME(inode)		(NFS_I(inode)->read_cache_mtime)
 #define NFS_CACHE_ISIZE(inode)		(NFS_I(inode)->read_cache_isize)
 #define NFS_CHANGE_ATTR(inode)		(NFS_I(inode)->change_attr)
-#define NFS_NEXTSCAN(inode)		(NFS_I(inode)->nextscan)
 #define NFS_CACHEINV(inode) \
 do { \
 	NFS_READTIME(inode) = jiffies - NFS_MAXATTRTIMEO(inode) - 1; \
@@ -256,8 +229,6 @@
  * linux/fs/nfs/inode.c
  */
 extern void nfs_zap_caches(struct inode *);
-extern int nfs_inode_is_stale(struct inode *, struct nfs_fh *,
-				struct nfs_fattr *);
 extern struct inode *nfs_fhget(struct dentry *, struct nfs_fh *,
 				struct nfs_fattr *);
 extern int __nfs_refresh_inode(struct inode *, struct nfs_fattr *);
@@ -321,6 +292,7 @@
  * linux/fs/nfs/write.c
  */
 extern int  nfs_writepage(struct page *);
+extern int  nfs_writepages(struct address_space *, struct writeback_control *);
 extern int  nfs_flush_incompatible(struct file *file, struct page *page);
 extern int  nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
 extern void nfs_writeback_done(struct rpc_task *task, int stable,
@@ -328,6 +300,7 @@
 extern void nfs_writedata_release(struct rpc_task *task);
 
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
+extern void nfs_commit_release(struct rpc_task *task);
 extern void nfs_commit_done(struct rpc_task *);
 #endif
 
@@ -338,25 +311,22 @@
 extern int  nfs_sync_file(struct inode *, struct file *, unsigned long, unsigned int, int);
 extern int  nfs_flush_file(struct inode *, struct file *, unsigned long, unsigned int, int);
 extern int  nfs_flush_list(struct list_head *, int, int);
-extern int  nfs_scan_lru_dirty(struct nfs_server *, struct list_head *);
-extern int  nfs_scan_lru_dirty_timeout(struct nfs_server *, struct list_head *);
 #if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
 extern int  nfs_commit_file(struct inode *, struct file *, unsigned long, unsigned int, int);
 extern int  nfs_commit_list(struct list_head *, int);
-extern int  nfs_scan_lru_commit(struct nfs_server *, struct list_head *);
-extern int  nfs_scan_lru_commit_timeout(struct nfs_server *, struct list_head *);
-#endif
-
+#else
 static inline int
-nfs_have_read(struct inode *inode)
+nfs_commit_file(struct inode *inode, struct file *file, unsigned long offset,
+		unsigned int len, int flags)
 {
-	return !list_empty(&NFS_I(inode)->read);
+	return 0;
 }
+#endif
 
 static inline int
 nfs_have_writebacks(struct inode *inode)
 {
-	return !list_empty(&NFS_I(inode)->writeback);
+	return NFS_I(inode)->npages != 0;
 }
 
 static inline int
@@ -396,10 +366,9 @@
  * linux/fs/nfs/read.c
  */
 extern int  nfs_readpage(struct file *, struct page *);
-extern int  nfs_pagein_inode(struct inode *, unsigned long, unsigned int);
+extern int  nfs_readpages(struct file *, struct address_space *,
+		struct list_head *, unsigned);
 extern int  nfs_pagein_list(struct list_head *, int);
-extern int  nfs_scan_lru_read(struct nfs_server *, struct list_head *);
-extern int  nfs_scan_lru_read_timeout(struct nfs_server *, struct list_head *);
 extern void nfs_readpage_result(struct rpc_task *, unsigned int count, int eof);
 extern void nfs_readdata_release(struct rpc_task *);
 
@@ -407,8 +376,8 @@
  * linux/fs/mount_clnt.c
  * (Used only by nfsroot module)
  */
-extern int  nfs_mount(struct sockaddr_in *, char *, struct nfs_fh *);
-extern int  nfs3_mount(struct sockaddr_in *, char *, struct nfs_fh *);
+extern int  nfsroot_mount(struct sockaddr_in *, char *, struct nfs_fh *,
+		int, int);
 
 /*
  * inline functions
diff -Nru a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
--- a/include/linux/nfs_fs_sb.h	Sun Nov 10 19:28:41 2002
+++ b/include/linux/nfs_fs_sb.h	Sun Nov 10 19:28:41 2002
@@ -2,6 +2,7 @@
 #define _NFS_FS_SB
 
 #include <linux/list.h>
+#include <linux/backing-dev.h>
 
 /*
  * NFS client parameters stored in the superblock.
@@ -9,6 +10,7 @@
 struct nfs_server {
 	struct rpc_clnt *	client;		/* RPC client handle */
 	struct nfs_rpc_ops *	rpc_ops;	/* NFS protocol vector */
+	struct backing_dev_info	backing_dev_info;
 	int			flags;		/* various flags */
 	unsigned int		caps;		/* server capabilities */
 	unsigned int		rsize;		/* read size */
@@ -23,11 +25,6 @@
 	unsigned int		acdirmax;
 	unsigned int		namelen;
 	char *			hostname;	/* remote hostname */
-	struct nfs_reqlist *	rw_requests;	/* async read/write requests */
-	struct list_head	lru_read,
-				lru_dirty,
-				lru_commit,
-				lru_busy;
 	struct nfs_fh		fh;
 	struct sockaddr_in	addr;
 #if CONFIG_NFS_V4
diff -Nru a/include/linux/nfs_page.h b/include/linux/nfs_page.h
--- a/include/linux/nfs_page.h	Sun Nov 10 19:28:37 2002
+++ b/include/linux/nfs_page.h	Sun Nov 10 19:28:37 2002
@@ -23,16 +23,13 @@
 #define PG_BUSY			0
 
 struct nfs_page {
-	struct list_head	wb_hash,	/* Inode */
-				wb_lru,		/* superblock lru list */
-				wb_list,	/* Defines state of page: */
+	struct list_head	wb_list,	/* Defines state of page: */
 				*wb_list_head;	/*      read/write/commit */
 	struct file		*wb_file;
 	struct inode		*wb_inode;
 	struct rpc_cred		*wb_cred;
 	struct page		*wb_page;	/* page to read in/write out */
 	wait_queue_head_t	wb_wait;	/* wait queue */
-	unsigned long		wb_timeout;	/* when to read/write/commit */
 	unsigned long		wb_index;	/* Offset within mapping */
 	unsigned int		wb_offset,	/* Offset within page */
 				wb_bytes,	/* Length of request */
@@ -53,8 +50,6 @@
 
 extern	void nfs_list_add_request(struct nfs_page *, struct list_head *);
 
-extern	int nfs_scan_lru(struct list_head *, struct list_head *, int);
-extern	int nfs_scan_lru_timeout(struct list_head *, struct list_head *, int);
 extern	int nfs_scan_list(struct list_head *, struct list_head *,
 			  struct file *, unsigned long, unsigned int);
 extern	int nfs_coalesce_requests(struct list_head *, struct list_head *,
@@ -123,32 +118,6 @@
 nfs_list_entry(struct list_head *head)
 {
 	return list_entry(head, struct nfs_page, wb_list);
-}
-
-static inline struct nfs_page *
-nfs_inode_wb_entry(struct list_head *head)
-{
-	return list_entry(head, struct nfs_page, wb_hash);
-}
-
-static inline void
-__nfs_add_lru(struct list_head *head, struct nfs_page *req)
-{
-	list_add_tail(&req->wb_lru, head);
-}
-
-static inline void
-__nfs_del_lru(struct nfs_page *req)
-{
-	if (list_empty(&req->wb_lru))
-		return;
-	list_del_init(&req->wb_lru);
-}
-
-static inline struct nfs_page *
-nfs_lru_entry(struct list_head *head)
-{
-        return list_entry(head, struct nfs_page, wb_lru);
 }
 
 #endif /* _LINUX_NFS_PAGE_H */
diff -Nru a/include/linux/nfsd/xdr.h b/include/linux/nfsd/xdr.h
--- a/include/linux/nfsd/xdr.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/nfsd/xdr.h	Sun Nov 10 19:28:40 2002
@@ -57,6 +57,11 @@
 	int			tlen;
 };
 
+struct nfsd_readlinkargs {
+	struct svc_fh		fh;
+	char *			buffer;
+};
+	
 struct nfsd_linkargs {
 	struct svc_fh		ffh;
 	struct svc_fh		tfh;
@@ -77,6 +82,7 @@
 	struct svc_fh		fh;
 	__u32			cookie;
 	__u32			count;
+	u32 *			buffer;
 };
 
 struct nfsd_attrstat {
@@ -128,7 +134,7 @@
 
 
 int nfssvc_decode_void(struct svc_rqst *, u32 *, void *);
-int nfssvc_decode_fhandle(struct svc_rqst *, u32 *, struct svc_fh *);
+int nfssvc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
 int nfssvc_decode_sattrargs(struct svc_rqst *, u32 *,
 				struct nfsd_sattrargs *);
 int nfssvc_decode_diropargs(struct svc_rqst *, u32 *,
@@ -141,6 +147,8 @@
 				struct nfsd_createargs *);
 int nfssvc_decode_renameargs(struct svc_rqst *, u32 *,
 				struct nfsd_renameargs *);
+int nfssvc_decode_readlinkargs(struct svc_rqst *, u32 *,
+				struct nfsd_readlinkargs *);
 int nfssvc_decode_linkargs(struct svc_rqst *, u32 *,
 				struct nfsd_linkargs *);
 int nfssvc_decode_symlinkargs(struct svc_rqst *, u32 *,
diff -Nru a/include/linux/nfsd/xdr3.h b/include/linux/nfsd/xdr3.h
--- a/include/linux/nfsd/xdr3.h	Sun Nov 10 19:28:38 2002
+++ b/include/linux/nfsd/xdr3.h	Sun Nov 10 19:28:38 2002
@@ -74,6 +74,11 @@
 	int			tlen;
 };
 
+struct nfsd3_readlinkargs {
+	struct svc_fh		fh;
+	char *			buffer;
+};
+
 struct nfsd3_linkargs {
 	struct svc_fh		ffh;
 	struct svc_fh		tfh;
@@ -96,6 +101,7 @@
 	__u32			dircount;
 	__u32			count;
 	__u32 *			verf;
+	u32 *			buffer;
 };
 
 struct nfsd3_commitargs {
@@ -238,7 +244,7 @@
 
 #define NFS3_SVC_XDRSIZE		sizeof(union nfsd3_xdrstore)
 
-int nfs3svc_decode_fhandle(struct svc_rqst *, u32 *, struct svc_fh *);
+int nfs3svc_decode_fhandle(struct svc_rqst *, u32 *, struct nfsd_fhandle *);
 int nfs3svc_decode_sattrargs(struct svc_rqst *, u32 *,
 				struct nfsd3_sattrargs *);
 int nfs3svc_decode_diropargs(struct svc_rqst *, u32 *,
@@ -257,6 +263,8 @@
 				struct nfsd3_mknodargs *);
 int nfs3svc_decode_renameargs(struct svc_rqst *, u32 *,
 				struct nfsd3_renameargs *);
+int nfs3svc_decode_readlinkargs(struct svc_rqst *, u32 *,
+				struct nfsd3_readlinkargs *);
 int nfs3svc_decode_linkargs(struct svc_rqst *, u32 *,
 				struct nfsd3_linkargs *);
 int nfs3svc_decode_symlinkargs(struct svc_rqst *, u32 *,
diff -Nru a/include/linux/nfsiod.h b/include/linux/nfsiod.h
--- a/include/linux/nfsiod.h	Sun Nov 10 19:28:40 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,52 +0,0 @@
-/*
- * linux/include/linux/nfsiod.h
- *
- * Declarations for asynchronous NFS RPC calls.
- *
- */
-
-#ifndef _LINUX_NFSIOD_H
-#define _LINUX_NFSIOD_H
-
-#include <linux/rpcsock.h>
-#include <linux/nfs_fs.h>
-
-#ifdef __KERNEL__
-
-/*
- * This is the callback handler for nfsiod requests.
- * Note that the callback procedure must NOT sleep.
- */
-struct nfsiod_req;
-typedef int	(*nfsiod_callback_t)(int result, struct nfsiod_req *);
-
-/*
- * This is the nfsiod request struct.
- */
-struct nfsiod_req {
-	struct nfsiod_req *	rq_next;
-	struct nfsiod_req *	rq_prev;
-	wait_queue_head_t	rq_wait;
-	struct rpc_ioreq	rq_rpcreq;
-	nfsiod_callback_t	rq_callback;
-	struct nfs_server *	rq_server;
-	struct inode *		rq_inode;
-	struct page *		rq_page;
-
-	/* user creds */
-	uid_t			rq_fsuid;
-	gid_t			rq_fsgid;
-	int			rq_groups[NGROUPS];
-
-	/* retry handling */
-	int			rq_retries;
-};
-
-struct nfsiod_req *	nfsiod_reserve(struct nfs_server *);
-void			nfsiod_release(struct nfsiod_req *);
-void			nfsiod_enqueue(struct nfsiod_req *);
-int			nfsiod(void);
-
-
-#endif /* __KERNEL__ */
-#endif /* _LINUX_NFSIOD_H */
diff -Nru a/include/linux/pagemap.h b/include/linux/pagemap.h
--- a/include/linux/pagemap.h	Sun Nov 10 19:28:36 2002
+++ b/include/linux/pagemap.h	Sun Nov 10 19:28:36 2002
@@ -63,6 +63,8 @@
 extern struct page * read_cache_page(struct address_space *mapping,
 				unsigned long index, filler_t *filler,
 				void *data);
+extern int read_cache_pages(struct address_space *mapping,
+		struct list_head *pages, filler_t *filler, void *data);
 
 extern int add_to_page_cache(struct page *page,
 		struct address_space *mapping, unsigned long index);
diff -Nru a/include/linux/pci.h b/include/linux/pci.h
--- a/include/linux/pci.h	Sun Nov 10 19:28:39 2002
+++ b/include/linux/pci.h	Sun Nov 10 19:28:39 2002
@@ -557,8 +557,12 @@
 				 unsigned int ss_vendor, unsigned int ss_device,
 				 const struct pci_dev *from);
 struct pci_dev *pci_find_class (unsigned int class, const struct pci_dev *from);
+struct pci_bus *pci_find_bus(unsigned char busnr);
 struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
+unsigned char pci_bus_max_busnr(struct pci_bus* bus);
+unsigned char pci_max_busnr(void);
 int pci_find_capability (struct pci_dev *dev, int cap);
+int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap);
 
 int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val);
 int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val);
@@ -613,6 +617,8 @@
 
 /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
 
+void pbus_assign_resources(struct pci_bus *bus);
+void pbus_size_bridges(struct pci_bus *bus);
 int pci_claim_resource(struct pci_dev *, int);
 void pci_assign_unassigned_resources(void);
 void pdev_enable_device(struct pci_dev *);
@@ -634,6 +640,7 @@
 const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev);
 unsigned int pci_do_scan_bus(struct pci_bus *bus);
 struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr);
+int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass);
 
 /* kmem_cache style wrapper around pci_alloc_consistent() */
 struct pci_pool *pci_pool_create (const char *name, struct pci_dev *dev,
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Sun Nov 10 19:28:39 2002
+++ b/include/linux/pci_ids.h	Sun Nov 10 19:28:39 2002
@@ -1012,6 +1012,7 @@
 #define PCI_DEVICE_ID_VIA_8233_0	0x3074
 #define PCI_DEVICE_ID_VIA_8633_0	0x3091
 #define PCI_DEVICE_ID_VIA_8367_0	0x3099 
+#define PCI_DEVICE_ID_VIA_8653_0	0x3101
 #define PCI_DEVICE_ID_VIA_8622		0x3102 
 #define PCI_DEVICE_ID_VIA_8233C_0	0x3109
 #define PCI_DEVICE_ID_VIA_8361		0x3112 
@@ -1029,6 +1030,7 @@
 #define PCI_DEVICE_ID_VIA_8505_1	0x8605
 #define PCI_DEVICE_ID_VIA_8633_1	0xB091
 #define PCI_DEVICE_ID_VIA_8367_1	0xB099
+#define PCI_DEVICE_ID_VIA_8653_1	0xB101
 
 #define PCI_VENDOR_ID_SIEMENS           0x110A
 #define PCI_DEVICE_ID_SIEMENS_DSCC4     0x2102
@@ -1100,6 +1102,9 @@
 #define PCI_DEVICE_ID_EICON_MAESTRAQ	0xe012
 #define PCI_DEVICE_ID_EICON_MAESTRAQ_U	0xe013
 #define PCI_DEVICE_ID_EICON_MAESTRAP	0xe014
+
+#define PCI_VENDOR_ID_ZIATECH		0x1138
+#define PCI_DEVICE_ID_ZIATECH_5550_HC	0x5550
  
 #define PCI_VENDOR_ID_CYCLONE		0x113c
 #define PCI_DEVICE_ID_CYCLONE_SDK	0x0001
diff -Nru a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
--- a/include/linux/pfkeyv2.h	Sun Nov 10 19:28:41 2002
+++ b/include/linux/pfkeyv2.h	Sun Nov 10 19:28:41 2002
@@ -187,7 +187,7 @@
 
 struct sadb_x_ipsecrequest {
 	uint16_t	sadb_x_ipsecrequest_len;
-	uint16_t	sadb_x_ipsecrequest_exttype;
+	uint16_t	sadb_x_ipsecrequest_proto;
 	uint8_t		sadb_x_ipsecrequest_mode;
 	uint8_t		sadb_x_ipsecrequest_level;
 	uint16_t	sadb_x_ipsecrequest_reqid;
@@ -249,8 +249,8 @@
 
 /* Encryption algorithms */
 #define SADB_EALG_NONE		0
-#define SADB_EALG_DESCBC	2
-#define SADB_EALG_3DESCBC	3
+#define SADB_EALG_DESCBC	1
+#define SADB_EALG_3DESCBC	2
 #define SADB_EALG_NULL		11
 #define SADB_EALG_MAX		11
 
diff -Nru a/include/linux/pnpbios.h b/include/linux/pnpbios.h
--- a/include/linux/pnpbios.h	Sun Nov 10 19:28:39 2002
+++ b/include/linux/pnpbios.h	Sun Nov 10 19:28:39 2002
@@ -3,7 +3,7 @@
  *
  * Original BIOS code (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de)
  * PnP handler parts (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
- * Minor reorganizations by David Hinds <dhinds@zen.stanford.edu>
+ * Minor reorganizations by David Hinds <dahinds@users.sourceforge.net>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
diff -Nru a/include/linux/poll.h b/include/linux/poll.h
--- a/include/linux/poll.h	Sun Nov 10 19:28:41 2002
+++ b/include/linux/poll.h	Sun Nov 10 19:28:41 2002
@@ -28,15 +28,6 @@
 		__pollwait(filp, wait_address, p);
 }
 
-static inline void poll_initwait(poll_table* pt)
-{
-	pt->queue = 1;
-	pt->qproc = NULL;
-	pt->priv = NULL;
-	pt->error = 0;
-	pt->table = NULL;
-}
-
 static inline void poll_initwait_ex(poll_table* pt, int queue,
 				    void (*qproc)(void *, wait_queue_head_t *),
 				    void *priv)
@@ -46,6 +37,12 @@
 	pt->priv = priv;
 	pt->error = 0;
 	pt->table = NULL;
+}
+
+static inline void poll_initwait(poll_table* pt)
+{
+
+	poll_initwait_ex(pt, 1, NULL, NULL);
 }
 
 extern void poll_freewait(poll_table* pt);
diff -Nru a/include/linux/resource.h b/include/linux/resource.h
--- a/include/linux/resource.h	Sun Nov 10 19:28:37 2002
+++ b/include/linux/resource.h	Sun Nov 10 19:28:37 2002
@@ -50,6 +50,12 @@
 #define	PRIO_USER	2
 
 /*
+ * Limit the stack by to some sane default: root can always
+ * increase this limit if needed..  8MB seems reasonable.
+ */
+#define _STK_LIM	(8*1024*1024)
+
+/*
  * Due to binary compatibility, the actual resource numbers
  * may be different for different linux versions..
  */
diff -Nru a/include/linux/rpcsock.h b/include/linux/rpcsock.h
--- a/include/linux/rpcsock.h	Sun Nov 10 19:28:38 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,121 +0,0 @@
-/*
- *  rpcsock.h	Declarations for the RPC call interface.
- *
- *  Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
- */
-
-
-#ifndef _LINUX_RPCSOCK_H
-#define _LINUX_RPCSOCK_H
-
-/*
- * The rpcsock code maintains an estimate on the maximum number of out-
- * standing RPC requests, using the congestion avoidance implemented in
- * 44BSD. This is basically the Van Jacobson slow start algorithm: If a
- * retransmit occurs, the congestion window is halved; otherwise, it is
- * incremented by 1/cwnd when a reply is received and a full number of
- * requests are outstanding.
- *
- * Upper procedures may check whether a request would block waiting for
- * a free RPC slot by using the RPC_CONGESTED() macro.
- *
- * Note: on machines with low memory we should probably use a smaller
- * MAXREQS value: At 32 outstanding reqs with 8 megs of RAM, fragment
- * reassembly will frequently run out of memory.
- */
-#define RPC_MAXREQS		32
-#define RPC_CWNDSCALE		256
-#define RPC_MAXCWND		(RPC_MAXREQS * RPC_CWNDSCALE)
-/* #define RPC_INITCWND		(RPC_MAXCWND / 2) */
-#define RPC_INITCWND		RPC_CWNDSCALE
-#define RPC_CONGESTED(rsock)	((rsock)->cong >= (rsock)->cwnd)
-
-/* RPC reply header size: xid, direction, status, accept_status (verifier
- * size computed separately)
- */
-#define RPC_HDRSIZE		(4 * 4)
-
-/*
- * This describes a timeout strategy
- */
-struct rpc_timeout {
-	unsigned long		to_initval,
-				to_maxval,
-				to_increment;
-	int			to_retries;
-	char			to_exponential;
-};
-
-/*
- * This describes a complete RPC request
- */
-struct rpc_ioreq {
-	struct rpc_wait *	rq_slot;
-	struct sockaddr	*	rq_addr;
-	int			rq_alen;
-	struct iovec		rq_svec[UIO_FASTIOV];
-	unsigned int		rq_snr;
-	unsigned long		rq_slen;
-	struct iovec		rq_rvec[UIO_FASTIOV];
-	unsigned int		rq_rnr;
-	unsigned long		rq_rlen;
-};
-
-/*
- * This is the callback handler for async RPC.
- */
-struct rpc_wait;
-typedef void	(*rpc_callback_fn_t)(int, struct rpc_wait *, void *);
-
-/*
- * Wait information. This struct defines all the state of an RPC
- * request currently in flight.
- */
-struct rpc_wait {
-	struct rpc_sock *	w_sock;
-	struct rpc_wait *	w_prev;
-	struct rpc_wait *	w_next;
-	struct rpc_ioreq *	w_req;
-	int			w_result;
-	wait_queue_head_t 	w_wait;
-	rpc_callback_fn_t	w_handler;
-	void *			w_cdata;
-	char			w_queued;
-	char			w_gotit;
-	__u32			w_xid;
-};
-
-struct rpc_sock {
-	struct file *		file;
-	struct socket *		sock;
-	struct sock *		inet;
-	struct rpc_wait		waiting[RPC_MAXREQS];
-	unsigned long		cong;
-	unsigned long		cwnd;
-	struct rpc_wait *	pending;
-	struct rpc_wait *	free;
-	wait_queue_head_t	backlog;
-	wait_queue_head_t	shutwait;
-	int			shutdown;
-};
-
-#ifdef __KERNEL__
-
-/* rpc_call: Call synchronously */
-int			rpc_call(struct rpc_sock *, struct rpc_ioreq *,
-					 struct rpc_timeout *);
-/* These implement asynch calls for nfsiod: Process calls rpc_reserve and
- * rpc_transmits, then passes the request to nfsiod, which collects the
- * results via rpc_doio
- */
-int			rpc_reserve(struct rpc_sock *, struct rpc_ioreq *, int);
-void			rpc_release(struct rpc_sock *, struct rpc_ioreq *);
-int			rpc_transmit(struct rpc_sock *, struct rpc_ioreq *);
-int			rpc_doio(struct rpc_sock *, struct rpc_ioreq *,
-					 struct rpc_timeout *, int);
-struct rpc_sock	*	rpc_makesock(struct file *);
-int			rpc_closesock(struct rpc_sock *);
-
-#endif /* __KERNEL__*/
-
-#endif /* _LINUX_RPCSOCK_H */
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Sun Nov 10 19:28:37 2002
+++ b/include/linux/sched.h	Sun Nov 10 19:28:37 2002
@@ -3,8 +3,6 @@
 
 #include <asm/param.h>	/* for HZ */
 
-extern unsigned long event;
-
 #include <linux/config.h>
 #include <linux/capability.h>
 #include <linux/threads.h>
@@ -90,6 +88,7 @@
 extern int last_pid;
 extern unsigned long nr_running(void);
 extern unsigned long nr_uninterruptible(void);
+extern unsigned long nr_iowait(void);
 
 #include <linux/time.h>
 #include <linux/param.h>
@@ -149,6 +148,8 @@
 extern void show_stack(unsigned long *stack);
 extern void show_regs(struct pt_regs *);
 
+void io_schedule(void);
+void io_schedule_timeout(long timeout);
 
 extern void cpu_init (void);
 extern void trap_init(void);
@@ -200,6 +201,11 @@
 	/* Architecture-specific MM context */
 	mm_context_t context;
 
+	/* coredumping support */
+	struct semaphore core_sem;
+	atomic_t core_waiters;
+	wait_queue_head_t core_wait;
+
 	/* aio bits */
 	rwlock_t		ioctx_list_lock;
 	struct kioctx		*ioctx_list;
@@ -390,6 +396,8 @@
 	void *journal_info;
 	struct dentry *proc_dentry;
 	struct backing_dev_info *backing_dev_info;
+/* threaded coredumping support */
+	int core_waiter;
 
 	unsigned long ptrace_message;
 };
@@ -435,12 +443,6 @@
 #define PT_TRACE_CLONE	0x00000040
 #define PT_TRACE_EXEC	0x00000080
 
-/*
- * Limit the stack by to some sane default: root can always
- * increase this limit if needed..  8MB seems reasonable.
- */
-#define _STK_LIM	(8*1024*1024)
-
 #if CONFIG_SMP
 extern void set_cpus_allowed(task_t *p, unsigned long new_mask);
 #else
@@ -534,6 +536,7 @@
 extern void notify_parent(struct task_struct *, int);
 extern void do_notify_parent(struct task_struct *, int);
 extern void force_sig(int, struct task_struct *);
+extern void force_sig_specific(int, struct task_struct *);
 extern int send_sig(int, struct task_struct *, int);
 extern int __broadcast_thread_group(struct task_struct *p, int sig);
 extern int kill_pg(pid_t, int, int);
diff -Nru a/include/linux/sctp.h b/include/linux/sctp.h
--- a/include/linux/sctp.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/sctp.h	Sun Nov 10 19:28:40 2002
@@ -1,40 +1,40 @@
 /* SCTP kernel reference Implementation
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
- * Copyright (c) 2001 International Business Machines, Corp.
+ * Copyright (c) 2001-2002 International Business Machines, Corp.
  * Copyright (c) 2001 Intel Corp.
  * Copyright (c) 2001 Nokia, Inc.
  * Copyright (c) 2001 La Monte H.P. Yarroll
- * 
+ *
  * This file is part of the SCTP kernel reference Implementation
- * 
- * Various protocol defined structures.  
- * 
- * The SCTP reference implementation is free software; 
- * you can redistribute it and/or modify it under the terms of 
+ *
+ * Various protocol defined structures.
+ *
+ * The SCTP reference implementation is free software;
+ * you can redistribute 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.
- * 
- * The SCTP reference implementation is distributed in the hope that it 
+ *
+ * The SCTP reference implementation is distributed in the hope that it
  * will be useful, but WITHOUT ANY WARRANTY; without even the implied
  *                 ************************
  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  * See the GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with GNU CC; see the file COPYING.  If not, write to
  * the Free Software Foundation, 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.  
- * 
+ * Boston, MA 02111-1307, USA.
+ *
  * Please send any bug reports or fixes you make to the
  * email address(es):
- *    lksctp developers <sctp-developers-list@cig.mot.com>
- * 
+ *    lksctp developers <lksctp-developerst@lists.sourceforge.net>
+ *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
  *
- * Written or modified by: 
+ * Written or modified by:
  *    La Monte H.P. Yarroll <piggy@acm.org>
  *    Karl Knutson <karl@athena.chicago.il.us>
  *    Jon Grimm <jgrimm@us.ibm.com>
@@ -42,7 +42,7 @@
  *    randall@sctp.chicago.il.us
  *    kmorneau@cisco.com
  *    qxie1@email.mot.com
- * 
+ *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
  */
@@ -70,9 +70,9 @@
 
 
 /* Section 3.2.  Chunk Type Values.
- * [Chunk Type] identifies the type of information contained in the Chunk 
- * Value field. It takes a value from 0 to 254. The value of 255 is 
- * reserved for future use as an extension field. 
+ * [Chunk Type] identifies the type of information contained in the Chunk
+ * Value field. It takes a value from 0 to 254. The value of 255 is
+ * reserved for future use as an extension field.
  */
 typedef enum {
 	SCTP_CID_DATA			= 0,
@@ -97,7 +97,7 @@
 } sctp_cid_t; /* enum */
 
 
-/* Section 3.2  
+/* Section 3.2
  *  Chunk Types are encoded such that the highest-order two bits specify
  *  the action that must be taken if the processing endpoint does not
  *  recognize the Chunk Type.
@@ -107,7 +107,7 @@
 	SCTP_CID_ACTION_DISCARD_ERR = 0x40,
 	SCTP_CID_ACTION_SKIP        = 0x80,
 	SCTP_CID_ACTION_SKIP_ERR    = 0xc0,
-} sctp_cid_action_t; 
+} sctp_cid_action_t;
 
 enum { SCTP_CID_ACTION_MASK = 0xc0, };
 
@@ -127,23 +127,23 @@
  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *     |   Type = 14   |Reserved     |T|      Length = 4               |
  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * 
+ *
  * Chunk Flags: 8 bits
- *   
+ *
  *   Reserved:  7 bits
  *     Set to 0 on transmit and ignored on receipt.
- * 
+ *
  *   T bit:  1 bit
  *     The T bit is set to 0 if the sender had a TCB that it destroyed. If
  *     the sender did NOT have a TCB it should set this bit to 1.
- * 
- * Note: Special rules apply to this chunk for verification, please 
+ *
+ * Note: Special rules apply to this chunk for verification, please
  * see Section 8.5.1 for details.
  */
 
 #define sctp_test_T_bit(c)    ((c)->chunk_hdr->flags & SCTP_CHUNK_FLAG_T)
 
-/* RFC 2960 
+/* RFC 2960
  * Section 3.2.1 Optional/Variable-length Parmaeter Format.
  */
 
@@ -167,11 +167,11 @@
 	SCTP_PARAM_ECN_CAPABLE			= __constant_htons(0x8000),
 
 	/* Add-IP Extension. Section 3.2 */
-	SCTP_PARAM_ADD_IP		= __constant_htons(0xc001),  
-	SCTP_PARAM_DEL_IP		= __constant_htons(0xc002),  
-	SCTP_PARAM_ERR_CAUSE		= __constant_htons(0xc003),  
-	SCTP_PARAM_SET_PRIMARY		= __constant_htons(0xc004),  
-	SCTP_PARAM_SUCCESS_REPORT	= __constant_htons(0xc005),  
+	SCTP_PARAM_ADD_IP		= __constant_htons(0xc001),
+	SCTP_PARAM_DEL_IP		= __constant_htons(0xc002),
+	SCTP_PARAM_ERR_CAUSE		= __constant_htons(0xc003),
+	SCTP_PARAM_SET_PRIMARY		= __constant_htons(0xc004),
+	SCTP_PARAM_SUCCESS_REPORT	= __constant_htons(0xc005),
 	SCTP_PARAM_ADAPTION_LAYER_IND   = __constant_htons(0xc006),
 
 } sctp_param_t; /* enum */
@@ -188,7 +188,7 @@
 	SCTP_PARAM_ACTION_DISCARD_ERR = __constant_htons(0x4000),
 	SCTP_PARAM_ACTION_SKIP        = __constant_htons(0x8000),
 	SCTP_PARAM_ACTION_SKIP_ERR    = __constant_htons(0xc000),
-} sctp_param_action_t; 
+} sctp_param_action_t;
 
 enum { SCTP_PARAM_ACTION_MASK = __constant_htons(0xc000), };
 
@@ -215,14 +215,14 @@
 	SCTP_DATA_NOT_FRAG	= 0x03,
 	SCTP_DATA_UNORDERED	= 0x04,
 };
-enum { SCTP_DATA_FRAG_MASK = 0x03, }; 
+enum { SCTP_DATA_FRAG_MASK = 0x03, };
 
 
 /* RFC 2960 Section 3.3.2 Initiation (INIT) (1)
  *
  *  This chunk is used to initiate a SCTP association between two
  *  endpoints.
- */  
+ */
 typedef struct sctp_inithdr {
 	__u32 init_tag;
 	__u32 a_rwnd;
@@ -249,7 +249,7 @@
 	sctp_paramhdr_t param_hdr;
 	struct in6_addr addr;
 } sctp_ipv6addr_param_t __attribute__((packed));
-	
+
 /* Section 3.3.2.1 Cookie Preservative (9) */
 typedef struct sctp_cookie_preserve_param {
 	sctp_paramhdr_t param_hdr;
@@ -344,8 +344,8 @@
 	sctp_chunkhdr_t chunk_hdr;
 	sctp_heartbeathdr_t hb_hdr;
 } sctp_heartbeat_chunk_t __attribute__((packed));
-	
-  
+
+
 /* For the abort and shutdown ACK we must carry the init tag in the
  * common header. Just the common header is all that is needed with a
  * chunk descriptor.
@@ -366,7 +366,7 @@
         sctp_chunkhdr_t    chunk_hdr;
         sctp_shutdownhdr_t shutdown_hdr;
 } __attribute__((packed));
-        
+
 
 
 /* RFC 2960.  Section 3.3.10 Operation Error (ERROR) (9) */
@@ -403,9 +403,9 @@
  */
 typedef enum {
 
-	SCTP_ERROR_NO_ERROR	   = __constant_htons(0x00), 
-	SCTP_ERROR_INV_STRM	   = __constant_htons(0x01), 
-	SCTP_ERROR_MISS_PARAM 	   = __constant_htons(0x02), 
+	SCTP_ERROR_NO_ERROR	   = __constant_htons(0x00),
+	SCTP_ERROR_INV_STRM	   = __constant_htons(0x01),
+	SCTP_ERROR_MISS_PARAM 	   = __constant_htons(0x02),
 	SCTP_ERROR_STALE_COOKIE	   = __constant_htons(0x03),
 	SCTP_ERROR_NO_RESOURCE 	   = __constant_htons(0x04),
 	SCTP_ERROR_DNS_FAILED      = __constant_htons(0x05),
@@ -416,13 +416,15 @@
 	SCTP_ERROR_COOKIE_IN_SHUTDOWN = __constant_htons(0x0a),
 
 
-	/* SCTP Implementation Guide: 
-	 *  11              Restart of an association with new addresses
-	 *  12              User Initiated Abort
+	/* SCTP Implementation Guide:
+	 *  11  Restart of an association with new addresses
+	 *  12  User Initiated Abort
+	 *  13  Protocol Violation
 	 */
 
 	SCTP_ERROR_RESTART         = __constant_htons(0x0b),
 	SCTP_ERROR_USER_ABORT      = __constant_htons(0x0c),
+	SCTP_ERROR_PROTO_VIOLATION = __constant_htons(0x0d),
 
 	/* ADDIP Section 3.3  New Error Causes
 	 *
@@ -436,16 +438,16 @@
 	 * 0x0102          Request to Delete Source IP Address.
 	 * 0x0103          Association Aborted due to illegal ASCONF-ACK
 	 */
-	SCTP_ERROR_DEL_LAST_IP	= __constant_htons(0x0100),	
-	SCTP_ERROR_RSRC_LOW	= __constant_htons(0x0101),	
-	SCTP_ERROR_DEL_SRC_IP	= __constant_htons(0x0102),	
+	SCTP_ERROR_DEL_LAST_IP	= __constant_htons(0x0100),
+	SCTP_ERROR_RSRC_LOW	= __constant_htons(0x0101),
+	SCTP_ERROR_DEL_SRC_IP	= __constant_htons(0x0102),
 	SCTP_ERROR_ASCONF_ACK   = __constant_htons(0x0103),
 
 } sctp_error_t;
 
 
 
-/* RFC 2960.  Appendix A.  Explicit Congestion Notification. 
+/* RFC 2960.  Appendix A.  Explicit Congestion Notification.
  *   Explicit Congestion Notification Echo (ECNE) (12)
  */
 typedef struct sctp_ecnehdr {
@@ -457,7 +459,7 @@
 	sctp_ecnehdr_t ence_hdr;
 } sctp_ecne_chunk_t __attribute__((packed));
 
-/* RFC 2960.  Appendix A.  Explicit Congestion Notification. 
+/* RFC 2960.  Appendix A.  Explicit Congestion Notification.
  *   Congestion Window Reduced (CWR) (13)
  */
 typedef struct sctp_cwrhdr {
@@ -478,18 +480,18 @@
 
 
 /* ADDIP Section 3.1.1
- * 
+ *
  * ASCONF-Request Correlation ID: 32 bits (unsigned integer)
- * 
+ *
  * This is an opaque integer assigned by the sender to identify each
  * request parameter. It is in host byte order and is only meaningful
  * to the sender. The receiver of the ASCONF Chunk will copy this 32
  * bit value into the ASCONF Correlation ID field of the
  * ASCONF-ACK. The sender of the ASCONF can use this same value in the
  * ASCONF-ACK to find which request the response is for.
- * 
+ *
  * ASCONF Parameter: TLV format
- * 
+ *
  * Each Address configuration change is represented by a TLV parameter
  * as defined in Section 3.2. One or more requests may be present in
  * an ASCONF Chunk.
@@ -502,7 +504,7 @@
 
 /* ADDIP
  * 3.1.1  Address/Stream Configuration Change Chunk (ASCONF)
- * 
+ *
  * This chunk is used to communicate to the remote endpoint one of the
  * configuration change requests that MUST be acknowledged.  The
  * information carried in the ASCONF Chunk uses the form of a
@@ -517,18 +519,18 @@
 	__u32	addr[4];
 	sctpAsconfReq_t requests[0];
 } sctpAsconf_t;
-  
+
 /* ADDIP
  * 3.1.2 Address/Stream Configuration Acknowledgment Chunk (ASCONF-ACK)
- * 
+ *
  * ASCONF-Request Correlation ID: 32 bits (unsigned integer)
- * 
+ *
  * This value is copied from the ASCONF Correlation ID received in the
  * ASCONF Chunk. It is used by the receiver of the ASCONF-ACK to identify
  * which ASCONF parameter this response is associated with.
- * 
+ *
  * ASCONF Parameter Response : TLV format
- * 
+ *
  * The ASCONF Parameter Response is used in the ASCONF-ACK to report
  * status of ASCONF processing. By default, if a responding endpoint
  * does not include any Error Cause, a success is indicated. Thus a
@@ -555,7 +557,7 @@
 
 /* ADDIP
  * 3.1.2 Address/Stream Configuration Acknowledgment Chunk (ASCONF-ACK)
- * 
+ *
  * This chunk is used by the receiver of an ASCONF Chunk to
  * acknowledge the reception. It carries zero or more results for any
  * ASCONF Parameters that were processed by the receiver.
@@ -579,11 +581,8 @@
 	struct list_head hook;
 	int length;	/* length of the TLV */
 
-	/* the actually TLV to be copied into ASCONF_ACK */ 
+	/* the actually TLV to be copied into ASCONF_ACK */
 	sctpAsconfAckRsp_t TLV;
 } sctpAsconfAckRspNode_t;
-
-
-
 
 #endif /* __LINUX_SCTP_H__ */
diff -Nru a/include/linux/slab.h b/include/linux/slab.h
--- a/include/linux/slab.h	Sun Nov 10 19:28:41 2002
+++ b/include/linux/slab.h	Sun Nov 10 19:28:41 2002
@@ -60,6 +60,7 @@
 
 extern void *kmalloc(size_t, int);
 extern void kfree(const void *);
+extern unsigned int ksize(const void *);
 
 extern int FASTCALL(kmem_cache_reap(int));
 
diff -Nru a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
--- a/include/linux/sunrpc/clnt.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/sunrpc/clnt.h	Sun Nov 10 19:28:40 2002
@@ -50,8 +50,6 @@
 				cl_droppriv : 1,/* enable NFS suid hack */
 				cl_oneshot  : 1,/* dispose after use */
 				cl_dead     : 1;/* abandoned */
-	unsigned int		cl_flags;	/* misc client flags */
-	unsigned long		cl_hardmax;	/* max hard timeout */
 
 	struct rpc_rtt		cl_rtt;		/* RTO estimator data */
 
@@ -132,17 +130,15 @@
 static __inline__
 int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
 {
-	struct rpc_message msg = { proc, argp, resp, NULL };
+	struct rpc_message msg = {
+		.rpc_proc	= proc,
+		.rpc_argp	= argp,
+		.rpc_resp	= resp,
+		.rpc_cred	= NULL
+	};
 	return rpc_call_sync(clnt, &msg, flags);
 }
 		
-
-static __inline__ void
-rpc_set_timeout(struct rpc_clnt *clnt, unsigned int retr, unsigned long incr)
-{
-	xprt_set_timeout(&clnt->cl_timeout, retr, incr);
-}
-
 extern void rpciod_wake_up(void);
 
 /*
diff -Nru a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
--- a/include/linux/sunrpc/sched.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/sunrpc/sched.h	Sun Nov 10 19:28:40 2002
@@ -14,12 +14,6 @@
 #include <linux/wait.h>
 
 /*
- * Define this if you want to test the fast scheduler for async calls.
- * This is still experimental and may not work.
- */
-#undef  CONFIG_RPC_FASTSCHED
-
-/*
  * This is the actual RPC procedure call info.
  */
 struct rpc_message {
@@ -48,6 +42,7 @@
 	 */
 	struct rpc_message	tk_msg;		/* RPC call info */
 	__u32 *			tk_buffer;	/* XDR buffer */
+	size_t			tk_bufsize;
 	__u8			tk_garb_retry,
 				tk_cred_retry,
 				tk_suid_retry;
@@ -184,20 +179,16 @@
 struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
 void		rpc_wake_up_status(struct rpc_wait_queue *, int);
 void		rpc_delay(struct rpc_task *, unsigned long);
-void *		rpc_allocate(unsigned int flags, unsigned int);
-void		rpc_free(void *);
+void *		rpc_malloc(struct rpc_task *, size_t);
+void		rpc_free(struct rpc_task *);
 int		rpciod_up(void);
 void		rpciod_down(void);
 void		rpciod_wake_up(void);
 #ifdef RPC_DEBUG
 void		rpc_show_tasks(void);
 #endif
-
-static __inline__ void *
-rpc_malloc(struct rpc_task *task, unsigned int size)
-{
-	return rpc_allocate(task->tk_flags, size);
-}
+int		rpc_init_mempool(void);
+void		rpc_destroy_mempool(void);
 
 static __inline__ void
 rpc_exit(struct rpc_task *task, int status)
diff -Nru a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
--- a/include/linux/sunrpc/svc.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/sunrpc/svc.h	Sun Nov 10 19:28:40 2002
@@ -15,6 +15,7 @@
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/svcauth.h>
 #include <linux/wait.h>
+#include <linux/mm.h>
 
 /*
  * RPC service.
@@ -166,18 +167,51 @@
 	char *cp = (char*)p;
 
 	vec->iov_len = cp - (char*)vec->iov_base;
-	rqstp->rq_res.len = vec->iov_len;
 
 	return vec->iov_len <= PAGE_SIZE;
 }
 
-static int inline take_page(struct svc_rqst *rqstp)
+static int inline svc_take_page(struct svc_rqst *rqstp)
 {
 	if (rqstp->rq_arghi <= rqstp->rq_argused)
 		return -ENOMEM;
 	rqstp->rq_respages[rqstp->rq_resused++] =
 		rqstp->rq_argpages[--rqstp->rq_arghi];
 	return 0;
+}
+
+static void inline svc_pushback_allpages(struct svc_rqst *rqstp)
+{
+        while (rqstp->rq_resused) {
+		if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
+			continue;
+		rqstp->rq_argpages[rqstp->rq_arghi++] =
+			rqstp->rq_respages[rqstp->rq_resused];
+		rqstp->rq_respages[rqstp->rq_resused] = NULL;
+	}
+}
+
+static void inline svc_pushback_unused_pages(struct svc_rqst *rqstp)
+{
+        while (rqstp->rq_resused) {
+		if (rqstp->rq_respages[--rqstp->rq_resused] != NULL) {
+			rqstp->rq_argpages[rqstp->rq_arghi++] =
+				rqstp->rq_respages[rqstp->rq_resused];
+			rqstp->rq_respages[rqstp->rq_resused] = NULL;
+		}
+		if (rqstp->rq_res.pages == &rqstp->rq_respages[rqstp->rq_resused])
+			break;
+	}
+}
+
+static void inline svc_free_allpages(struct svc_rqst *rqstp)
+{
+        while (rqstp->rq_resused) {
+		if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
+			continue;
+		put_page(rqstp->rq_respages[rqstp->rq_resused]);
+		rqstp->rq_respages[rqstp->rq_resused] = NULL;
+	}
 }
 
 struct svc_deferred_req {
diff -Nru a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
--- a/include/linux/sunrpc/svcsock.h	Sun Nov 10 19:28:38 2002
+++ b/include/linux/sunrpc/svcsock.h	Sun Nov 10 19:28:38 2002
@@ -37,6 +37,7 @@
 
 	struct list_head	sk_deferred;	/* deferred requests that need to
 						 * be revisted */
+	struct semaphore        sk_sem;		/* to serialize sending data */
 
 	int			(*sk_recvfrom)(struct svc_rqst *rqstp);
 	int			(*sk_sendto)(struct svc_rqst *rqstp);
diff -Nru a/include/linux/sunrpc/timer.h b/include/linux/sunrpc/timer.h
--- a/include/linux/sunrpc/timer.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/sunrpc/timer.h	Sun Nov 10 19:28:40 2002
@@ -12,16 +12,16 @@
 #include <asm/atomic.h>
 
 struct rpc_rtt {
-	long timeo;		/* default timeout value */
-	long srtt[5];		/* smoothed round trip time << 3 */
-	long sdrtt[5];		/* soothed medium deviation of RTT */
+	unsigned long timeo;	/* default timeout value */
+	unsigned long srtt[5];	/* smoothed round trip time << 3 */
+	unsigned long sdrtt[5];	/* smoothed medium deviation of RTT */
 	atomic_t  ntimeouts;	/* Global count of the number of timeouts */
 };
 
 
-extern void rpc_init_rtt(struct rpc_rtt *rt, long timeo);
-extern void rpc_update_rtt(struct rpc_rtt *rt, int timer, long m);
-extern long rpc_calc_rto(struct rpc_rtt *rt, int timer);
+extern void rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo);
+extern void rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m);
+extern unsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned timer);
 
 static inline void rpc_inc_timeo(struct rpc_rtt *rt)
 {
diff -Nru a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
--- a/include/linux/sunrpc/xdr.h	Sun Nov 10 19:28:41 2002
+++ b/include/linux/sunrpc/xdr.h	Sun Nov 10 19:28:41 2002
@@ -127,7 +127,6 @@
 }
 
 void xdr_shift_iovec(struct iovec *, int, size_t);
-void xdr_zero_iovec(struct iovec *, int, size_t);
 
 /*
  * Maximum number of iov's we use.
@@ -155,12 +154,6 @@
 
 extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int,
 		skb_reader_t *, skb_read_actor_t);
-
-extern int xdr_copy_skb(struct xdr_buf *xdr, unsigned int base,
-		struct sk_buff *skb, unsigned int offset);
-
-extern int xdr_copy_and_csum_skb(struct xdr_buf *xdr, unsigned int base,
-		struct sk_buff *skb, unsigned int offset, unsigned int csum);
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
--- a/include/linux/sunrpc/xprt.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/sunrpc/xprt.h	Sun Nov 10 19:28:40 2002
@@ -71,7 +71,7 @@
 				to_initval,		/* initial timeout */
 				to_maxval,		/* max timeout */
 				to_increment;		/* if !exponential */
-	short			to_retries;		/* max # of retries */
+	unsigned int		to_retries;		/* max # of retries */
 	unsigned char		to_exponential;
 };
 
@@ -109,7 +109,7 @@
 	
 	u32			rq_bytes_sent;	/* Bytes we have sent */
 
-	long			rq_xtime;	/* when transmitted */
+	unsigned long		rq_xtime;	/* when transmitted */
 	int			rq_ntimeo;
 	int			rq_nresend;
 };
diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h
--- a/include/linux/sysctl.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/sysctl.h	Sun Nov 10 19:28:40 2002
@@ -351,6 +351,8 @@
 	NET_IPV4_CONF_TAG=12,
 	NET_IPV4_CONF_ARPFILTER=13,
 	NET_IPV4_CONF_MEDIUM_ID=14,
+	NET_IPV4_CONF_NOXFRM=15,
+	NET_IPV4_CONF_NOPOLICY=16,
 };
 
 /* /proc/sys/net/ipv6 */
diff -Nru a/include/linux/timer.h b/include/linux/timer.h
--- a/include/linux/timer.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/timer.h	Sun Nov 10 19:28:40 2002
@@ -3,6 +3,7 @@
 
 #include <linux/config.h>
 #include <linux/list.h>
+#include <linux/spinlock.h>
 
 struct tvec_t_base_s;
 
@@ -10,12 +11,26 @@
 	struct list_head entry;
 	unsigned long expires;
 
+	spinlock_t lock;
+	unsigned long magic;
+
 	void (*function)(unsigned long);
 	unsigned long data;
 
 	struct tvec_t_base_s *base;
 };
 
+#define TIMER_MAGIC	0x4b87ad6e
+
+#define TIMER_INITIALIZER(_function, _expires, _data) {		\
+		.function = (_function),			\
+		.expires = (_expires),				\
+		.data = (_data),				\
+		.base = NULL,					\
+		.magic = TIMER_MAGIC,				\
+		.lock = SPIN_LOCK_UNLOCKED,			\
+	}
+
 /***
  * init_timer - initialize a timer.
  * @timer: the timer to be initialized
@@ -26,6 +41,8 @@
 static inline void init_timer(struct timer_list * timer)
 {
 	timer->base = NULL;
+	timer->magic = TIMER_MAGIC;
+	spin_lock_init(&timer->lock);
 }
 
 /***
diff -Nru a/include/linux/umem.h b/include/linux/umem.h
--- a/include/linux/umem.h	Sun Nov 10 19:28:37 2002
+++ b/include/linux/umem.h	Sun Nov 10 19:28:37 2002
@@ -127,4 +127,5 @@
 
 #define PCI_VENDOR_ID_MICRO_MEMORY		0x1332
 #define PCI_DEVICE_ID_MICRO_MEMORY_5415CN	0x5415
+#define PCI_DEVICE_ID_MICRO_MEMORY_5425CN	0x5425
 #endif
diff -Nru a/include/linux/vmalloc.h b/include/linux/vmalloc.h
--- a/include/linux/vmalloc.h	Sun Nov 10 19:28:41 2002
+++ b/include/linux/vmalloc.h	Sun Nov 10 19:28:41 2002
@@ -2,6 +2,7 @@
 #define _LINUX_VMALLOC_H
 
 #include <linux/spinlock.h>
+#include <asm/page.h>		/* pgprot_t */
 
 /* bits in vm_struct->flags */
 #define VM_IOREMAP	0x00000001	/* ioremap() and friends */
diff -Nru a/include/linux/workqueue.h b/include/linux/workqueue.h
--- a/include/linux/workqueue.h	Sun Nov 10 19:28:40 2002
+++ b/include/linux/workqueue.h	Sun Nov 10 19:28:40 2002
@@ -22,7 +22,9 @@
 #define __WORK_INITIALIZER(n, f, d) {				\
         .entry	= { &(n).entry, &(n).entry },			\
 	.func = (f),						\
-	.data = (d) }
+	.data = (d),						\
+	.timer = TIMER_INITIALIZER(NULL, 0, 0),			\
+	}
 
 #define DECLARE_WORK(n, f, d)					\
 	struct work_struct n = __WORK_INITIALIZER(n, f, d)
diff -Nru a/include/net/dst.h b/include/net/dst.h
--- a/include/net/dst.h	Sun Nov 10 19:28:41 2002
+++ b/include/net/dst.h	Sun Nov 10 19:28:41 2002
@@ -11,6 +11,7 @@
 #include <linux/config.h>
 #include <linux/rtnetlink.h>
 #include <net/neighbour.h>
+#include <asm/processor.h>
 
 /*
  * 0 - no debugging messages
@@ -44,6 +45,7 @@
 #define DST_HOST		1
 #define DST_NOXFRM		2
 #define DST_NOPOLICY		4
+#define DST_NOHASH		8
 	unsigned long		lastuse;
 	unsigned long		expires;
 
@@ -138,8 +140,14 @@
 static inline
 void dst_release(struct dst_entry * dst)
 {
-	if (dst)
+	if (dst) {
+		if (atomic_read(&dst->__refcnt) < 1) {
+			printk("BUG: dst underflow %d: %p\n",
+			       atomic_read(&dst->__refcnt),
+			       current_text_addr());
+		}
 		atomic_dec(&dst->__refcnt);
+	}
 }
 
 /* Children define the path of the packet through the
@@ -237,7 +245,7 @@
 struct flowi;
 extern int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
 		       struct sock *sk, int flags);
-
+extern void xfrm_init(void);
 
 #endif
 
diff -Nru a/include/net/protocol.h b/include/net/protocol.h
--- a/include/net/protocol.h	Sun Nov 10 19:28:39 2002
+++ b/include/net/protocol.h	Sun Nov 10 19:28:39 2002
@@ -38,6 +38,7 @@
 {
 	int			(*handler)(struct sk_buff *skb);
 	void			(*err_handler)(struct sk_buff *skb, u32 info);
+	int			no_policy;
 };
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
diff -Nru a/include/net/route.h b/include/net/route.h
--- a/include/net/route.h	Sun Nov 10 19:28:36 2002
+++ b/include/net/route.h	Sun Nov 10 19:28:36 2002
@@ -114,6 +114,7 @@
 extern void		rt_cache_flush(int how);
 extern int		__ip_route_output_key(struct rtable **, const struct flowi *flp);
 extern int		ip_route_output_key(struct rtable **, struct flowi *flp);
+extern int		ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
 extern int		ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
 extern unsigned short	ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
 extern void		ip_rt_send_redirect(struct sk_buff *skb);
diff -Nru a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
--- a/include/net/sctp/sctp.h	Sun Nov 10 19:28:38 2002
+++ b/include/net/sctp/sctp.h	Sun Nov 10 19:28:38 2002
@@ -83,6 +83,7 @@
 #include <asm/uaccess.h>
 #include <asm/page.h>
 #include <net/sock.h>
+#include <net/snmp.h>
 #include <net/sctp/structs.h>
 #include <net/sctp/constants.h>
 #include <net/sctp/sm.h>
@@ -201,6 +202,11 @@
 #define SCTP_SOCK_SLEEP_PRE(sk) SOCK_SLEEP_PRE(sk)
 #define SCTP_SOCK_SLEEP_POST(sk) SOCK_SLEEP_POST(sk)
 
+/* SCTP SNMP MIB stats handlers */
+extern struct sctp_mib sctp_statistics[NR_CPUS * 2];
+#define SCTP_INC_STATS(field)		SNMP_INC_STATS(sctp_statistics, field)
+#define SCTP_INC_STATS_BH(field)	SNMP_INC_STATS_BH(sctp_statistics, field)
+#define SCTP_INC_STATS_USER(field)	SNMP_INC_STATS_USER(sctp_statistics, field)
 
 /* Determine if this is a valid kernel address.  */
 static inline int sctp_is_valid_kaddr(unsigned long addr)
diff -Nru a/include/net/sctp/sm.h b/include/net/sctp/sm.h
--- a/include/net/sctp/sm.h	Sun Nov 10 19:28:39 2002
+++ b/include/net/sctp/sm.h	Sun Nov 10 19:28:39 2002
@@ -44,6 +44,7 @@
  *    Dajiang Zhang <dajiang.zhang@nokia.com>
  *    Sridhar Samudrala <sri@us.ibm.com>
  *    Daisy Chang <daisyc@us.ibm.com>
+ *    Ardelle Fan <ardelle.fan@intel.com>
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -253,6 +254,9 @@
 sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *,
 				      const sctp_chunk_t *,
 				      __u32 tsn);
+sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *,
+				   const sctp_chunk_t *,
+				   const struct msghdr *);
 sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *,
 				  const sctp_transport_t *,
 				  const void *payload,
diff -Nru a/include/net/sctp/structs.h b/include/net/sctp/structs.h
--- a/include/net/sctp/structs.h	Sun Nov 10 19:28:41 2002
+++ b/include/net/sctp/structs.h	Sun Nov 10 19:28:41 2002
@@ -246,7 +246,10 @@
 					 int optname,
 					 char *optval,
 					 int *optlen);
-	int		(*get_dst_mtu)	(const sockaddr_storage_t *address);
+	struct dst_entry *(*get_dst)	(sockaddr_storage_t *daddr,
+					 sockaddr_storage_t *saddr);
+	int		(*cmp_saddr)	(struct dst_entry *dst,
+					 sockaddr_storage_t *saddr);
 	__u16		net_header_len;	
 	int		sockaddr_len;
 	sa_family_t	sa_family;
@@ -476,6 +479,8 @@
 
 	/* What is the origin IP address for this chunk?  */
 	sockaddr_storage_t source;
+	/* Destination address for this chunk. */
+	sockaddr_storage_t dest;
 
 	/* For an inbound chunk, this tells us where it came from.
 	 * For an outbound chunk, it tells us where we'd like it to
@@ -492,7 +497,7 @@
 int sctp_user_addto_chunk(sctp_chunk_t *chunk, int len, struct iovec *data);
 sctp_chunk_t *sctp_chunkify(struct sk_buff *, const sctp_association_t *,
 			    struct sock *);
-void sctp_init_source(sctp_chunk_t *chunk);
+void sctp_init_addrs(sctp_chunk_t *chunk);
 const sockaddr_storage_t *sctp_source(const sctp_chunk_t *chunk);
 
 /* This is a structure for holding either an IPv6 or an IPv4 address.  */
@@ -655,6 +660,9 @@
 	/* PMTU       : The current known path MTU.  */
 	__u32 pmtu;
 
+	/* Destination */
+	struct dst_entry *dst;
+
 	/* When was the last time(in jiffies) that a data packet was sent on
 	 * this transport?  This is used to adjust the cwnd when the transport
 	 * becomes inactive.
@@ -735,6 +743,7 @@
 extern sctp_transport_t *sctp_transport_init(sctp_transport_t *,
 					     const sockaddr_storage_t *, int);
 extern void sctp_transport_set_owner(sctp_transport_t *, sctp_association_t *);
+extern void sctp_transport_route(sctp_transport_t *, sockaddr_storage_t *);
 extern void sctp_transport_free(sctp_transport_t *);
 extern void sctp_transport_destroy(sctp_transport_t *);
 extern void sctp_transport_reset_timers(sctp_transport_t *);
diff -Nru a/include/net/snmp.h b/include/net/snmp.h
--- a/include/net/snmp.h	Sun Nov 10 19:28:39 2002
+++ b/include/net/snmp.h	Sun Nov 10 19:28:39 2002
@@ -189,6 +189,35 @@
 	unsigned long   __pad[0];
 } ____cacheline_aligned; 
 
+/* draft-ietf-sigtran-sctp-mib-07.txt */
+struct sctp_mib
+{
+	unsigned long   SctpCurrEstab;
+	unsigned long   SctpActiveEstabs;
+	unsigned long   SctpPassiveEstabs;
+	unsigned long   SctpAborteds;
+	unsigned long   SctpShutdowns;
+	unsigned long   SctpOutOfBlues;
+	unsigned long   SctpChecksumErrors;
+	unsigned long   SctpOutCtrlChunks;
+	unsigned long   SctpOutOrderChunks;
+	unsigned long   SctpOutUnorderChunks;
+	unsigned long   SctpInCtrlChunks;
+	unsigned long   SctpInOrderChunks;
+	unsigned long   SctpInUnorderChunks;
+	unsigned long   SctpFragUsrMsgs;
+	unsigned long   SctpReasmUsrMsgs;
+	unsigned long   SctpOutSCTPPacks;
+	unsigned long   SctpInSCTPPacks;
+	unsigned long   SctpRtoAlgorithm;
+	unsigned long   SctpRtoMin;
+	unsigned long   SctpRtoMax;
+	unsigned long   SctpRtoInitial;
+	unsigned long   SctpValCookieLife;
+	unsigned long   SctpMaxInitRetr;
+	unsigned long   __pad[0];
+} ____cacheline_aligned;
+
 struct linux_mib 
 {
 	unsigned long	SyncookiesSent;
diff -Nru a/include/net/sock.h b/include/net/sock.h
--- a/include/net/sock.h	Sun Nov 10 19:28:40 2002
+++ b/include/net/sock.h	Sun Nov 10 19:28:40 2002
@@ -107,6 +107,7 @@
 	wait_queue_head_t	*sleep;		/* Sock wait queue			*/
 	struct dst_entry	*dst_cache;	/* Destination cache			*/
 	rwlock_t		dst_lock;
+	struct xfrm_policy	*policy[2];
 	atomic_t		rmem_alloc;	/* Receive queue bytes committed	*/
 	struct sk_buff_head	receive_queue;	/* Incoming packets			*/
 	atomic_t		wmem_alloc;	/* Transmit queue bytes committed	*/
diff -Nru a/include/net/xfrm.h b/include/net/xfrm.h
--- a/include/net/xfrm.h	Sun Nov 10 19:28:38 2002
+++ b/include/net/xfrm.h	Sun Nov 10 19:28:38 2002
@@ -3,6 +3,7 @@
 #include <linux/list.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
+#include <linux/crypto.h>
 
 #include <net/dst.h>
 #include <net/route.h>
@@ -52,8 +53,6 @@
    7. ->share		Sharing mode.
       Q: how to implement private sharing mode? To add struct sock* to
       flow id?
-   8. ->resolved	If template uniquely resolves to a static xfrm_state,
-                        the reference is stores here.
 
    Having this template we search through SAD searching for entries
    with appropriate mode/proto/algo, permitted by selector.
@@ -113,6 +112,40 @@
 	void	*owner;
 };
 
+#define XFRM_INF (~(u64)0)
+
+struct xfrm_lifetime_cfg
+{
+	u64	soft_byte_limit;
+	u64	hard_byte_limit;
+	u64	soft_packet_limit;
+	u64	hard_packet_limit;
+	u64	soft_add_expires_seconds;
+	u64	hard_add_expires_seconds;
+	u64	soft_use_expires_seconds;
+	u64	hard_use_expires_seconds;
+};
+
+struct xfrm_lifetime_cur
+{
+	u64	bytes;
+	u64	packets;
+	u64	add_time;
+	u64	use_time;
+};
+
+struct xfrm_replay_state
+{
+	u32	oseq;
+	u32	seq;
+	u32	bitmap;
+};
+
+struct xfrm_algo {
+	char	alg_name[CRYPTO_MAX_ALG_NAME];
+	int	alg_key_len;    /* in bits */
+	char	alg_key[0];
+};
 
 /* Full description of state of transformer. */
 struct xfrm_state
@@ -128,42 +161,42 @@
 
 	/* Key manger bits */
 	struct {
-		int		state;
+		u8		state;
+		u8		dying;
 		u32		seq;
-		u32		warn_bytes;
 	} km;
 
 	/* Parameters of this state. */
 	struct {
 		u8		mode;
-		u8		algo;
+		u8		replay_window;
+		u8		aalgo, ealgo, calgo;
+		u16		reqid;
 		xfrm_address_t	saddr;
 		int		header_len;
 		int		trailer_len;
-		u32		hard_byte_limit;
-		u32		soft_byte_limit;
-		u32		replay_window;
-		/* More... */
 	} props;
 
+	struct xfrm_lifetime_cfg lft;
+
+	/* Data for transformer */
+	struct xfrm_algo	*aalg;
+	struct xfrm_algo	*ealg;
+	struct xfrm_algo	*calg;
+
 	/* State for replay detection */
-	struct {
-		u32		oseq;
-		u32		seq;
-		u32		bitmap;
-	} replay;
+	struct xfrm_replay_state replay;
 
 	/* Statistics */
 	struct {
-		unsigned long	lastuse;
-		unsigned long	expires;
-		u32		bytes;
 		u32		replay_window;
 		u32		replay;
 		u32		integrity_failed;
-		/* More... */
 	} stats;
 
+	struct xfrm_lifetime_cur curlft;
+	struct timer_list	timer;
+
 	/* Reference to data common to all the instances of this
 	 * transformer. */
 	struct xfrm_type	*type;
@@ -182,14 +215,12 @@
 	XFRM_STATE_DEAD
 };
 
-#define XFRM_DST_HSIZE		1024
 
 struct xfrm_type
 {
 	char			*description;
-	atomic_t		refcnt;
+	struct module		*owner;
 	__u8			proto;
-	__u8			algo;
 
 	int			(*init_state)(struct xfrm_state *x, void *args);
 	void			(*destructor)(struct xfrm_state *);
@@ -199,6 +230,11 @@
 	u32			(*get_max_size)(struct xfrm_state *, int size);
 };
 
+extern int xfrm_register_type(struct xfrm_type *type);
+extern int xfrm_unregister_type(struct xfrm_type *type);
+extern struct xfrm_type *xfrm_get_type(u8 proto);
+extern void xfrm_put_type(struct xfrm_type *type);
+
 struct xfrm_tmpl
 {
 /* id in template is interpreted as:
@@ -212,17 +248,21 @@
 /* Source address of tunnel. Ignored, if it is not a tunnel. */
 	xfrm_address_t		saddr;
 
+	__u16			reqid;
+
 /* Mode: transport/tunnel */
 	__u8			mode;
 
 /* Sharing mode: unique, this session only, this user only etc. */
 	__u8			share;
 
-/* Bit mask of algos allowed for acquisition */
-	__u32			algos;
+/* May skip this transfomration if no SA is found */
+	__u8			optional;
 
-/* If template statically resolved, hold ref here */
-	struct xfrm_state      *resolved;
+/* Bit mask of algos allowed for acquisition */
+	__u32			aalgos;
+	__u32			ealgos;
+	__u32			calgos;
 };
 
 #define XFRM_MAX_DEPTH		3
@@ -238,8 +278,8 @@
 enum
 {
 	XFRM_POLICY_IN	= 0,
-	XFRM_POLICY_FWD	= 1,
-	XFRM_POLICY_OUT	= 2,
+	XFRM_POLICY_OUT	= 1,
+	XFRM_POLICY_FWD	= 2,
 	XFRM_POLICY_MAX	= 3
 };
 
@@ -254,8 +294,8 @@
 	u32			priority;
 	u32			index;
 	struct xfrm_selector	selector;
-	unsigned long		expires;
-	unsigned long		lastuse;
+	struct xfrm_lifetime_cfg lft;
+	struct xfrm_lifetime_cur curlft;
 	struct dst_entry       *bundles;
 	__u8			action;
 #define XFRM_POLICY_ALLOW	0
@@ -267,6 +307,19 @@
 	struct xfrm_tmpl       	xfrm_vec[XFRM_MAX_DEPTH];
 };
 
+struct xfrm_mgr
+{
+	struct list_head	list;
+	char			*id;
+	int			(*notify)(struct xfrm_state *x, int event);
+	int			(*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir);
+	struct xfrm_policy	*(*compile_policy)(int opt, u8 *data, int len, int *dir);
+};
+
+extern int xfrm_register_km(struct xfrm_mgr *km);
+extern int xfrm_unregister_km(struct xfrm_mgr *km);
+
+
 extern struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX];
 
 static inline void xfrm_pol_hold(struct xfrm_policy *policy)
@@ -346,13 +399,16 @@
 		__secpath_destroy(sp);
 }
 
-extern int __xfrm_policy_check(int dir, struct sk_buff *skb);
+extern int __xfrm_policy_check(struct sock *, int dir, struct sk_buff *skb);
 
-static inline int xfrm_policy_check(int dir, struct sk_buff *skb)
+static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb)
 {
+	if (sk && sk->policy[XFRM_POLICY_IN])
+		return __xfrm_policy_check(sk, dir, skb);
+		
 	return	!xfrm_policy_list[dir] ||
 		(skb->dst->flags & DST_NOPOLICY) ||
-		__xfrm_policy_check(dir, skb);
+		__xfrm_policy_check(sk, dir, skb);
 }
 
 extern int __xfrm_route_forward(struct sk_buff *skb);
@@ -364,23 +420,64 @@
 		__xfrm_route_forward(skb);
 }
 
+extern int __xfrm_sk_clone_policy(struct sock *sk);
+
+static inline int xfrm_sk_clone_policy(struct sock *sk)
+{
+	if (unlikely(sk->policy[0] || sk->policy[1]))
+		return xfrm_sk_clone_policy(sk);
+	return 0;
+}
+
+extern void __xfrm_sk_free_policy(struct xfrm_policy *);
+
+static inline void xfrm_sk_free_policy(struct sock *sk)
+{
+	if (unlikely(sk->policy[0] != NULL)) {
+		__xfrm_sk_free_policy(sk->policy[0]);
+		sk->policy[0] = NULL;
+	}
+	if (unlikely(sk->policy[1] != NULL)) {
+		__xfrm_sk_free_policy(sk->policy[1]);
+		sk->policy[1] = NULL;
+	}
+}
+
 extern void xfrm_state_init(void);
 extern void xfrm_input_init(void);
+extern int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), void *);
 extern struct xfrm_state *xfrm_state_alloc(void);
-extern struct xfrm_state *xfrm_state_find(u32 daddr, struct flowi *fl, struct xfrm_tmpl *tmpl);
+extern struct xfrm_state *xfrm_state_find(u32 daddr, u32 saddr, struct flowi *fl, struct xfrm_tmpl *tmpl,
+					  struct xfrm_policy *pol, int *err);
 extern int xfrm_state_check_expire(struct xfrm_state *x);
 extern void xfrm_state_insert(struct xfrm_state *x);
 extern int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb);
-extern struct xfrm_state * xfrm_state_lookup(u32 daddr, u32 spi, u8 proto);
-extern struct xfrm_policy *xfrm_policy_lookup(int dir, struct flowi *fl);
+extern struct xfrm_state *xfrm_state_lookup(u32 daddr, u32 spi, u8 proto);
+extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq);
+extern void xfrm_state_delete(struct xfrm_state *x);
+extern void xfrm_state_flush(u8 proto);
 extern int xfrm_replay_check(struct xfrm_state *x, u32 seq);
 extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
 extern int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl);
 extern int xfrm4_rcv(struct sk_buff *skb);
+extern int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen);
 
+struct xfrm_policy *xfrm_policy_alloc(int gfp);
+extern int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), void *);
+struct xfrm_policy *xfrm_policy_lookup(int dir, struct flowi *fl);
+int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
+struct xfrm_policy *xfrm_policy_delete(int dir, struct xfrm_selector *sel);
+struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete);
+void xfrm_policy_flush(void);
+void xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
+struct xfrm_state * xfrm_find_acq(u8 mode, u16 reqid, u8 proto, u32 daddr, u32 saddr);
+extern void xfrm_policy_flush(void);
+extern void xfrm_policy_kill(struct xfrm_policy *);
+extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
+extern struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl);
+extern int xfrm_flush_bundles(struct xfrm_state *x);
 
 extern wait_queue_head_t *km_waitq;
-extern void km_notify(struct xfrm_state *x, int event);
-extern int km_query(struct xfrm_state *x);
-
-extern int ah4_init(void);
+extern void km_warn_expired(struct xfrm_state *x);
+extern void km_expired(struct xfrm_state *x);
+extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *pol);
diff -Nru a/include/pcmcia/ciscode.h b/include/pcmcia/ciscode.h
--- a/include/pcmcia/ciscode.h	Sun Nov 10 19:28:40 2002
+++ b/include/pcmcia/ciscode.h	Sun Nov 10 19:28:40 2002
@@ -1,5 +1,5 @@
 /*
- * ciscode.h 1.45 2000/08/12 02:08:23
+ * ciscode.h 1.56 2002/10/25 06:37:30
  *
  * The contents of this file are subject to the Mozilla Public License
  * Version 1.1 (the "License"); you may not use this file except in
@@ -16,8 +16,8 @@
  * are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
  *
  * Alternatively, the contents of this file may be used under the
- * terms of the GNU General Public License version 2 (the "GPL"), in which
- * case the provisions of the GPL are applicable instead of the
+ * terms of the GNU General Public License version 2 (the "GPL"), in
+ * which case the provisions of the GPL are applicable instead of the
  * above.  If you wish to allow the use of your version of this file
  * only under the terms of the GPL and not to allow others to use
  * your version of this file under the MPL, indicate your decision by
@@ -60,6 +60,10 @@
 #define PRODID_INTEL_DUAL_RS232		0x0301
 #define PRODID_INTEL_2PLUS		0x8422
 
+#define MANFID_KME			0x0032
+#define PRODID_KME_KXLC005_A		0x0704
+#define PRODID_KME_KXLC005_B		0x2904
+
 #define MANFID_LINKSYS			0x0143
 #define PRODID_LINKSYS_PCMLM28		0xc0ab
 #define PRODID_LINKSYS_3400		0x3341
@@ -94,6 +98,8 @@
 #define PRODID_OSITECH_JACK_336		0x0007
 #define PRODID_OSITECH_SEVEN		0x0008
 
+#define MANFID_OXSEMI			0x0279
+
 #define MANFID_PIONEER			0x000b
 
 #define MANFID_PSION			0x016c
@@ -103,7 +109,10 @@
 #define PRODID_QUATECH_SPP100		0x0003
 #define PRODID_QUATECH_DUAL_RS232	0x0012
 #define PRODID_QUATECH_DUAL_RS232_D1	0x0007
+#define PRODID_QUATECH_DUAL_RS232_D2	0x0052
 #define PRODID_QUATECH_QUAD_RS232	0x001b
+#define PRODID_QUATECH_DUAL_RS422	0x000e
+#define PRODID_QUATECH_QUAD_RS422	0x0045
 
 #define MANFID_SMC			0x0108
 #define PRODID_SMC_ETHER		0x0105
@@ -118,8 +127,11 @@
 
 #define MANFID_TDK			0x0105
 #define PRODID_TDK_CF010		0x0900
+#define PRODID_TDK_GN3410		0x4815
 
 #define MANFID_TOSHIBA			0x0098
+
+#define MANFID_UNGERMANN 0x02c0
 
 #define MANFID_XIRCOM			0x0105
 
diff -Nru a/include/sound/core.h b/include/sound/core.h
--- a/include/sound/core.h	Sun Nov 10 19:28:41 2002
+++ b/include/sound/core.h	Sun Nov 10 19:28:41 2002
@@ -241,11 +241,15 @@
 void snd_hidden_vfree(void *obj);
 #define kmalloc(size, flags) snd_hidden_kmalloc(size, flags)
 #define kfree(obj) snd_hidden_kfree(obj)
-#define kfree_nocheck(obj) snd_wrapper_kfree(obj)
 #define vmalloc(size) snd_hidden_vmalloc(size)
 #define vfree(obj) snd_hidden_vfree(obj)
+#define kmalloc_nocheck(size, flags) snd_wrapper_kmalloc(size, flags)
+#define vmalloc_nocheck(size) snd_wrapper_vmalloc(size)
+#define kfree_nocheck(obj) snd_wrapper_kfree(obj)
 #define vfree_nocheck(obj) snd_wrapper_vfree(obj)
 #else
+#define kmalloc_nocheck(size, flags) kmalloc(size, flags)
+#define vmalloc_nocheck(size) vmalloc(size)
 #define kfree_nocheck(obj) kfree(obj)
 #define vfree_nocheck(obj) vfree(obj)
 #endif
diff -Nru a/include/sound/cs4231.h b/include/sound/cs4231.h
--- a/include/sound/cs4231.h	Sun Nov 10 19:28:39 2002
+++ b/include/sound/cs4231.h	Sun Nov 10 19:28:39 2002
@@ -26,9 +26,24 @@
 #include "pcm.h"
 #include "timer.h"
 
+#ifdef CONFIG_SBUS
+#define SBUS_SUPPORT
+#include <asm/sbus.h>
+#endif
+
+#if defined(CONFIG_PCI) && defined(CONFIG_SPARC64)
+#define EBUS_SUPPORT
+#include <linux/pci.h>
+#include <asm/ebus.h>
+#endif
+
+#if !defined(SBUS_SUPPORT) && !defined(EBUS_SUPPORT)
+#define LEGACY_SUPPORT
+#endif
+
 /* IO ports */
 
-#define CS4231P(chip, x)	((chip)->port + c_d_c_CS4231##x)
+#define CS4231P(x)		(c_d_c_CS4231##x)
 
 #define c_d_c_CS4231REGSEL	0
 #define c_d_c_CS4231REG		1
@@ -221,17 +236,38 @@
 
 struct _snd_cs4231 {
 	unsigned long port;		/* base i/o port */
+#ifdef LEGACY_SUPPORT
 	struct resource *res_port;
 	unsigned long cport;		/* control base i/o port (CS4236) */
 	struct resource *res_cport;
 	int irq;			/* IRQ line */
 	int dma1;			/* playback DMA */
 	int dma2;			/* record DMA */
+#endif
 	unsigned short version;		/* version of CODEC chip */
 	unsigned short mode;		/* see to CS4231_MODE_XXXX */
 	unsigned short hardware;	/* see to CS4231_HW_XXXX */
 	unsigned short hwshare;		/* shared resources */
-	unsigned short single_dma:1;	/* forced single DMA mode (GUS 16-bit daughter board) or dma1 == dma2 */
+	unsigned short single_dma:1,	/* forced single DMA mode (GUS 16-bit daughter board) or dma1 == dma2 */
+		       ebus_flag:1;	/* SPARC: EBUS present */
+
+#ifdef EBUS_SUPPORT
+	struct ebus_dma_info eb2c;
+        struct ebus_dma_info eb2p;
+#endif
+
+#if defined(SBUS_SUPPORT) || defined(EBUS_SUPPORT)
+	union {
+#ifdef SBUS_SUPPORT
+		struct sbus_dev         *sdev;
+#endif
+#ifdef EBUS_SUPPORT
+		struct pci_dev          *pdev;
+#endif
+	} dev_u;
+	unsigned int p_periods_sent;
+	unsigned int c_periods_sent;
+#endif
 
 	snd_card_t *card;
 	snd_pcm_t *pcm;
@@ -245,8 +281,10 @@
 	int mce_bit;
 	int calibrate_mute;
 	int sw_3d_bit;
+#ifdef LEGACY_SUPPORT
 	unsigned int p_dma_size;
 	unsigned int c_dma_size;
+#endif
 
 	spinlock_t reg_lock;
 	struct semaphore mce_mutex;
@@ -255,14 +293,17 @@
 	int (*rate_constraint) (snd_pcm_runtime_t *runtime);
 	void (*set_playback_format) (cs4231_t *chip, snd_pcm_hw_params_t *hw_params, unsigned char pdfr);
 	void (*set_capture_format) (cs4231_t *chip, snd_pcm_hw_params_t *hw_params, unsigned char cdfr);
+	void (*trigger) (cs4231_t *chip, unsigned int what, int start);
 #ifdef CONFIG_PM
 	struct pm_dev *pm_dev;
 	void (*suspend) (cs4231_t *chip);
 	void (*resume) (cs4231_t *chip);
 #endif
 	void *dma_private_data;
+#ifdef LEGACY_SUPPORT
 	int (*claim_dma) (cs4231_t *chip, void *dma_private_data, int dma);
 	int (*release_dma) (cs4231_t *chip, void *dma_private_data, int dma);
+#endif
 };
 
 /* exported functions */
diff -Nru a/include/sound/cs46xx.h b/include/sound/cs46xx.h
--- a/include/sound/cs46xx.h	Sun Nov 10 19:28:38 2002
+++ b/include/sound/cs46xx.h	Sun Nov 10 19:28:38 2002
@@ -196,80 +196,6 @@
 #define BA1_OMNI_MEM                            0x000E0000
 
 
-
-
-/*
- * The following define the offsets of the AC97 shadow registers, which appear
- * as a virtual extension to the base address register zero memory range.
- */
-#define AC97_REG_OFFSET_MASK                    0x0000007EL
-#define AC97_CODEC_NUMBER_MASK                  0x00003000L
-
-#define BA0_AC97_RESET                          0x00001000L
-#define BA0_AC97_MASTER_VOLUME                  0x00001002L
-#define BA0_AC97_HEADPHONE_VOLUME               0x00001004L
-#define BA0_AC97_MASTER_VOLUME_MONO             0x00001006L
-#define BA0_AC97_MASTER_TONE                    0x00001008L
-#define BA0_AC97_PC_BEEP_VOLUME                 0x0000100AL
-#define BA0_AC97_PHONE_VOLUME                   0x0000100CL
-#define BA0_AC97_MIC_VOLUME                     0x0000100EL
-#define BA0_AC97_LINE_IN_VOLUME                 0x00001010L
-#define BA0_AC97_CD_VOLUME                      0x00001012L
-#define BA0_AC97_VIDEO_VOLUME                   0x00001014L
-#define BA0_AC97_AUX_VOLUME                     0x00001016L
-#define BA0_AC97_PCM_OUT_VOLUME                 0x00001018L
-#define BA0_AC97_RECORD_SELECT                  0x0000101AL
-#define BA0_AC97_RECORD_GAIN                    0x0000101CL
-#define BA0_AC97_RECORD_GAIN_MIC                0x0000101EL
-#define BA0_AC97_GENERAL_PURPOSE                0x00001020L
-#define BA0_AC97_3D_CONTROL                     0x00001022L
-#define BA0_AC97_MODEM_RATE                     0x00001024L
-#define BA0_AC97_POWERDOWN                      0x00001026L
-#define BA0_AC97_EXT_AUDIO_ID                   0x00001028L
-#define BA0_AC97_EXT_AUDIO_POWER                0x0000102AL
-#define BA0_AC97_PCM_FRONT_DAC_RATE             0x0000102CL
-#define BA0_AC97_PCM_SURR_DAC_RATE              0x0000102EL
-#define BA0_AC97_PCM_LFE_DAC_RATE               0x00001030L
-#define BA0_AC97_PCM_LR_ADC_RATE                0x00001032L
-#define BA0_AC97_MIC_ADC_RATE                   0x00001034L
-#define BA0_AC97_6CH_VOL_C_LFE                  0x00001036L
-#define BA0_AC97_6CH_VOL_SURROUND               0x00001038L
-#define BA0_AC97_RESERVED_3A                    0x0000103AL
-#define BA0_AC97_EXT_MODEM_ID                   0x0000103CL
-#define BA0_AC97_EXT_MODEM_POWER                0x0000103EL
-#define BA0_AC97_LINE1_CODEC_RATE               0x00001040L
-#define BA0_AC97_LINE2_CODEC_RATE               0x00001042L
-#define BA0_AC97_HANDSET_CODEC_RATE             0x00001044L
-#define BA0_AC97_LINE1_CODEC_LEVEL              0x00001046L
-#define BA0_AC97_LINE2_CODEC_LEVEL              0x00001048L
-#define BA0_AC97_HANDSET_CODEC_LEVEL            0x0000104AL
-#define BA0_AC97_GPIO_PIN_CONFIG                0x0000104CL
-#define BA0_AC97_GPIO_PIN_TYPE                  0x0000104EL
-#define BA0_AC97_GPIO_PIN_STICKY                0x00001050L
-#define BA0_AC97_GPIO_PIN_WAKEUP                0x00001052L
-#define BA0_AC97_GPIO_PIN_STATUS                0x00001054L
-#define BA0_AC97_MISC_MODEM_AFE_STAT            0x00001056L
-#define BA0_AC97_RESERVED_58                    0x00001058L
-#define BA0_AC97_CRYSTAL_REV_N_FAB_ID           0x0000105AL
-#define BA0_AC97_TEST_AND_MISC_CTRL             0x0000105CL
-#define BA0_AC97_AC_MODE                        0x0000105EL
-#define BA0_AC97_MISC_CRYSTAL_CONTROL           0x00001060L
-#define BA0_AC97_LINE1_HYPRID_CTRL              0x00001062L
-#define BA0_AC97_VENDOR_RESERVED_64             0x00001064L
-#define BA0_AC97_VENDOR_RESERVED_66             0x00001066L
-#define BA0_AC97_SPDIF_CONTROL                  0x00001068L
-#define BA0_AC97_VENDOR_RESERVED_6A             0x0000106AL
-#define BA0_AC97_VENDOR_RESERVED_6C             0x0000106CL
-#define BA0_AC97_VENDOR_RESERVED_6E             0x0000106EL
-#define BA0_AC97_VENDOR_RESERVED_70             0x00001070L
-#define BA0_AC97_VENDOR_RESERVED_72             0x00001072L
-#define BA0_AC97_VENDOR_RESERVED_74             0x00001074L
-#define BA0_AC97_CAL_ADDRESS                    0x00001076L
-#define BA0_AC97_CAL_DATA                       0x00001078L
-#define BA0_AC97_VENDOR_RESERVED_7A             0x0000107AL
-#define BA0_AC97_VENDOR_ID1                     0x0000107CL
-#define BA0_AC97_VENDOR_ID2                     0x0000107EL
-
 /*
  *  The following defines are for the flags in the host interrupt status
  *  register.
@@ -1790,6 +1716,7 @@
 	struct pci_dev *pci;
 	snd_card_t *card;
 	snd_pcm_t *pcm;
+
 	snd_rawmidi_t *rmidi;
 	snd_rawmidi_substream_t *midi_input;
 	snd_rawmidi_substream_t *midi_output;
@@ -1814,12 +1741,15 @@
 	struct pm_dev *pm_dev;
 #endif
 #ifdef CONFIG_SND_CS46XX_DEBUG_GPIO
-  int current_gpio;
+	int current_gpio;
 #endif
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 	struct semaphore spos_mutex;
 
 	dsp_spos_instance_t * dsp_spos_instance;
+
+	snd_pcm_t *pcm_rear;
+	snd_pcm_t *pcm_iec958;
 #else /* for compatibility */
 	cs46xx_pcm_t *playback_pcm;
 	unsigned int play_ctl;
@@ -1832,8 +1762,11 @@
 		      cs46xx_t **rcodec);
 
 int snd_cs46xx_pcm(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
+int snd_cs46xx_pcm_rear(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
+int snd_cs46xx_pcm_iec958(cs46xx_t *chip, int device, snd_pcm_t **rpcm);
 int snd_cs46xx_mixer(cs46xx_t *chip);
 int snd_cs46xx_midi(cs46xx_t *chip, int device, snd_rawmidi_t **rmidi);
+int snd_cs46xx_start_dsp(cs46xx_t *chip);
 void snd_cs46xx_gameport(cs46xx_t *chip);
 
 #ifdef CONFIG_PM
diff -Nru a/include/sound/cs46xx_dsp_spos.h b/include/sound/cs46xx_dsp_spos.h
--- a/include/sound/cs46xx_dsp_spos.h	Sun Nov 10 19:28:40 2002
+++ b/include/sound/cs46xx_dsp_spos.h	Sun Nov 10 19:28:40 2002
@@ -36,24 +36,35 @@
 #define SEGTYPE_SP_COEFFICIENT          0x00000004
 
 #define DSP_SPOS_UU      0x0deadul     /* unused */
-#define DSP_SPOS_DC      0x0badul     /* dont care */
-#define DSP_SPOS_DC_DC   0x0bad0badul     /* dont care */
+#define DSP_SPOS_DC      0x0badul      /* dont care */
+#define DSP_SPOS_DC_DC   0x0bad0badul  /* dont care */
 #define DSP_SPOS_UUUU    0xdeadc0edul  /* unused */
 #define DSP_SPOS_UUHI    0xdeadul
 #define DSP_SPOS_UULO    0xc0edul
-#define DSP_SPOS_DCDC    0x0badf1d0ul /* dont care */
+#define DSP_SPOS_DCDC    0x0badf1d0ul  /* dont care */
 #define DSP_SPOS_DCDCHI  0x0badul
 #define DSP_SPOS_DCDCLO  0xf1d0ul
 
-#define DSP_MAX_TASK_NAME 60
+#define DSP_MAX_TASK_NAME   60
 #define DSP_MAX_SYMBOL_NAME 100
-#define DSP_MAX_SCB_NAME  60
-#define DSP_MAX_SCB_DESC  200
-#define DSP_MAX_TASK_DESC 50
+#define DSP_MAX_SCB_NAME    60
+#define DSP_MAX_SCB_DESC    200
+#define DSP_MAX_TASK_DESC   50
 
 #define DSP_MAX_PCM_CHANNELS 32
 #define DSP_MAX_SRC_NR       6
 
+#define DSP_PCM_MAIN_CHANNEL    1
+#define DSP_PCM_REAR_CHANNEL    2
+#define DSP_PCM_CENTER_CHANNEL  3
+#define DSP_PCM_LFE_CHANNEL     4
+#define DSP_IEC958_CHANNEL      5
+
+#define DSP_SPDIF_STATUS_OUTPUT_ENABLED 1
+#define DSP_SPDIF_STATUS_PLAYBACK_OPEN  2
+#define DSP_SPDIF_STATUS_HW_ENABLED     4
+#define DSP_SPDIF_STATUS_AC3_MODE       8
+
 struct _dsp_module_desc_t;
 
 typedef struct _symbol_entry_t {
@@ -129,6 +140,8 @@
 	u32 unlinked;
 	dsp_scb_descriptor_t * pcm_reader_scb;
 	dsp_scb_descriptor_t * src_scb;
+	dsp_scb_descriptor_t * mixer_scb;
+	int pcm_channel_id;
 
 	void * private_data;
 } pcm_channel_descriptor_t;
@@ -141,8 +154,14 @@
 
 	segment_desc_t code;
 
-	/* PCM playback */
+	/* Main PCM playback mixer */
 	dsp_scb_descriptor_t * master_mix_scb;
+	u16 dac_volume_right;
+	u16 dac_volume_left;
+
+	/* Rear PCM playback mixer */
+	dsp_scb_descriptor_t * rear_mix_scb;
+
 	int npcm_channels;
 	int nsrc_scb;
 	pcm_channel_descriptor_t pcm_channels[DSP_MAX_PCM_CHANNELS];
@@ -175,7 +194,8 @@
 	/* SPDIF status */
 	int spdif_status_out;
 	int spdif_status_in;
-	u32 spdif_input_volume;
+	u16 spdif_input_volume_right;
+	u16 spdif_input_volume_left;
 
 	/* SPDIF input sample rate converter */
 	dsp_scb_descriptor_t * spdif_in_src;
@@ -191,6 +211,12 @@
 	/* reference snooper */
 	dsp_scb_descriptor_t * ref_snoop_scb;
 
+	/* SPDIF output  PCM reference  */
+	dsp_scb_descriptor_t * spdif_pcm_input_scb;
+
+	/* asynch TX task */
+	dsp_scb_descriptor_t * asynch_tx_scb;
+
 	/* record sources */
 	dsp_scb_descriptor_t * pcm_input;
 	dsp_scb_descriptor_t * adc_input;
@@ -199,4 +225,3 @@
 } dsp_spos_instance_t;
 
 #endif /* __DSP_SPOS_H__ */
-
diff -Nru a/include/sound/info.h b/include/sound/info.h
--- a/include/sound/info.h	Sun Nov 10 19:28:40 2002
+++ b/include/sound/info.h	Sun Nov 10 19:28:40 2002
@@ -130,8 +130,9 @@
 int snd_info_store_text(snd_info_entry_t * entry);
 int snd_info_restore_text(snd_info_entry_t * entry);
 
+int snd_info_card_create(snd_card_t * card);
 int snd_info_card_register(snd_card_t * card);
-int snd_info_card_unregister(snd_card_t * card);
+int snd_info_card_free(snd_card_t * card);
 int snd_info_register(snd_info_entry_t * entry);
 int snd_info_unregister(snd_info_entry_t * entry);
 
diff -Nru a/include/sound/pcm.h b/include/sound/pcm.h
--- a/include/sound/pcm.h	Sun Nov 10 19:28:39 2002
+++ b/include/sound/pcm.h	Sun Nov 10 19:28:39 2002
@@ -96,7 +96,7 @@
 		    void *buf, snd_pcm_uframes_t count);
 	int (*silence)(snd_pcm_substream_t *substream, int channel, 
 		       snd_pcm_uframes_t pos, snd_pcm_uframes_t count);
-	void *(*page)(snd_pcm_substream_t *substream, unsigned long offset);
+	struct page *(*page)(snd_pcm_substream_t *substream, unsigned long offset);
 } snd_pcm_ops_t;
 
 /*
@@ -125,7 +125,7 @@
 #define SNDRV_PCM_DMA_TYPE_PCI		2	/* PCI continuous */
 #define SNDRV_PCM_DMA_TYPE_SBUS		3	/* SBUS continuous */
 
-/* If you change this don't forget to changed snd_pcm_rates table in pcm_lib.c */
+/* If you change this don't forget to change rates[] table in pcm_native.c */
 #define SNDRV_PCM_RATE_5512		(1<<0)		/* 5512Hz */
 #define SNDRV_PCM_RATE_8000		(1<<1)		/* 8000Hz */
 #define SNDRV_PCM_RATE_11025		(1<<2)		/* 11025Hz */
diff -Nru a/include/sound/pcm_sgbuf.h b/include/sound/pcm_sgbuf.h
--- a/include/sound/pcm_sgbuf.h	Sun Nov 10 19:28:40 2002
+++ b/include/sound/pcm_sgbuf.h	Sun Nov 10 19:28:40 2002
@@ -61,7 +61,7 @@
 int snd_pcm_sgbuf_ops_copy_playback(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
 int snd_pcm_sgbuf_ops_copy_capture(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, void *buf, snd_pcm_uframes_t count);
 int snd_pcm_sgbuf_ops_silence(snd_pcm_substream_t *substream, int channel, snd_pcm_uframes_t hwoff, snd_pcm_uframes_t count);
-void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
+struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset);
 
 
 #endif /* __SOUND_PCM_SGBUF_H */
diff -Nru a/include/sound/version.h b/include/sound/version.h
--- a/include/sound/version.h	Sun Nov 10 19:28:39 2002
+++ b/include/sound/version.h	Sun Nov 10 19:28:39 2002
@@ -1,3 +1,3 @@
 /* include/version.h.  Generated automatically by configure.  */
 #define CONFIG_SND_VERSION "0.9.0rc5"
-#define CONFIG_SND_DATE " (Tue Oct 29 09:19:27 2002 UTC)"
+#define CONFIG_SND_DATE " (Sun Nov 10 19:48:18 2002 UTC)"
diff -Nru a/kernel/cpufreq.c b/kernel/cpufreq.c
--- a/kernel/cpufreq.c	Sun Nov 10 19:28:37 2002
+++ b/kernel/cpufreq.c	Sun Nov 10 19:28:37 2002
@@ -677,19 +677,19 @@
 #error please extend CPU enumeration
 #endif
 	{
-		ctl_name:	0,
+		.ctl_name	= 0,
 	}
 };
 
 static ctl_table ctl_cpu[2] = {
 	{
-		ctl_name:	CTL_CPU,
-		procname:	"cpu",
-		mode:		0555,
-		child:		ctl_cpu_table,
+		.ctl_name	= CTL_CPU,
+		.procname	= "cpu",
+		.mode		= 0555,
+		.child		= ctl_cpu_table,
 	},
 	{
-		ctl_name:	0,
+		.ctl_name	= 0,
 	}
 };
 
diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Sun Nov 10 19:28:41 2002
+++ b/kernel/exit.c	Sun Nov 10 19:28:41 2002
@@ -416,19 +416,31 @@
  */
 static inline void __exit_mm(struct task_struct * tsk)
 {
-	struct mm_struct * mm = tsk->mm;
+	struct mm_struct *mm = tsk->mm;
 
 	mm_release();
-	if (mm) {
-		atomic_inc(&mm->mm_count);
-		if (mm != tsk->active_mm) BUG();
-		/* more a memory barrier than a real lock */
-		task_lock(tsk);
-		tsk->mm = NULL;
-		enter_lazy_tlb(mm, current, smp_processor_id());
-		task_unlock(tsk);
-		mmput(mm);
+	if (!mm)
+		return;
+	/*
+	 * Serialize with any possible pending coredump:
+	 */
+	if (!mm->dumpable) {
+		current->core_waiter = 1;
+		atomic_inc(&mm->core_waiters);
+		if (atomic_read(&mm->core_waiters) ==atomic_read(&mm->mm_users))
+			wake_up(&mm->core_wait);
+		down(&mm->core_sem);
+		up(&mm->core_sem);
+		atomic_dec(&mm->core_waiters);
 	}
+	atomic_inc(&mm->mm_count);
+	if (mm != tsk->active_mm) BUG();
+	/* more a memory barrier than a real lock */
+	task_lock(tsk);
+	tsk->mm = NULL;
+	enter_lazy_tlb(mm, current, smp_processor_id());
+	task_unlock(tsk);
+	mmput(mm);
 }
 
 void exit_mm(struct task_struct *tsk)
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Sun Nov 10 19:28:37 2002
+++ b/kernel/fork.c	Sun Nov 10 19:28:37 2002
@@ -306,6 +306,9 @@
 	atomic_set(&mm->mm_users, 1);
 	atomic_set(&mm->mm_count, 1);
 	init_rwsem(&mm->mmap_sem);
+	init_MUTEX(&mm->core_sem);
+	init_waitqueue_head(&mm->core_wait);
+	atomic_set(&mm->core_waiters, 0);
 	mm->page_table_lock = SPIN_LOCK_UNLOCKED;
 	mm->ioctx_list_lock = RW_LOCK_UNLOCKED;
 	mm->default_kioctx = (struct kioctx)INIT_KIOCTX(mm->default_kioctx, *mm);
@@ -772,6 +775,7 @@
 	p->start_time = jiffies;
 	p->security = NULL;
 
+	p->core_waiter = 0;
 	retval = -ENOMEM;
 	if (security_ops->task_alloc_security(p))
 		goto bad_fork_cleanup;
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Sun Nov 10 19:28:36 2002
+++ b/kernel/ksyms.c	Sun Nov 10 19:28:36 2002
@@ -281,9 +281,11 @@
 EXPORT_SYMBOL(ROOT_DEV);
 EXPORT_SYMBOL(find_get_page);
 EXPORT_SYMBOL(find_lock_page);
+EXPORT_SYMBOL(find_trylock_page);
 EXPORT_SYMBOL(find_or_create_page);
 EXPORT_SYMBOL(grab_cache_page_nowait);
 EXPORT_SYMBOL(read_cache_page);
+EXPORT_SYMBOL(read_cache_pages);
 EXPORT_SYMBOL(mark_page_accessed);
 EXPORT_SYMBOL(vfs_readlink);
 EXPORT_SYMBOL(vfs_follow_link);
@@ -552,7 +554,6 @@
 EXPORT_SYMBOL(buffer_insert_list);
 EXPORT_SYMBOL(make_bad_inode);
 EXPORT_SYMBOL(is_bad_inode);
-EXPORT_SYMBOL(event);
 EXPORT_SYMBOL(__inode_dir_notify);
 
 #ifdef CONFIG_UID16
diff -Nru a/kernel/pid.c b/kernel/pid.c
--- a/kernel/pid.c	Sun Nov 10 19:28:40 2002
+++ b/kernel/pid.c	Sun Nov 10 19:28:40 2002
@@ -131,7 +131,7 @@
 	 */
 scan_more:
 	offset = find_next_zero_bit(map->page, BITS_PER_PAGE, offset);
-	if (offset == BITS_PER_PAGE)
+	if (offset >= BITS_PER_PAGE)
 		goto next_map;
 	if (test_and_set_bit(offset, map->page))
 		goto scan_more;
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Sun Nov 10 19:28:40 2002
+++ b/kernel/sched.c	Sun Nov 10 19:28:40 2002
@@ -157,6 +157,7 @@
 	task_t *migration_thread;
 	struct list_head migration_queue;
 
+	atomic_t nr_iowait;
 } ____cacheline_aligned;
 
 static struct runqueue runqueues[NR_CPUS] __cacheline_aligned;
@@ -557,9 +558,11 @@
 {
 	unsigned long i, sum = 0;
 
-	for (i = 0; i < NR_CPUS; i++)
+	for (i = 0; i < NR_CPUS; i++) {
+		if (!cpu_online(i))
+			continue;
 		sum += cpu_rq(i)->nr_uninterruptible;
-
+	}
 	return sum;
 }
 
@@ -567,9 +570,23 @@
 {
 	unsigned long i, sum = 0;
 
-	for (i = 0; i < NR_CPUS; i++)
+	for (i = 0; i < NR_CPUS; i++) {
+		if (!cpu_online(i))
+			continue;
 		sum += cpu_rq(i)->nr_switches;
+	}
+	return sum;
+}
+
+unsigned long nr_iowait(void)
+{
+	unsigned long i, sum = 0;
 
+	for (i = 0; i < NR_CPUS; ++i) {
+		if (!cpu_online(i))
+			continue;
+		sum += atomic_read(&cpu_rq(i)->nr_iowait);
+	}
 	return sum;
 }
 
@@ -770,7 +787,7 @@
 		idx = sched_find_first_bit(array->bitmap);
 	else
 		idx = find_next_bit(array->bitmap, MAX_PRIO, idx);
-	if (idx == MAX_PRIO) {
+	if (idx >= MAX_PRIO) {
 		if (array == busiest->expired) {
 			array = busiest->active;
 			goto new_array;
@@ -875,7 +892,7 @@
 		/* note: this timer irq context must be accounted for as well */
 		if (irq_count() - HARDIRQ_OFFSET >= SOFTIRQ_OFFSET)
 			kstat_cpu(cpu).cpustat.system += sys_ticks;
-		else if (atomic_read(&nr_iowait_tasks) > 0)
+		else if (atomic_read(&rq->nr_iowait) > 0)
 			kstat_cpu(cpu).cpustat.iowait += sys_ticks;
 		else
 			kstat_cpu(cpu).cpustat.idle += sys_ticks;
@@ -1712,6 +1729,31 @@
 	sys_sched_yield();
 }
 
+/*
+ * This task is about to go to sleep on IO.  Increment rq->nr_iowait so
+ * that process accounting knows that this is a task in IO wait state.
+ *
+ * But don't do that if it is a deliberate, throttling IO wait (this task
+ * has set its backing_dev_info: the queue against which it should throttle)
+ */
+void io_schedule(void)
+{
+	struct runqueue *rq = this_rq();
+
+	atomic_inc(&rq->nr_iowait);
+	schedule();
+	atomic_dec(&rq->nr_iowait);
+}
+
+void io_schedule_timeout(long timeout)
+{
+	struct runqueue *rq = this_rq();
+
+	atomic_inc(&rq->nr_iowait);
+	schedule_timeout(timeout);
+	atomic_dec(&rq->nr_iowait);
+}
+
 /**
  * sys_sched_get_priority_max - return maximum RT priority.
  * @policy: scheduling class.
@@ -2160,6 +2202,7 @@
 		rq->expired = rq->arrays + 1;
 		spin_lock_init(&rq->lock);
 		INIT_LIST_HEAD(&rq->migration_queue);
+		atomic_set(&rq->nr_iowait, 0);
 
 		for (j = 0; j < 2; j++) {
 			array = rq->arrays + j;
diff -Nru a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c	Sun Nov 10 19:28:39 2002
+++ b/kernel/signal.c	Sun Nov 10 19:28:39 2002
@@ -96,7 +96,12 @@
 #define M_SIGEMT	0
 #endif
 
+#if SIGRTMIN > BITS_PER_LONG
+#define M(sig) (1ULL << (sig))
+#else
 #define M(sig) (1UL << (sig))
+#endif
+#define T(sig, mask) (M(sig) & mask)
 
 #define SIG_USER_SPECIFIC_MASK (\
 	M(SIGILL)    |  M(SIGTRAP)   |  M(SIGABRT)   |  M(SIGBUS)    | \
@@ -131,9 +136,6 @@
         M(SIGFPE)    |  M(SIGSEGV)   |  M(SIGBUS)    |  M(SIGSYS)    | \
         M(SIGXCPU)   |  M(SIGXFSZ)   |  M_SIGEMT                     )
 
-#define T(sig, mask) \
-	((1UL << (sig)) & mask)
-
 #define sig_user_specific(sig) \
 		(((sig) < SIGRTMIN)  && T(sig, SIG_USER_SPECIFIC_MASK))
 #define sig_user_load_balance(sig) \
@@ -768,7 +770,7 @@
 }
 
 static int
-specific_force_sig_info(int sig, struct task_struct *t)
+__specific_force_sig_info(int sig, struct task_struct *t)
 {
 	if (!t->sig)
 		return -ESRCH;
@@ -781,6 +783,20 @@
 	return specific_send_sig_info(sig, (void *)2, t, 0);
 }
 
+void
+force_sig_specific(int sig, struct task_struct *t)
+{
+	unsigned long int flags;
+
+	spin_lock_irqsave(&t->sig->siglock, flags);
+	if (t->sig->action[sig-1].sa.sa_handler == SIG_IGN)
+		t->sig->action[sig-1].sa.sa_handler = SIG_DFL;
+	sigdelset(&t->blocked, sig);
+	recalc_sigpending_tsk(t);
+	specific_send_sig_info(sig, (void *)2, t, 0);
+	spin_unlock_irqrestore(&t->sig->siglock, flags);
+}
+
 #define can_take_signal(p, sig)	\
 	(((unsigned long) p->sig->action[sig-1].sa.sa_handler > 1) && \
 	!sigismember(&p->blocked, sig) && (task_curr(p) || !signal_pending(p)))
@@ -846,7 +862,7 @@
 	int err = 0;
 
 	for_each_task_pid(p->tgid, PIDTYPE_TGID, tmp, l, pid)
-		err = specific_force_sig_info(sig, tmp);
+		err = __specific_force_sig_info(sig, tmp);
 
 	return err;
 }
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c	Sun Nov 10 19:28:37 2002
+++ b/kernel/sysctl.c	Sun Nov 10 19:28:37 2002
@@ -31,7 +31,7 @@
 #include <linux/sysrq.h>
 #include <linux/highuid.h>
 #include <linux/writeback.h>
-
+#include <linux/hugetlb.h>
 #include <asm/uaccess.h>
 
 #ifdef CONFIG_ROOT_NFS
@@ -99,11 +99,6 @@
 extern int acct_parm[];
 #endif
 
-#ifdef CONFIG_HUGETLB_PAGE
-extern int htlbpage_max;
-extern int set_hugetlb_mem_size(int);
-#endif
-
 static int parse_table(int *, int, void *, size_t *, void *, size_t,
 		       ctl_table *, void **);
 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
@@ -315,8 +310,7 @@
 	 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &zero,
 	 &one_hundred },
 #ifdef CONFIG_HUGETLB_PAGE
-	 {VM_HUGETLB_PAGES, "nr_hugepages", &htlbpage_max, sizeof(int), 0644, NULL, 
-	  &proc_dointvec},
+	 {VM_HUGETLB_PAGES, "nr_hugepages", &htlbpage_max, sizeof(int), 0644, NULL, &hugetlb_sysctl_handler},
 #endif
 	{0}
 };
@@ -907,10 +901,6 @@
 				val = -val;
 			buffer += len;
 			left -= len;
-#ifdef CONFIG_HUGETLB_PAGE
-			if (i == &htlbpage_max)
-				val = set_hugetlb_mem_size(val);
-#endif
 			switch(op) {
 			case OP_SET:	*i = val; break;
 			case OP_AND:	*i &= val; break;
diff -Nru a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c	Sun Nov 10 19:28:38 2002
+++ b/kernel/timer.c	Sun Nov 10 19:28:38 2002
@@ -69,6 +69,30 @@
 /* Fake initialization needed to avoid compiler breakage */
 static DEFINE_PER_CPU(struct tasklet_struct, timer_tasklet) = { NULL };
 
+static void check_timer_failed(timer_t *timer)
+{
+	static int whine_count;
+	if (whine_count < 16) {
+		whine_count++;
+		printk("Uninitialised timer!\n");
+		printk("This is just a warning.  Your computer is OK\n");
+		printk("function=0x%p, data=0x%lx\n",
+			timer->function, timer->data);
+		dump_stack();
+	}
+	/*
+	 * Now fix it up
+	 */
+	spin_lock_init(&timer->lock);
+	timer->magic = TIMER_MAGIC;
+}
+
+static inline void check_timer(timer_t *timer)
+{
+	if (timer->magic != TIMER_MAGIC)
+		check_timer_failed(timer);
+}
+
 static inline void internal_add_timer(tvec_base_t *base, timer_t *timer)
 {
 	unsigned long expires = timer->expires;
@@ -129,6 +153,8 @@
   
   	BUG_ON(timer_pending(timer) || !timer->function);
 
+	check_timer(timer);
+
 	spin_lock_irqsave(&base->lock, flags);
 	internal_add_timer(base, timer);
 	timer->base = base;
@@ -150,6 +176,8 @@
   
   	BUG_ON(timer_pending(timer) || !timer->function);
 
+	check_timer(timer);
+
 	spin_lock_irqsave(&base->lock, flags);
 	internal_add_timer(base, timer);
 	timer->base = base;
@@ -182,6 +210,9 @@
 	int ret = 0;
 
 	BUG_ON(!timer->function);
+
+	check_timer(timer);
+
 	/*
 	 * This is a common optimization triggered by the
 	 * networking code - if the timer is re-modified
@@ -190,7 +221,7 @@
 	if (timer->expires == expires && timer_pending(timer))
 		return 1;
 
-	local_irq_save(flags);
+	spin_lock_irqsave(&timer->lock, flags);
 	new_base = &per_cpu(tvec_bases, smp_processor_id());
 repeat:
 	old_base = timer->base;
@@ -207,7 +238,7 @@
 			spin_lock(&new_base->lock);
 		}
 		/*
-		 * The timer base might have changed while we were
+		 * The timer base might have been cancelled while we were
 		 * trying to take the lock(s):
 		 */
 		if (timer->base != old_base) {
@@ -232,7 +263,8 @@
 
 	if (old_base && (new_base != old_base))
 		spin_unlock(&old_base->lock);
-	spin_unlock_irqrestore(&new_base->lock, flags);
+	spin_unlock(&new_base->lock);
+	spin_unlock_irqrestore(&timer->lock, flags);
 
 	return ret;
 }
@@ -253,6 +285,8 @@
 	unsigned long flags;
 	tvec_base_t *base;
 
+	check_timer(timer);
+
 repeat:
  	base = timer->base;
 	if (!base)
@@ -289,6 +323,8 @@
 {
 	tvec_base_t *base;
 	int i, ret = 0;
+
+	check_timer(timer);
 
 del_again:
 	ret += del_timer(timer);
diff -Nru a/lib/Kconfig b/lib/Kconfig
--- a/lib/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/lib/Kconfig	Sun Nov 10 19:28:40 2002
@@ -17,8 +17,8 @@
 #
 config ZLIB_INFLATE
 	tristate
-	default m if CRAMFS!=y && PPP_DEFLATE!=y && JFFS2_FS!=y && ZISOFS_FS!=y && (CRAMFS=m || PPP_DEFLATE=m || JFFS2_FS=m || ZISOFS_FS=m)
-	default y if CRAMFS=y || PPP_DEFLATE=y || JFFS2_FS=y || ZISOFS_FS=y
+	default y if CRAMFS=y || PPP_DEFLATE=y || JFFS2_FS=y || ZISOFS_FS=y || BINFMT_ZFLAT=y
+	default m if CRAMFS=m || PPP_DEFLATE=m || JFFS2_FS=m || ZISOFS_FS=m || BINFMT_ZFLAT=m
 
 config ZLIB_DEFLATE
 	tristate
diff -Nru a/lib/vsprintf.c b/lib/vsprintf.c
--- a/lib/vsprintf.c	Sun Nov 10 19:28:41 2002
+++ b/lib/vsprintf.c	Sun Nov 10 19:28:41 2002
@@ -517,6 +517,7 @@
 {
 	const char *str = buf;
 	char *next;
+	char digit;
 	int num = 0;
 	int qualifier;
 	int base;
@@ -638,12 +639,16 @@
 		while (isspace(*str))
 			str++;
 
-		if (!*str
-                    || (base == 16 && !isxdigit(*str))
-                    || (base == 10 && !isdigit(*str))
-                    || (base == 8 && (!isdigit(*str) || *str > '7'))
-                    || (base == 0 && !isdigit(*str)))
-			break;
+		digit = *str;
+		if (is_sign && digit == '-')
+			digit = *(str + 1);
+
+		if (!digit
+                    || (base == 16 && !isxdigit(digit))
+                    || (base == 10 && !isdigit(digit))
+                    || (base == 8 && (!isdigit(digit) || digit > '7'))
+                    || (base == 0 && !isdigit(digit)))
+				break;
 
 		switch(qualifier) {
 		case 'h':
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Sun Nov 10 19:28:38 2002
+++ b/mm/filemap.c	Sun Nov 10 19:28:38 2002
@@ -791,6 +791,7 @@
 		if (seg == 0)
 			return -EFAULT;
 		nr_segs = seg;
+		count -= iv->iov_len;	/* This segment is no good */
 		break;
 	}
 
@@ -888,8 +889,8 @@
 	return written;
 }
 
-ssize_t generic_file_sendfile(struct file *out_file, struct file *in_file,
-			      loff_t *ppos, size_t count)
+ssize_t generic_file_sendfile(struct file *in_file, loff_t *ppos,
+			 size_t count, read_actor_t actor, void *target)
 {
 	read_descriptor_t desc;
 
@@ -898,10 +899,10 @@
 
 	desc.written = 0;
 	desc.count = count;
-	desc.buf = (char *)out_file;
+	desc.buf = target;
 	desc.error = 0;
 
-	do_generic_file_read(in_file, ppos, &desc, file_send_actor);
+	do_generic_file_read(in_file, ppos, &desc, actor);
 	if (desc.written)
 		return desc.written;
 	return desc.error;
@@ -1578,6 +1579,7 @@
 		if (seg == 0)
 			return -EFAULT;
 		nr_segs = seg;
+		ocount -= iv->iov_len;	/* This segment is no good */
 		break;
 	}
 	count = ocount;
diff -Nru a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c	Sun Nov 10 19:28:40 2002
+++ b/mm/mmap.c	Sun Nov 10 19:28:40 2002
@@ -767,7 +767,7 @@
 	return prev ? prev->vm_next : vma;
 }
 
-#ifdef ARCH_STACK_GROWSUP
+#ifdef CONFIG_STACK_GROWSUP
 /*
  * vma is the first one with address > vma->vm_end.  Have to extend vma.
  */
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Sun Nov 10 19:28:37 2002
+++ b/mm/page_alloc.c	Sun Nov 10 19:28:37 2002
@@ -175,7 +175,6 @@
 		/* have to delete it as __free_pages_bulk list manipulates */
 		list_del(&page->list);
 		__free_pages_bulk(page, base, zone, area, mask, order);
-		mod_page_state(pgfree, count<<order);
 		ret++;
 	}
 	spin_unlock_irqrestore(&zone->lock, flags);
@@ -186,6 +185,7 @@
 {
 	LIST_HEAD(list);
 
+	mod_page_state(pgfree, 1 << order);
 	free_pages_check(__FUNCTION__, page);
 	list_add(&page->list, &list);
 	free_pages_bulk(page_zone(page), 1, &list, order);
@@ -291,32 +291,19 @@
 			unsigned long count, struct list_head *list)
 {
 	unsigned long flags;
-	int i, allocated = 0;
+	int i;
+	int allocated = 0;
 	struct page *page;
-	struct list_head *curr;
-	LIST_HEAD(temp);
 	
 	spin_lock_irqsave(&zone->lock, flags);
 	for (i = 0; i < count; ++i) {
 		page = __rmqueue(zone, order);
 		if (page == NULL)
 			break;
-		++allocated;
-		list_add(&page->list, &temp);
+		allocated++;
+		list_add_tail(&page->list, list);
 	}
 	spin_unlock_irqrestore(&zone->lock, flags);
-
-	/*
-	 * This may look inefficient because we're walking the list again,
-	 * but the cachelines are hot, so it's very cheap, and this way we
-	 * can drop the zone lock much earlier
-	 */
-	list_for_each(curr, &temp) {
-		page = list_entry(curr, struct page, list);
-		BUG_ON(bad_range(zone, page));
-		prep_new_page(page, order);
-	}
-	list_splice(&temp, list->prev);
 	return allocated;
 }
 
@@ -354,6 +341,7 @@
 	struct per_cpu_pages *pcp;
 	unsigned long flags;
 
+	inc_page_state(pgfree);
 	free_pages_check(__FUNCTION__, page);
 	pcp = &zone->pageset[get_cpu()].pcp[cold];
 	local_irq_save(flags);
@@ -405,6 +393,7 @@
 
 	if (page != NULL) {
 		BUG_ON(bad_range(zone, page));
+		mod_page_state(pgalloc, 1 << order);
 		prep_new_page(page, order);
 	}
 	return page;
@@ -430,8 +419,6 @@
 	cold = 0;
 	if (gfp_mask & __GFP_COLD)
 		cold = 1;
-
-	mod_page_state(pgalloc, 1<<order);
 
 	zones = zonelist->zones;  /* the list of zones suitable for gfp_mask */
 	classzone = zones[0]; 
diff -Nru a/mm/readahead.c b/mm/readahead.c
--- a/mm/readahead.c	Sun Nov 10 19:28:37 2002
+++ b/mm/readahead.c	Sun Nov 10 19:28:37 2002
@@ -42,6 +42,46 @@
 	return (VM_MIN_READAHEAD * 1024) / PAGE_CACHE_SIZE;
 }
 
+/**
+ * read_cache_pages - populate an address space with some pages, and
+ * 			start reads against them.
+ * @mapping: the address_space
+ * @pages: The address of a list_head which contains the target pages.  These
+ *   pages have their ->index populated and are otherwise uninitialised.
+ * @filler: callback routine for filling a single page.
+ * @data: private data for the callback routine.
+ *
+ * Hides the details of the LRU cache etc from the filesystems.
+ */
+int
+read_cache_pages(struct address_space *mapping,
+		 struct list_head *pages,
+		 int (*filler)(void *, struct page *),
+		 void *data)
+{
+	struct page *page;
+	struct pagevec lru_pvec;
+	int ret = 0;
+
+	pagevec_init(&lru_pvec, 0);
+
+	while (!list_empty(pages)) {
+		page = list_entry(pages->prev, struct page, list);
+		list_del(&page->list);
+		if (add_to_page_cache(page, mapping, page->index)) {
+			page_cache_release(page);
+			continue;
+		}
+		ret = filler(data, page);
+		if (!pagevec_add(&lru_pvec, page))
+			__pagevec_lru_add(&lru_pvec);
+		if (ret)
+			break;
+	}
+	pagevec_lru_add(&lru_pvec);
+	return ret;
+}
+
 static int
 read_pages(struct address_space *mapping, struct file *filp,
 		struct list_head *pages, unsigned nr_pages)
@@ -52,7 +92,7 @@
 	pagevec_init(&lru_pvec, 0);
 
 	if (mapping->a_ops->readpages)
-		return mapping->a_ops->readpages(mapping, pages, nr_pages);
+		return mapping->a_ops->readpages(filp, mapping, pages, nr_pages);
 
 	for (page_idx = 0; page_idx < nr_pages; page_idx++) {
 		struct page *page = list_entry(pages->prev, struct page, list);
diff -Nru a/mm/shmem.c b/mm/shmem.c
--- a/mm/shmem.c	Sun Nov 10 19:28:39 2002
+++ b/mm/shmem.c	Sun Nov 10 19:28:39 2002
@@ -1387,8 +1387,8 @@
 	return desc.error;
 }
 
-static ssize_t shmem_file_sendfile(struct file *out_file,
-	struct file *in_file, loff_t *ppos, size_t count)
+static ssize_t shmem_file_sendfile(struct file *in_file, loff_t *ppos,
+			 size_t count, read_actor_t actor, void *target)
 {
 	read_descriptor_t desc;
 
@@ -1397,10 +1397,10 @@
 
 	desc.written = 0;
 	desc.count = count;
-	desc.buf = (char *)out_file;
+	desc.buf = target;
 	desc.error = 0;
 
-	do_shmem_file_read(in_file, ppos, &desc, file_send_actor);
+	do_shmem_file_read(in_file, ppos, &desc, actor);
 	if (desc.written)
 		return desc.written;
 	return desc.error;
diff -Nru a/mm/slab.c b/mm/slab.c
--- a/mm/slab.c	Sun Nov 10 19:28:40 2002
+++ b/mm/slab.c	Sun Nov 10 19:28:40 2002
@@ -437,7 +437,8 @@
 /* internal cache of cache description objs */
 static kmem_cache_t cache_cache = {
 	.lists		= LIST3_INIT(cache_cache.lists),
-	.array		= { [0] = &initarray_cache.cache },
+	/* Allow for boot cpu != 0 */
+	.array		= { [0 ... NR_CPUS-1] = &initarray_cache.cache },
 	.batchcount	= 1,
 	.limit		= BOOT_CPUCACHE_ENTRIES,
 	.objsize	= sizeof(kmem_cache_t),
@@ -2284,3 +2285,20 @@
 	return res;
 }
 #endif
+
+unsigned int ksize(const void *objp)
+{
+	kmem_cache_t *c;
+	unsigned long flags;
+	unsigned int size = 0;
+
+	if (likely(objp != NULL)) {
+		local_irq_save(flags);
+		c = GET_PAGE_CACHE(virt_to_page(objp));
+		size = kmem_cache_size(c);
+		local_irq_restore(flags);
+	}
+
+	return size;
+}
+
diff -Nru a/net/Kconfig b/net/Kconfig
--- a/net/Kconfig	Sun Nov 10 19:28:36 2002
+++ b/net/Kconfig	Sun Nov 10 19:28:36 2002
@@ -139,6 +139,15 @@
 
 	  Say Y unless you know what you are doing.
 
+config NET_KEY
+	tristate "PF_KEY sockets"
+	---help---
+	  PF_KEYv2 socket family, compatible to KAME ones.
+	  They are required if you are going to use IPsec tools ported
+	  from KAME.
+
+	  Say Y unless you know what you are doing.
+
 config INET
 	bool "TCP/IP networking"
 	---help---
@@ -382,10 +391,10 @@
 	  for location. Please read the Bridge mini-HOWTO for more
 	  information.
 
-	  Note that if your box acts as a bridge, it probably contains several
-	  Ethernet devices, but the kernel is not able to recognize more than
-	  one at boot time without help; for details read the Ethernet-HOWTO,
-	  available from in <http://www.linuxdoc.org/docs.html#howto>.
+	  If you enable iptables support along with the bridge support then you
+	  turn your bridge into a bridging firewall.
+	  iptables will then see the IP packets being bridged, so you need to
+	  take this into account when setting up your firewall rules.
 
 	  If you want to compile this code as a module ( = code which can be
 	  inserted in and removed from the running kernel whenever you want),
@@ -619,6 +628,26 @@
 source "net/sched/Kconfig"
 
 #bool 'Network code profiler' CONFIG_NET_PROFILE
+endmenu
+
+menu "Network testing"
+
+config NET_PKTGEN
+	tristate "Packet Generator (USE WITH CAUTION)"
+	---help---
+	  This module will inject preconfigured packets, at a configurable
+	  rate, out of a given interface.  It is used for network interface
+	  stress testing and performance analysis.  If you don't understand
+	  what was just said, you don't need it: say N.
+
+	  Documentation on how to use the packet generaor can be found
+	  at <file:Documentation/networking/pktgen.txt>.
+
+	  This code is also available as a module called pktgen.o ( = code
+	  which can be inserted in and removed from the running kernel
+	  whenever you want).  If you want to compile it as a module, say M
+	  here and read <file:Documentation/modules.txt>.
+
 endmenu
 
 endmenu
diff -Nru a/net/Makefile b/net/Makefile
--- a/net/Makefile	Sun Nov 10 19:28:39 2002
+++ b/net/Makefile	Sun Nov 10 19:28:39 2002
@@ -16,6 +16,7 @@
 obj-$(CONFIG_UNIX)		+= unix/
 obj-$(CONFIG_IPV6)		+= ipv6/
 obj-$(CONFIG_PACKET)		+= packet/
+obj-$(CONFIG_NET_KEY)		+= key/
 obj-$(CONFIG_NET_SCHED)		+= sched/
 obj-$(CONFIG_BRIDGE)		+= bridge/
 obj-$(CONFIG_IPX)		+= ipx/
diff -Nru a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c
--- a/net/ax25/ax25_dev.c	Sun Nov 10 19:28:37 2002
+++ b/net/ax25/ax25_dev.c	Sun Nov 10 19:28:37 2002
@@ -98,6 +98,10 @@
 	ax25_dev->values[AX25_VALUES_PROTOCOL]  = AX25_DEF_PROTOCOL;
 	ax25_dev->values[AX25_VALUES_DS_TIMEOUT]= AX25_DEF_DS_TIMEOUT;
 
+#if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER)
+	init_timer(&ax25_dev->dama.slave_timer);
+#endif
+
 	spin_lock_bh(&ax25_dev_lock);
 	ax25_dev->next = ax25_dev_list;
 	ax25_dev_list  = ax25_dev;
diff -Nru a/net/bridge/br_if.c b/net/bridge/br_if.c
--- a/net/bridge/br_if.c	Sun Nov 10 19:28:41 2002
+++ b/net/bridge/br_if.c	Sun Nov 10 19:28:41 2002
@@ -106,6 +106,8 @@
 	memset(br, 0, sizeof(*br));
 	dev = &br->dev;
 
+	init_timer(&br->tick);
+
 	strncpy(dev->name, name, IFNAMSIZ);
 	dev->priv = br;
 	ether_setup(dev);
diff -Nru a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
--- a/net/bridge/br_netfilter.c	Sun Nov 10 19:28:41 2002
+++ b/net/bridge/br_netfilter.c	Sun Nov 10 19:28:41 2002
@@ -57,7 +57,8 @@
 		dst: {
 			__refcnt:		ATOMIC_INIT(1),
 			dev:			&__fake_net_device,
-			pmtu:			1500
+			path:			&__fake_rtable.u.dst,
+			metrics:		{[RTAX_MTU] 1500},
 		}
 	},
 
@@ -109,8 +110,8 @@
  * Let us now consider the case that ip_route_input() fails:
  *
  * After a "echo '0' > /proc/sys/net/ipv4/ip_forward" ip_route_input()
- * will fail, while ip_route_output() will return success. The source
- * address for ip_route_output() is set to zero, so ip_route_output()
+ * will fail, while __ip_route_output_key() will return success. The source
+ * address for __ip_route_output_key() is set to zero, so __ip_route_output_key
  * thinks we're handling a locally generated packet and won't care
  * if IP forwarding is allowed. We send a warning message to the users's
  * log telling her to put IP forwarding on.
@@ -158,8 +159,11 @@
 		if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
 		    dev)) {
 			struct rtable *rt;
+			struct flowi fl = { .nl_u = 
+			{ .ip4_u = { .daddr = iph->daddr, .saddr = 0 ,
+				     .tos = iph->tos} }, .proto = 0};
 
-			if (!ip_route_output(&rt, iph->daddr, 0, iph->tos, 0)) {
+			if (!ip_route_output_key(&rt, &fl)) {
 				/* Bridged-and-DNAT'ed traffic doesn't
 				 * require ip_forwarding.
 				 */
diff -Nru a/net/core/Makefile b/net/core/Makefile
--- a/net/core/Makefile	Sun Nov 10 19:28:41 2002
+++ b/net/core/Makefile	Sun Nov 10 19:28:41 2002
@@ -17,6 +17,7 @@
 obj-$(CONFIG_NETFILTER) += netfilter.o
 obj-$(CONFIG_NET_DIVERT) += dv.o
 obj-$(CONFIG_NET_PROFILE) += profile.o
+obj-$(CONFIG_NET_PKTGEN) += pktgen.o
 obj-$(CONFIG_NET_RADIO) += wireless.o
 # Ugly. I wish all wireless drivers were moved in drivers/net/wireless
 obj-$(CONFIG_NET_PCMCIA_RADIO) += wireless.o
diff -Nru a/net/core/dev.c b/net/core/dev.c
--- a/net/core/dev.c	Sun Nov 10 19:28:40 2002
+++ b/net/core/dev.c	Sun Nov 10 19:28:40 2002
@@ -14,7 +14,7 @@
  *	Additional Authors:
  *		Florian la Roche <rzsfl@rz.uni-sb.de>
  *		Alan Cox <gw4pts@gw4pts.ampr.org>
- *		David Hinds <dhinds@allegro.stanford.edu>
+ *		David Hinds <dahinds@users.sourceforge.net>
  *		Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
  *		Adam Sulmicki <adam@cfar.umd.edu>
  *              Pekka Riikonen <priikone@poesidon.pspt.fi>
@@ -172,7 +172,7 @@
 
 #ifdef OFFLINE_SAMPLE
 static void sample_queue(unsigned long dummy);
-static struct timer_list samp_timer = { function: sample_queue };
+static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0);
 #endif
 
 #ifdef CONFIG_HOTPLUG
diff -Nru a/net/core/dst.c b/net/core/dst.c
--- a/net/core/dst.c	Sun Nov 10 19:28:40 2002
+++ b/net/core/dst.c	Sun Nov 10 19:28:40 2002
@@ -36,9 +36,10 @@
 static unsigned long dst_gc_timer_expires;
 static unsigned long dst_gc_timer_inc = DST_GC_MAX;
 static void dst_run_gc(unsigned long);
+static void ___dst_free(struct dst_entry * dst);
 
 static struct timer_list dst_gc_timer =
-	{ data: DST_GC_MIN, function: dst_run_gc };
+	TIMER_INITIALIZER(dst_run_gc, 0, DST_GC_MIN);
 
 static void dst_run_gc(unsigned long dummy)
 {
@@ -59,12 +60,26 @@
 			delayed++;
 			continue;
 		}
-		if (dst->child) {
-			dst->child->next = dst->next;
-			*dstp = dst->child;
-		} else
-			*dstp = dst->next;
-		dst_destroy(dst);
+		*dstp = dst->next;
+
+		dst = dst_destroy(dst);
+		if (dst) {
+			/* NOHASH and still referenced. Unless it is already
+			 * on gc list, invalidate it and add to gc list.
+			 *
+			 * Note: this is temporary. Actually, NOHASH dst's
+			 * must be obsoleted when parent is obsoleted.
+			 * But we do not have state "obsoleted, but
+			 * referenced by parent", so it is right.
+			 */
+			if (dst->obsolete > 1)
+				continue;
+
+			___dst_free(dst);
+			dst->next = *dstp;
+			*dstp = dst;
+			dstp = &dst->next;
+		}
 	}
 	if (!dst_garbage_list) {
 		dst_gc_timer_inc = DST_GC_MAX;
@@ -120,10 +135,8 @@
 	return dst;
 }
 
-void __dst_free(struct dst_entry * dst)
+static void ___dst_free(struct dst_entry * dst)
 {
-	spin_lock_bh(&dst_lock);
-
 	/* The first case (dev==NULL) is required, when
 	   protocol module is unloaded.
 	 */
@@ -132,6 +145,12 @@
 		dst->output = dst_blackhole;
 	}
 	dst->obsolete = 2;
+}
+
+void __dst_free(struct dst_entry * dst)
+{
+	spin_lock_bh(&dst_lock);
+	___dst_free(dst);
 	dst->next = dst_garbage_list;
 	dst_garbage_list = dst;
 	if (dst_gc_timer_inc > DST_GC_INC) {
@@ -141,7 +160,6 @@
 		dst_gc_timer.expires = jiffies + dst_gc_timer_expires;
 		add_timer(&dst_gc_timer);
 	}
-
 	spin_unlock_bh(&dst_lock);
 }
 
@@ -177,10 +195,19 @@
 	kmem_cache_free(dst->ops->kmem_cachep, dst);
 
 	dst = child;
-	if (dst && !atomic_read(&dst->__refcnt))
-		goto again;
-
-	return dst;
+	if (dst) {
+		if (atomic_dec_and_test(&dst->__refcnt)) {
+			/* We were real parent of this dst, so kill child. */
+			if (dst->flags&DST_NOHASH)
+				goto again;
+		} else {
+			/* Child is still referenced, return it for freeing. */
+			if (dst->flags&DST_NOHASH)
+				return dst;
+			/* Child is still in his hash table */
+		}
+	}
+	return NULL;
 }
 
 static int dst_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
diff -Nru a/net/core/netfilter.c b/net/core/netfilter.c
--- a/net/core/netfilter.c	Sun Nov 10 19:28:39 2002
+++ b/net/core/netfilter.c	Sun Nov 10 19:28:39 2002
@@ -138,7 +138,6 @@
 
 #ifdef CONFIG_NETFILTER_DEBUG
 #include <net/ip.h>
-#include <net/route.h>
 #include <net/tcp.h>
 #include <linux/netfilter_ipv4.h>
 
diff -Nru a/net/core/pktgen.c b/net/core/pktgen.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/core/pktgen.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,1388 @@
+/* -*-linux-c-*-
+ * $Id: pktgen.c,v 1.8 2002/07/15 19:30:17 robert Exp $
+ * pktgen.c: Packet Generator for performance evaluation.
+ *
+ * Copyright 2001, 2002 by Robert Olsson <robert.olsson@its.uu.se>
+ *				 Uppsala University, Sweden
+ *
+ * A tool for loading the network with preconfigurated packets.
+ * The tool is implemented as a linux module.  Parameters are output 
+ * device, IPG (interpacket gap), number of packets, and whether
+ * to use multiple SKBs or just the same one.
+ * pktgen uses the installed interface's output routine.
+ *
+ * Additional hacking by:
+ *
+ * Jens.Laas@data.slu.se
+ * Improved by ANK. 010120.
+ * Improved by ANK even more. 010212.
+ * MAC address typo fixed. 010417 --ro
+ * Integrated.  020301 --DaveM
+ * Added multiskb option 020301 --DaveM
+ * Scaling of results. 020417--sigurdur@linpro.no
+ * Significant re-work of the module:
+ *   *  Updated to support generation over multiple interfaces at once
+ *       by creating 32 /proc/net/pg* files.  Each file can be manipulated
+ *       individually.
+ *   *  Converted many counters to __u64 to allow longer runs.
+ *   *  Allow configuration of ranges, like min/max IP address, MACs,
+ *       and UDP-ports, for both source and destination, and can
+ *       set to use a random distribution or sequentially walk the range.
+ *   *  Can now change some values after starting.
+ *   *  Place 12-byte packet in UDP payload with magic number,
+ *       sequence number, and timestamp.  Will write receiver next.
+ *   *  The new changes seem to have a performance impact of around 1%,
+ *       as far as I can tell.
+ *   --Ben Greear <greearb@candelatech.com>
+ * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br)
+ *
+ * Renamed multiskb to clone_skb and cleaned up sending core for two distinct 
+ * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0 
+ * as a "fastpath" with a configurable number of clones after alloc's.
+ *
+ * clone_skb=0 means all packets are allocated this also means ranges time 
+ * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100 
+ * clones.
+ *
+ * Also moved to /proc/net/pktgen/ 
+ * --ro 
+ *
+ * See Documentation/networking/pktgen.txt for how to use this.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/inet.h>
+#include <asm/byteorder.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/uaccess.h>
+
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/udp.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/proc_fs.h>
+#include <linux/if_arp.h>
+#include <net/checksum.h>
+#include <asm/timex.h>
+
+#define cycles()	((u32)get_cycles())
+
+
+#define VERSION "pktgen version 1.2"
+static char version[] __initdata = 
+  "pktgen.c: v1.2: Packet Generator for packet performance testing.\n";
+
+/* Used to help with determining the pkts on receive */
+
+#define PKTGEN_MAGIC 0xbe9be955
+
+
+/* Keep information per interface */
+struct pktgen_info {
+	/* Parameters */
+
+	/* If min != max, then we will either do a linear iteration, or
+	 * we will do a random selection from within the range.
+	 */
+	__u32 flags;     
+
+#define F_IPSRC_RND   (1<<0)  /* IP-Src Random  */
+#define F_IPDST_RND   (1<<1)  /* IP-Dst Random  */
+#define F_UDPSRC_RND  (1<<2)  /* UDP-Src Random */
+#define F_UDPDST_RND  (1<<3)  /* UDP-Dst Random */
+#define F_MACSRC_RND  (1<<4)  /* MAC-Src Random */
+#define F_MACDST_RND  (1<<5)  /* MAC-Dst Random */
+#define F_SET_SRCMAC  (1<<6)  /* Specify-Src-Mac 
+				 (default is to use Interface's MAC Addr) */
+#define F_SET_SRCIP   (1<<7)  /*  Specify-Src-IP
+				  (default is to use Interface's IP Addr) */ 
+
+	
+	int pkt_size;    /* = ETH_ZLEN; */
+	int nfrags;
+	__u32 ipg;       /* Default Interpacket gap in nsec */
+	__u64 count;     /* Default No packets to send */
+	__u64 sofar;     /* How many pkts we've sent so far */
+	__u64 errors;    /* Errors when trying to transmit, pkts will be re-sent */
+	struct timeval started_at;
+	struct timeval stopped_at;
+	__u64 idle_acc;
+	__u32 seq_num;
+	
+	int clone_skb;   /* Use multiple SKBs during packet gen.  If this number
+			  * is greater than 1, then that many coppies of the same
+			  * packet will be sent before a new packet is allocated.
+			  * For instance, if you want to send 1024 identical packets
+			  * before creating a new packet, set clone_skb to 1024.
+			  */
+	int busy;
+	int do_run_run;   /* if this changes to false, the test will stop */
+	
+	char outdev[32];
+	char dst_min[32];
+	char dst_max[32];
+	char src_min[32];
+	char src_max[32];
+
+	/* If we're doing ranges, random or incremental, then this
+	 * defines the min/max for those ranges.
+	 */
+	__u32 saddr_min; /* inclusive, source IP address */
+	__u32 saddr_max; /* exclusive, source IP address */
+	__u32 daddr_min; /* inclusive, dest IP address */
+	__u32 daddr_max; /* exclusive, dest IP address */
+
+	__u16 udp_src_min; /* inclusive, source UDP port */
+	__u16 udp_src_max; /* exclusive, source UDP port */
+	__u16 udp_dst_min; /* inclusive, dest UDP port */
+	__u16 udp_dst_max; /* exclusive, dest UDP port */
+
+	__u32 src_mac_count; /* How many MACs to iterate through */
+	__u32 dst_mac_count; /* How many MACs to iterate through */
+	
+	unsigned char dst_mac[6];
+	unsigned char src_mac[6];
+	
+	__u32 cur_dst_mac_offset;
+	__u32 cur_src_mac_offset;
+	__u32 cur_saddr;
+	__u32 cur_daddr;
+	__u16 cur_udp_dst;
+	__u16 cur_udp_src;
+	
+	__u8 hh[14];
+	/* = { 
+	   0x00, 0x80, 0xC8, 0x79, 0xB3, 0xCB, 
+	   
+	   We fill in SRC address later
+	   0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	   0x08, 0x00
+	   };
+	*/
+	__u16 pad; /* pad out the hh struct to an even 16 bytes */
+	char result[512];
+
+	/* proc file names */
+	char fname[80];
+	char busy_fname[80];
+	
+	struct proc_dir_entry *proc_ent;
+	struct proc_dir_entry *busy_proc_ent;
+};
+
+struct pktgen_hdr {
+	__u32 pgh_magic;
+	__u32 seq_num;
+	struct timeval timestamp;
+};
+
+static int cpu_speed;
+static int debug;
+
+/* Module parameters, defaults. */
+static int count_d = 100000;
+static int ipg_d = 0;
+static int clone_skb_d = 0;
+
+
+#define MAX_PKTGEN 8
+static struct pktgen_info pginfos[MAX_PKTGEN];
+
+
+/** Convert to miliseconds */
+inline __u64 tv_to_ms(const struct timeval* tv) {
+	__u64 ms = tv->tv_usec / 1000;
+	ms += (__u64)tv->tv_sec * (__u64)1000;
+	return ms;
+}
+
+inline __u64 getCurMs(void) {
+	struct timeval tv;
+	do_gettimeofday(&tv);
+	return tv_to_ms(&tv);
+}
+
+#define PG_PROC_DIR "pktgen"
+static struct proc_dir_entry *proc_dir = 0;
+
+static struct net_device *setup_inject(struct pktgen_info* info)
+{
+	struct net_device *odev;
+
+	rtnl_lock();
+	odev = __dev_get_by_name(info->outdev);
+	if (!odev) {
+		sprintf(info->result, "No such netdevice: \"%s\"", info->outdev);
+		goto out_unlock;
+	}
+
+	if (odev->type != ARPHRD_ETHER) {
+		sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev);
+		goto out_unlock;
+	}
+
+	if (!netif_running(odev)) {
+		sprintf(info->result, "Device is down: \"%s\"", info->outdev);
+		goto out_unlock;
+	}
+
+	/* Default to the interface's mac if not explicitly set. */
+	if (!(info->flags & F_SET_SRCMAC)) {
+		memcpy(&(info->hh[6]), odev->dev_addr, 6);
+	}
+	else {
+		memcpy(&(info->hh[6]), info->src_mac, 6);
+	}
+
+	/* Set up Dest MAC */
+	memcpy(&(info->hh[0]), info->dst_mac, 6);
+	
+	info->saddr_min = 0;
+	info->saddr_max = 0;
+	if (strlen(info->src_min) == 0) {
+		if (odev->ip_ptr) {
+			struct in_device *in_dev = odev->ip_ptr;
+
+			if (in_dev->ifa_list) {
+				info->saddr_min = in_dev->ifa_list->ifa_address;
+				info->saddr_max = info->saddr_min;
+			}
+		}
+	}
+	else {
+		info->saddr_min = in_aton(info->src_min);
+		info->saddr_max = in_aton(info->src_max);
+	}
+
+	info->daddr_min = in_aton(info->dst_min);
+	info->daddr_max = in_aton(info->dst_max);
+
+	/* Initialize current values. */
+	info->cur_dst_mac_offset = 0;
+	info->cur_src_mac_offset = 0;
+	info->cur_saddr = info->saddr_min;
+	info->cur_daddr = info->daddr_min;
+	info->cur_udp_dst = info->udp_dst_min;
+	info->cur_udp_src = info->udp_src_min;
+	
+	atomic_inc(&odev->refcnt);
+	rtnl_unlock();
+
+	return odev;
+
+out_unlock:
+	rtnl_unlock();
+	return NULL;
+}
+
+static void nanospin(int ipg, struct pktgen_info* info)
+{
+	u32 idle_start, idle;
+
+	idle_start = cycles();
+
+	for (;;) {
+		barrier();
+		idle = cycles() - idle_start;
+		if (idle * 1000 >= ipg * cpu_speed)
+			break;
+	}
+	info->idle_acc += idle;
+}
+
+static int calc_mhz(void)
+{
+	struct timeval start, stop;
+	u32 start_s, elapsed;
+
+	do_gettimeofday(&start);
+	start_s = cycles();
+	do {
+		barrier();
+		elapsed = cycles() - start_s;
+		if (elapsed == 0)
+			return 0;
+	} while (elapsed < 1000 * 50000);
+	do_gettimeofday(&stop);
+	return elapsed/(stop.tv_usec-start.tv_usec+1000000*(stop.tv_sec-start.tv_sec));
+}
+
+static void cycles_calibrate(void)
+{
+	int i;
+
+	for (i = 0; i < 3; i++) {
+		int res = calc_mhz();
+		if (res > cpu_speed)
+			cpu_speed = res;
+	}
+}
+
+
+/* Increment/randomize headers according to flags and current values
+ * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
+ */
+static void mod_cur_headers(struct pktgen_info* info) {	
+	__u32 imn;
+	__u32 imx;
+	
+	/*  Deal with source MAC */
+	if (info->src_mac_count > 1) {
+		__u32 mc;
+		__u32 tmp;
+		if (info->flags & F_MACSRC_RND) {
+			mc = net_random() % (info->src_mac_count);
+		}
+		else {
+			mc = info->cur_src_mac_offset++;
+			if (info->cur_src_mac_offset > info->src_mac_count) {
+				info->cur_src_mac_offset = 0;
+			}
+		}
+
+		tmp = info->src_mac[5] + (mc & 0xFF);
+		info->hh[11] = tmp;
+		tmp = (info->src_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
+		info->hh[10] = tmp;
+		tmp = (info->src_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
+		info->hh[9] = tmp;
+		tmp = (info->src_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
+		info->hh[8] = tmp;
+		tmp = (info->src_mac[1] + (tmp >> 8));
+		info->hh[7] = tmp;	
+	}
+
+	/*  Deal with Destination MAC */
+	if (info->dst_mac_count > 1) {
+		__u32 mc;
+		__u32 tmp;
+		if (info->flags & F_MACDST_RND) {
+			mc = net_random() % (info->dst_mac_count);
+		}
+		else {
+			mc = info->cur_dst_mac_offset++;
+			if (info->cur_dst_mac_offset > info->dst_mac_count) {
+				info->cur_dst_mac_offset = 0;
+			}
+		}
+
+		tmp = info->dst_mac[5] + (mc & 0xFF);
+		info->hh[5] = tmp;
+		tmp = (info->dst_mac[4] + ((mc >> 8) & 0xFF) + (tmp >> 8));
+		info->hh[4] = tmp;
+		tmp = (info->dst_mac[3] + ((mc >> 16) & 0xFF) + (tmp >> 8));
+		info->hh[3] = tmp;
+		tmp = (info->dst_mac[2] + ((mc >> 24) & 0xFF) + (tmp >> 8));
+		info->hh[2] = tmp;
+		tmp = (info->dst_mac[1] + (tmp >> 8));
+		info->hh[1] = tmp;	
+	}
+
+	if (info->udp_src_min < info->udp_src_max) {
+		if (info->flags & F_UDPSRC_RND) {
+			info->cur_udp_src = ((net_random() % (info->udp_src_max - info->udp_src_min))
+					     + info->udp_src_min);
+		}
+		else {
+		     info->cur_udp_src++;
+		     if (info->cur_udp_src >= info->udp_src_max) {
+			     info->cur_udp_src = info->udp_src_min;
+		     }
+		}
+	}
+
+	if (info->udp_dst_min < info->udp_dst_max) {
+		if (info->flags & F_UDPDST_RND) {
+			info->cur_udp_dst = ((net_random() % (info->udp_dst_max - info->udp_dst_min))
+					     + info->udp_dst_min);
+		}
+		else {
+		     info->cur_udp_dst++;
+		     if (info->cur_udp_dst >= info->udp_dst_max) {
+			     info->cur_udp_dst = info->udp_dst_min;
+		     }
+		}
+	}
+
+	if ((imn = ntohl(info->saddr_min)) < (imx = ntohl(info->saddr_max))) {
+		__u32 t;
+		if (info->flags & F_IPSRC_RND) {
+			t = ((net_random() % (imx - imn)) + imn);
+		}
+		else {
+		     t = ntohl(info->cur_saddr);
+		     t++;
+		     if (t >= imx) {
+			     t = imn;
+		     }
+		}
+		info->cur_saddr = htonl(t);
+	}
+
+	if ((imn = ntohl(info->daddr_min)) < (imx = ntohl(info->daddr_max))) {
+		__u32 t;
+		if (info->flags & F_IPDST_RND) {
+			t = ((net_random() % (imx - imn)) + imn);
+		}
+		else {
+		     t = ntohl(info->cur_daddr);
+		     t++;
+		     if (t >= imx) {
+			     t = imn;
+		     }
+		}
+		info->cur_daddr = htonl(t);
+	}
+}/* mod_cur_headers */
+
+
+static struct sk_buff *fill_packet(struct net_device *odev, struct pktgen_info* info)
+{
+	struct sk_buff *skb = NULL;
+	__u8 *eth;
+	struct udphdr *udph;
+	int datalen, iplen;
+	struct iphdr *iph;
+	struct pktgen_hdr *pgh = NULL;
+	
+	skb = alloc_skb(info->pkt_size + 64 + 16, GFP_ATOMIC);
+	if (!skb) {
+		sprintf(info->result, "No memory");
+		return NULL;
+	}
+
+	skb_reserve(skb, 16);
+
+	/*  Reserve for ethernet and IP header  */
+	eth = (__u8 *) skb_push(skb, 14);
+	iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
+	udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
+
+	/* Update any of the values, used when we're incrementing various
+	 * fields.
+	 */
+	mod_cur_headers(info);
+
+	memcpy(eth, info->hh, 14);
+	
+	datalen = info->pkt_size - 14 - 20 - 8; /* Eth + IPh + UDPh */
+	if (datalen < sizeof(struct pktgen_hdr)) {
+		datalen = sizeof(struct pktgen_hdr);
+	}
+	
+	udph->source = htons(info->cur_udp_src);
+	udph->dest = htons(info->cur_udp_dst);
+	udph->len = htons(datalen + 8); /* DATA + udphdr */
+	udph->check = 0;  /* No checksum */
+
+	iph->ihl = 5;
+	iph->version = 4;
+	iph->ttl = 3;
+	iph->tos = 0;
+	iph->protocol = IPPROTO_UDP; /* UDP */
+	iph->saddr = info->cur_saddr;
+	iph->daddr = info->cur_daddr;
+	iph->frag_off = 0;
+	iplen = 20 + 8 + datalen;
+	iph->tot_len = htons(iplen);
+	iph->check = 0;
+	iph->check = ip_fast_csum((void *) iph, iph->ihl);
+	skb->protocol = __constant_htons(ETH_P_IP);
+	skb->mac.raw = ((u8 *)iph) - 14;
+	skb->dev = odev;
+	skb->pkt_type = PACKET_HOST;
+
+	if (info->nfrags <= 0) {
+		pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
+	} else {
+		int frags = info->nfrags;
+		int i;
+
+		/* TODO: Verify this is OK...it sure is ugly. --Ben */
+		pgh = (struct pktgen_hdr*)(((char*)(udph)) + 8);
+		
+		if (frags > MAX_SKB_FRAGS)
+			frags = MAX_SKB_FRAGS;
+		if (datalen > frags*PAGE_SIZE) {
+			skb_put(skb, datalen-frags*PAGE_SIZE);
+			datalen = frags*PAGE_SIZE;
+		}
+
+		i = 0;
+		while (datalen > 0) {
+			struct page *page = alloc_pages(GFP_KERNEL, 0);
+			skb_shinfo(skb)->frags[i].page = page;
+			skb_shinfo(skb)->frags[i].page_offset = 0;
+			skb_shinfo(skb)->frags[i].size =
+				(datalen < PAGE_SIZE ? datalen : PAGE_SIZE);
+			datalen -= skb_shinfo(skb)->frags[i].size;
+			skb->len += skb_shinfo(skb)->frags[i].size;
+			skb->data_len += skb_shinfo(skb)->frags[i].size;
+			i++;
+			skb_shinfo(skb)->nr_frags = i;
+		}
+
+		while (i < frags) {
+			int rem;
+
+			if (i == 0)
+				break;
+
+			rem = skb_shinfo(skb)->frags[i - 1].size / 2;
+			if (rem == 0)
+				break;
+
+			skb_shinfo(skb)->frags[i - 1].size -= rem;
+
+			skb_shinfo(skb)->frags[i] = skb_shinfo(skb)->frags[i - 1];
+			get_page(skb_shinfo(skb)->frags[i].page);
+			skb_shinfo(skb)->frags[i].page = skb_shinfo(skb)->frags[i - 1].page;
+			skb_shinfo(skb)->frags[i].page_offset += skb_shinfo(skb)->frags[i - 1].size;
+			skb_shinfo(skb)->frags[i].size = rem;
+			i++;
+			skb_shinfo(skb)->nr_frags = i;
+		}
+	}
+
+	/* Stamp the time, and sequence number, convert them to network byte order */
+	if (pgh) {
+		pgh->pgh_magic = htonl(PKTGEN_MAGIC);
+		do_gettimeofday(&(pgh->timestamp));
+		pgh->timestamp.tv_usec = htonl(pgh->timestamp.tv_usec);
+		pgh->timestamp.tv_sec = htonl(pgh->timestamp.tv_sec);
+		pgh->seq_num = htonl(info->seq_num);
+	}
+	
+	return skb;
+}
+
+
+static void inject(struct pktgen_info* info)
+{
+	struct net_device *odev = NULL;
+	struct sk_buff *skb = NULL;
+	__u64 total = 0;
+	__u64 idle = 0;
+	__u64 lcount = 0;
+	int nr_frags = 0;
+	int last_ok = 1;	   /* Was last skb sent? 
+				    * Or a failed transmit of some sort?  This will keep
+				    * sequence numbers in order, for example.
+				    */
+	__u64 fp = 0;
+	__u32 fp_tmp = 0;
+
+	odev = setup_inject(info);
+	if (!odev)
+		return;
+
+	info->do_run_run = 1; /* Cranke yeself! */
+	info->idle_acc = 0;
+	info->sofar = 0;
+	lcount = info->count;
+
+
+	/* Build our initial pkt and place it as a re-try pkt. */
+	skb = fill_packet(odev, info);
+	if (skb == NULL) goto out_reldev;
+
+	do_gettimeofday(&(info->started_at));
+
+	while(info->do_run_run) {
+
+		/* Set a time-stamp, so build a new pkt each time */
+
+		if (last_ok) {
+			if (++fp_tmp >= info->clone_skb ) {
+				kfree_skb(skb);
+				skb = fill_packet(odev, info);
+				if (skb == NULL) {
+					break;
+				}
+				fp++;
+				fp_tmp = 0; /* reset counter */
+			}
+			atomic_inc(&skb->users);
+		}
+
+		nr_frags = skb_shinfo(skb)->nr_frags;
+		   
+		spin_lock_bh(&odev->xmit_lock);
+		if (!netif_queue_stopped(odev)) {
+
+			if (odev->hard_start_xmit(skb, odev)) {
+				if (net_ratelimit()) {
+				   printk(KERN_INFO "Hard xmit error\n");
+				}
+				info->errors++;
+				last_ok = 0;
+			}
+			else {
+			   last_ok = 1;	
+			   info->sofar++;
+			   info->seq_num++;
+			}
+		}
+		else {
+			/* Re-try it next time */
+			last_ok = 0;
+		}
+		
+
+		spin_unlock_bh(&odev->xmit_lock);
+
+		if (info->ipg) {
+			/* Try not to busy-spin if we have larger sleep times.
+			 * TODO:  Investigate better ways to do this.
+			 */
+			if (info->ipg < 10000) { /* 10 usecs or less */
+				nanospin(info->ipg, info);
+			}
+			else if (info->ipg < 10000000) { /* 10ms or less */
+				udelay(info->ipg / 1000);
+			}
+			else {
+				mdelay(info->ipg / 1000000);
+			}
+		}
+		
+		if (signal_pending(current)) {
+			break;
+		}
+
+		/* If lcount is zero, then run forever */
+		if ((lcount != 0) && (--lcount == 0)) {
+			if (atomic_read(&skb->users) != 1) {
+				u32 idle_start, idle;
+
+				idle_start = cycles();
+				while (atomic_read(&skb->users) != 1) {
+					if (signal_pending(current)) {
+						break;
+					}
+					schedule();
+				}
+				idle = cycles() - idle_start;
+				info->idle_acc += idle;
+			}
+			break;
+		}
+
+		if (netif_queue_stopped(odev) || need_resched()) {
+			u32 idle_start, idle;
+
+			idle_start = cycles();
+			do {
+				if (signal_pending(current)) {
+					info->do_run_run = 0;
+					break;
+				}
+				if (!netif_running(odev)) {
+					info->do_run_run = 0;
+					break;
+				}
+				if (need_resched())
+					schedule();
+				else
+					do_softirq();
+			} while (netif_queue_stopped(odev));
+			idle = cycles() - idle_start;
+			info->idle_acc += idle;
+		}
+	}/* while we should be running */
+
+	do_gettimeofday(&(info->stopped_at));
+
+	total = (info->stopped_at.tv_sec - info->started_at.tv_sec) * 1000000 +
+		info->stopped_at.tv_usec - info->started_at.tv_usec;
+
+	idle = (__u32)(info->idle_acc)/(__u32)(cpu_speed);
+
+	{
+		char *p = info->result;
+		__u64 pps = (__u32)(info->sofar * 1000) / ((__u32)(total) / 1000);
+		__u64 bps = pps * 8 * (info->pkt_size + 4); /* take 32bit ethernet CRC into account */
+		p += sprintf(p, "OK: %llu(c%llu+d%llu) usec, %llu (%dbyte,%dfrags) %llupps %lluMb/sec (%llubps)  errors: %llu",
+			     (unsigned long long) total,
+			     (unsigned long long) (total - idle),
+			     (unsigned long long) idle,
+			     (unsigned long long) info->sofar,
+			     skb->len + 4, /* Add 4 to account for the ethernet checksum */
+			     nr_frags,
+			     (unsigned long long) pps,
+			     (unsigned long long) (bps / (u64) 1024 / (u64) 1024),
+			     (unsigned long long) bps,
+			     (unsigned long long) info->errors
+			     );
+	}
+	
+out_reldev:
+	if (odev) {
+		dev_put(odev);
+		odev = NULL;
+	}
+
+	/* TODO:  Is this worth printing out (other than for debug?) */
+	printk("fp = %llu\n", (unsigned long long) fp);
+	return;
+
+}
+
+/* proc/net/pktgen/pg */
+
+static int proc_busy_read(char *buf , char **start, off_t offset,
+			     int len, int *eof, void *data)
+{
+	char *p;
+	int idx = (int)(long)(data);
+	struct pktgen_info* info = NULL;
+	
+	if ((idx < 0) || (idx >= MAX_PKTGEN)) {
+		printk("ERROR: idx: %i is out of range in proc_write\n", idx);
+		return -EINVAL;
+	}
+	info = &(pginfos[idx]);
+  
+	p = buf;
+	p += sprintf(p, "%d\n", info->busy);
+	*eof = 1;
+  
+	return p-buf;
+}
+
+static int proc_read(char *buf , char **start, off_t offset,
+			int len, int *eof, void *data)
+{
+	char *p;
+	int i;
+	int idx = (int)(long)(data);
+	struct pktgen_info* info = NULL;
+	__u64 sa;
+	__u64 stopped;
+	__u64 now = getCurMs();
+	
+	if ((idx < 0) || (idx >= MAX_PKTGEN)) {
+		printk("ERROR: idx: %i is out of range in proc_write\n", idx);
+		return -EINVAL;
+	}
+	info = &(pginfos[idx]);
+  
+	p = buf;
+	p += sprintf(p, "%s\n", VERSION); /* Help with parsing compatibility */
+	p += sprintf(p, "Params: count %llu  pkt_size: %u  frags: %d  ipg: %u  clone_skb: %d odev \"%s\"\n",
+		     (unsigned long long) info->count,
+		     info->pkt_size, info->nfrags, info->ipg,
+		     info->clone_skb, info->outdev);
+	p += sprintf(p, "     dst_min: %s  dst_max: %s  src_min: %s  src_max: %s\n",
+		     info->dst_min, info->dst_max, info->src_min, info->src_max);
+	p += sprintf(p, "     src_mac: ");
+	for (i = 0; i < 6; i++) {
+		p += sprintf(p, "%02X%s", info->src_mac[i], i == 5 ? "  " : ":");
+	}
+	p += sprintf(p, "dst_mac: ");
+	for (i = 0; i < 6; i++) {
+		p += sprintf(p, "%02X%s", info->dst_mac[i], i == 5 ? "\n" : ":");
+	}
+	p += sprintf(p, "     udp_src_min: %d  udp_src_max: %d  udp_dst_min: %d  udp_dst_max: %d\n",
+		     info->udp_src_min, info->udp_src_max, info->udp_dst_min,
+		     info->udp_dst_max);
+	p += sprintf(p, "     src_mac_count: %d  dst_mac_count: %d\n     Flags: ",
+		     info->src_mac_count, info->dst_mac_count);
+	if (info->flags &  F_IPSRC_RND) {
+		p += sprintf(p, "IPSRC_RND  ");
+	}
+	if (info->flags & F_IPDST_RND) {
+		p += sprintf(p, "IPDST_RND  ");
+	}
+	if (info->flags & F_UDPSRC_RND) {
+		p += sprintf(p, "UDPSRC_RND  ");
+	}
+	if (info->flags & F_UDPDST_RND) {
+		p += sprintf(p, "UDPDST_RND  ");
+	}
+	if (info->flags & F_MACSRC_RND) {
+		p += sprintf(p, "MACSRC_RND  ");
+	}
+	if (info->flags & F_MACDST_RND) {
+		p += sprintf(p, "MACDST_RND  ");
+	}
+	p += sprintf(p, "\n");
+	
+	sa = tv_to_ms(&(info->started_at));
+	stopped = tv_to_ms(&(info->stopped_at));
+	if (info->do_run_run) {
+		stopped = now; /* not really stopped, more like last-running-at */
+	}
+	p += sprintf(p, "Current:\n     pkts-sofar: %llu  errors: %llu\n     started: %llums  stopped: %llums  now: %llums  idle: %lluns\n",
+		     (unsigned long long) info->sofar,
+		     (unsigned long long) info->errors,
+		     (unsigned long long) sa,
+		     (unsigned long long) stopped,
+		     (unsigned long long) now,
+		     (unsigned long long) info->idle_acc);
+	p += sprintf(p, "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
+		     info->seq_num, info->cur_dst_mac_offset, info->cur_src_mac_offset);
+	p += sprintf(p, "     cur_saddr: 0x%x  cur_daddr: 0x%x  cur_udp_dst: %d  cur_udp_src: %d\n",
+		     info->cur_saddr, info->cur_daddr, info->cur_udp_dst, info->cur_udp_src);
+	
+	if (info->result[0])
+		p += sprintf(p, "Result: %s\n", info->result);
+	else
+		p += sprintf(p, "Result: Idle\n");
+	*eof = 1;
+
+	return p - buf;
+}
+
+static int count_trail_chars(const char *user_buffer, unsigned int maxlen)
+{
+	int i;
+
+	for (i = 0; i < maxlen; i++) {
+		char c;
+
+		if (get_user(c, &user_buffer[i]))
+			return -EFAULT;
+		switch (c) {
+		case '\"':
+		case '\n':
+		case '\r':
+		case '\t':
+		case ' ':
+		case '=':
+			break;
+		default:
+			goto done;
+		};
+	}
+done:
+	return i;
+}
+
+static unsigned long num_arg(const char *user_buffer, unsigned long maxlen,
+			     unsigned long *num)
+{
+	int i = 0;
+
+	*num = 0;
+  
+	for(; i < maxlen; i++) {
+		char c;
+
+		if (get_user(c, &user_buffer[i]))
+			return -EFAULT;
+		if ((c >= '0') && (c <= '9')) {
+			*num *= 10;
+			*num += c -'0';
+		} else
+			break;
+	}
+	return i;
+}
+
+static int strn_len(const char *user_buffer, unsigned int maxlen)
+{
+	int i = 0;
+
+	for(; i < maxlen; i++) {
+		char c;
+
+		if (get_user(c, &user_buffer[i]))
+			return -EFAULT;
+		switch (c) {
+		case '\"':
+		case '\n':
+		case '\r':
+		case '\t':
+		case ' ':
+			goto done_str;
+		default:
+			break;
+		};
+	}
+done_str:
+	return i;
+}
+
+static int proc_write(struct file *file, const char *user_buffer,
+			 unsigned long count, void *data)
+{
+	int i = 0, max, len;
+	char name[16], valstr[32];
+	unsigned long value = 0;
+	int idx = (int)(long)(data);
+	struct pktgen_info* info = NULL;
+	char* result = NULL;
+	int tmp;
+	
+	if ((idx < 0) || (idx >= MAX_PKTGEN)) {
+		printk("ERROR: idx: %i is out of range in proc_write\n", idx);
+		return -EINVAL;
+	}
+	info = &(pginfos[idx]);
+	result = &(info->result[0]);
+	
+	if (count < 1) {
+		sprintf(result, "Wrong command format");
+		return -EINVAL;
+	}
+  
+	max = count - i;
+	tmp = count_trail_chars(&user_buffer[i], max);
+	if (tmp < 0)
+		return tmp;
+	i += tmp;
+  
+	/* Read variable name */
+
+	len = strn_len(&user_buffer[i], sizeof(name) - 1);
+	if (len < 0)
+		return len;
+	memset(name, 0, sizeof(name));
+	copy_from_user(name, &user_buffer[i], len);
+	i += len;
+  
+	max = count -i;
+	len = count_trail_chars(&user_buffer[i], max);
+	if (len < 0)
+		return len;
+	i += len;
+
+	if (debug)
+		printk("pg: %s,%lu\n", name, count);
+
+	if (!strcmp(name, "stop")) {
+		if (info->do_run_run) {
+			strcpy(result, "Stopping");
+		}
+		else {
+			strcpy(result, "Already stopped...\n");
+		}
+		info->do_run_run = 0;
+		return count;
+	}
+
+	if (!strcmp(name, "pkt_size")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+		if (value < 14+20+8)
+			value = 14+20+8;
+		info->pkt_size = value;
+		sprintf(result, "OK: pkt_size=%u", info->pkt_size);
+		return count;
+	}
+	if (!strcmp(name, "frags")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+		info->nfrags = value;
+		sprintf(result, "OK: frags=%u", info->nfrags);
+		return count;
+	}
+	if (!strcmp(name, "ipg")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+		info->ipg = value;
+		sprintf(result, "OK: ipg=%u", info->ipg);
+		return count;
+	}
+ 	if (!strcmp(name, "udp_src_min")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+	 	info->udp_src_min = value;
+		sprintf(result, "OK: udp_src_min=%u", info->udp_src_min);
+		return count;
+	}
+ 	if (!strcmp(name, "udp_dst_min")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+	 	info->udp_dst_min = value;
+		sprintf(result, "OK: udp_dst_min=%u", info->udp_dst_min);
+		return count;
+	}
+ 	if (!strcmp(name, "udp_src_max")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+	 	info->udp_src_max = value;
+		sprintf(result, "OK: udp_src_max=%u", info->udp_src_max);
+		return count;
+	}
+ 	if (!strcmp(name, "udp_dst_max")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+	 	info->udp_dst_max = value;
+		sprintf(result, "OK: udp_dst_max=%u", info->udp_dst_max);
+		return count;
+	}
+	if (!strcmp(name, "clone_skb")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+		info->clone_skb = value;
+	
+		sprintf(result, "OK: clone_skb=%d", info->clone_skb);
+		return count;
+	}
+	if (!strcmp(name, "count")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+		info->count = value;
+		sprintf(result, "OK: count=%llu", (unsigned long long) info->count);
+		return count;
+	}
+	if (!strcmp(name, "src_mac_count")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+		info->src_mac_count = value;
+		sprintf(result, "OK: src_mac_count=%d", info->src_mac_count);
+		return count;
+	}
+	if (!strcmp(name, "dst_mac_count")) {
+		len = num_arg(&user_buffer[i], 10, &value);
+		if (len < 0)
+			return len;
+		i += len;
+		info->dst_mac_count = value;
+		sprintf(result, "OK: dst_mac_count=%d", info->dst_mac_count);
+		return count;
+	}
+	if (!strcmp(name, "odev")) {
+		len = strn_len(&user_buffer[i], sizeof(info->outdev) - 1);
+		if (len < 0)
+			return len;
+		memset(info->outdev, 0, sizeof(info->outdev));
+		copy_from_user(info->outdev, &user_buffer[i], len);
+		i += len;
+		sprintf(result, "OK: odev=%s", info->outdev);
+		return count;
+	}
+	if (!strcmp(name, "flag")) {
+		char f[32];
+		memset(f, 0, 32);
+		len = strn_len(&user_buffer[i], sizeof(f) - 1);
+		if (len < 0)
+			return len;
+		copy_from_user(f, &user_buffer[i], len);
+		i += len;
+		if (strcmp(f, "IPSRC_RND") == 0) {
+			info->flags |= F_IPSRC_RND;
+		}
+		else if (strcmp(f, "!IPSRC_RND") == 0) {
+			info->flags &= ~F_IPSRC_RND;
+		}
+		else if (strcmp(f, "IPDST_RND") == 0) {
+			info->flags |= F_IPDST_RND;
+		}
+		else if (strcmp(f, "!IPDST_RND") == 0) {
+			info->flags &= ~F_IPDST_RND;
+		}
+		else if (strcmp(f, "UDPSRC_RND") == 0) {
+			info->flags |= F_UDPSRC_RND;
+		}
+		else if (strcmp(f, "!UDPSRC_RND") == 0) {
+			info->flags &= ~F_UDPSRC_RND;
+		}
+		else if (strcmp(f, "UDPDST_RND") == 0) {
+			info->flags |= F_UDPDST_RND;
+		}
+		else if (strcmp(f, "!UDPDST_RND") == 0) {
+			info->flags &= ~F_UDPDST_RND;
+		}
+		else if (strcmp(f, "MACSRC_RND") == 0) {
+			info->flags |= F_MACSRC_RND;
+		}
+		else if (strcmp(f, "!MACSRC_RND") == 0) {
+			info->flags &= ~F_MACSRC_RND;
+		}
+		else if (strcmp(f, "MACDST_RND") == 0) {
+			info->flags |= F_MACDST_RND;
+		}
+		else if (strcmp(f, "!MACDST_RND") == 0) {
+			info->flags &= ~F_MACDST_RND;
+		}
+		else {
+			sprintf(result, "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
+				f,
+				"IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, MACSRC_RND, MACDST_RND\n");
+			return count;
+		}
+		sprintf(result, "OK: flags=0x%x", info->flags);
+		return count;
+	}
+	if (!strcmp(name, "dst_min") || !strcmp(name, "dst")) {
+		len = strn_len(&user_buffer[i], sizeof(info->dst_min) - 1);
+		if (len < 0)
+			return len;
+		memset(info->dst_min, 0, sizeof(info->dst_min));
+		copy_from_user(info->dst_min, &user_buffer[i], len);
+		if(debug)
+			printk("pg: dst_min set to: %s\n", info->dst_min);
+		i += len;
+		sprintf(result, "OK: dst_min=%s", info->dst_min);
+		return count;
+	}
+	if (!strcmp(name, "dst_max")) {
+		len = strn_len(&user_buffer[i], sizeof(info->dst_max) - 1);
+		if (len < 0)
+			return len;
+		memset(info->dst_max, 0, sizeof(info->dst_max));
+		copy_from_user(info->dst_max, &user_buffer[i], len);
+		if(debug)
+			printk("pg: dst_max set to: %s\n", info->dst_max);
+		i += len;
+		sprintf(result, "OK: dst_max=%s", info->dst_max);
+		return count;
+	}
+	if (!strcmp(name, "src_min")) {
+		len = strn_len(&user_buffer[i], sizeof(info->src_min) - 1);
+		if (len < 0)
+			return len;
+		memset(info->src_min, 0, sizeof(info->src_min));
+		copy_from_user(info->src_min, &user_buffer[i], len);
+		if(debug)
+			printk("pg: src_min set to: %s\n", info->src_min);
+		i += len;
+		sprintf(result, "OK: src_min=%s", info->src_min);
+		return count;
+	}
+	if (!strcmp(name, "src_max")) {
+		len = strn_len(&user_buffer[i], sizeof(info->src_max) - 1);
+		if (len < 0)
+			return len;
+		memset(info->src_max, 0, sizeof(info->src_max));
+		copy_from_user(info->src_max, &user_buffer[i], len);
+		if(debug)
+			printk("pg: src_max set to: %s\n", info->src_max);
+		i += len;
+		sprintf(result, "OK: src_max=%s", info->src_max);
+		return count;
+	}
+	if (!strcmp(name, "dstmac")) {
+		char *v = valstr;
+		unsigned char *m = info->dst_mac;
+
+		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
+		if (len < 0)
+			return len;
+		memset(valstr, 0, sizeof(valstr));
+		copy_from_user(valstr, &user_buffer[i], len);
+		i += len;
+
+		for(*m = 0;*v && m < info->dst_mac + 6; v++) {
+			if (*v >= '0' && *v <= '9') {
+				*m *= 16;
+				*m += *v - '0';
+			}
+			if (*v >= 'A' && *v <= 'F') {
+				*m *= 16;
+				*m += *v - 'A' + 10;
+			}
+			if (*v >= 'a' && *v <= 'f') {
+				*m *= 16;
+				*m += *v - 'a' + 10;
+			}
+			if (*v == ':') {
+				m++;
+				*m = 0;
+			}
+		}	  
+		sprintf(result, "OK: dstmac");
+		return count;
+	}
+	if (!strcmp(name, "srcmac")) {
+		char *v = valstr;
+		unsigned char *m = info->src_mac;
+
+		len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
+		if (len < 0)
+			return len;
+		memset(valstr, 0, sizeof(valstr));
+		copy_from_user(valstr, &user_buffer[i], len);
+		i += len;
+
+		for(*m = 0;*v && m < info->src_mac + 6; v++) {
+			if (*v >= '0' && *v <= '9') {
+				*m *= 16;
+				*m += *v - '0';
+			}
+			if (*v >= 'A' && *v <= 'F') {
+				*m *= 16;
+				*m += *v - 'A' + 10;
+			}
+			if (*v >= 'a' && *v <= 'f') {
+				*m *= 16;
+				*m += *v - 'a' + 10;
+			}
+			if (*v == ':') {
+				m++;
+				*m = 0;
+			}
+		}	  
+		sprintf(result, "OK: srcmac");
+		return count;
+	}
+
+	if (!strcmp(name, "inject") || !strcmp(name, "start")) {
+		MOD_INC_USE_COUNT;
+		if (info->busy) {
+			strcpy(info->result, "Already running...\n");
+		}
+		else {
+			info->busy = 1;
+			strcpy(info->result, "Starting");
+			inject(info);
+			info->busy = 0;
+		}
+		MOD_DEC_USE_COUNT;
+		return count;
+	}
+
+	sprintf(info->result, "No such parameter \"%s\"", name);
+	return -EINVAL;
+}
+
+
+int create_proc_dir(void)
+{
+	int     len;
+	/*  does proc_dir already exists */
+	len = strlen(PG_PROC_DIR);
+
+	for (proc_dir = proc_net->subdir; proc_dir;
+	     proc_dir=proc_dir->next) {
+		if ((proc_dir->namelen == len) &&
+		    (! memcmp(proc_dir->name, PG_PROC_DIR, len)))
+			break;
+	}
+	if (!proc_dir)
+		proc_dir = create_proc_entry(PG_PROC_DIR, S_IFDIR, proc_net);
+	if (!proc_dir) return -ENODEV;
+	return 1;
+}
+
+int remove_proc_dir(void)
+{
+	remove_proc_entry(PG_PROC_DIR, proc_net);
+	return 1;
+}
+
+static int __init init(void)
+{
+	int i;
+	printk(version);
+	cycles_calibrate();
+	if (cpu_speed == 0) {
+		printk("pktgen: Error: your machine does not have working cycle counter.\n");
+		return -EINVAL;
+	}
+
+	create_proc_dir();
+
+	for (i = 0; i<MAX_PKTGEN; i++) {
+		memset(&(pginfos[i]), 0, sizeof(pginfos[i]));
+		pginfos[i].pkt_size = ETH_ZLEN;
+		pginfos[i].nfrags = 0;
+		pginfos[i].clone_skb = clone_skb_d;
+		pginfos[i].ipg = ipg_d;
+		pginfos[i].count = count_d;
+		pginfos[i].sofar = 0;
+		pginfos[i].hh[12] = 0x08; /* fill in protocol.  Rest is filled in later. */
+		pginfos[i].hh[13] = 0x00;
+		pginfos[i].udp_src_min = 9; /* sink NULL */
+		pginfos[i].udp_src_max = 9;
+		pginfos[i].udp_dst_min = 9;
+		pginfos[i].udp_dst_max = 9;
+		
+		sprintf(pginfos[i].fname, "net/%s/pg%i", PG_PROC_DIR, i);
+		pginfos[i].proc_ent = create_proc_entry(pginfos[i].fname, 0600, 0);
+		if (!pginfos[i].proc_ent) {
+			printk("pktgen: Error: cannot create net/%s/pg procfs entry.\n", PG_PROC_DIR);
+			goto cleanup_mem;
+		}
+		pginfos[i].proc_ent->read_proc = proc_read;
+		pginfos[i].proc_ent->write_proc = proc_write;
+		pginfos[i].proc_ent->data = (void*)(long)(i);
+
+		sprintf(pginfos[i].busy_fname, "net/%s/pg_busy%i",  PG_PROC_DIR, i);
+		pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, 0);
+		if (!pginfos[i].busy_proc_ent) {
+			printk("pktgen: Error: cannot create net/%s/pg_busy procfs entry.\n", PG_PROC_DIR);
+			goto cleanup_mem;
+		}
+		pginfos[i].busy_proc_ent->read_proc = proc_busy_read;
+		pginfos[i].busy_proc_ent->data = (void*)(long)(i);
+	}
+	return 0;
+	
+cleanup_mem:
+	for (i = 0; i<MAX_PKTGEN; i++) {
+		if (strlen(pginfos[i].fname)) {
+			remove_proc_entry(pginfos[i].fname, NULL);
+		}
+		if (strlen(pginfos[i].busy_fname)) {
+			remove_proc_entry(pginfos[i].busy_fname, NULL);
+		}
+	}
+	return -ENOMEM;
+}
+
+
+static void __exit cleanup(void)
+{
+	int i;
+	for (i = 0; i<MAX_PKTGEN; i++) {
+		if (strlen(pginfos[i].fname)) {
+			remove_proc_entry(pginfos[i].fname, NULL);
+		}
+		if (strlen(pginfos[i].busy_fname)) {
+			remove_proc_entry(pginfos[i].busy_fname, NULL);
+		}
+	}
+	remove_proc_dir();
+}
+
+module_init(init);
+module_exit(cleanup);
+
+MODULE_AUTHOR("Robert Olsson <robert.olsson@its.uu.se");
+MODULE_DESCRIPTION("Packet Generator tool");
+MODULE_LICENSE("GPL");
+MODULE_PARM(count_d, "i");
+MODULE_PARM(ipg_d, "i");
+MODULE_PARM(cpu_speed, "i");
+MODULE_PARM(clone_skb_d, "i");
diff -Nru a/net/core/profile.c b/net/core/profile.c
--- a/net/core/profile.c	Sun Nov 10 19:28:41 2002
+++ b/net/core/profile.c	Sun Nov 10 19:28:41 2002
@@ -34,8 +34,7 @@
 
 static void alpha_tick(unsigned long);
 
-static struct timer_list alpha_timer =
-	{ .function = alpha_tick };
+static struct timer_list alpha_timer = TIMER_INITIALIZER(alpha_tick, 0, 0);
 
 void alpha_tick(unsigned long dummy)
 {
@@ -158,7 +157,7 @@
 int whitehole_init(struct net_device *dev);
 
 static struct timer_list whitehole_timer =
-	{ .function = whitehole_inject };
+		TIMER_INITIALIZER(whitehole_inject, 0, 0);
 
 static struct net_device whitehole_dev = {
 	"whitehole", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, NULL, whitehole_init, };
diff -Nru a/net/decnet/dn_route.c b/net/decnet/dn_route.c
--- a/net/decnet/dn_route.c	Sun Nov 10 19:28:41 2002
+++ b/net/decnet/dn_route.c	Sun Nov 10 19:28:41 2002
@@ -109,7 +109,8 @@
 static unsigned dn_rt_hash_mask;
 
 static struct timer_list dn_route_timer;
-static struct timer_list dn_rt_flush_timer = { .function = dn_run_flush };
+static struct timer_list dn_rt_flush_timer =
+		TIMER_INITIALIZER(dn_run_flush, 0, 0);
 int decnet_dst_gc_interval = 2;
 
 static struct dst_ops dn_dst_ops = {
@@ -1260,6 +1261,7 @@
 	if (!dn_dst_ops.kmem_cachep)
 		panic("DECnet: Failed to allocate dn_dst_cache\n");
 
+	init_timer(&dn_route_timer);
 	dn_route_timer.function = dn_dst_check_expire;
 	dn_route_timer.expires = jiffies + decnet_dst_gc_interval * HZ;
 	add_timer(&dn_route_timer);
diff -Nru a/net/ipv4/Kconfig b/net/ipv4/Kconfig
--- a/net/ipv4/Kconfig	Sun Nov 10 19:28:40 2002
+++ b/net/ipv4/Kconfig	Sun Nov 10 19:28:40 2002
@@ -348,5 +348,19 @@
 
 	  If unsure, say N.
 
+config INET_AH
+	tristate "IP: AH transformation"
+	---help---
+	  Support for IPsec AH.
+
+	  If unsure, say Y.
+
+config INET_ESP
+	tristate "IP: ESP transformation"
+	---help---
+	  Support for IPsec ESP.
+
+	  If unsure, say Y.
+
 source "net/ipv4/netfilter/Kconfig"
 
diff -Nru a/net/ipv4/Makefile b/net/ipv4/Makefile
--- a/net/ipv4/Makefile	Sun Nov 10 19:28:38 2002
+++ b/net/ipv4/Makefile	Sun Nov 10 19:28:38 2002
@@ -16,9 +16,11 @@
 obj-$(CONFIG_NET_IPIP) += ipip.o
 obj-$(CONFIG_NET_IPGRE) += ip_gre.o
 obj-$(CONFIG_SYN_COOKIES) += syncookies.o
+obj-$(CONFIG_INET_AH) += ah.o
+obj-$(CONFIG_INET_ESP) += esp.o
 obj-$(CONFIG_IP_PNP) += ipconfig.o
 obj-$(CONFIG_NETFILTER)	+= netfilter/
 
-obj-y += xfrm_policy.o xfrm_state.o xfrm_input.o ah.o
+obj-y += xfrm_policy.o xfrm_state.o xfrm_input.o
 
 include $(TOPDIR)/Rules.make
diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
--- a/net/ipv4/af_inet.c	Sun Nov 10 19:28:37 2002
+++ b/net/ipv4/af_inet.c	Sun Nov 10 19:28:37 2002
@@ -110,6 +110,7 @@
 #include <net/icmp.h>
 #include <net/ipip.h>
 #include <net/inet_common.h>
+#include <net/xfrm.h>
 #ifdef CONFIG_IP_MROUTE
 #include <linux/mroute.h>
 #endif
@@ -196,6 +197,8 @@
 
 	sock_orphan(sk);
 
+	xfrm_sk_free_policy(sk);
+
 #ifdef INET_REFCNT_DEBUG
 	if (atomic_read(&sk->refcnt) != 1)
 		printk(KERN_DEBUG "Destruction inet %p delayed, c=%d\n",
@@ -722,6 +725,7 @@
 		sin->sin_port = inet->sport;
 		sin->sin_addr.s_addr = addr;
 	}
+	memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
 	*uaddr_len = sizeof(*sin);
 	return 0;
 }
@@ -1038,11 +1042,13 @@
 static struct inet_protocol tcp_protocol = {
 	.handler =	tcp_v4_rcv,
 	.err_handler =	tcp_v4_err,
+	.no_policy =	1,
 };
 
 static struct inet_protocol udp_protocol = {
 	.handler =	udp_rcv,
 	.err_handler =	udp_err,
+	.no_policy =	1,
 };
 
 static struct inet_protocol icmp_protocol = {
diff -Nru a/net/ipv4/ah.c b/net/ipv4/ah.c
--- a/net/ipv4/ah.c	Sun Nov 10 19:28:41 2002
+++ b/net/ipv4/ah.c	Sun Nov 10 19:28:41 2002
@@ -1,15 +1,20 @@
+#include <linux/config.h>
+#include <linux/module.h>
 #include <net/ip.h>
 #include <net/xfrm.h>
 #include <linux/crypto.h>
+#include <linux/pfkeyv2.h>
 #include <net/icmp.h>
+#include <asm/scatterlist.h>
 
 struct ah_data
 {
 	u8			*key;
 	int			key_len;
+	u8			*work_digest;
 	int			digest_len;
 
-	void			(*digest)(struct xfrm_state*,
+	void			(*digest)(struct ah_data*,
 					  struct sk_buff *skb,
 					  u8 *digest);
 
@@ -67,12 +72,19 @@
 	int len = skb->len;
 	int start = skb->len - skb->data_len;
 	int i, copy = start - offset;
+	struct scatterlist sg;
 
 	/* Checksum header. */
 	if (copy > 0) {
 		if (copy > len)
 			copy = len;
-		tfm->__crt_alg->cra_digest.dia_update(tfm->crt_ctx, skb->data+offset, copy);
+		
+		sg.page = virt_to_page(skb->data + offset);
+		sg.offset = (unsigned long)(skb->data + offset) % PAGE_SIZE;
+		sg.length = copy;
+		
+		crypto_hmac_update(tfm, &sg, 1);
+		
 		if ((len -= copy) == 0)
 			return;
 		offset += copy;
@@ -85,14 +97,17 @@
 
 		end = start + skb_shinfo(skb)->frags[i].size;
 		if ((copy = end - offset) > 0) {
-			u8 *vaddr;
 			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
 			if (copy > len)
 				copy = len;
-			vaddr = kmap_skb_frag(frag);
-			tfm->__crt_alg->cra_digest.dia_update(tfm->crt_ctx, vaddr+frag->page_offset+offset-start, copy);
-			kunmap_skb_frag(vaddr);
+			
+			sg.page = frag->page;
+			sg.offset = frag->page_offset + offset-start;
+			sg.length = copy;
+			
+			crypto_hmac_update(tfm, &sg, 1);
+			
 			if (!(len -= copy))
 				return;
 			offset += copy;
@@ -124,6 +139,18 @@
 		BUG();
 }
 
+static void
+ah_hmac_digest(struct ah_data *ahp, struct sk_buff *skb, u8 *auth_data)
+{
+	struct crypto_tfm *tfm = ahp->tfm;
+
+	memset(auth_data, 0, ahp->digest_len);
+ 	crypto_hmac_init(tfm, ahp->key, &ahp->key_len);
+  	skb_ah_walk(skb, tfm);
+	crypto_hmac_final(tfm, ahp->key, &ahp->key_len, ahp->work_digest);
+	memcpy(auth_data, ahp->work_digest, ahp->digest_len);
+}
+
 int ah_output(struct sk_buff *skb)
 {
 	int err;
@@ -149,12 +176,13 @@
 	iph = skb->nh.iph;
 	if (x->props.mode) {
 		top_iph = (struct iphdr*)skb_push(skb, x->props.header_len);
-		top_iph->ihl = 4;
-		top_iph->version = 5;
+		top_iph->ihl = 5;
+		top_iph->version = 4;
 		top_iph->tos = 0;
 		top_iph->tot_len = htons(skb->len);
-		top_iph->id = inet_getid(((struct rtable*)dst)->peer, 0);
 		top_iph->frag_off = 0;
+		if (!(iph->frag_off&htons(IP_DF)))
+			__ip_select_ident(top_iph, dst, 0);
 		top_iph->ttl = 0;
 		top_iph->protocol = IPPROTO_AH;
 		top_iph->check = 0;
@@ -186,7 +214,7 @@
 	ah->reserved = 0;
 	ah->spi = x->id.spi;
 	ah->seq_no = htonl(++x->replay.oseq);
-	ahp->digest(x, skb, ah->auth_data);
+	ahp->digest(ahp, skb, ah->auth_data);
 	top_iph->tos = iph->tos;
 	top_iph->ttl = iph->ttl;
 	if (x->props.mode) {
@@ -202,7 +230,8 @@
 
 	skb->nh.raw = skb->data;
 
-	x->stats.bytes += skb->len;
+	x->curlft.bytes += skb->len;
+	x->curlft.packets++;
 	spin_unlock_bh(&x->lock);
 	if ((skb->dst = dst_pop(dst)) == NULL)
 		goto error;
@@ -258,7 +287,7 @@
 		u8 auth_data[ahp->digest_len];
 		memcpy(auth_data, ah->auth_data, ahp->digest_len);
 		skb_push(skb, skb->data - skb->nh.raw);
-		ahp->digest(x, skb, ah->auth_data);
+		ahp->digest(ahp, skb, ah->auth_data);
 		if (memcmp(ah->auth_data, auth_data, ahp->digest_len)) {
 			x->stats.integrity_failed++;
 			goto out;
@@ -295,16 +324,90 @@
 	xfrm_state_put(x);
 }
 
+int ah_init_state(struct xfrm_state *x, void *args)
+{
+	struct ah_data *ahp = NULL;
+
+	if (x->aalg == NULL || x->aalg->alg_key_len == 0 ||
+	    x->aalg->alg_key_len > 512)
+		goto error;
+
+	ahp = kmalloc(sizeof(*ahp), GFP_KERNEL);
+	if (ahp == NULL)
+		return -ENOMEM;
+
+	memset(ahp, 0, sizeof(*ahp));
+
+	ahp->key = x->aalg->alg_key;
+	ahp->key_len = (x->aalg->alg_key_len+7)/8;
+	ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
+	if (!ahp->tfm)
+		goto error;
+	ahp->digest = ah_hmac_digest;
+	ahp->digest_len = 12;
+	ahp->work_digest = kmalloc(crypto_tfm_alg_digestsize(ahp->tfm),
+				   GFP_KERNEL);
+	if (!ahp->work_digest)
+		goto error;
+	x->props.header_len = (12 + ahp->digest_len + 7)&~7;
+	if (x->props.mode)
+		x->props.header_len += 20;
+	x->data = ahp;
+
+	return 0;
+
+error:
+	if (ahp) {
+		if (ahp->work_digest)
+			kfree(ahp->work_digest);
+		if (ahp->tfm)
+			crypto_free_tfm(ahp->tfm);
+		kfree(ahp);
+	}
+	return -EINVAL;
+}
+
+void ah_destroy(struct xfrm_state *x)
+{
+	struct ah_data *ahp = x->data;
+
+	if (ahp->work_digest) {
+		kfree(ahp->work_digest);
+		ahp->work_digest = NULL;
+	}
+	if (ahp->tfm) {
+		crypto_free_tfm(ahp->tfm);
+		ahp->tfm = NULL;
+	}
+}
+
+
+static struct xfrm_type ah_type =
+{
+	.description	= "AH4",
+	.proto	     	= IPPROTO_AH,
+	.init_state	= ah_init_state,
+	.destructor	= ah_destroy,
+	.input		= ah_input,
+	.output		= ah_output
+};
+
 static struct inet_protocol ah4_protocol = {
 	.handler	=	xfrm4_rcv,
 	.err_handler	=	ah4_err,
+	.no_policy	=	1,
 };
 
-
 int __init ah4_init(void)
 {
+	SET_MODULE_OWNER(&ah_type);
+	if (xfrm_register_type(&ah_type) < 0) {
+		printk(KERN_INFO "ip ah init: can't add xfrm type\n");
+		return -EAGAIN;
+	}
 	if (inet_add_protocol(&ah4_protocol, IPPROTO_AH) < 0) {
 		printk(KERN_INFO "ip ah init: can't add protocol\n");
+		xfrm_unregister_type(&ah_type);
 		return -EAGAIN;
 	}
 	return 0;
@@ -314,4 +417,10 @@
 {
 	if (inet_del_protocol(&ah4_protocol, IPPROTO_AH) < 0)
 		printk(KERN_INFO "ip ah close: can't remove protocol\n");
+	if (xfrm_unregister_type(&ah_type) < 0)
+		printk(KERN_INFO "ip ah close: can't remove xfrm type\n");
 }
+
+module_init(ah4_init);
+module_exit(ah4_fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/devinet.c b/net/ipv4/devinet.c
--- a/net/ipv4/devinet.c	Sun Nov 10 19:28:38 2002
+++ b/net/ipv4/devinet.c	Sun Nov 10 19:28:38 2002
@@ -857,6 +857,8 @@
 				memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
 				inet_insert_ifa(ifa);
 			}
+			in_dev->cnf.no_xfrm = 1;
+			in_dev->cnf.no_policy = 1;
 		}
 		ip_mc_up(in_dev);
 		break;
@@ -1041,7 +1043,7 @@
 
 static struct devinet_sysctl_table {
 	struct ctl_table_header *sysctl_header;
-	ctl_table		devinet_vars[15];
+	ctl_table		devinet_vars[17];
 	ctl_table		devinet_dev[2];
 	ctl_table		devinet_conf_dir[2];
 	ctl_table		devinet_proto_dir[2];
@@ -1156,6 +1158,22 @@
 			.ctl_name =	NET_IPV4_CONF_ARPFILTER,
 			.procname =	"arp_filter",
 			.data =	&ipv4_devconf.arp_filter,
+			.maxlen =		sizeof(int),
+			.mode =	0644,
+			.proc_handler =&proc_dointvec,
+		},
+		{
+			.ctl_name =	NET_IPV4_CONF_NOXFRM,
+			.procname =	"disable_xfrm",
+			.data =	&ipv4_devconf.no_xfrm,
+			.maxlen =		sizeof(int),
+			.mode =	0644,
+			.proc_handler =&proc_dointvec,
+		},
+		{
+			.ctl_name =	NET_IPV4_CONF_NOPOLICY,
+			.procname =	"disable_policy",
+			.data =	&ipv4_devconf.no_policy,
 			.maxlen =		sizeof(int),
 			.mode =	0644,
 			.proc_handler =&proc_dointvec,
diff -Nru a/net/ipv4/esp.c b/net/ipv4/esp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/esp.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,693 @@
+#include <linux/config.h>
+#include <linux/module.h>
+#include <net/ip.h>
+#include <net/xfrm.h>
+#include <asm/scatterlist.h>
+#include <linux/crypto.h>
+#include <linux/pfkeyv2.h>
+#include <linux/random.h>
+#include <net/icmp.h>
+
+#define MAX_SG_ONSTACK 4
+
+/* BUGS:
+ * - we assume replay seqno is always present.
+ */
+
+struct esp_data
+{
+	/* Confidentiality */
+	struct {
+		u8			*key;		/* Key */
+		int			key_len;	/* Key length */
+		u8			*ivec;		/* ivec buffer */
+		/* ivlen is offset from enc_data, where encrypted data start.
+		 * It is logically different of crypto_tfm_alg_ivsize(tfm).
+		 * We assume that it is either zero (no ivec), or
+		 * >= crypto_tfm_alg_ivsize(tfm). */
+		int			ivlen;
+		int			padlen;		/* 0..255 */
+		struct crypto_tfm	*tfm;		/* crypto handle */
+	} conf;
+
+	/* Integrity. It is active when authlen != 0 */
+	struct {
+		u8			*key;		/* Key */
+		int			key_len;	/* Length of the key */
+		u8			*work_digest;
+		/* authlen is length of trailer containing auth token.
+		 * If it is not zero it is assumed to be
+		 * >= crypto_tfm_alg_digestsize(atfm) */
+		int			authlen;
+		void			(*digest)(struct esp_data*,
+						  struct sk_buff *skb,
+						  int offset,
+						  int len,
+						  u8 *digest);
+		struct crypto_tfm	*tfm;
+	} auth;
+};
+
+/* Move to common area: it is shared with AH. */
+
+void skb_digest_walk(const struct sk_buff *skb, struct crypto_tfm *tfm,
+		     int offset, int len)
+{
+	int start = skb->len - skb->data_len;
+	int i, copy = start - offset;
+
+	/* Checksum header. */
+	if (copy > 0) {
+		if (copy > len)
+			copy = len;
+		tfm->__crt_alg->cra_digest.dia_update(tfm->crt_ctx, skb->data+offset, copy);
+		if ((len -= copy) == 0)
+			return;
+		offset += copy;
+	}
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		int end;
+
+		BUG_TRAP(start <= offset + len);
+
+		end = start + skb_shinfo(skb)->frags[i].size;
+		if ((copy = end - offset) > 0) {
+			u8 *vaddr;
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+			if (copy > len)
+				copy = len;
+			vaddr = kmap_skb_frag(frag);
+			tfm->__crt_alg->cra_digest.dia_update(tfm->crt_ctx, vaddr+frag->page_offset+offset-start, copy);
+			kunmap_skb_frag(vaddr);
+			if (!(len -= copy))
+				return;
+			offset += copy;
+		}
+		start = end;
+	}
+
+	if (skb_shinfo(skb)->frag_list) {
+		struct sk_buff *list = skb_shinfo(skb)->frag_list;
+
+		for (; list; list = list->next) {
+			int end;
+
+			BUG_TRAP(start <= offset + len);
+
+			end = start + list->len;
+			if ((copy = end - offset) > 0) {
+				if (copy > len)
+					copy = len;
+				skb_digest_walk(list, tfm, offset-start, copy);
+				if ((len -= copy) == 0)
+					return;
+				offset += copy;
+			}
+			start = end;
+		}
+	}
+	if (len)
+		BUG();
+}
+
+
+/* Looking generic it is not used in another places. */
+
+int
+skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
+{
+	int start = skb->len - skb->data_len;
+	int i, copy = start - offset;
+	int elt = 0;
+
+	if (copy > 0) {
+		if (copy > len)
+			copy = len;
+		sg[elt].page = virt_to_page(skb->data + offset);
+		sg[elt].offset = (unsigned long)(skb->data + offset) % PAGE_SIZE;
+		sg[elt].length = copy;
+		elt++;
+		if ((len -= copy) == 0)
+			return elt;
+		offset += copy;
+	}
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+		int end;
+
+		BUG_TRAP(start <= offset + len);
+
+		end = start + skb_shinfo(skb)->frags[i].size;
+		if ((copy = end - offset) > 0) {
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+			if (copy > len)
+				copy = len;
+			sg[elt].page = frag->page;
+			sg[elt].offset = frag->page_offset+offset-start;
+			sg[elt].length = copy;
+			elt++;
+			if (!(len -= copy))
+				return elt;
+			offset += copy;
+		}
+		start = end;
+	}
+
+	if (skb_shinfo(skb)->frag_list) {
+		struct sk_buff *list = skb_shinfo(skb)->frag_list;
+
+		for (; list; list = list->next) {
+			int end;
+
+			BUG_TRAP(start <= offset + len);
+
+			end = start + list->len;
+			if ((copy = end - offset) > 0) {
+				if (copy > len)
+					copy = len;
+				elt += skb_to_sgvec(list, sg+elt, offset - start, copy);
+				if ((len -= copy) == 0)
+					return elt;
+				offset += copy;
+			}
+			start = end;
+		}
+	}
+	if (len)
+		BUG();
+	return elt;
+}
+
+/* Common with AH after some work on arguments. */
+
+static void
+esp_hmac_digest(struct esp_data *esp, struct sk_buff *skb, int offset,
+		int len, u8 *auth_data)
+{
+	struct crypto_tfm *tfm = esp->auth.tfm;
+	char *digest = esp->auth.work_digest;
+
+	memset(auth_data, 0, esp->auth.authlen);
+ 	crypto_hmac_init(tfm, esp->auth.key, &esp->auth.key_len);
+	skb_digest_walk(skb, tfm, offset, len);
+	crypto_hmac_final(tfm, esp->auth.key, &esp->auth.key_len, digest);
+	memcpy(auth_data, digest, crypto_tfm_alg_digestsize(tfm));
+}
+
+/* Check that skb data bits are writable. If they are not, copy data
+ * to newly created private area. If "tailbits" is given, make sure that
+ * tailbits bytes beyond current end of skb are writable.
+ *
+ * Returns amount of elements of scatterlist to load for subsequent
+ * transformations and pointer to writable trailer skb.
+ */
+
+int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
+{
+	int copyflag;
+	int elt;
+	struct sk_buff *skb1, **skb_p;
+
+	/* If skb is cloned or its head is paged, reallocate
+	 * head pulling out all the pages (pages are considered not writable
+	 * at the moment even if they are anonymous).
+	 */
+	if ((skb_cloned(skb) || skb_shinfo(skb)->nr_frags) &&
+	    __pskb_pull_tail(skb, skb_pagelen(skb)-skb_headlen(skb)) == NULL)
+		return -ENOMEM;
+
+	/* Easy case. Most of packets will go this way. */
+	if (!skb_shinfo(skb)->frag_list) {
+		/* A little of trouble, not enough of space for trailer.
+		 * This should not happen, when stack is tuned to generate
+		 * good frames. OK, on miss we reallocate and reserve even more
+		 * space, 128 bytes is fair. */
+
+		if (skb_tailroom(skb) < tailbits &&
+		    pskb_expand_head(skb, 0, tailbits-skb_tailroom(skb)+128, GFP_ATOMIC))
+			return -ENOMEM;
+
+		/* Voila! */
+		*trailer = skb;
+		return 1;
+	}
+
+	/* Misery. We are in troubles, going to mincer fragments... */
+
+	elt = 1;
+	skb_p = &skb_shinfo(skb)->frag_list;
+	copyflag = 0;
+
+	while ((skb1 = *skb_p) != NULL) {
+		int ntail = 0;
+
+		/* The fragment is partially pulled by someone,
+		 * this can happen on input. Copy it and everything
+		 * after it. */
+
+		if (skb_shared(skb1))
+			copyflag = 1;
+
+		/* If the skb is the last, worry about trailer. */
+
+		if (skb1->next == NULL && tailbits) {
+			if (skb_shinfo(skb1)->nr_frags ||
+			    skb_shinfo(skb1)->frag_list ||
+			    skb_tailroom(skb1) < tailbits)
+				ntail = tailbits + 128;
+		}
+
+		if (copyflag ||
+		    skb_cloned(skb1) ||
+		    ntail ||
+		    skb_shinfo(skb1)->nr_frags ||
+		    skb_shinfo(skb1)->frag_list) {
+			struct sk_buff *skb2;
+
+			/* Fuck, we are miserable poor guys... */
+			if (ntail == 0)
+				skb2 = skb_copy(skb1, GFP_ATOMIC);
+			else
+				skb2 = skb_copy_expand(skb1,
+						       skb_headroom(skb1),
+						       ntail,
+						       GFP_ATOMIC);
+			if (unlikely(skb2 == NULL))
+				return -ENOMEM;
+
+			if (skb1->sk)
+				skb_set_owner_w(skb, skb1->sk);
+
+			/* Looking around. Are we still alive?
+			 * OK, link new skb, drop old one */
+
+			skb2->next = skb1->next;
+			*skb_p = skb2;
+			kfree_skb(skb1);
+			skb1 = skb2;
+		}
+		elt++;
+		*trailer = skb1;
+		skb_p = &skb1->next;
+	}
+
+	return elt;
+}
+
+void *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len)
+{
+	if (tail != skb) {
+		skb->data_len += len;
+		skb->len += len;
+	}
+	return skb_put(tail, len);
+}
+
+int esp_output(struct sk_buff *skb)
+{
+	int err;
+	struct dst_entry *dst = skb->dst;
+	struct xfrm_state *x  = dst->xfrm;
+	struct iphdr *iph, *top_iph;
+	struct ip_esp_hdr *esph;
+	struct crypto_tfm *tfm;
+	struct esp_data *esp;
+	struct sk_buff *trailer;
+	int blksize;
+	int clen;
+	int nfrags;
+	union {
+		struct iphdr	iph;
+		char 		buf[60];
+	} tmp_iph;
+
+	/* First, if the skb is not checksummed, complete checksum. */
+	if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL)
+		return -EINVAL;
+
+	spin_lock_bh(&x->lock);
+	if ((err = xfrm_state_check_expire(x)) != 0)
+		goto error;
+	if ((err = xfrm_state_check_space(x, skb)) != 0)
+		goto error;
+
+	err = -ENOMEM;
+
+	/* Strip IP header in transport mode. Save it. */
+	if (!x->props.mode) {
+		iph = skb->nh.iph;
+		memcpy(&tmp_iph, iph, iph->ihl*4);
+		__skb_pull(skb, iph->ihl*4);
+	}
+	/* Now skb is pure payload to encrypt */
+
+	/* Round to block size */
+	clen = skb->len;
+
+	esp = x->data;
+	tfm = esp->conf.tfm;
+	blksize = crypto_tfm_alg_blocksize(tfm);
+	clen = (clen + 2 + blksize-1)&~(blksize-1);
+	if (esp->conf.padlen)
+		clen = (clen + esp->conf.padlen-1)&~(esp->conf.padlen-1);
+
+	if ((nfrags = skb_cow_data(skb, clen-skb->len+esp->auth.authlen, &trailer)) < 0)
+		goto error;
+
+	/* Fill padding... */
+	do {
+		int i;
+		for (i=0; i<clen-skb->len - 2; i++)
+			*(u8*)(trailer->tail + i) = i+1;
+	} while (0);
+	*(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2;
+	pskb_put(skb, trailer, clen - skb->len);
+
+	iph = skb->nh.iph;
+	if (x->props.mode) {
+		top_iph = (struct iphdr*)skb_push(skb, x->props.header_len);
+		esph = (struct ip_esp_hdr*)(top_iph+1);
+		*(u8*)(trailer->tail - 1) = IPPROTO_IP;
+		top_iph->ihl = 5;
+		top_iph->version = 4;
+		top_iph->tos = iph->tos;	/* DS disclosed */
+		top_iph->tot_len = htons(skb->len + esp->auth.authlen);
+		top_iph->frag_off = iph->frag_off&htons(IP_DF);
+		if (!(top_iph->frag_off))
+			ip_select_ident(top_iph, dst, 0);
+		top_iph->ttl = iph->ttl;	/* TTL disclosed */
+		top_iph->protocol = IPPROTO_ESP;
+		top_iph->check = 0;
+		top_iph->saddr = x->props.saddr.xfrm4_addr;
+		top_iph->daddr = x->id.daddr.xfrm4_addr;
+		memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+	} else {
+		esph = (struct ip_esp_hdr*)skb_push(skb, x->props.header_len);
+		top_iph = (struct iphdr*)skb_push(skb, iph->ihl*4);
+		memcpy(top_iph, &tmp_iph, iph->ihl*4);
+		iph = &tmp_iph.iph;
+		top_iph->tot_len = htons(skb->len + esp->auth.authlen);
+		top_iph->protocol = IPPROTO_ESP;
+		top_iph->check = 0;
+		top_iph->frag_off = iph->frag_off;
+		*(u8*)(trailer->tail - 1) = iph->protocol;
+	}
+
+	esph->spi = x->id.spi;
+	esph->seq_no = htonl(++x->replay.oseq);
+
+	if (esp->conf.ivlen)
+		crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
+
+	do {
+		struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags];
+		struct scatterlist *sg = sgbuf;
+
+		if (unlikely(nfrags > MAX_SG_ONSTACK)) {
+			sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
+			if (!sg)
+				goto error;
+		}
+		skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen);
+		crypto_cipher_encrypt(tfm, sg, nfrags);
+		if (unlikely(sg != sgbuf))
+			kfree(sg);
+	} while (0);
+
+	if (esp->conf.ivlen) {
+		memcpy(esph->enc_data, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
+		crypto_cipher_get_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm));
+	}
+
+	if (esp->auth.authlen) {
+		esp->auth.digest(esp, skb, (u8*)esph-skb->data,
+				 8+esp->conf.ivlen+clen, trailer->tail);
+		pskb_put(skb, trailer, esp->auth.authlen);
+	}
+
+	ip_send_check(top_iph);
+
+	skb->nh.raw = skb->data;
+
+	x->curlft.bytes += skb->len;
+	x->curlft.packets++;
+	spin_unlock_bh(&x->lock);
+	if ((skb->dst = dst_pop(dst)) == NULL)
+		goto error;
+	return NET_XMIT_BYPASS;
+
+error:
+	spin_unlock_bh(&x->lock);
+	kfree_skb(skb);
+	return err;
+}
+
+int esp_input(struct xfrm_state *x, struct sk_buff *skb)
+{
+	struct iphdr *iph;
+	struct ip_esp_hdr *esph;
+	struct esp_data *esp = x->data;
+	struct sk_buff *trailer;
+	int blksize = crypto_tfm_alg_blocksize(esp->conf.tfm);
+	int elen = skb->len - 8 - esp->conf.ivlen - esp->auth.authlen;
+	int nfrags;
+
+	if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr)))
+		goto out;
+
+	if (elen <= 0 || (elen & (blksize-1)))
+		goto out;
+
+	/* If integrity check is required, do this. */
+	if (esp->auth.authlen) {
+		int icvsize = crypto_tfm_alg_digestsize(esp->auth.tfm);
+		u8 sum[icvsize];
+		u8 sum1[icvsize];
+
+		esp->auth.digest(esp, skb, 0, skb->len-esp->auth.authlen, sum);
+
+		if (skb_copy_bits(skb, skb->len-esp->auth.authlen, sum1, icvsize))
+			BUG();
+
+		if (unlikely(memcmp(sum, sum1, icvsize))) {
+			x->stats.integrity_failed++;
+			goto out;
+		}
+	}
+
+	if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0)
+		goto out;
+
+	esph = (struct ip_esp_hdr*)skb->data;
+	iph = skb->nh.iph;
+
+	/* Get ivec. This can be wrong, check against another impls. */
+	if (esp->conf.ivlen)
+		crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm));
+
+        {
+		u8 nexthdr[2];
+		struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags];
+		struct scatterlist *sg = sgbuf;
+		u8 workbuf[60];
+		int padlen;
+
+		if (unlikely(nfrags > MAX_SG_ONSTACK)) {
+			sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC);
+			if (!sg)
+				goto out;
+		}
+		skb_to_sgvec(skb, sg, 8+esp->conf.ivlen, elen);
+		crypto_cipher_decrypt(esp->conf.tfm, sg, nfrags);
+		if (unlikely(sg != sgbuf))
+			kfree(sg);
+
+		if (skb_copy_bits(skb, skb->len-esp->auth.authlen-2,
+				  nexthdr, 2))
+			BUG();
+
+		padlen = nexthdr[0];
+		if (padlen+2 >= elen)
+			goto out;
+
+		/* ... check padding bits here. Silly. :-) */ 
+
+		iph->protocol = nexthdr[1];
+		pskb_trim(skb, skb->len - esp->auth.authlen - padlen - 2);
+		memcpy(workbuf, skb->nh.raw, iph->ihl*4);
+		skb->h.raw = skb_pull(skb, 8 + esp->conf.ivlen);
+		skb->nh.raw += 8 + esp->conf.ivlen;
+		memcpy(skb->nh.raw, workbuf, iph->ihl*4);
+		skb->nh.iph->tot_len = htons(skb->len);
+	}
+
+	return 0;
+
+out:
+	return -EINVAL;
+}
+
+static u32 esp4_get_max_size(struct xfrm_state *x, int mtu)
+{
+	struct esp_data *esp = x->data;
+	u32 blksize = crypto_tfm_alg_blocksize(esp->conf.tfm);
+
+	if (x->props.mode) {
+		mtu = (mtu + 2 + blksize-1)&~(blksize-1);
+	} else {
+		/* The worst case. */
+		mtu += 2 + blksize;
+	}
+	if (esp->conf.padlen)
+		mtu = (mtu + esp->conf.padlen-1)&~(esp->conf.padlen-1);
+
+	return mtu + x->props.header_len + esp->auth.authlen;
+}
+
+void esp4_err(struct sk_buff *skb, u32 info)
+{
+	struct iphdr *iph = (struct iphdr*)skb->data;
+	struct ip_esp_hdr *esph = (struct ip_esp_hdr*)(skb->data+(iph->ihl<<2));
+	struct xfrm_state *x;
+
+	if (skb->h.icmph->type != ICMP_DEST_UNREACH ||
+	    skb->h.icmph->code != ICMP_FRAG_NEEDED)
+		return;
+
+	x = xfrm_state_lookup(iph->daddr, esph->spi, IPPROTO_ESP);
+	if (!x)
+		return;
+	printk(KERN_DEBUG "pmtu discvovery on SA ESP/%08x/%08x\n",
+	       ntohl(esph->spi), ntohl(iph->daddr));
+	xfrm_state_put(x);
+}
+
+void esp_destroy(struct xfrm_state *x)
+{
+	struct esp_data *esp = x->data;
+
+	if (esp->conf.tfm) {
+		crypto_free_tfm(esp->conf.tfm);
+		esp->conf.tfm = NULL;
+	}
+	if (esp->conf.ivec) {
+		kfree(esp->conf.ivec);
+		esp->conf.ivec = NULL;
+	}
+	if (esp->auth.tfm) {
+		crypto_free_tfm(esp->auth.tfm);
+		esp->auth.tfm = NULL;
+	}
+	if (esp->auth.work_digest) {
+		kfree(esp->auth.work_digest);
+		esp->auth.work_digest = NULL;
+	}
+}
+
+int esp_init_state(struct xfrm_state *x, void *args)
+{
+	struct esp_data *esp = NULL;
+
+	if (x->aalg) {
+		if (x->aalg->alg_key_len == 0 || x->aalg->alg_key_len > 512)
+			goto error;
+	}
+	if (x->ealg == NULL || x->ealg->alg_key_len == 0)
+		goto error;
+
+	esp = kmalloc(sizeof(*esp), GFP_KERNEL);
+	if (esp == NULL)
+		return -ENOMEM;
+
+	memset(esp, 0, sizeof(*esp));
+
+	if (x->aalg) {
+		esp->auth.key = x->aalg->alg_key;
+		esp->auth.key_len = (x->aalg->alg_key_len+7)/8;
+		esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
+		if (esp->auth.tfm == NULL)
+			goto error;
+		esp->auth.digest = esp_hmac_digest;
+		esp->auth.authlen = crypto_tfm_alg_digestsize(esp->auth.tfm);
+		esp->auth.work_digest = kmalloc(esp->auth.authlen, GFP_KERNEL);
+		if (!esp->auth.work_digest)
+			goto error;
+	}
+	esp->conf.key = x->ealg->alg_key;
+	esp->conf.key_len = (x->ealg->alg_key_len+7)/8;
+	esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_CBC);
+	if (esp->conf.tfm == NULL)
+		goto error;
+	esp->conf.ivlen = crypto_tfm_alg_ivsize(esp->conf.tfm);
+	esp->conf.padlen = 0;
+	if (esp->conf.ivlen) {
+		esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL);
+		get_random_bytes(esp->conf.ivec, esp->conf.ivlen);
+	}
+	crypto_cipher_setkey(esp->conf.tfm, esp->conf.key, esp->conf.key_len);
+	x->props.header_len = 8 + esp->conf.ivlen;
+	if (x->props.mode)
+		x->props.header_len += 20;
+	x->props.trailer_len = esp->auth.authlen + crypto_tfm_alg_blocksize(esp->conf.tfm);
+	x->data = esp;
+	return 0;
+
+error:
+	if (esp) {
+		if (esp->auth.tfm)
+			crypto_free_tfm(esp->auth.tfm);
+		if (esp->auth.work_digest)
+			kfree(esp->auth.work_digest);
+		if (esp->conf.tfm)
+			crypto_free_tfm(esp->conf.tfm);
+		kfree(esp);
+	}
+	return -EINVAL;
+}
+
+static struct xfrm_type esp_type =
+{
+	.description	= "ESP4",
+	.proto	     	= IPPROTO_ESP,
+	.init_state	= esp_init_state,
+	.destructor	= esp_destroy,
+	.get_max_size	= esp4_get_max_size,
+	.input		= esp_input,
+	.output		= esp_output
+};
+
+static struct inet_protocol esp4_protocol = {
+	.handler	=	xfrm4_rcv,
+	.err_handler	=	esp4_err,
+	.no_policy	=	1,
+};
+
+int __init esp4_init(void)
+{
+	SET_MODULE_OWNER(&esp_type);
+	if (xfrm_register_type(&esp_type) < 0) {
+		printk(KERN_INFO "ip esp init: can't add xfrm type\n");
+		return -EAGAIN;
+	}
+	if (inet_add_protocol(&esp4_protocol, IPPROTO_ESP) < 0) {
+		printk(KERN_INFO "ip esp init: can't add protocol\n");
+		xfrm_unregister_type(&esp_type);
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+static void __exit esp4_fini(void)
+{
+	if (inet_del_protocol(&esp4_protocol, IPPROTO_ESP) < 0)
+		printk(KERN_INFO "ip esp close: can't remove protocol\n");
+	if (xfrm_unregister_type(&esp_type) < 0)
+		printk(KERN_INFO "ip esp close: can't remove xfrm type\n");
+}
+
+module_init(esp4_init);
+module_exit(esp4_fini);
+MODULE_LICENSE("GPL");
diff -Nru a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
--- a/net/ipv4/fib_hash.c	Sun Nov 10 19:28:39 2002
+++ b/net/ipv4/fib_hash.c	Sun Nov 10 19:28:39 2002
@@ -1026,7 +1026,8 @@
 			 "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
 			 fi->fib_dev ? fi->fib_dev->name : "*", prefix,
 			 fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority,
-			 mask, fi->fib_advmss + 40, fi->fib_window,
+			 mask, (fi->fib_advmss ? fi->fib_advmss + 40 : 0),
+			 fi->fib_window,
 			 fi->fib_rtt >> 3);
 	else
 		snprintf(bf, sizeof(bf),
diff -Nru a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c
--- a/net/ipv4/inetpeer.c	Sun Nov 10 19:28:41 2002
+++ b/net/ipv4/inetpeer.c	Sun Nov 10 19:28:41 2002
@@ -98,7 +98,7 @@
 
 static void peer_check_expire(unsigned long dummy);
 static struct timer_list peer_periodic_timer =
-	{ .function = &peer_check_expire };
+	TIMER_INITIALIZER(peer_check_expire, 0, 0);
 
 /* Exported for sysctl_net_ipv4.  */
 int inet_peer_gc_mintime = 10 * HZ,
diff -Nru a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
--- a/net/ipv4/ip_forward.c	Sun Nov 10 19:28:36 2002
+++ b/net/ipv4/ip_forward.c	Sun Nov 10 19:28:36 2002
@@ -60,7 +60,7 @@
 	struct rtable *rt;	/* Route we use */
 	struct ip_options * opt	= &(IPCB(skb)->opt);
 
-	if (!xfrm_policy_check(XFRM_POLICY_FWD, skb))
+	if (!xfrm_policy_check(NULL, XFRM_POLICY_FWD, skb))
 		goto drop;
 
 	if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))
diff -Nru a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
--- a/net/ipv4/ip_gre.c	Sun Nov 10 19:28:40 2002
+++ b/net/ipv4/ip_gre.c	Sun Nov 10 19:28:40 2002
@@ -523,11 +523,11 @@
 
 	/* change mtu on this route */
 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
-		if (rel_info > skb2->dst->pmtu) {
+		if (rel_info > dst_pmtu(skb2->dst)) {
 			kfree_skb(skb2);
 			return;
 		}
-		skb2->dst->pmtu = rel_info;
+		skb2->dst->ops->update_pmtu(skb2->dst, rel_info);
 		rel_info = htonl(rel_info);
 	} else if (type == ICMP_TIME_EXCEEDED) {
 		struct ip_tunnel *t = (struct ip_tunnel*)skb2->dev->priv;
diff -Nru a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
--- a/net/ipv4/ip_input.c	Sun Nov 10 19:28:36 2002
+++ b/net/ipv4/ip_input.c	Sun Nov 10 19:28:36 2002
@@ -223,15 +223,6 @@
 		struct inet_protocol *ipprot;
 
 	resubmit:
-
-		/* Fuck... This IS ugly. */
-		if (protocol != IPPROTO_AH &&
-		    protocol != IPPROTO_ESP &&
-		    !xfrm_policy_check(XFRM_POLICY_IN, skb)) {
-			kfree_skb(skb);
-			return 0;
-		}
-
 		hash = protocol & (MAX_INET_PROTOS - 1);
 		raw_sk = raw_v4_htable[hash];
 
@@ -242,7 +233,14 @@
 			raw_v4_input(skb, skb->nh.iph, hash);
 
 		if ((ipprot = inet_protos[hash]) != NULL) {
-			int ret = ipprot->handler(skb);
+			int ret;
+
+			if (!ipprot->no_policy &&
+			    !xfrm_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+				kfree_skb(skb);
+				return 0;
+			}
+			ret = ipprot->handler(skb);
 			if (ret < 0) {
 				protocol = -ret;
 				goto resubmit;
@@ -250,9 +248,11 @@
 			IP_INC_STATS_BH(IpInDelivers);
 		} else {
 			if (!raw_sk) {
-				IP_INC_STATS_BH(IpInUnknownProtos);
-				icmp_send(skb, ICMP_DEST_UNREACH,
-					  ICMP_PROT_UNREACH, 0);
+				if (xfrm_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+					IP_INC_STATS_BH(IpInUnknownProtos);
+					icmp_send(skb, ICMP_DEST_UNREACH,
+						  ICMP_PROT_UNREACH, 0);
+				}
 			} else
 				IP_INC_STATS_BH(IpInDelivers);
 			kfree_skb(skb);
diff -Nru a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
--- a/net/ipv4/ip_output.c	Sun Nov 10 19:28:41 2002
+++ b/net/ipv4/ip_output.c	Sun Nov 10 19:28:41 2002
@@ -321,7 +321,7 @@
 			 * keep trying until route appears or the connection times
 			 * itself out.
 			 */
-			if (ip_route_output_key(&rt, &fl))
+			if (ip_route_output_flow(&rt, &fl, sk, 0))
 				goto no_route;
 		}
 		__sk_dst_set(sk, &rt->u.dst);
@@ -1220,6 +1220,10 @@
 					      { .daddr = daddr,
 						.saddr = rt->rt_spec_dst,
 						.tos = RT_TOS(skb->nh.iph->tos) } },
+				    /* Not quite clean, but right. */
+				    .uli_u = { .ports =
+					       { .sport = skb->h.th->dest,
+					         .dport = skb->h.th->source } },
 				    .proto = sk->protocol };
 		if (ip_route_output_key(&rt, &fl))
 			return;
diff -Nru a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
--- a/net/ipv4/ip_sockglue.c	Sun Nov 10 19:28:38 2002
+++ b/net/ipv4/ip_sockglue.c	Sun Nov 10 19:28:38 2002
@@ -36,6 +36,7 @@
 #include <linux/route.h>
 #include <linux/mroute.h>
 #include <net/route.h>
+#include <net/xfrm.h>
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 #include <net/transp_v6.h>
 #endif
@@ -624,6 +625,10 @@
 			inet->freebind = !!val; 
 	                break;			
  
+		case IP_IPSEC_POLICY:
+			err = xfrm_user_policy(sk, optname, optval, optlen);
+			break;
+
 		default:
 #ifdef CONFIG_NETFILTER
 			err = nf_setsockopt(sk, PF_INET, optname, optval, 
diff -Nru a/net/ipv4/ipip.c b/net/ipv4/ipip.c
--- a/net/ipv4/ipip.c	Sun Nov 10 19:28:41 2002
+++ b/net/ipv4/ipip.c	Sun Nov 10 19:28:41 2002
@@ -452,11 +452,11 @@
 
 	/* change mtu on this route */
 	if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
-		if (rel_info > skb2->dst->pmtu) {
+		if (rel_info > dst_pmtu(skb2->dst)) {
 			kfree_skb(skb2);
 			return;
 		}
-		skb2->dst->pmtu = rel_info;
+		skb2->dst->ops->update_pmtu(skb2->dst, rel_info);
 		rel_info = htonl(rel_info);
 	} else if (type == ICMP_TIME_EXCEEDED) {
 		struct ip_tunnel *t = (struct ip_tunnel*)skb2->dev->priv;
diff -Nru a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
--- a/net/ipv4/ipmr.c	Sun Nov 10 19:28:39 2002
+++ b/net/ipv4/ipmr.c	Sun Nov 10 19:28:39 2002
@@ -1111,7 +1111,7 @@
 {
 	struct dst_entry *dst = skb->dst;
 
-	if (skb->len <= dst->pmtu)
+	if (skb->len <= dst_pmtu(dst))
 		return dst->output(skb);
 	else
 		return ip_fragment(skb, dst->output);
@@ -1167,7 +1167,7 @@
 
 	dev = rt->u.dst.dev;
 
-	if (skb->len+encap > rt->u.dst.pmtu && (ntohs(iph->frag_off) & IP_DF)) {
+	if (skb->len+encap > dst_pmtu(&rt->u.dst) && (ntohs(iph->frag_off) & IP_DF)) {
 		/* Do not fragment multicasts. Alas, IPv4 does not
 		   allow to send ICMP, so that packets will disappear
 		   to blackhole.
diff -Nru a/net/ipv4/netfilter/ipt_TCPMSS.c b/net/ipv4/netfilter/ipt_TCPMSS.c
--- a/net/ipv4/netfilter/ipt_TCPMSS.c	Sun Nov 10 19:28:40 2002
+++ b/net/ipv4/netfilter/ipt_TCPMSS.c	Sun Nov 10 19:28:40 2002
@@ -85,14 +85,14 @@
 			return NF_DROP; /* or IPT_CONTINUE ?? */
 		}
 
-		if((*pskb)->dst->pmtu <= (sizeof(struct iphdr) + sizeof(struct tcphdr))) {
+		if(dst_pmtu((*pskb)->dst) <= (sizeof(struct iphdr) + sizeof(struct tcphdr))) {
 			if (net_ratelimit())
 				printk(KERN_ERR
-		       			"ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", (*pskb)->dst->pmtu);
+		       			"ipt_tcpmss_target: unknown or invalid path-MTU (%d)\n", dst_pmtu((*pskb)->dst));
 			return NF_DROP; /* or IPT_CONTINUE ?? */
 		}
 
-		newmss = (*pskb)->dst->pmtu - sizeof(struct iphdr) - sizeof(struct tcphdr);
+		newmss = dst_pmtu((*pskb)->dst->pmtu) - sizeof(struct iphdr) - sizeof(struct tcphdr);
 	} else
 		newmss = tcpmssinfo->mss;
 
diff -Nru a/net/ipv4/netfilter/ipt_physdev.c b/net/ipv4/netfilter/ipt_physdev.c
--- a/net/ipv4/netfilter/ipt_physdev.c	Sun Nov 10 19:28:38 2002
+++ b/net/ipv4/netfilter/ipt_physdev.c	Sun Nov 10 19:28:38 2002
@@ -38,8 +38,8 @@
 			& ((const unsigned long *)info->in_mask)[i];
 	}
 
-	if ((ret != 0) ^ !(info->invert & IPT_PHYSDEV_OP_MATCH_IN))
-		return 1;
+	if ((ret == 0) ^ !(info->invert & IPT_PHYSDEV_OP_MATCH_IN))
+		return 0;
 
 	for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
 		ret |= (((const unsigned long *)outdev)[i]
diff -Nru a/net/ipv4/raw.c b/net/ipv4/raw.c
--- a/net/ipv4/raw.c	Sun Nov 10 19:28:36 2002
+++ b/net/ipv4/raw.c	Sun Nov 10 19:28:36 2002
@@ -64,6 +64,7 @@
 #include <net/raw.h>
 #include <net/inet_common.h>
 #include <net/checksum.h>
+#include <net/xfrm.h>
 #include <linux/netfilter_ipv4.h>
 
 struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE];
@@ -237,6 +238,11 @@
 
 int raw_rcv(struct sock *sk, struct sk_buff *skb)
 {
+	if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb)) {
+		kfree_skb(skb);
+		return NET_RX_DROP;
+	}
+
 	skb_push(skb, skb->data - skb->nh.raw);
 
 	raw_rcv_skb(sk, skb);
@@ -424,8 +430,8 @@
 					      { .daddr = daddr,
 						.saddr = saddr,
 						.tos = tos } },
-				    .proto = IPPROTO_RAW };
-		err = ip_route_output_key(&rt, &fl);
+				    .proto = inet->hdrincl ? IPPROTO_RAW : sk->protocol };
+		err = ip_route_output_flow(&rt, &fl, sk, msg->msg_flags&MSG_DONTWAIT);
 	}
 	if (err)
 		goto done;
diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c
--- a/net/ipv4/route.c	Sun Nov 10 19:28:41 2002
+++ b/net/ipv4/route.c	Sun Nov 10 19:28:41 2002
@@ -1265,6 +1265,8 @@
 
 	atomic_set(&rth->u.dst.__refcnt, 1);
 	rth->u.dst.flags= DST_HOST;
+	if (in_dev->cnf.no_policy)
+		rth->u.dst.flags |= DST_NOPOLICY;
 	rth->fl.fl4_dst	= daddr;
 	rth->rt_dst	= daddr;
 	rth->fl.fl4_tos	= tos;
@@ -1470,6 +1472,10 @@
 
 	atomic_set(&rth->u.dst.__refcnt, 1);
 	rth->u.dst.flags= DST_HOST;
+	if (in_dev->cnf.no_policy)
+		rth->u.dst.flags |= DST_NOPOLICY;
+	if (in_dev->cnf.no_xfrm)
+		rth->u.dst.flags |= DST_NOXFRM;
 	rth->fl.fl4_dst	= daddr;
 	rth->rt_dst	= daddr;
 	rth->fl.fl4_tos	= tos;
@@ -1547,6 +1553,8 @@
 
 	atomic_set(&rth->u.dst.__refcnt, 1);
 	rth->u.dst.flags= DST_HOST;
+	if (in_dev->cnf.no_policy)
+		rth->u.dst.flags |= DST_NOPOLICY;
 	rth->fl.fl4_dst	= daddr;
 	rth->rt_dst	= daddr;
 	rth->fl.fl4_tos	= tos;
@@ -1719,6 +1727,7 @@
 	unsigned flags = 0;
 	struct rtable *rth;
 	struct net_device *dev_out = NULL;
+	struct in_device *in_dev = NULL;
 	unsigned hash;
 	int free_res = 0;
 	int err;
@@ -1895,6 +1904,10 @@
 	if (dev_out->flags & IFF_LOOPBACK)
 		flags |= RTCF_LOCAL;
 
+	in_dev = in_dev_get(dev_out);
+	if (!in_dev)
+		goto e_inval;
+
 	if (res.type == RTN_BROADCAST) {
 		flags |= RTCF_BROADCAST | RTCF_LOCAL;
 		if (res.fi) {
@@ -1903,11 +1916,8 @@
 		}
 	} else if (res.type == RTN_MULTICAST) {
 		flags |= RTCF_MULTICAST|RTCF_LOCAL;
-		read_lock(&inetdev_lock);
-		if (!__in_dev_get(dev_out) ||
-		    !ip_check_mc(__in_dev_get(dev_out), oldflp->fl4_dst))
+		if (!ip_check_mc(in_dev, oldflp->fl4_dst))
 			flags &= ~RTCF_LOCAL;
-		read_unlock(&inetdev_lock);
 		/* If multicast route do not exist use
 		   default one, but do not gateway in this case.
 		   Yes, it is hack.
@@ -1924,6 +1934,10 @@
 
 	atomic_set(&rth->u.dst.__refcnt, 1);
 	rth->u.dst.flags= DST_HOST;
+	if (in_dev->cnf.no_xfrm)
+		rth->u.dst.flags |= DST_NOXFRM;
+	if (in_dev->cnf.no_policy)
+		rth->u.dst.flags |= DST_NOPOLICY;
 	rth->fl.fl4_dst	= oldflp->fl4_dst;
 	rth->fl.fl4_tos	= tos;
 	rth->fl.fl4_src	= oldflp->fl4_src;
@@ -1959,20 +1973,17 @@
 		}
 #ifdef CONFIG_IP_MROUTE
 		if (res.type == RTN_MULTICAST) {
-			struct in_device *in_dev = in_dev_get(dev_out);
-			if (in_dev) {
-				if (IN_DEV_MFORWARD(in_dev) &&
-				    !LOCAL_MCAST(oldflp->fl4_dst)) {
-					rth->u.dst.input = ip_mr_input;
-					rth->u.dst.output = ip_mc_output;
-				}
-				in_dev_put(in_dev);
+			if (IN_DEV_MFORWARD(in_dev) &&
+			    !LOCAL_MCAST(oldflp->fl4_dst)) {
+				rth->u.dst.input = ip_mr_input;
+				rth->u.dst.output = ip_mc_output;
 			}
 		}
 #endif
 	}
 
 	rt_set_nexthop(rth, &res, 0);
+	
 
 	rth->rt_flags = flags;
 
@@ -1983,6 +1994,8 @@
 		fib_res_put(&res);
 	if (dev_out)
 		dev_put(dev_out);
+	if (in_dev)
+		in_dev_put(in_dev);
 out:	return err;
 
 e_inval:
@@ -2034,6 +2047,15 @@
 	return flp->proto ? xfrm_lookup((struct dst_entry**)rp, flp, NULL, 0) : 0;
 }
 
+int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags)
+{
+	int err;
+
+	if ((err = __ip_route_output_key(rp, flp)) != 0)
+		return err;
+	return flp->proto ? xfrm_lookup((struct dst_entry**)rp, flp, sk, flags) : 0;
+}
+
 static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
 			int nowait)
 {
@@ -2526,7 +2548,9 @@
 	devinet_init();
 	ip_fib_init();
 
+	init_timer(&rt_flush_timer);
 	rt_flush_timer.function = rt_run_flush;
+	init_timer(&rt_periodic_timer);
 	rt_periodic_timer.function = rt_check_expire;
 
 	/* All the timers, started at system startup tend
diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c
--- a/net/ipv4/tcp.c	Sun Nov 10 19:28:38 2002
+++ b/net/ipv4/tcp.c	Sun Nov 10 19:28:38 2002
@@ -257,6 +257,7 @@
 
 #include <net/icmp.h>
 #include <net/tcp.h>
+#include <net/xfrm.h>
 
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
@@ -1919,6 +1920,8 @@
 	sk->prot->destroy(sk);
 
 	tcp_kill_sk_queues(sk);
+
+	xfrm_sk_free_policy(sk);
 
 #ifdef INET_REFCNT_DEBUG
 	if (atomic_read(&sk->refcnt) != 1) {
diff -Nru a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
--- a/net/ipv4/tcp_input.c	Sun Nov 10 19:28:40 2002
+++ b/net/ipv4/tcp_input.c	Sun Nov 10 19:28:40 2002
@@ -3454,10 +3454,6 @@
 				__set_current_state(TASK_RUNNING);
 
 				if (!tcp_copy_to_iovec(sk, skb, tcp_header_len)) {
-					__skb_pull(skb, tcp_header_len);
-					tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
-					NET_INC_STATS_BH(TCPHPHitsToUser);
-					eaten = 1;
 					/* Predicted packet is in window by definition.
 					 * seq == rcv_nxt and rcv_wup <= rcv_nxt.
 					 * Hence, check seq<=rcv_wup reduces to:
@@ -3467,6 +3463,11 @@
 					     TCPOLEN_TSTAMP_ALIGNED) &&
 					    tp->rcv_nxt == tp->rcv_wup)
 						tcp_store_ts_recent(tp);
+
+					__skb_pull(skb, tcp_header_len);
+					tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq;
+					NET_INC_STATS_BH(TCPHPHitsToUser);
+					eaten = 1;
 				}
 			}
 			if (!eaten) {
diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
--- a/net/ipv4/tcp_ipv4.c	Sun Nov 10 19:28:38 2002
+++ b/net/ipv4/tcp_ipv4.c	Sun Nov 10 19:28:38 2002
@@ -64,11 +64,11 @@
 #include <net/tcp.h>
 #include <net/ipv6.h>
 #include <net/inet_common.h>
+#include <net/xfrm.h>
 
 #include <linux/inet.h>
 #include <linux/ipv6.h>
 #include <linux/stddef.h>
-#include <linux/ipsec.h>
 
 extern int sysctl_ip_dynaddr;
 extern int sysctl_ip_default_ttl;
@@ -1299,7 +1299,7 @@
 				       { .sport = inet_sk(sk)->sport,
 					 .dport = req->rmt_port } } };
 
-	if (ip_route_output_key(&rt, &fl)) {
+	if (ip_route_output_flow(&rt, &fl, sk, 0)) {
 		IP_INC_STATS_BH(IpOutNoRoutes);
 		return NULL;
 	}
@@ -1796,12 +1796,12 @@
 		goto no_tcp_socket;
 
 process:
-	if (!ipsec_sk_policy(sk, skb))
-		goto discard_and_relse;
-
 	if (sk->state == TCP_TIME_WAIT)
 		goto do_time_wait;
 
+	if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb))
+		goto discard_and_relse;
+
 	skb->dev = NULL;
 
 	bh_lock_sock(sk);
@@ -1818,6 +1818,9 @@
 	return ret;
 
 no_tcp_socket:
+	if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb))
+		goto discard_it;
+
 	if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
 bad_packet:
 		TCP_INC_STATS_BH(TcpInErrs);
@@ -1835,6 +1838,9 @@
 	goto discard_it;
 
 do_time_wait:
+	if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb))
+		goto discard_and_relse;
+
 	if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
 		TCP_INC_STATS_BH(TcpInErrs);
 		goto discard_and_relse;
@@ -1950,7 +1956,7 @@
 					       { .sport = inet->sport,
 						 .dport = inet->dport } } };
 						
-		err = ip_route_output_key(&rt, &fl);
+		err = ip_route_output_flow(&rt, &fl, sk, 0);
 	}
 	if (!err) {
 		__sk_dst_set(sk, &rt->u.dst);
diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
--- a/net/ipv4/tcp_minisocks.c	Sun Nov 10 19:28:40 2002
+++ b/net/ipv4/tcp_minisocks.c	Sun Nov 10 19:28:40 2002
@@ -25,6 +25,7 @@
 #include <linux/sysctl.h>
 #include <net/tcp.h>
 #include <net/inet_common.h>
+#include <net/xfrm.h>
 
 #ifdef CONFIG_SYSCTL
 #define SYNC_INIT 0 /* let the user enable it */
@@ -428,7 +429,7 @@
 
 static struct tcp_tw_bucket *tcp_tw_death_row[TCP_TWKILL_SLOTS];
 static spinlock_t tw_death_lock = SPIN_LOCK_UNLOCKED;
-static struct timer_list tcp_tw_timer = { .function = tcp_twkill };
+static struct timer_list tcp_tw_timer = TIMER_INITIALIZER(tcp_twkill, 0, 0);
 
 static void SMP_TIMER_NAME(tcp_twkill)(unsigned long dummy)
 {
@@ -495,7 +496,8 @@
 static int tcp_twcal_hand = -1;
 static int tcp_twcal_jiffie;
 static void tcp_twcal_tick(unsigned long);
-static struct timer_list tcp_twcal_timer = {.function = tcp_twcal_tick};
+static struct timer_list tcp_twcal_timer =
+		TIMER_INITIALIZER(tcp_twcal_tick, 0, 0);
 static struct tcp_tw_bucket *tcp_twcal_row[TCP_TW_RECYCLE_SLOTS];
 
 void tcp_tw_schedule(struct tcp_tw_bucket *tw, int timeo)
@@ -684,6 +686,13 @@
 		if ((filter = newsk->filter) != NULL)
 			sk_filter_charge(newsk, filter);
 #endif
+		if (unlikely(xfrm_sk_clone_policy(newsk))) {
+			/* It is still raw copy of parent, so invalidate
+			 * destructor and make plain sk_free() */
+			newsk->destruct = NULL;
+			sk_free(newsk);
+			return NULL;
+		}
 
 		/* Now setup tcp_opt */
 		newtp = tcp_sk(newsk);
diff -Nru a/net/ipv4/udp.c b/net/ipv4/udp.c
--- a/net/ipv4/udp.c	Sun Nov 10 19:28:37 2002
+++ b/net/ipv4/udp.c	Sun Nov 10 19:28:37 2002
@@ -104,6 +104,7 @@
 #include <net/route.h>
 #include <net/inet_common.h>
 #include <net/checksum.h>
+#include <net/xfrm.h>
 
 /*
  *	Snmp MIB for the UDP layer
@@ -600,7 +601,7 @@
 				    .uli_u = { .ports =
 					       { .sport = inet->sport,
 						 .dport = dport } } };
-		err = ip_route_output_key(&rt, &fl);
+		err = ip_route_output_flow(&rt, &fl, sk, msg->msg_flags&MSG_DONTWAIT);
 		if (err)
 			goto out;
 
@@ -943,6 +944,10 @@
 	/*
 	 *	Charge it to the socket, dropping if the queue is full.
 	 */
+	if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+		kfree_skb(skb);
+		return -1;
+	}
 
 #if defined(CONFIG_FILTER)
 	if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
@@ -1070,6 +1075,9 @@
 		return 0;
 	}
 
+	if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb))
+		goto drop;
+
 	/* No socket. Drop packet silently, if checksum is wrong */
 	if (udp_checksum_complete(skb))
 		goto csum_error;
@@ -1110,6 +1118,7 @@
 			NIPQUAD(daddr),
 			ntohs(uh->dest),
 			ulen));
+drop:
 	UDP_INC_STATS_BH(UdpInErrors);
 	kfree_skb(skb);
 	return(0);
diff -Nru a/net/ipv4/xfrm_input.c b/net/ipv4/xfrm_input.c
--- a/net/ipv4/xfrm_input.c	Sun Nov 10 19:28:36 2002
+++ b/net/ipv4/xfrm_input.c	Sun Nov 10 19:28:36 2002
@@ -81,6 +81,9 @@
 		if (x->props.replay_window)
 			xfrm_replay_advance(x, seq);
 
+		x->curlft.bytes += skb->len;
+		x->curlft.packets++;
+
 		spin_unlock(&x->lock);
 
 		xfrm_vec[xfrm_nr++] = x;
@@ -123,8 +126,10 @@
 	skb->sp->len += xfrm_nr;
 
 	if (decaps) {
-		dst_release(skb->dst);
-		skb->dst = NULL;
+		if (!(skb->dev->flags&IFF_LOOPBACK)) {
+			dst_release(skb->dst);
+			skb->dst = NULL;
+		}
 		netif_rx(skb);
 		return 0;
 	} else {
diff -Nru a/net/ipv4/xfrm_policy.c b/net/ipv4/xfrm_policy.c
--- a/net/ipv4/xfrm_policy.c	Sun Nov 10 19:28:40 2002
+++ b/net/ipv4/xfrm_policy.c	Sun Nov 10 19:28:40 2002
@@ -155,16 +155,63 @@
 	memset(flow_table, 0, PAGE_SIZE<<order);
 }
 
+static struct xfrm_type *xfrm_type_map[256];
+static rwlock_t xfrm_type_lock = RW_LOCK_UNLOCKED;
+
+int xfrm_register_type(struct xfrm_type *type)
+{
+	int err = 0;
+
+	write_lock(&xfrm_type_lock);
+	if (xfrm_type_map[type->proto] == NULL)
+		xfrm_type_map[type->proto] = type;
+	else
+		err = -EEXIST;
+	write_unlock(&xfrm_type_lock);
+	return err;
+}
+
+int xfrm_unregister_type(struct xfrm_type *type)
+{
+	int err = 0;
+
+	write_lock(&xfrm_type_lock);
+	if (xfrm_type_map[type->proto] != type)
+		err = -ENOENT;
+	else
+		xfrm_type_map[type->proto] = NULL;
+	write_unlock(&xfrm_type_lock);
+	return err;
+}
+
+struct xfrm_type *xfrm_get_type(u8 proto)
+{
+	struct xfrm_type *type;
+
+	read_lock(&xfrm_type_lock);
+	type = xfrm_type_map[proto];
+	if (type && !try_inc_mod_count(type->owner))
+		type = NULL;
+	read_unlock(&xfrm_type_lock);
+	return type;
+}
+
+void xfrm_put_type(struct xfrm_type *type)
+{
+	if (type->owner)
+		__MOD_DEC_USE_COUNT(type->owner);
+}
+
 
 /* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2
  * SPD calls.
  */
 
-struct xfrm_policy *xfrm_policy_alloc(void)
+struct xfrm_policy *xfrm_policy_alloc(int gfp)
 {
 	struct xfrm_policy *policy;
 
-	policy = kmalloc(sizeof(struct xfrm_policy), GFP_KERNEL);
+	policy = kmalloc(sizeof(struct xfrm_policy), gfp);
 
 	if (policy) {
 		memset(policy, 0, sizeof(struct xfrm_policy));
@@ -178,16 +225,9 @@
 
 void __xfrm_policy_destroy(struct xfrm_policy *policy)
 {
-	int i;
-
 	if (!policy->dead)
 		BUG();
 
-	for (i=0; i<policy->xfrm_nr; i++) {
-		if (policy->xfrm_vec[i].resolved)
-			BUG();
-	}
-
 	if (policy->bundles)
 		BUG();
 
@@ -201,21 +241,161 @@
 void xfrm_policy_kill(struct xfrm_policy *policy)
 {
 	struct dst_entry *dst;
-	int i;
 
-	policy->dead = 1;
+	write_lock_bh(&policy->lock);
+	if (policy->dead)
+		goto out;
 
-	for (i=0; i<policy->xfrm_nr; i++) {
-		if (policy->xfrm_vec[i].resolved) {
-			xfrm_state_put(policy->xfrm_vec[i].resolved);
-			policy->xfrm_vec[i].resolved = NULL;
-		}
-	}
+	policy->dead = 1;
 
 	while ((dst = policy->bundles) != NULL) {
 		policy->bundles = dst->next;
 		dst_free(dst);
 	}
+
+out:
+	write_unlock_bh(&policy->lock);
+}
+
+/* Generate new index... KAME seems to generate them ordered by cost
+ * of an absolute inpredictability of ordering of rules. This will not pass. */
+static u32 xfrm_gen_index(int dir)
+{
+	u32 idx;
+	struct xfrm_policy *p;
+	static u32 pol_id;
+
+	for (;;) {
+		idx = (++pol_id ? : ++pol_id);
+		for (p = xfrm_policy_list[dir]; p; p = p->next) {
+			if (p->index == idx)
+				break;
+		}
+		if (!p)
+			return idx;
+	}
+}
+
+int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
+{
+	struct xfrm_policy *pol, **p;
+
+	write_lock_bh(&xfrm_policy_lock);
+	for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) {
+		if (memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0) {
+			if (excl) {
+				write_unlock_bh(&xfrm_policy_lock);
+				return -EEXIST;
+			}
+			break;
+		}
+	}
+	atomic_inc(&policy->refcnt);
+	policy->next = pol ? pol->next : NULL;
+	*p = policy;
+	xfrm_policy_genid++;
+	policy->index = pol ? pol->index : xfrm_gen_index(dir);
+	policy->curlft.add_time = (unsigned long)xtime.tv_sec;
+	policy->curlft.use_time = 0;
+	write_unlock_bh(&xfrm_policy_lock);
+
+	if (pol) {
+		xfrm_policy_kill(pol);
+		xfrm_pol_put(pol);
+	}
+	return 0;
+}
+
+struct xfrm_policy *xfrm_policy_delete(int dir, struct xfrm_selector *sel)
+{
+	struct xfrm_policy *pol, **p;
+
+	write_lock_bh(&xfrm_policy_lock);
+	for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) {
+		if (memcmp(sel, &pol->selector, sizeof(*sel)) == 0) {
+			*p = pol->next;
+			break;
+		}
+	}
+	if (pol)
+		xfrm_policy_genid++;
+	write_unlock_bh(&xfrm_policy_lock);
+	return pol;
+}
+
+struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete)
+{
+	struct xfrm_policy *pol, **p;
+
+	write_lock_bh(&xfrm_policy_lock);
+	for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) {
+		if (pol->index == id) {
+			if (delete)
+				*p = pol->next;
+			break;
+		}
+	}
+	if (pol) {
+		if (delete)
+			xfrm_policy_genid++;
+		else
+			atomic_inc(&pol->refcnt);
+	}
+	write_unlock_bh(&xfrm_policy_lock);
+	return pol;
+}
+
+void xfrm_policy_flush()
+{
+	struct xfrm_policy *xp;
+	int dir;
+
+	write_lock_bh(&xfrm_policy_lock);
+	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
+		while ((xp = xfrm_policy_list[dir]) != NULL) {
+			xfrm_policy_list[dir] = xp->next;
+			write_unlock_bh(&xfrm_policy_lock);
+
+			xfrm_policy_kill(xp);
+			xfrm_pol_put(xp);
+
+			write_lock_bh(&xfrm_policy_lock);
+		}
+	}
+	xfrm_policy_genid++;
+	write_unlock_bh(&xfrm_policy_lock);
+}
+
+int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*),
+		     void *data)
+{
+	struct xfrm_policy *xp;
+	int dir;
+	int count = 0;
+	int error = 0;
+
+	read_lock(&xfrm_policy_lock);
+	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
+		for (xp = xfrm_policy_list[dir]; xp; xp = xp->next)
+			count++;
+	}
+
+	if (count == 0) {
+		error = -ENOENT;
+		goto out;
+	}
+
+	for (dir = 0; dir < XFRM_POLICY_MAX; dir++) {
+		for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) {
+			error = func(xp, dir, --count, data);
+			if (error)
+				goto out;
+		}
+	}
+
+out:
+	read_unlock(&xfrm_policy_lock);
+	return error;
 }
 
 
@@ -224,14 +404,12 @@
 struct xfrm_policy *xfrm_policy_lookup(int dir, struct flowi *fl)
 {
 	struct xfrm_policy *pol;
-	unsigned long now = xtime.tv_sec;
 
 	read_lock(&xfrm_policy_lock);
 	for (pol = xfrm_policy_list[dir]; pol; pol = pol->next) {
 		struct xfrm_selector *sel = &pol->selector;
 
-		if (xfrm4_selector_match(sel, fl) && now < pol->expires) {
-			pol->lastuse = now;
+		if (xfrm4_selector_match(sel, fl)) {
 			atomic_inc(&pol->refcnt);
 			break;
 		}
@@ -240,48 +418,120 @@
 	return pol;
 }
 
+struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl)
+{
+	struct xfrm_policy *pol;
+
+	read_lock(&xfrm_policy_lock);
+	for (pol = sk->policy[dir]; pol; pol = pol->next) {
+		struct xfrm_selector *sel = &pol->selector;
+
+		if (xfrm4_selector_match(sel, fl)) {
+			atomic_inc(&pol->refcnt);
+			break;
+		}
+	}
+	read_unlock(&xfrm_policy_lock);
+	return pol;
+}
+
+int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
+{
+	struct xfrm_policy *old_pol;
+
+	write_lock_bh(&xfrm_policy_lock);
+	old_pol = sk->policy[dir];
+	sk->policy[dir] = pol;
+	write_unlock_bh(&xfrm_policy_lock);
+
+	if (old_pol) {
+		xfrm_policy_kill(old_pol);
+		xfrm_pol_put(old_pol);
+	}
+	return 0;
+}
+
+static struct xfrm_policy *clone_policy(struct xfrm_policy *old)
+{
+	struct xfrm_policy *newp = xfrm_policy_alloc(GFP_ATOMIC);
+
+	if (newp) {
+		newp->selector = old->selector;
+		newp->lft = old->lft;
+		newp->curlft = old->curlft;
+		newp->action = old->action;
+		newp->flags = old->flags;
+		newp->xfrm_nr = old->xfrm_nr;
+		memcpy(newp->xfrm_vec, old->xfrm_vec,
+		       newp->xfrm_nr*sizeof(struct xfrm_tmpl));
+	}
+	return newp;
+}
+
+int __xfrm_sk_clone_policy(struct sock *sk)
+{
+	struct xfrm_policy *p0, *p1;
+	p0 = sk->policy[0];
+	p1 = sk->policy[1];
+	sk->policy[0] = NULL;
+	sk->policy[1] = NULL;
+	if (p0 && (sk->policy[0] = clone_policy(p0)) == NULL)
+		return -ENOMEM;
+	if (p1 && (sk->policy[1] = clone_policy(p1)) == NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+void __xfrm_sk_free_policy(struct xfrm_policy *pol)
+{
+	xfrm_policy_kill(pol);
+	xfrm_pol_put(pol);
+}
+
 /* Resolve list of templates for the flow, given policy. */
 
 static int
 xfrm_tmpl_resolve(struct xfrm_policy *policy, struct flowi *fl,
 		  struct xfrm_state **xfrm)
 {
+	int nx;
 	int i, error;
 	u32 daddr = fl->fl4_dst;
+	u32 saddr = fl->fl4_src;
 
-	for (i = 0; i < policy->xfrm_nr; i++) {
+	for (nx=0, i = 0; i < policy->xfrm_nr; i++) {
+		struct xfrm_state *x;
+		u32 remote = daddr;
+		u32 local = saddr;
 		struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i];
-		if (tmpl->mode)
-			daddr = tmpl->id.daddr.xfrm4_addr;
-		if (tmpl->resolved) {
-			if (tmpl->resolved->km.state != XFRM_STATE_VALID) {
-				error = -EINVAL;
-				goto fail;
-			}
-			xfrm[i] = tmpl->resolved;
-			atomic_inc(&tmpl->resolved->refcnt);
-		} else {
-			xfrm[i] = xfrm_state_find(daddr, fl, tmpl);
-			if (xfrm[i] == NULL) {
-				error = -ENOMEM;
-				goto fail;
-			}
-			if (xfrm[i]->km.state == XFRM_STATE_VALID)
-				continue;
 
-			i++;
-			if (xfrm[i]->km.state == XFRM_STATE_ERROR)
-				error = -EINVAL;
-			else
-				error = -EAGAIN;
-			goto fail;
+		if (tmpl->mode) {
+			remote = tmpl->id.daddr.xfrm4_addr;
+			local = tmpl->saddr.xfrm4_addr;
 		}
+
+		x = xfrm_state_find(remote, local, fl, tmpl, policy, &error);
+
+		if (x && x->km.state == XFRM_STATE_VALID) {
+			xfrm[nx++] = x;
+			daddr = remote;
+			saddr = local;
+			continue;
+		}
+		if (x) {
+			error = (x->km.state == XFRM_STATE_ERROR ?
+				 -EINVAL : -EAGAIN);
+			xfrm_state_put(x);
+		}
+
+		if (!tmpl->optional)
+			goto fail;
 	}
-	return 0;
+	return nx;
 
 fail:
-	for (i--; i>=0; i--)
-		xfrm_state_put(xfrm[i]);
+	for (nx--; nx>=0; nx--)
+		xfrm_state_put(xfrm[nx]);
 	return error;
 }
 
@@ -310,12 +560,13 @@
  * all the metrics... Shortly, bundle a bundle.
  */
 
-int
-xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm,
+static int
+xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int nx,
 		   struct flowi *fl, struct dst_entry **dst_p)
 {
 	struct dst_entry *dst, *dst_prev;
-	struct rtable *rt = (struct rtable*)(*dst_p);
+	struct rtable *rt0 = (struct rtable*)(*dst_p);
+	struct rtable *rt = rt0;
 	u32 remote = fl->fl4_dst;
 	u32 local  = fl->fl4_src;
 	int i;
@@ -324,7 +575,7 @@
 
 	dst = dst_prev = NULL;
 
-	for (i = 0; i < policy->xfrm_nr; i++) {
+	for (i = 0; i < nx; i++) {
 		struct dst_entry *dst1 = dst_alloc(&xfrm4_dst_ops);
 
 		if (unlikely(dst1 == NULL)) {
@@ -335,8 +586,11 @@
 		dst1->xfrm = xfrm[i];
 		if (!dst)
 			dst = dst1;
-		else
+		else {
 			dst_prev->child = dst1;
+			dst1->flags |= DST_NOHASH;
+			dst_clone(dst1);
+		}
 		dst_prev = dst1;
 		if (xfrm[i]->props.mode) {
 			remote = xfrm[i]->id.daddr.xfrm4_addr;
@@ -351,11 +605,11 @@
 						       .saddr = local }
 					           }
 				         };
-		err = ip_route_output_key(&rt, &fl_tunnel);
+		err = __ip_route_output_key(&rt, &fl_tunnel);
 		if (err)
 			goto error;
-		dst_release(*dst_p);
-		*dst_p = &rt->u.dst;
+	} else {
+		dst_clone(&rt->u.dst);
 	}
 	dst_prev->child = &rt->u.dst;
 	for (dst_prev = dst; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
@@ -365,10 +619,11 @@
 		dst_prev->dev = rt->u.dst.dev;
 		if (rt->u.dst.dev)
 			dev_hold(rt->u.dst.dev);
-		dst_prev->flags		= DST_HOST;
+		dst_prev->obsolete	= -1;
+		dst_prev->flags	       |= DST_HOST;
 		dst_prev->lastuse	= jiffies;
 		dst_prev->header_len	= header_len;
-		memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(&dst_prev->metrics));
+		memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics));
 		dst_prev->path		= &rt->u.dst;
 
 		/* Copy neighbout for reachability confirmation */
@@ -378,13 +633,14 @@
 		if (rt->peer)
 			atomic_inc(&rt->peer->refcnt);
 		x->u.rt.peer = rt->peer;
-		x->u.rt.rt_flags = rt->rt_flags;
+		/* Sheit... I remember I did this right. Apparently,
+		 * it was magically lost, so this code needs audit */
+		x->u.rt.rt_flags = rt0->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);
 		x->u.rt.rt_type = rt->rt_type;
-		x->u.rt.rt_src = rt->rt_src;
-		x->u.rt.rt_src = rt->rt_src;
-		x->u.rt.rt_dst = rt->rt_dst;
+		x->u.rt.rt_src = rt0->rt_src;
+		x->u.rt.rt_dst = rt0->rt_dst;
 		x->u.rt.rt_gateway = rt->rt_gateway;
-		x->u.rt.rt_spec_dst = rt->rt_spec_dst;
+		x->u.rt.rt_spec_dst = rt0->rt_spec_dst;
 		header_len -= x->u.dst.xfrm->props.header_len;
 	}
 	*dst_p = dst;
@@ -408,21 +664,31 @@
 	struct xfrm_state *xfrm[XFRM_MAX_DEPTH];
 	struct rtable *rt = (struct rtable*)*dst_p;
 	struct dst_entry *dst;
+	int nx = 0;
 	int err;
 	u32 genid;
 
-	/* To accelerate a bit...  */
-	if ((rt->u.dst.flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT])
-		return 0;
-
 	fl->oif = rt->u.dst.dev->ifindex;
 	fl->fl4_src = rt->rt_src;
 
 restart:
 	genid = xfrm_policy_genid;
-	policy = flow_lookup(XFRM_POLICY_OUT, fl);
-	if (!policy)
-		return 0;
+	policy = NULL;
+	if (sk && sk->policy[1])
+		policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
+
+	if (!policy) {
+		/* To accelerate a bit...  */
+		if ((rt->u.dst.flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT])
+			return 0;
+
+		policy = flow_lookup(XFRM_POLICY_OUT, fl);
+		if (!policy)
+			return 0;
+	}
+
+	if (!policy->curlft.use_time)
+		policy->curlft.use_time = (unsigned long)xtime.tv_sec;
 
 	switch (policy->action) {
 	case XFRM_POLICY_BLOCK:
@@ -458,8 +724,9 @@
 		if (dst)
 			break;
 
-		err = xfrm_tmpl_resolve(policy, fl, xfrm);
-		if (unlikely(err)) {
+		nx = xfrm_tmpl_resolve(policy, fl, xfrm);
+		if (unlikely(nx<0)) {
+			err = nx;
 			if (err == -EAGAIN) {
 				struct task_struct *tsk = current;
 				DECLARE_WAITQUEUE(wait, tsk);
@@ -484,15 +751,18 @@
 			}
 			if (err)
 				goto error;
+		} else if (nx == 0) {
+			/* Flow passes not transformed. */
+			xfrm_pol_put(policy);
+			return 0;
 		}
 
 		dst = &rt->u.dst;
-		err = xfrm_bundle_create(policy, xfrm, fl, &dst);
+		err = xfrm_bundle_create(policy, xfrm, nx, fl, &dst);
 		if (unlikely(err)) {
 			int i;
-			for (i=0; i<policy->xfrm_nr; i++)
+			for (i=0; i<nx; i++)
 				xfrm_state_put(xfrm[i]);
-			err = -EPERM;
 			goto error;
 		}
 
@@ -505,14 +775,13 @@
 			write_unlock_bh(&policy->lock);
 
 			xfrm_pol_put(policy);
-			if (dst) {
-				dst_release(dst);
+			if (dst)
 				dst_free(dst);
-			}
 			goto restart;
 		}
 		dst->next = policy->bundles;
 		policy->bundles = dst;
+		dst_clone(dst);
 		write_unlock_bh(&policy->lock);
 	}
 	*dst_p = dst;
@@ -539,7 +808,7 @@
 	return	x->id.proto == tmpl->id.proto &&
 		(x->id.spi == tmpl->id.spi || !tmpl->id.spi) &&
 		x->props.mode == tmpl->mode &&
-		(tmpl->algos & (1<<x->props.algo)) &&
+		(tmpl->aalgos & (1<<x->props.aalgo)) &&
 		(!x->props.mode || !tmpl->saddr.xfrm4_addr ||
 		 tmpl->saddr.xfrm4_addr == x->props.saddr.xfrm4_addr);
 }
@@ -601,7 +870,7 @@
 	fl->fl4_src = iph->saddr;
 }
 
-int __xfrm_policy_check(int dir, struct sk_buff *skb)
+int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb)
 {
 	struct xfrm_policy *pol;
 	struct flowi fl;
@@ -611,17 +880,25 @@
 	/* First, check used SA against their selectors. */
 	if (skb->sp) {
 		int i;
-		for (i=skb->sp->len-1; i>=0; i++) {
+		for (i=skb->sp->len-1; i>=0; i--) {
 			if (!xfrm4_selector_match(&skb->sp->xvec[i]->sel, &fl))
 				return 0;
 		}
 	}
 
-	pol = flow_lookup(dir, &fl);
+	pol = NULL;
+	if (sk && sk->policy[dir])
+		pol =xfrm_sk_policy_lookup(sk, dir, &fl);
+
+	if (!pol)
+		pol = flow_lookup(dir, &fl);
 
 	if (!pol)
 		return 1;
 
+	if (!pol->curlft.use_time)
+		pol->curlft.use_time = (unsigned long)xtime.tv_sec;
+
 	if (pol->action == XFRM_POLICY_ALLOW) {
 		if (pol->xfrm_nr != 0) {
 			struct sec_path *sp;
@@ -659,10 +936,22 @@
 	return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0;
 }
 
+/* Optimize later using cookies and generation ids. */
+
 static struct dst_entry *xfrm4_dst_check(struct dst_entry *dst, u32 cookie)
 {
-	dst_release(dst);
-	return NULL;
+	struct dst_entry *child = dst;
+
+	while (child) {
+		if (child->obsolete > 0 ||
+		    (child->xfrm && child->xfrm->km.state != XFRM_STATE_VALID)) {
+			dst_release(dst);
+			return NULL;
+		}
+		child = child->child;
+	}
+
+	return dst;
 }
 
 static void xfrm4_dst_destroy(struct dst_entry *dst)
@@ -717,12 +1006,56 @@
 	while (gc_list) {
 		dst = gc_list;
 		gc_list = dst->next;
-		dst_destroy(dst);
+		dst_free(dst);
 	}
 
 	return (atomic_read(&xfrm4_dst_ops.entries) > xfrm4_dst_ops.gc_thresh*2);
 }
 
+static int bundle_depends_on(struct dst_entry *dst, struct xfrm_state *x)
+{
+	do {
+		if (dst->xfrm == x)
+			return 1;
+	} while ((dst = dst->child) != NULL);
+	return 0;
+}
+
+int xfrm_flush_bundles(struct xfrm_state *x)
+{
+	int i;
+	struct xfrm_policy *pol;
+	struct dst_entry *dst, **dstp, *gc_list = NULL;
+
+	read_lock_bh(&xfrm_policy_lock);
+	for (i=0; i<XFRM_POLICY_MAX; i++) {
+		for (pol = xfrm_policy_list[i]; pol; pol = pol->next) {
+			write_lock(&pol->lock);
+			dstp = &pol->bundles;
+			while ((dst=*dstp) != NULL) {
+				if (bundle_depends_on(dst, x)) {
+					*dstp = dst->next;
+					dst->next = gc_list;
+					gc_list = dst;
+				} else {
+					dstp = &dst->next;
+				}
+			}
+			write_unlock(&pol->lock);
+		}
+	}
+	read_unlock_bh(&xfrm_policy_lock);
+
+	while (gc_list) {
+		dst = gc_list;
+		gc_list = dst->next;
+		dst_free(dst);
+	}
+
+	return 0;
+}
+
+
 static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu)
 {
 	struct dst_entry *path = dst->path;
@@ -753,10 +1086,13 @@
 		do {
 			struct xfrm_state *x = d->xfrm;
 			if (x) {
-				if (x->type->get_max_size)
+				spin_lock_bh(&x->lock);
+				if (x->km.state == XFRM_STATE_VALID &&
+				    x->type && x->type->get_max_size)
 					m = x->type->get_max_size(d->xfrm, m);
 				else
 					m += x->props.header_len;
+				spin_unlock_bh(&x->lock);
 			}
 		} while ((d = d->child) != NULL);
 
@@ -798,5 +1134,4 @@
 
 	xfrm_state_init();
 	xfrm_input_init();
-	ah4_init();
 }
diff -Nru a/net/ipv4/xfrm_state.c b/net/ipv4/xfrm_state.c
--- a/net/ipv4/xfrm_state.c	Sun Nov 10 19:28:40 2002
+++ b/net/ipv4/xfrm_state.c	Sun Nov 10 19:28:40 2002
@@ -1,19 +1,17 @@
 #include <net/xfrm.h>
 #include <linux/pfkeyv2.h>
+#include <linux/ipsec.h>
 
-/* Each xfrm_state is linked to three tables:
+/* Each xfrm_state may be linked to two tables:
 
    1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl)
    2. Hash table by daddr to find what SAs exist for given
       destination/tunnel endpoint. (output)
-   3. (optional, NI) Radix tree by _selector_ for the case,
-      when we have to find a tunnel mode SA appropriate for given flow,
-      but do not know tunnel endpoint. At the moment we do
-      not support this and assume that tunnel endpoint is given
-      by policy. (output)
  */
 
-spinlock_t xfrm_state_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t xfrm_state_lock = SPIN_LOCK_UNLOCKED;
+
+#define XFRM_DST_HSIZE		1024
 
 /* Hash table to find appropriate SA towards given target (endpoint
  * of tunnel or destination of transport mode) allowed by selector.
@@ -21,11 +19,87 @@
  * Main use is finding SA after policy selected tunnel or transport mode.
  * Also, it can be used by ah/esp icmp error handler to find offending SA.
  */
-struct list_head xfrm_state_bydst[XFRM_DST_HSIZE];
-struct list_head xfrm_state_byspi[XFRM_DST_HSIZE];
+static struct list_head xfrm_state_bydst[XFRM_DST_HSIZE];
+static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE];
 
 wait_queue_head_t *km_waitq;
 
+#define ACQ_EXPIRES 30
+
+static void __xfrm_state_delete(struct xfrm_state *x);
+
+unsigned long make_jiffies(long secs)
+{
+	if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
+		return MAX_SCHEDULE_TIMEOUT-1;
+	else
+	        return secs*HZ;
+}
+
+static void xfrm_timer_handler(unsigned long data)
+{
+	struct xfrm_state *x = (struct xfrm_state*)data;
+	unsigned long now = (unsigned long)xtime.tv_sec;
+	long next = LONG_MAX;
+	int warn = 0;
+
+	spin_lock(&x->lock);
+	if (x->km.state == XFRM_STATE_DEAD)
+		goto out;
+	if (x->km.state == XFRM_STATE_EXPIRED)
+		goto expired;
+	if (x->lft.hard_add_expires_seconds) {
+		long tmo = x->lft.hard_add_expires_seconds +
+			x->curlft.add_time - now;
+		if (tmo <= 0)
+			goto expired;
+		if (tmo < next)
+			next = tmo;
+	}
+	if (x->lft.hard_use_expires_seconds && x->curlft.use_time) {
+		long tmo = x->lft.hard_use_expires_seconds +
+			x->curlft.use_time - now;
+		if (tmo <= 0)
+			goto expired;
+		if (tmo < next)
+			next = tmo;
+	}
+	if (x->km.dying)
+		goto resched;
+	if (x->lft.soft_add_expires_seconds) {
+		long tmo = x->lft.soft_add_expires_seconds +
+			x->curlft.add_time - now;
+		if (tmo <= 0)
+			warn = 1;
+		else if (tmo < next)
+			next = tmo;
+	}
+	if (x->lft.soft_use_expires_seconds && x->curlft.use_time) {
+		long tmo = x->lft.soft_use_expires_seconds +
+			x->curlft.use_time - now;
+		if (tmo <= 0)
+			warn = 1;
+		else if (tmo < next)
+			next = tmo;
+	}
+
+	if (warn)
+		km_warn_expired(x);
+resched:
+	if (next != LONG_MAX &&
+	    !mod_timer(&x->timer, jiffies + make_jiffies(next)))
+		atomic_inc(&x->refcnt);
+	goto out;
+
+expired:
+	km_expired(x);
+	__xfrm_state_delete(x);
+
+out:
+	spin_unlock(&x->lock);
+	xfrm_state_put(x);
+}
+
 struct xfrm_state *xfrm_state_alloc(void)
 {
 	struct xfrm_state *x;
@@ -37,6 +111,14 @@
 		atomic_set(&x->refcnt, 1);
 		INIT_LIST_HEAD(&x->bydst);
 		INIT_LIST_HEAD(&x->byspi);
+		init_timer(&x->timer);
+		x->timer.function = xfrm_timer_handler;
+		x->timer.data	  = (unsigned long)x;
+		x->curlft.add_time = (unsigned long)xtime.tv_sec;
+		x->lft.soft_byte_limit = XFRM_INF;
+		x->lft.soft_packet_limit = XFRM_INF;
+		x->lft.hard_byte_limit = XFRM_INF;
+		x->lft.hard_packet_limit = XFRM_INF;
 		x->lock = SPIN_LOCK_UNLOCKED;
 	}
 	return x;
@@ -45,24 +127,93 @@
 void __xfrm_state_destroy(struct xfrm_state *x)
 {
 	BUG_TRAP(x->km.state == XFRM_STATE_DEAD);
+	if (del_timer(&x->timer))
+		BUG();
+	if (x->aalg)
+		kfree(x->aalg);
+	if (x->ealg)
+		kfree(x->ealg);
+	if (x->calg)
+		kfree(x->calg);
 	if (x->type)
-		x->type->destructor(x);
+		xfrm_put_type(x->type);
 	kfree(x);
 }
 
+static void __xfrm_state_delete(struct xfrm_state *x)
+{
+	int kill = 0;
+
+	if (x->km.state != XFRM_STATE_DEAD) {
+		x->km.state = XFRM_STATE_DEAD;
+		kill = 1;
+		spin_lock(&xfrm_state_lock);
+		list_del(&x->bydst);
+		atomic_dec(&x->refcnt);
+		if (x->id.spi) {
+			list_del(&x->byspi);
+			atomic_dec(&x->refcnt);
+		}
+		spin_unlock(&xfrm_state_lock);
+		if (del_timer(&x->timer))
+			atomic_dec(&x->refcnt);
+		if (atomic_read(&x->refcnt) != 1)
+			xfrm_flush_bundles(x);
+	}
+
+	if (kill && x->type)
+		x->type->destructor(x);
+	wake_up(km_waitq);
+}
+
+void xfrm_state_delete(struct xfrm_state *x)
+{
+	spin_lock_bh(&x->lock);
+	__xfrm_state_delete(x);
+	spin_unlock_bh(&x->lock);
+}
+
+void xfrm_state_flush(u8 proto)
+{
+	int i;
+	struct xfrm_state *x;
+
+	spin_lock_bh(&xfrm_state_lock);
+	for (i = 0; i < XFRM_DST_HSIZE; i++) {
+restart:
+		list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
+			if (proto == IPSEC_PROTO_ANY || x->id.proto == proto) {
+				atomic_inc(&x->refcnt);
+				spin_unlock_bh(&xfrm_state_lock);
+
+				xfrm_state_delete(x);
+				xfrm_state_put(x);
+
+				spin_lock_bh(&xfrm_state_lock);
+				goto restart;
+			}
+		}
+	}
+	spin_unlock_bh(&xfrm_state_lock);
+	wake_up(km_waitq);
+}
+
 struct xfrm_state *
-xfrm_state_find(u32 daddr, struct flowi *fl, struct xfrm_tmpl *tmpl)
+xfrm_state_find(u32 daddr, u32 saddr, struct flowi *fl, struct xfrm_tmpl *tmpl,
+		struct xfrm_policy *pol, int *err)
 {
 	unsigned h = ntohl(daddr);
 	struct xfrm_state *x;
 	int acquire_in_progress = 0;
 	int error = 0;
+	struct xfrm_state *best = NULL;
 
 	h = (h ^ (h>>16)) % XFRM_DST_HSIZE;
 
 	spin_lock_bh(&xfrm_state_lock);
 	list_for_each_entry(x, xfrm_state_bydst+h, bydst) {
 		if (daddr == x->id.daddr.xfrm4_addr &&
+		    (saddr == x->props.saddr.xfrm4_addr || !saddr || !x->props.saddr.xfrm4_addr) &&
 		    tmpl->mode == x->props.mode &&
 		    tmpl->id.proto == x->id.proto) {
 			/* Resolution logic:
@@ -81,18 +232,27 @@
 			if (x->km.state == XFRM_STATE_VALID) {
 				if (!xfrm4_selector_match(&x->sel, fl))
 					continue;
-				atomic_inc(&x->refcnt);
-				spin_unlock_bh(&xfrm_state_lock);
-				return x;
+				if (!best ||
+				    best->km.dying > x->km.dying ||
+				    (best->km.dying == x->km.dying &&
+				     best->curlft.add_time < x->curlft.add_time))
+					best = x;
 			} else if (x->km.state == XFRM_STATE_ACQ) {
 				acquire_in_progress = 1;
-			} else if (x->km.state == XFRM_STATE_ERROR) {
+			} else if (x->km.state == XFRM_STATE_ERROR ||
+				   x->km.state == XFRM_STATE_EXPIRED) {
 				if (xfrm4_selector_match(&x->sel, fl))
 					error = 1;
 			}
 		}
 	}
 
+	if (best) {
+		atomic_inc(&best->refcnt);
+		spin_unlock_bh(&xfrm_state_lock);
+		return best;
+	}
+
 	x = NULL;
 	if (!error && !acquire_in_progress &&
 	    ((x = xfrm_state_alloc()) != NULL)) {
@@ -112,10 +272,26 @@
 		x->sel.proto = fl->proto;
 		x->sel.ifindex = fl->oif;
 		x->id = tmpl->id;
+		if (x->id.daddr.xfrm4_addr == 0)
+			x->id.daddr.xfrm4_addr = daddr;
+		x->props.saddr = tmpl->saddr;
+		if (x->props.saddr.xfrm4_addr == 0)
+			x->props.saddr.xfrm4_addr = saddr;
+		x->props.mode = tmpl->mode;
 
-		if (km_query(x) == 0) {
+		if (km_query(x, tmpl, pol) == 0) {
+			x->km.state = XFRM_STATE_ACQ;
 			list_add_tail(&x->bydst, xfrm_state_bydst+h);
 			atomic_inc(&x->refcnt);
+			if (x->id.spi) {
+				h = ntohl(x->id.daddr.xfrm4_addr^x->id.spi^x->id.proto);
+				h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE;
+				list_add(&x->byspi, xfrm_state_byspi+h);
+				atomic_inc(&x->refcnt);
+			}
+			x->lft.hard_add_expires_seconds = ACQ_EXPIRES;
+			atomic_inc(&x->refcnt);
+			mod_timer(&x->timer, ACQ_EXPIRES*HZ);
 		} else {
 			x->km.state = XFRM_STATE_DEAD;
 			xfrm_state_put(x);
@@ -123,6 +299,8 @@
 		}
 	}
 	spin_unlock_bh(&xfrm_state_lock);
+	if (!x)
+		*err = acquire_in_progress ? -EAGAIN : -ENOMEM;
 	return x;
 }
 
@@ -141,25 +319,33 @@
 	list_add(&x->byspi, xfrm_state_byspi+h);
 	atomic_inc(&x->refcnt);
 
+	if (!mod_timer(&x->timer, jiffies + HZ))
+		atomic_inc(&x->refcnt);
+
 	spin_unlock_bh(&xfrm_state_lock);
+	wake_up(km_waitq);
 }
 
 int xfrm_state_check_expire(struct xfrm_state *x)
 {
+	if (!x->curlft.use_time)
+		x->curlft.use_time = (unsigned long)xtime.tv_sec;
+
 	if (x->km.state != XFRM_STATE_VALID)
 		return -EINVAL;
 
-	if (x->props.hard_byte_limit &&
-	    x->stats.bytes >= x->props.hard_byte_limit) {
-		km_notify(x, SADB_EXT_LIFETIME_HARD);
+	if (x->curlft.bytes >= x->lft.hard_byte_limit ||
+	    x->curlft.packets >= x->lft.hard_packet_limit) {
+		km_expired(x);
+		if (!mod_timer(&x->timer, jiffies + ACQ_EXPIRES*HZ))
+			atomic_inc(&x->refcnt);
 		return -EINVAL;
 	}
 
-	if (x->km.warn_bytes &&
-	    x->stats.bytes >= x->km.warn_bytes) {
-		x->km.warn_bytes = 0;
-		km_notify(x, SADB_EXT_LIFETIME_SOFT);
-	}
+	if (!x->km.dying &&
+	    (x->curlft.bytes >= x->lft.soft_byte_limit ||
+	     x->curlft.packets >= x->lft.soft_packet_limit))
+		km_warn_expired(x);
 	return 0;
 }
 
@@ -189,7 +375,6 @@
 		    daddr == x->id.daddr.xfrm4_addr &&
 		    proto == x->id.proto) {
 			atomic_inc(&x->refcnt);
-			x->stats.lastuse = xtime.tv_sec;
 			spin_unlock_bh(&xfrm_state_lock);
 			return x;
 		}
@@ -198,6 +383,153 @@
 	return NULL;
 }
 
+struct xfrm_state *
+xfrm_find_acq(u8 mode, u16 reqid, u8 proto, u32 daddr, u32 saddr)
+{
+	struct xfrm_state *x, *x0;
+	unsigned h = ntohl(daddr);
+
+	h = (h ^ (h>>16)) % XFRM_DST_HSIZE;
+	x0 = NULL;
+
+	spin_lock_bh(&xfrm_state_lock);
+	list_for_each_entry(x, xfrm_state_bydst+h, bydst) {
+		if (daddr == x->id.daddr.xfrm4_addr &&
+		    mode == x->props.mode &&
+		    proto == x->id.proto &&
+		    saddr == x->props.saddr.xfrm4_addr &&
+		    (!reqid || reqid == x->props.reqid)) {
+			    if (!x0)
+				    x0 = x;
+			    if (x->km.state != XFRM_STATE_ACQ)
+				    continue;
+			    x0 = x;
+			    break;
+		    }
+	}
+	if (x0) {
+		atomic_inc(&x0->refcnt);
+	} else if ((x0 = xfrm_state_alloc()) != NULL) {
+		x0->sel.daddr.xfrm4_addr = daddr;
+		x0->sel.daddr.xfrm4_mask = ~0;
+		x0->sel.saddr.xfrm4_addr = saddr;
+		x0->sel.saddr.xfrm4_mask = ~0;
+		x0->sel.prefixlen_d = 32;
+		x0->sel.prefixlen_s = 32;
+		x0->props.saddr.xfrm4_addr = saddr;
+		x0->km.state = XFRM_STATE_ACQ;
+		x0->id.daddr.xfrm4_addr = daddr;
+		x0->id.proto = proto;
+		x0->props.mode = mode;
+		x0->props.reqid = reqid;
+		x0->lft.hard_add_expires_seconds = ACQ_EXPIRES;
+		atomic_inc(&x0->refcnt);
+		mod_timer(&x0->timer, jiffies + ACQ_EXPIRES*HZ);
+		atomic_inc(&x0->refcnt);
+		list_add_tail(&x0->bydst, xfrm_state_bydst+h);
+		wake_up(km_waitq);
+	}
+	spin_unlock_bh(&xfrm_state_lock);
+	return x0;
+}
+
+/* Silly enough, but I'm lazy to build resolution list */
+
+struct xfrm_state * xfrm_find_acq_byseq(u32 seq)
+{
+	int i;
+	struct xfrm_state *x;
+
+	spin_lock_bh(&xfrm_state_lock);
+	for (i = 0; i < XFRM_DST_HSIZE; i++) {
+		list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
+			if (x->km.seq == seq) {
+				atomic_inc(&x->refcnt);
+				spin_unlock_bh(&xfrm_state_lock);
+				return x;
+			}
+		}
+	}
+	spin_unlock_bh(&xfrm_state_lock);
+	return NULL;
+}
+
+
+void
+xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi)
+{
+	u32 h;
+	struct xfrm_state *x0;
+
+	if (x->id.spi)
+		return;
+
+	if (minspi == maxspi) {
+		x0 = xfrm_state_lookup(x->id.daddr.xfrm4_addr, minspi, x->id.proto);
+		if (x0) {
+			xfrm_state_put(x0);
+			return;
+		}
+		x->id.spi = minspi;
+	} else {
+		u32 spi = 0;
+		minspi = ntohl(minspi);
+		maxspi = ntohl(maxspi);
+		for (h=0; h<maxspi-minspi+1; h++) {
+			spi = minspi + net_random()%(maxspi-minspi+1);
+			x0 = xfrm_state_lookup(x->id.daddr.xfrm4_addr, htonl(spi), x->id.proto);
+			if (x0 == NULL)
+				break;
+			xfrm_state_put(x0);
+		}
+		x->id.spi = htonl(spi);
+	}
+	if (x->id.spi) {
+		spin_lock_bh(&xfrm_state_lock);
+		h = ntohl(x->id.daddr.xfrm4_addr^x->id.spi^x->id.proto);
+		h = (h ^ (h>>10) ^ (h>>20)) % XFRM_DST_HSIZE;
+		list_add(&x->byspi, xfrm_state_byspi+h);
+		atomic_inc(&x->refcnt);
+		spin_unlock_bh(&xfrm_state_lock);
+		wake_up(km_waitq);
+	}
+}
+
+int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*),
+		    void *data)
+{
+	int i;
+	struct xfrm_state *x;
+	int count = 0;
+	int err = 0;
+
+	spin_lock_bh(&xfrm_state_lock);
+	for (i = 0; i < XFRM_DST_HSIZE; i++) {
+		list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
+			if (proto == IPSEC_PROTO_ANY || x->id.proto == proto)
+				count++;
+		}
+	}
+	if (count == 0) {
+		err = -ENOENT;
+		goto out;
+	}
+
+	for (i = 0; i < XFRM_DST_HSIZE; i++) {
+		list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
+			if (proto != IPSEC_PROTO_ANY && x->id.proto != proto)
+				continue;
+			err = func(x, --count, data);
+			if (err)
+				goto out;
+		}
+	}
+out:
+	spin_unlock_bh(&xfrm_state_lock);
+	return err;
+}
+
+
 int xfrm_replay_check(struct xfrm_state *x, u32 seq)
 {
 	u32 diff;
@@ -253,13 +585,98 @@
 	return 0;
 }
 
-void km_notify(struct xfrm_state *x, int event)
+static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);
+static rwlock_t		xfrm_km_lock = RW_LOCK_UNLOCKED;
+
+void km_warn_expired(struct xfrm_state *x)
+{
+	struct xfrm_mgr *km;
+
+	x->km.dying = 1;
+	read_lock(&xfrm_km_lock);
+	list_for_each_entry(km, &xfrm_km_list, list)
+		km->notify(x, 0);
+	read_unlock(&xfrm_km_lock);
+}
+
+void km_expired(struct xfrm_state *x)
+{
+	struct xfrm_mgr *km;
+
+	x->km.state = XFRM_STATE_EXPIRED;
+
+	read_lock(&xfrm_km_lock);
+	list_for_each_entry(km, &xfrm_km_list, list)
+		km->notify(x, 1);
+	read_unlock(&xfrm_km_lock);
+}
+
+int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
+{
+	int err = -EINVAL;
+	struct xfrm_mgr *km;
+
+	read_lock(&xfrm_km_lock);
+	list_for_each_entry(km, &xfrm_km_list, list) {
+		err = km->acquire(x, t, pol, XFRM_POLICY_OUT);
+		if (!err)
+			break;
+	}
+	read_unlock(&xfrm_km_lock);
+	return err;
+}
+
+int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen)
+{
+	int err;
+	u8 *data;
+	struct xfrm_mgr *km;
+	struct xfrm_policy *pol = NULL;
+
+	if (optlen <= 0 || optlen > PAGE_SIZE)
+		return -EMSGSIZE;
+
+	data = kmalloc(optlen, GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	err = -EFAULT;
+	if (copy_from_user(data, optval, optlen))
+		goto out;
+
+	err = -EINVAL;
+	read_lock(&xfrm_km_lock);
+	list_for_each_entry(km, &xfrm_km_list, list) {
+		pol = km->compile_policy(optname, data, optlen, &err);
+		if (err >= 0)
+			break;
+	}
+	read_unlock(&xfrm_km_lock);
+
+	if (err >= 0) {
+		xfrm_sk_policy_insert(sk, err, pol);
+		err = 0;
+	}
+
+out:
+	kfree(data);
+	return err;
+}
+
+int xfrm_register_km(struct xfrm_mgr *km)
 {
+	write_lock_bh(&xfrm_km_lock);
+	list_add_tail(&km->list, &xfrm_km_list);
+	write_unlock_bh(&xfrm_km_lock);
+	return 0;
 }
 
-int km_query(struct xfrm_state *x)
+int xfrm_unregister_km(struct xfrm_mgr *km)
 {
-	return -EINVAL;
+	write_lock_bh(&xfrm_km_lock);
+	list_del(&km->list);
+	write_unlock_bh(&xfrm_km_lock);
+	return 0;
 }
 
 void __init xfrm_state_init(void)
diff -Nru a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
--- a/net/ipv6/addrconf.c	Sun Nov 10 19:28:41 2002
+++ b/net/ipv6/addrconf.c	Sun Nov 10 19:28:41 2002
@@ -94,7 +94,8 @@
 
 static void addrconf_verify(unsigned long);
 
-static struct timer_list addr_chk_timer = { .function = addrconf_verify };
+static struct timer_list addr_chk_timer =
+			TIMER_INITIALIZER(addrconf_verify, 0, 0);
 static spinlock_t addrconf_verify_lock = SPIN_LOCK_UNLOCKED;
 
 static int addrconf_ifdown(struct net_device *dev, int how);
diff -Nru a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
--- a/net/ipv6/ip6_fib.c	Sun Nov 10 19:28:40 2002
+++ b/net/ipv6/ip6_fib.c	Sun Nov 10 19:28:40 2002
@@ -93,7 +93,7 @@
 
 static __u32	rt_sernum	= 0;
 
-static struct timer_list ip6_fib_timer = { .function = fib6_run_gc };
+static struct timer_list ip6_fib_timer = TIMER_INITIALIZER(fib6_run_gc, 0, 0);
 
 static struct fib6_walker_t fib6_walker_list = {
 	&fib6_walker_list, &fib6_walker_list, 
diff -Nru a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
--- a/net/ipv6/reassembly.c	Sun Nov 10 19:28:38 2002
+++ b/net/ipv6/reassembly.c	Sun Nov 10 19:28:38 2002
@@ -314,7 +314,7 @@
 	ipv6_addr_copy(&fq->saddr, src);
 	ipv6_addr_copy(&fq->daddr, dst);
 
-	/* init_timer has been done by the memset */
+	init_timer(&fq->timer);
 	fq->timer.function = ip6_frag_expire;
 	fq->timer.data = (long) fq;
 	fq->lock = SPIN_LOCK_UNLOCKED;
diff -Nru a/net/ipv6/route.c b/net/ipv6/route.c
--- a/net/ipv6/route.c	Sun Nov 10 19:28:40 2002
+++ b/net/ipv6/route.c	Sun Nov 10 19:28:40 2002
@@ -107,7 +107,8 @@
 			.error		= -ENETUNREACH,
 			.input		= ip6_pkt_discard,
 			.output		= ip6_pkt_discard,
-			.ops		= &ip6_dst_ops
+			.ops		= &ip6_dst_ops,
+			.path		= (struct dst_entry*)&ip6_null_entry,
 		}
 	},
 	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
@@ -1252,6 +1253,9 @@
 	*/
 
 	idev = __in6_dev_get(arg->dev);
+	if (idev == NULL)
+		return 0;
+
 	/* For administrative MTU increase, there is no way to discover
 	   IPv6 PMTU increase, so PMTU increase should be updated here.
 	   Since RFC 1981 doesn't include administrative MTU increase
diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
--- a/net/ipv6/tcp_ipv6.c	Sun Nov 10 19:28:40 2002
+++ b/net/ipv6/tcp_ipv6.c	Sun Nov 10 19:28:40 2002
@@ -1638,8 +1638,6 @@
 		goto no_tcp_socket;
 
 process:
-	if(!ipsec_sk_policy(sk,skb))
-		goto discard_and_relse;
 	if(sk->state == TCP_TIME_WAIT)
 		goto do_time_wait;
 
@@ -1673,10 +1671,6 @@
 
 	kfree_skb(skb);
 	return 0;
-
-discard_and_relse:
-	sock_put(sk);
-	goto discard_it;
 
 do_time_wait:
 	if (skb->len < (th->doff<<2) || tcp_checksum_complete(skb)) {
diff -Nru a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
--- a/net/irda/irlap_frame.c	Sun Nov 10 19:28:38 2002
+++ b/net/irda/irlap_frame.c	Sun Nov 10 19:28:38 2002
@@ -1280,6 +1280,20 @@
 		return -1;
 	}
 
+	/* We are no longer an "old" protocol, so we need to handle
+	 * share and non linear skbs. This should never happen, so
+	 * we don't need to be clever about it. Jean II */
+	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
+		ERROR("%s: can't clone shared skb!\n", __FUNCTION__);
+		return -1;
+	}
+	if (skb_is_nonlinear(skb))
+		if (skb_linearize(skb, GFP_ATOMIC) != 0) {
+			ERROR("%s: can't linearize skb!\n", __FUNCTION__);
+			dev_kfree_skb(skb);
+			return -1;
+		}
+
 	/* Check if frame is large enough for parsing */
 	if (skb->len < 2) {
 		ERROR("%s: frame to short!\n", __FUNCTION__);
diff -Nru a/net/irda/irsyms.c b/net/irda/irsyms.c
--- a/net/irda/irsyms.c	Sun Nov 10 19:28:41 2002
+++ b/net/irda/irsyms.c	Sun Nov 10 19:28:41 2002
@@ -180,13 +180,16 @@
 __u32 irda_debug = IRDA_DEBUG_LEVEL;
 #endif
 
+/* Packet type handler.
+ * Tell the kernel how IrDA packets should be handled.
+ */
 static struct packet_type irda_packet_type = 
 {
-	0,	/* MUTTER ntohs(ETH_P_IRDA),*/
-	NULL,
-	irlap_driver_rcv,
-	NULL,
-	NULL,
+	.type	= __constant_htons(ETH_P_IRDA),
+	.dev	= NULL,			/* Wildcard : All devices */
+	.func	= irlap_driver_rcv,	/* Packet type handler irlap_frame.c */
+	.data	= (void*) 1,		/* Understand shared skbs */
+	//.next	= NULL,
 };
 
 /*
@@ -267,7 +270,6 @@
 	irsock_init();
 	
 	/* Add IrDA packet type (Start receiving packets) */
-	irda_packet_type.type = htons(ETH_P_IRDA);
         dev_add_pack(&irda_packet_type);
 
 	/* Notifier for Interface changes */
diff -Nru a/net/key/Makefile b/net/key/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/key/Makefile	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,7 @@
+#
+# Makefile for the key AF.
+#
+
+obj-$(CONFIG_NET_KEY) += af_key.o
+
+include $(TOPDIR)/Rules.make
diff -Nru a/net/key/af_key.c b/net/key/af_key.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/key/af_key.c	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,2329 @@
+/*
+ * net/key/pfkeyv2.c	An implemenation of PF_KEYv2 sockets.
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ *
+ * Authors:	Maxim Giryaev	<gem@asplinux.ru>
+ *		David S. Miller	<davem@redhat.com>
+ *		Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/socket.h>
+#include <linux/pfkeyv2.h>
+#include <linux/ipsec.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <net/xfrm.h>
+
+#include <net/sock.h>
+
+#define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x))
+#define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x))
+
+/* List of all pfkey sockets. */
+static struct sock * pfkey_table;
+static DECLARE_WAIT_QUEUE_HEAD(pfkey_table_wait);
+static rwlock_t pfkey_table_lock = RW_LOCK_UNLOCKED;
+static atomic_t pfkey_table_users = ATOMIC_INIT(0);
+
+static atomic_t pfkey_socks_nr = ATOMIC_INIT(0);
+
+struct pfkey_opt {
+	int	registered;
+	int	promisc;
+};
+#define pfkey_sk(__sk) ((struct pfkey_opt *)(__sk)->protinfo)
+
+static void pfkey_sock_destruct(struct sock *sk)
+{
+	skb_queue_purge(&sk->receive_queue);
+
+	if (!sk->dead) {
+		printk("Attempt to release alive pfkey socket: %p\n", sk);
+		return;
+	}
+
+	BUG_TRAP(atomic_read(&sk->rmem_alloc)==0);
+	BUG_TRAP(atomic_read(&sk->wmem_alloc)==0);
+
+	kfree(pfkey_sk(sk));
+
+	atomic_dec(&pfkey_socks_nr);
+
+	MOD_DEC_USE_COUNT;
+}
+
+static void pfkey_table_grab(void)
+{
+	write_lock_bh(&pfkey_table_lock);
+
+	if (atomic_read(&pfkey_table_users)) {
+		DECLARE_WAITQUEUE(wait, current);
+
+		add_wait_queue_exclusive(&pfkey_table_wait, &wait);
+		for(;;) {
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			if (atomic_read(&pfkey_table_users) == 0)
+				break;
+			write_unlock_bh(&pfkey_table_lock);
+			schedule();
+			write_lock_bh(&pfkey_table_lock);
+		}
+
+		__set_current_state(TASK_RUNNING);
+		remove_wait_queue(&pfkey_table_wait, &wait);
+	}
+}
+
+static __inline__ void pfkey_table_ungrab(void)
+{
+	write_unlock_bh(&pfkey_table_lock);
+	wake_up(&pfkey_table_wait);
+}
+
+static __inline__ void pfkey_lock_table(void)
+{
+	/* read_lock() synchronizes us to pfkey_table_grab */
+
+	read_lock(&pfkey_table_lock);
+	atomic_inc(&pfkey_table_users);
+	read_unlock(&pfkey_table_lock);
+}
+
+static __inline__ void pfkey_unlock_table(void)
+{
+	if (atomic_dec_and_test(&pfkey_table_users))
+		wake_up(&pfkey_table_wait);
+}
+
+
+static struct proto_ops pfkey_ops;
+
+static void pfkey_insert(struct sock *sk)
+{
+	pfkey_table_grab();
+	sk->next = pfkey_table;
+	pfkey_table = sk;
+	sock_hold(sk);
+	pfkey_table_ungrab();
+}
+
+static void pfkey_remove(struct sock *sk)
+{
+	struct sock **skp;
+
+	pfkey_table_grab();
+	for (skp = &pfkey_table; *skp; skp = &((*skp)->next)) {
+		if (*skp == sk) {
+			*skp = sk->next;
+			__sock_put(sk);
+			break;
+		}
+	}
+	pfkey_table_ungrab();
+}
+
+static int pfkey_create(struct socket *sock, int protocol)
+{
+	struct sock *sk;
+	struct pfkey_opt *pfk;
+	int err;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+	if (sock->type != SOCK_RAW)
+		return -ESOCKTNOSUPPORT;
+	if (protocol != PF_KEY_V2)
+		return -EPROTONOSUPPORT;
+
+	MOD_INC_USE_COUNT;
+
+	err = -ENOMEM;
+	sk = sk_alloc(PF_KEY, GFP_KERNEL, 1, NULL);
+	if (sk == NULL)
+		goto out;
+
+	sock->ops = &pfkey_ops;
+	sock_init_data(sock, sk);
+
+	err = -ENOMEM;
+	pfk = pfkey_sk(sk) = kmalloc(sizeof(*pfk), GFP_KERNEL);
+	if (!pfk) {
+		sk_free(sk);
+		goto out;
+	}
+	memset(pfk, 0, sizeof(*pfk));
+
+	sk->family = PF_KEY;
+	sk->destruct = pfkey_sock_destruct;
+
+	atomic_inc(&pfkey_socks_nr);
+
+	pfkey_insert(sk);
+
+	return 0;
+
+out:
+	MOD_DEC_USE_COUNT;
+	return err;
+}
+
+static int pfkey_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+
+	if (!sk)
+		return 0;
+
+	pfkey_remove(sk);
+
+	sock_orphan(sk);
+	sock->sk = NULL;
+	skb_queue_purge(&sk->write_queue);
+	sock_put(sk);
+
+	return 0;
+}
+
+static void pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2,
+				int allocation, struct sock *sk)
+{
+	sock_hold(sk);
+	if (*skb2 == NULL) {
+		if (atomic_read(&skb->users) != 1) {
+			*skb2 = skb_clone(skb, allocation);
+		} else {
+			*skb2 = skb;
+			atomic_inc(&skb->users);
+		}
+	}
+	if (*skb2 != NULL) {
+		if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) {
+			skb_orphan(*skb2);
+			skb_set_owner_r(*skb2, sk);
+			skb_queue_tail(&sk->receive_queue, *skb2);
+			sk->data_ready(sk, (*skb2)->len);
+			*skb2 = NULL;
+		}
+	}
+	sock_put(sk);
+}
+
+/* Send SKB to all pfkey sockets matching selected criteria.  */
+#define BROADCAST_ALL		0
+#define BROADCAST_ONE		1
+#define BROADCAST_REGISTERED	2
+#define BROADCAST_PROMISC_ONLY	4
+static void pfkey_broadcast(struct sk_buff *skb, int allocation,
+			    int broadcast_flags, struct sock *one_sk)
+{
+	struct sock *sk;
+	struct sk_buff *skb2 = NULL;
+
+	/* XXX Do we need something like netlink_overrun?  I think
+	 * XXX PF_KEY socket apps will not mind current behavior.
+	 */
+	if (!skb)
+		return;
+
+	pfkey_lock_table();
+	for (sk = pfkey_table; sk; sk = sk->next) {
+		struct pfkey_opt *pfk = pfkey_sk(sk);
+
+		/* Yes, it means that if you are meant to receive this
+		 * pfkey message you receive it twice as promiscuous
+		 * socket.
+		 */
+		if (pfk->promisc)
+			pfkey_broadcast_one(skb, &skb2, allocation, sk);
+
+		/* the exact target will be processed later */
+		if (sk == one_sk)
+			continue;
+		if (broadcast_flags != BROADCAST_ALL) {
+			if (broadcast_flags & BROADCAST_PROMISC_ONLY)
+				continue;
+			if ((broadcast_flags & BROADCAST_REGISTERED) &&
+			    !pfk->registered)
+				continue;
+			if (broadcast_flags & BROADCAST_ONE)
+				continue;
+		}
+
+		pfkey_broadcast_one(skb, &skb2, allocation, sk);
+	}
+	pfkey_unlock_table();
+
+	if (one_sk != NULL)
+		pfkey_broadcast_one(skb, &skb2, allocation, one_sk);
+
+	if (skb2)
+		kfree_skb(skb2);
+	kfree_skb(skb);
+}
+
+static inline void pfkey_hdr_dup(struct sadb_msg *new, struct sadb_msg *orig)
+{
+	*new = *orig;
+}
+
+static int pfkey_error(struct sadb_msg *orig, int err, struct sock *sk)
+{
+	struct sk_buff *skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
+	struct sadb_msg *hdr;
+
+	if (!skb)
+		return -ENOBUFS;
+
+	/* Woe be to the platform trying to support PFKEY yet
+	 * having normal errnos outside the 1-255 range, inclusive.
+	 */
+	err = -err;
+	if (err == ERESTARTSYS ||
+	    err == ERESTARTNOHAND ||
+	    err == ERESTARTNOINTR)
+		err = EINTR;
+	if (err >= 512)
+		err = EINVAL;
+	if (err <= 0 || err >= 256)
+		BUG();
+
+	hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
+	pfkey_hdr_dup(hdr, orig);
+	hdr->sadb_msg_errno = (uint8_t) err;
+	hdr->sadb_msg_len = (sizeof(struct sadb_msg) /
+			     sizeof(uint64_t));
+
+	pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk);
+
+	return 0;
+}
+
+static u8 sadb_ext_min_len[] = {
+	[SADB_EXT_RESERVED]		= (u8) 0,
+	[SADB_EXT_SA]			= (u8) sizeof(struct sadb_sa),
+	[SADB_EXT_LIFETIME_CURRENT]	= (u8) sizeof(struct sadb_lifetime),
+	[SADB_EXT_LIFETIME_HARD]	= (u8) sizeof(struct sadb_lifetime),
+	[SADB_EXT_LIFETIME_SOFT]	= (u8) sizeof(struct sadb_lifetime),
+	[SADB_EXT_ADDRESS_SRC]		= (u8) sizeof(struct sadb_address),
+	[SADB_EXT_ADDRESS_DST]		= (u8) sizeof(struct sadb_address),
+	[SADB_EXT_ADDRESS_PROXY]	= (u8) sizeof(struct sadb_address),
+	[SADB_EXT_KEY_AUTH]		= (u8) sizeof(struct sadb_key),
+	[SADB_EXT_KEY_ENCRYPT]		= (u8) sizeof(struct sadb_key),
+	[SADB_EXT_IDENTITY_SRC]		= (u8) sizeof(struct sadb_ident),
+	[SADB_EXT_IDENTITY_DST]		= (u8) sizeof(struct sadb_ident),
+	[SADB_EXT_SENSITIVITY]		= (u8) sizeof(struct sadb_sens),
+	[SADB_EXT_PROPOSAL]		= (u8) sizeof(struct sadb_prop),
+	[SADB_EXT_SUPPORTED_AUTH]	= (u8) sizeof(struct sadb_supported),
+	[SADB_EXT_SUPPORTED_ENCRYPT]	= (u8) sizeof(struct sadb_supported),
+	[SADB_EXT_SPIRANGE]		= (u8) sizeof(struct sadb_spirange),
+	[SADB_X_EXT_KMPRIVATE]		= (u8) sizeof(struct sadb_x_kmprivate),
+	[SADB_X_EXT_POLICY]		= (u8) sizeof(struct sadb_x_policy),
+	[SADB_X_EXT_SA2]		= (u8) sizeof(struct sadb_x_sa2),
+};
+
+/* Verify sadb_address_{len,prefixlen} against sa_family.  */
+static int verify_address_len(void *p)
+{
+	struct sadb_address *sp = p;
+	struct sockaddr *addr = (struct sockaddr *)(sp + 1);
+	struct sockaddr_in *sin;
+	struct sockaddr_in6 *sin6;
+	int len;
+
+	switch (addr->sa_family) {
+	case AF_INET:
+		len  = sizeof(*sp) + sizeof(*sin) + (sizeof(uint64_t) - 1);
+		len /= sizeof(uint64_t);
+		if (sp->sadb_address_len != len ||
+		    sp->sadb_address_prefixlen > 32)
+			return -EINVAL;
+		break;
+
+	case AF_INET6:
+		len  = sizeof(*sp) + sizeof(*sin6) + (sizeof(uint64_t) - 1);
+		len /= sizeof(uint64_t);
+		if (sp->sadb_address_len != len ||
+		    sp->sadb_address_prefixlen > 128)
+			return -EINVAL;
+		break;
+
+	default:
+		/* It is user using kernel to keep track of security
+		 * associations for another protocol, such as
+		 * OSPF/RSVP/RIPV2/MIP.  It is user's job to verify
+		 * lengths.
+		 *
+		 * XXX Actually, association/policy database is not yet
+		 * XXX able to cope with arbitrary sockaddr families.
+		 * XXX When it can, remove this -EINVAL.  -DaveM
+		 */
+		return -EINVAL;
+		break;
+	};
+
+	return 0;
+}
+
+static int present_and_same_family(struct sadb_address *src,
+				   struct sadb_address *dst)
+{
+	struct sockaddr *s_addr, *d_addr;
+
+	if (!src || !dst)
+		return 0;
+
+	s_addr = (struct sockaddr *)(src + 1);
+	d_addr = (struct sockaddr *)(dst + 1);
+	if (s_addr->sa_family != d_addr->sa_family)
+		return 0;
+	if (s_addr->sa_family != AF_INET)
+		return 0;
+
+	return 1;
+}
+
+static int parse_exthdrs(struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	char *p = (char *) hdr;
+	int len = skb->len;
+
+	len -= sizeof(*hdr);
+	p += sizeof(*hdr);
+	while (len > 0) {
+		struct sadb_ext *ehdr = (struct sadb_ext *) p;
+		uint16_t ext_type;
+		int ext_len;
+
+		ext_len  = ehdr->sadb_ext_len;
+		ext_len *= sizeof(uint64_t);
+		ext_type = ehdr->sadb_ext_type;
+		if (ext_len < sizeof(uint64_t) ||
+		    ext_len > len ||
+		    ext_type == SADB_EXT_RESERVED)
+			return -EINVAL;
+
+		if (ext_type <= SADB_EXT_MAX) {
+			int min = (int) sadb_ext_min_len[ext_type];
+			if (ext_len < min)
+				return -EINVAL;
+			if (ext_hdrs[ext_type-1] != NULL)
+				return -EINVAL;
+			if (ext_type == SADB_EXT_ADDRESS_SRC ||
+			    ext_type == SADB_EXT_ADDRESS_DST ||
+			    ext_type == SADB_EXT_ADDRESS_PROXY) {
+				if (verify_address_len(p))
+					return -EINVAL;
+			}				
+			ext_hdrs[ext_type-1] = p;
+		}
+		p   += ext_len;
+		len -= ext_len;
+	}
+
+	return 0;
+}
+
+static uint16_t
+pfkey_satype2proto(uint8_t satype)
+{
+	switch (satype) {
+	case SADB_SATYPE_UNSPEC:
+		return IPSEC_PROTO_ANY;
+	case SADB_SATYPE_AH:
+		return IPPROTO_AH;
+	case SADB_SATYPE_ESP:
+		return IPPROTO_ESP;
+	case SADB_X_SATYPE_IPCOMP:
+		return IPPROTO_COMP;
+		break;
+	default:
+		return 0;
+	}
+	/* NOTREACHED */
+}
+
+static uint8_t
+pfkey_proto2satype(uint16_t proto)
+{
+	switch (proto) {
+	case IPPROTO_AH:
+		return SADB_SATYPE_AH;
+	case IPPROTO_ESP:
+		return SADB_SATYPE_ESP;
+	case IPPROTO_COMP:
+		return SADB_X_SATYPE_IPCOMP;
+		break;
+	default:
+		return 0;
+	}
+	/* NOTREACHED */
+}
+
+/* BTW, this scheme means that there is no way with PFKEY2 sockets to
+ * say specifically 'just raw sockets' as we encode them as 255.
+ */
+
+static uint8_t pfkey_proto_to_xfrm(uint8_t proto)
+{
+	return (proto == IPSEC_PROTO_ANY ? 0 : proto);
+}
+
+static uint8_t pfkey_proto_from_xfrm(uint8_t proto)
+{
+	return (proto ? proto : IPSEC_PROTO_ANY);
+}
+
+static xfrm_address_t *pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr,
+						 xfrm_address_t *xaddr)
+{
+	switch (((struct sockaddr*)(addr + 1))->sa_family) {
+	case AF_INET:
+		xaddr->xfrm4_addr = 
+			((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr;
+		if (addr->sadb_address_prefixlen)
+			xaddr->xfrm4_mask = htonl(~0 << (32 - addr->sadb_address_prefixlen));
+		break;
+	case AF_INET6:
+		memcpy(xaddr->a6, 
+		       &((struct sockaddr_in6*)(addr + 1))->sin6_addr,
+		       sizeof(xaddr->a6));
+	default:
+		return NULL;
+	}
+
+	return xaddr;
+}
+
+static struct  xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **ext_hdrs)
+{
+	struct xfrm_state *x;
+	struct sadb_sa *sa;
+	struct sadb_address *addr;
+	uint16_t proto;
+
+	sa = (struct sadb_sa *) ext_hdrs[SADB_EXT_SA-1];
+	if (sa == NULL)
+		return NULL;
+
+	proto = pfkey_satype2proto(hdr->sadb_msg_satype);
+	if (proto == 0)
+		return NULL;
+
+	/* sadb_address_len should be checked by caller */
+	addr = (struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1];
+	if (addr == NULL)
+		return NULL;
+
+	switch (((struct sockaddr *)(addr + 1))->sa_family) {
+	case AF_INET:
+		x = xfrm_state_lookup(
+				      ((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr,
+				      sa->sadb_sa_spi, proto);
+		break;
+	case AF_INET6:
+		/* XXX handle IPv6 */
+	default:
+		x = NULL;
+		break;
+	}
+
+	return x;
+}
+
+/* Table of algos supported by pfkeyv2 interface. */
+
+struct algo_desc {
+	char		*id;
+	struct sadb_alg desc;
+};
+
+struct algo_desc aalg_list[] = {
+{ .id	= NULL,
+	  .desc	= {
+		  .sadb_alg_id =	SADB_AALG_NONE,
+		  .sadb_alg_ivlen = 0,
+		  .sadb_alg_minbits = 0,
+		  .sadb_alg_maxbits = 0
+	  }
+},
+{ .id	= "md5",
+	  .desc	= {
+		  .sadb_alg_id =	SADB_AALG_MD5HMAC,
+		  .sadb_alg_ivlen = 0,
+		  .sadb_alg_minbits = 128,
+		  .sadb_alg_maxbits = 128
+	  }
+},
+{ .id	= "sha1",
+	  .desc	= {
+		  .sadb_alg_id =	SADB_AALG_SHA1HMAC,
+		  .sadb_alg_ivlen = 0,
+		  .sadb_alg_minbits = 160,
+		  .sadb_alg_maxbits = 160
+	  }
+}
+};
+
+struct algo_desc ealg_list[] = {
+{ .id	= NULL,
+	  .desc	= {
+		  .sadb_alg_id =	SADB_EALG_NONE,
+		  .sadb_alg_ivlen = 0,
+		  .sadb_alg_minbits = 0,
+		  .sadb_alg_maxbits = 2048
+	  }
+},
+{ .id	= "des",
+	  .desc	= {
+		  .sadb_alg_id =	SADB_EALG_DESCBC,
+		  .sadb_alg_ivlen = 8,
+		  .sadb_alg_minbits = 64,
+		  .sadb_alg_maxbits = 64
+	  }
+},
+{ .id	= "des3_ede",
+	  .desc	= {
+		  .sadb_alg_id =	SADB_EALG_3DESCBC,
+		  .sadb_alg_ivlen = 8,
+		  .sadb_alg_minbits = 192,
+		  .sadb_alg_maxbits = 192
+	  }
+}
+};
+
+static struct algo_desc *aalg_get_byid(int alg_id)	
+{
+	int i;
+
+	for (i=0; i<sizeof(aalg_list)/sizeof(aalg_list[0]); i++) {
+		if (aalg_list[i].desc.sadb_alg_id == alg_id)
+			return &aalg_list[i];
+	}
+	return NULL;
+}
+
+static struct algo_desc *ealg_get_byid(int alg_id)	
+{
+	int i;
+
+	for (i=0; i<sizeof(ealg_list)/sizeof(ealg_list[0]); i++) {
+		if (ealg_list[i].desc.sadb_alg_id == alg_id)
+			return &ealg_list[i];
+	}
+	return NULL;
+}
+
+static struct algo_desc *aalg_get_byname(char *name)	
+{
+	int i;
+
+	if (!name)
+		return NULL;
+
+	for (i=1; i<sizeof(aalg_list)/sizeof(aalg_list[0]); i++) {
+		if (strcmp(name, aalg_list[i].id) == 0)
+			return &aalg_list[i];
+	}
+	return NULL;
+}
+
+static struct algo_desc *ealg_get_byname(char *name)	
+{
+	int i;
+
+	if (!name)
+		return NULL;
+
+	for (i=1; i<sizeof(ealg_list)/sizeof(ealg_list[0]); i++) {
+		if (strcmp(name, ealg_list[i].id) == 0)
+			return &ealg_list[i];
+	}
+	return NULL;
+}
+
+
+#define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1)))
+static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, int hsc)
+{
+	struct sk_buff *skb;
+	struct sadb_msg *hdr;
+	struct sadb_sa *sa;
+	struct sadb_lifetime *lifetime;
+	struct sadb_address *addr;
+	struct sadb_key *key;
+	struct sadb_x_sa2 *sa2;
+	int size;
+	int auth_key_size = 0;
+	int encrypt_key_size = 0;
+
+	/* base, SA, (lifetime (HSC),) address(SD), (address(P),)
+	   key(AE), (identity(SD),) (sensitivity)> */
+	size = sizeof(struct sadb_msg) +sizeof(struct sadb_sa) + 
+		sizeof(struct sadb_lifetime) +
+		((hsc & 1) ? sizeof(struct sadb_lifetime) : 0) +
+		((hsc & 2) ? sizeof(struct sadb_lifetime) : 0) +
+			sizeof(struct sadb_address)*2 + 
+				sizeof(struct sockaddr_in)*2 + /* XXX */
+					sizeof(struct sadb_x_sa2);
+	/* XXX identity & sensitivity */
+
+	if (x->sel.saddr.xfrm4_addr != x->props.saddr.xfrm4_addr)
+		size += sizeof(struct sadb_address) + 
+			sizeof(struct sockaddr_in); /* XXX */
+
+	if (add_keys) {
+		if (x->aalg && x->aalg->alg_key_len) {
+			auth_key_size = 
+				PFKEY_ALIGN8((x->aalg->alg_key_len + 7) / 8); 
+			size += sizeof(struct sadb_key) + auth_key_size;
+		}
+		if (x->ealg && x->ealg->alg_key_len) {
+			encrypt_key_size = 
+				PFKEY_ALIGN8((x->ealg->alg_key_len+7) / 8); 
+			size += sizeof(struct sadb_key) + encrypt_key_size;
+		}
+	}
+	skb =  alloc_skb(size + 16, GFP_ATOMIC);
+	if (skb == NULL)
+		return ERR_PTR(-ENOBUFS);
+
+	/* call should fill header later */
+	hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
+	memset(hdr, 0, size);	/* XXX do we need this ? */
+	hdr->sadb_msg_len = size / sizeof(uint64_t);
+
+	/* sa */
+	sa = (struct sadb_sa *)  skb_put(skb, sizeof(struct sadb_sa));
+	sa->sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t);
+	sa->sadb_sa_exttype = SADB_EXT_SA;
+	sa->sadb_sa_spi = x->id.spi;
+	sa->sadb_sa_replay = x->props.replay_window;
+	sa->sadb_sa_state = SADB_SASTATE_DYING;
+	if (x->km.state == XFRM_STATE_VALID && !x->km.dying)
+		sa->sadb_sa_state = SADB_SASTATE_MATURE;
+	else if (x->km.state == XFRM_STATE_ACQ)
+		sa->sadb_sa_state = SADB_SASTATE_LARVAL;
+	else if (x->km.state == XFRM_STATE_EXPIRED)
+		sa->sadb_sa_state = SADB_SASTATE_DEAD;
+	sa->sadb_sa_auth = 0;
+	if (x->aalg) {
+		struct algo_desc *a = aalg_get_byname(x->aalg->alg_name);
+		sa->sadb_sa_auth = a ? a->desc.sadb_alg_id : 0;
+	}
+	sa->sadb_sa_encrypt = 0;
+	if (x->ealg) {
+		struct algo_desc *a = ealg_get_byname(x->ealg->alg_name);
+		sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0;
+	}
+	sa->sadb_sa_flags = 0;
+
+	/* hard time */
+	if (hsc & 2) {
+		lifetime = (struct sadb_lifetime *)  skb_put(skb, 
+							     sizeof(struct sadb_lifetime));
+		lifetime->sadb_lifetime_len =
+			sizeof(struct sadb_lifetime)/sizeof(uint64_t);
+		lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
+		lifetime->sadb_lifetime_allocations =  _X2KEY(x->lft.hard_packet_limit);
+		lifetime->sadb_lifetime_bytes = _X2KEY(x->lft.hard_byte_limit);
+		lifetime->sadb_lifetime_addtime = x->lft.hard_add_expires_seconds;
+		lifetime->sadb_lifetime_usetime = x->lft.hard_use_expires_seconds;
+	}
+	/* soft time */
+	if (hsc & 1) {
+		lifetime = (struct sadb_lifetime *)  skb_put(skb, 
+							     sizeof(struct sadb_lifetime));
+		lifetime->sadb_lifetime_len =
+			sizeof(struct sadb_lifetime)/sizeof(uint64_t);
+		lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
+		lifetime->sadb_lifetime_allocations =  _X2KEY(x->lft.soft_packet_limit);
+		lifetime->sadb_lifetime_bytes = _X2KEY(x->lft.soft_byte_limit);
+		lifetime->sadb_lifetime_addtime = x->lft.soft_add_expires_seconds;
+		lifetime->sadb_lifetime_usetime = x->lft.soft_use_expires_seconds;
+	}
+	/* current time */
+	lifetime = (struct sadb_lifetime *)  skb_put(skb,
+						     sizeof(struct sadb_lifetime));
+	lifetime->sadb_lifetime_len =
+		sizeof(struct sadb_lifetime)/sizeof(uint64_t);
+	lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
+	lifetime->sadb_lifetime_allocations = x->curlft.packets;
+	lifetime->sadb_lifetime_bytes = x->curlft.bytes;
+	lifetime->sadb_lifetime_addtime = x->curlft.add_time;
+	lifetime->sadb_lifetime_usetime = x->curlft.use_time;
+	/* src address */
+	addr = (struct sadb_address*) skb_put(skb, 
+					      sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
+	addr->sadb_address_len = 
+		(sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
+			sizeof(uint64_t);
+	addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+	/* "if the ports are non-zero, then the sadb_address_proto field, 
+	   normally zero, MUST be filled in with the transport 
+	   protocol's number." - RFC2367 */
+	addr->sadb_address_proto = 0; 
+	addr->sadb_address_prefixlen = 32; /* XXX */ 
+	addr->sadb_address_reserved = 0;
+	((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET;
+	((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr = 
+		x->props.saddr.xfrm4_addr;
+	/* dst address */
+	addr = (struct sadb_address*) skb_put(skb, 
+					      sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
+	addr->sadb_address_len = 
+		(sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
+			sizeof(uint64_t);
+	addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+	addr->sadb_address_proto = 0; 
+	addr->sadb_address_prefixlen = 32; /* XXX */ 
+	addr->sadb_address_reserved = 0;
+	((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET;
+	((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr = 
+		x->id.daddr.xfrm4_addr;
+
+	if (x->sel.saddr.xfrm4_addr != x->props.saddr.xfrm4_addr) {
+		addr = (struct sadb_address*) skb_put(skb, 
+						      sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
+		addr->sadb_address_len = 
+			(sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
+				sizeof(uint64_t);
+		addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY;
+		addr->sadb_address_proto = pfkey_proto_from_xfrm(x->sel.proto);
+		addr->sadb_address_prefixlen = x->sel.prefixlen_s;
+		addr->sadb_address_reserved = 0;
+		((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET;
+		((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr = 
+			x->sel.saddr.xfrm4_addr;
+		((struct sockaddr_in*)(addr + 1))->sin_port = 
+			x->sel.sport;
+	}
+
+	/* auth key */
+	if (add_keys && auth_key_size) {
+		key = (struct sadb_key *) skb_put(skb, 
+						  sizeof(struct sadb_key)+auth_key_size);
+		key->sadb_key_len = (sizeof(struct sadb_key) + auth_key_size) /
+			sizeof(uint64_t);
+		key->sadb_key_exttype = SADB_EXT_KEY_AUTH;
+		key->sadb_key_bits = x->aalg->alg_key_len;
+		key->sadb_key_reserved = 0;
+		memcpy(key + 1, x->aalg->alg_key, (x->aalg->alg_key_len+7)/8);
+	}
+	/* encrypt key */
+	if (add_keys && encrypt_key_size) {
+		key = (struct sadb_key *) skb_put(skb, 
+						  sizeof(struct sadb_key)+encrypt_key_size);
+		key->sadb_key_len = (sizeof(struct sadb_key) + 
+				     encrypt_key_size) / sizeof(uint64_t);
+		key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT;
+		key->sadb_key_bits = x->ealg->alg_key_len;
+		key->sadb_key_reserved = 0;
+		memcpy(key + 1, x->ealg->alg_key, 
+		       (x->ealg->alg_key_len+7)/8);
+	}
+
+	/* sa */
+	sa2 = (struct sadb_x_sa2 *)  skb_put(skb, sizeof(struct sadb_x_sa2));
+	sa2->sadb_x_sa2_len = sizeof(struct sadb_x_sa2)/sizeof(uint64_t);
+	sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
+	sa2->sadb_x_sa2_mode = x->props.mode + 1;
+	sa2->sadb_x_sa2_reserved1 = 0;
+	sa2->sadb_x_sa2_reserved2 = 0;
+	sa2->sadb_x_sa2_sequence = 0;
+	sa2->sadb_x_sa2_reqid = x->props.reqid;
+
+	return skb;
+}
+
+static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, 
+						void **ext_hdrs)
+{
+	struct xfrm_state *x; 
+	struct sadb_lifetime *lifetime;
+	struct sadb_sa *sa;
+	struct sadb_key *key;
+	uint16_t proto;
+	
+
+	sa = (struct sadb_sa *) ext_hdrs[SADB_EXT_SA-1];
+	if (!sa ||
+	    !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
+				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]))
+		return ERR_PTR(-EINVAL);
+	if (hdr->sadb_msg_satype == SADB_SATYPE_ESP &&
+	    !ext_hdrs[SADB_EXT_KEY_ENCRYPT-1])
+		return ERR_PTR(-EINVAL);
+	if (hdr->sadb_msg_satype == SADB_SATYPE_AH &&
+	    !ext_hdrs[SADB_EXT_KEY_AUTH-1])
+		return ERR_PTR(-EINVAL);
+	if (!!ext_hdrs[SADB_EXT_LIFETIME_HARD-1] !=
+	    !!ext_hdrs[SADB_EXT_LIFETIME_SOFT-1])
+		return ERR_PTR(-EINVAL);
+
+	/* XXX Do we need this check ? */
+	if (((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_SRC-1])->sadb_address_prefixlen != 32 ||
+	    ((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1])->sadb_address_prefixlen != 32)
+		return ERR_PTR(-EINVAL);
+	proto = pfkey_satype2proto(hdr->sadb_msg_satype);
+	if (proto == 0)
+		return ERR_PTR(-EINVAL);
+
+	/* RFC2367:
+
+   Only SADB_SASTATE_MATURE SAs may be submitted in an SADB_ADD message.
+   SADB_SASTATE_LARVAL SAs are created by SADB_GETSPI and it is not
+   sensible to add a new SA in the DYING or SADB_SASTATE_DEAD state.
+   Therefore, the sadb_sa_state field of all submitted SAs MUST be
+   SADB_SASTATE_MATURE and the kernel MUST return an error if this is
+   not true.
+
+           However, KAME setkey always uses SADB_SASTATE_LARVAL.
+	   Hence, we have to _ignore_ sadb_sa_state, which is also reasonable.
+	 */
+	if (sa->sadb_sa_auth > SADB_AALG_MAX ||
+	    sa->sadb_sa_encrypt > SADB_EALG_MAX)
+		return ERR_PTR(-EINVAL);
+	key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1];
+	if (key != NULL &&
+	    ((key->sadb_key_bits+7) / 8 == 0 ||
+	     (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t)))
+		return ERR_PTR(-EINVAL);
+	key = ext_hdrs[SADB_EXT_KEY_ENCRYPT-1];
+	if (key != NULL &&
+	    ((key->sadb_key_bits+7) / 8 == 0 ||
+	     (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t)))
+		return ERR_PTR(-EINVAL);
+
+	x = xfrm_state_alloc();
+	if (x == NULL)
+		return ERR_PTR(-ENOBUFS);
+
+	x->id.proto = proto;
+	x->id.spi = sa->sadb_sa_spi;
+	x->props.replay_window = sa->sadb_sa_replay;
+
+	lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_HARD-1];
+	if (lifetime != NULL) {
+		x->lft.hard_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations);
+		x->lft.hard_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes);
+		x->lft.hard_add_expires_seconds = lifetime->sadb_lifetime_addtime;
+		x->lft.hard_use_expires_seconds = lifetime->sadb_lifetime_usetime;
+	}
+	lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_SOFT-1];
+	if (lifetime != NULL) {
+		x->lft.soft_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations);
+		x->lft.soft_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes);
+		x->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime;
+		x->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime;
+	}
+	key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1];
+	if (sa->sadb_sa_auth) {
+		int keysize = 0;
+		struct algo_desc *a = aalg_get_byid(sa->sadb_sa_auth);
+		if (!a)
+			goto out;
+		if (key)
+			keysize = (key->sadb_key_bits + 7) / 8;
+		x->aalg = kmalloc(sizeof(*x->aalg) + keysize, GFP_KERNEL);
+		if (!x->aalg)
+			goto out;
+		strcpy(x->aalg->alg_name, a->id);
+		x->aalg->alg_key_len = 0;
+		if (key) {
+			x->aalg->alg_key_len = key->sadb_key_bits;
+			memcpy(x->aalg->alg_key, key+1, keysize);
+		}
+		x->props.aalgo = sa->sadb_sa_auth;
+		/* x->algo.flags = sa->sadb_sa_flags; */
+	}
+	key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_ENCRYPT-1];
+	if (sa->sadb_sa_encrypt) {
+		int keysize = 0;
+		struct algo_desc *a = ealg_get_byid(sa->sadb_sa_encrypt);
+		if (!a)
+			goto out;
+		if (key)
+			keysize = (key->sadb_key_bits + 7) / 8;
+		x->ealg = kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL);
+		if (!x->ealg)
+			goto out;
+		strcpy(x->ealg->alg_name, a->id);
+		x->ealg->alg_key_len = 0;
+		if (key) {
+			x->ealg->alg_key_len = key->sadb_key_bits;
+			memcpy(x->ealg->alg_key, key+1, keysize);
+		}
+		x->props.ealgo = sa->sadb_sa_encrypt;
+	}
+	/* x->algo.flags = sa->sadb_sa_flags; */
+
+	pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 
+				  &x->props.saddr);
+	pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1], 
+				  &x->id.daddr);
+
+	if (ext_hdrs[SADB_X_EXT_SA2-1]) {
+		struct sadb_x_sa2 *sa2 = (void*)ext_hdrs[SADB_X_EXT_SA2-1];
+		x->props.mode = sa2->sadb_x_sa2_mode;
+		if (x->props.mode)
+			x->props.mode--;
+		x->props.reqid = sa2->sadb_x_sa2_reqid;
+	}
+
+	if (ext_hdrs[SADB_EXT_ADDRESS_PROXY-1]) {
+		struct sadb_address *addr = ext_hdrs[SADB_EXT_ADDRESS_PROXY-1];
+
+		/* Nobody uses this, but we try. */
+		pfkey_sadb_addr2xfrm_addr(addr, &x->sel.saddr);
+		x->sel.prefixlen_s = addr->sadb_address_prefixlen;
+	}
+
+	x->type = xfrm_get_type(proto);
+	if (x->type == NULL)
+		goto out;
+	if (x->type->init_state(x, NULL))
+		goto out;
+	x->km.seq = hdr->sadb_msg_seq;
+	x->km.state = XFRM_STATE_VALID;
+	return x;
+
+out:
+	if (x->aalg)
+		kfree(x->aalg);
+	if (x->ealg)
+		kfree(x->ealg);
+	kfree(x);
+	return ERR_PTR(-ENOBUFS);
+}
+
+static int pfkey_reserved(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	return -EOPNOTSUPP;
+}
+
+static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	struct sk_buff *resp_skb;
+	struct sadb_x_sa2 *sa2;
+	struct sadb_address *addr;
+	struct sockaddr_in *saddr, *daddr;
+	struct sadb_msg *out_hdr;
+	struct xfrm_state *x;
+	u8 mode;
+	u16 reqid;
+	u8 proto;
+
+	if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
+				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]))
+		return -EINVAL;
+
+	proto = pfkey_satype2proto(hdr->sadb_msg_satype);
+	if (proto == 0)
+		return -EINVAL;
+
+	if ((sa2 = ext_hdrs[SADB_X_EXT_SA2-1]) != NULL) {
+		mode = sa2->sadb_x_sa2_mode - 1;
+		reqid = sa2->sadb_x_sa2_reqid;
+	} else {
+		mode = 0;
+		reqid = 0;
+	}
+
+	addr = ext_hdrs[SADB_EXT_ADDRESS_SRC-1];
+	saddr = (struct sockaddr_in*)(addr + 1);
+	addr = ext_hdrs[SADB_EXT_ADDRESS_DST-1];
+	daddr = (struct sockaddr_in*)(addr + 1);
+
+	x = xfrm_find_acq(mode, reqid, proto, daddr->sin_addr.s_addr,
+			  saddr->sin_addr.s_addr);
+	if (x == NULL)
+		return -ENOENT;
+
+	resp_skb = ERR_PTR(-ENOENT);
+
+	spin_lock_bh(&x->lock);
+	if (x->km.state != XFRM_STATE_DEAD) {
+		struct sadb_spirange *range = ext_hdrs[SADB_EXT_SPIRANGE-1];
+		u32 min_spi, max_spi;
+
+		if (range != NULL) {
+			min_spi = range->sadb_spirange_min;
+			max_spi = range->sadb_spirange_max;
+		} else {
+			min_spi = htonl(0x100);
+			max_spi = htonl(0x0fffffff);
+		}
+		xfrm_alloc_spi(x, min_spi, max_spi);
+		if (x->id.spi)
+			resp_skb = pfkey_xfrm_state2msg(x, 0, 3);
+	}
+	spin_unlock_bh(&x->lock);
+
+	if (IS_ERR(resp_skb)) {
+		xfrm_state_put(x);
+		return  PTR_ERR(resp_skb);
+	}
+
+	out_hdr = (struct sadb_msg *) resp_skb->data;
+	out_hdr->sadb_msg_version = hdr->sadb_msg_version;
+	out_hdr->sadb_msg_type = SADB_GETSPI;
+	out_hdr->sadb_msg_satype = pfkey_proto2satype(proto);
+	out_hdr->sadb_msg_errno = 0;
+	out_hdr->sadb_msg_reserved = 0;
+	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
+	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
+
+	xfrm_state_put(x);
+
+	pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk);
+
+	return 0;
+}
+
+static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	struct xfrm_state *x;
+
+	if (hdr->sadb_msg_len != sizeof(struct sadb_msg)/8)
+		return -EOPNOTSUPP;
+
+	if (hdr->sadb_msg_seq == 0 || hdr->sadb_msg_errno == 0)
+		return 0;
+
+	x = xfrm_find_acq_byseq(hdr->sadb_msg_seq);
+	if (x == NULL)
+		return 0;
+
+	if (x->km.state == XFRM_STATE_ACQ)
+		xfrm_state_delete(x);
+	xfrm_state_put(x);
+	return 0;
+}
+
+
+static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	struct sk_buff *out_skb;
+	struct sadb_msg *out_hdr;
+	struct xfrm_state *x;
+	struct xfrm_state *x1;
+
+	x = pfkey_msg2xfrm_state(hdr, ext_hdrs);
+	if (IS_ERR(x))
+		return PTR_ERR(x);
+
+	/* XXX there is race condition */
+	x1 = pfkey_xfrm_state_lookup(hdr, ext_hdrs);
+	if (x1 && hdr->sadb_msg_type == SADB_ADD) {
+		x->km.state = XFRM_STATE_DEAD;
+		xfrm_state_put(x);
+		xfrm_state_put(x1);
+		return -EEXIST;
+	}
+
+	xfrm_state_insert(x);
+
+	if (x1 && hdr->sadb_msg_type != SADB_ADD) {
+		xfrm_state_delete(x1);
+		xfrm_state_put(x1);
+	}
+
+	out_skb = pfkey_xfrm_state2msg(x, 0, 3);
+	if (IS_ERR(out_skb))
+		return  PTR_ERR(out_skb); /* XXX Should we return 0 here ? */
+
+	out_hdr = (struct sadb_msg *) out_skb->data;
+	out_hdr->sadb_msg_version = hdr->sadb_msg_version;
+	out_hdr->sadb_msg_type = hdr->sadb_msg_type;
+	out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
+	out_hdr->sadb_msg_errno = 0;
+	out_hdr->sadb_msg_reserved = 0;
+	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
+	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
+
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+
+	return 0;
+}
+
+static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	struct xfrm_state *x;
+
+	if (!ext_hdrs[SADB_EXT_SA-1] ||
+	    !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
+				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]))
+		return -EINVAL;
+
+	x = pfkey_xfrm_state_lookup(hdr, ext_hdrs);
+	if (x == NULL)
+		return -ESRCH;
+
+	xfrm_state_delete(x);
+	xfrm_state_put(x);
+
+	pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, 
+			BROADCAST_ALL, sk);
+
+	return 0;
+}
+
+static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	struct sk_buff *out_skb;
+	struct sadb_msg *out_hdr;
+	struct xfrm_state *x;
+
+	if (!ext_hdrs[SADB_EXT_SA-1] ||
+	    !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
+				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]))
+		return -EINVAL;
+
+	x = pfkey_xfrm_state_lookup(hdr, ext_hdrs);
+	if (x == NULL)
+		return -ESRCH;
+
+	out_skb = pfkey_xfrm_state2msg(x, 1, 3);
+	xfrm_state_put(x);
+	if (IS_ERR(out_skb))
+		return  PTR_ERR(out_skb);
+
+	out_hdr = (struct sadb_msg *) out_skb->data;
+	out_hdr->sadb_msg_version = hdr->sadb_msg_version;
+	out_hdr->sadb_msg_type = SADB_DUMP;
+	out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
+	out_hdr->sadb_msg_errno = 0;
+	out_hdr->sadb_msg_reserved = 0;
+	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
+	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk);
+
+	return 0;
+}
+
+static struct sk_buff *compose_sadb_supported(struct sadb_msg *orig, int allocation)
+{
+	struct sk_buff *skb;
+	struct sadb_msg *hdr;
+	int len, ah_len, esp_len, i;
+
+	ah_len = sizeof(aalg_list)/sizeof(aalg_list[0]) - 1;
+	ah_len *= sizeof(struct sadb_alg);
+	esp_len = sizeof(ealg_list)/sizeof(ealg_list[0]) - 1;
+	esp_len *= sizeof(struct sadb_alg);
+	if (ah_len)
+		ah_len += sizeof(struct sadb_supported);
+	if (esp_len)
+		esp_len += sizeof(struct sadb_supported);
+	len = esp_len + ah_len + sizeof(struct sadb_msg);
+
+	skb = alloc_skb(allocation, len + 16);
+	if (!skb)
+		goto out_put_algs;
+
+	hdr = (struct sadb_msg *) skb_put(skb, sizeof(*hdr));
+	pfkey_hdr_dup(hdr, orig);
+	hdr->sadb_msg_errno = 0;
+	hdr->sadb_msg_len = len / sizeof(uint64_t);
+
+	if (ah_len) {
+		struct sadb_supported *sp;
+		struct sadb_alg *ap;
+
+		sp = (struct sadb_supported *) skb_put(skb, ah_len);
+		ap = (struct sadb_alg *) (sp + 1);
+
+		sp->sadb_supported_len = ah_len / sizeof(uint64_t);
+		sp->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH;
+
+		for (i=1; i<sizeof(aalg_list)/sizeof(aalg_list[0]); i++)
+			*ap++ = aalg_list[i].desc;
+	}
+
+	if (esp_len) {
+		struct sadb_supported *sp;
+		struct sadb_alg *ap;
+
+		sp = (struct sadb_supported *) skb_put(skb, esp_len);
+		ap = (struct sadb_alg *) (sp + 1);
+
+		sp->sadb_supported_len = esp_len / sizeof(uint64_t);
+		sp->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT;
+
+		for (i=1; i<sizeof(ealg_list)/sizeof(ealg_list[0]); i++)
+			*ap++ = ealg_list[i].desc;
+	}
+
+out_put_algs:
+	return skb;
+}
+
+static int pfkey_register(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	struct pfkey_opt *pfk = pfkey_sk(sk);
+	struct sk_buff *supp_skb;
+
+	if (hdr->sadb_msg_satype > SADB_SATYPE_MAX)
+		return -EINVAL;
+
+	if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) {
+		if (pfk->registered&(1<<hdr->sadb_msg_satype))
+			return -EEXIST;
+		pfk->registered |= (1<<hdr->sadb_msg_satype);
+	}
+
+	supp_skb = compose_sadb_supported(hdr, GFP_KERNEL);
+	if (!supp_skb) {
+		if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC)
+			pfk->registered &= ~(1<<hdr->sadb_msg_satype);
+
+		return -ENOBUFS;
+	}
+
+	pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk);
+
+	return 0;
+}
+
+static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	unsigned proto;
+	struct sk_buff *skb_out;
+	struct sadb_msg *hdr_out;
+
+	proto = pfkey_satype2proto(hdr->sadb_msg_satype);
+	if (proto == 0)
+		return -EINVAL;
+
+	skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
+	if (!skb_out)
+		return -ENOBUFS;
+
+	xfrm_state_flush(proto);
+
+	hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
+	pfkey_hdr_dup(hdr_out, hdr);
+	hdr_out->sadb_msg_errno = (uint8_t) 0;
+	hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+
+	pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL);
+
+	return 0;
+}
+
+struct pfkey_dump_data
+{
+	struct sk_buff *skb;
+	struct sadb_msg *hdr;
+	struct sock *sk;
+};
+
+static int dump_sa(struct xfrm_state *x, int count, void *ptr)
+{
+	struct pfkey_dump_data *data = ptr;
+	struct sk_buff *out_skb;
+	struct sadb_msg *out_hdr;
+
+	out_skb = pfkey_xfrm_state2msg(x, 1, 3);
+	if (IS_ERR(out_skb))
+		return PTR_ERR(out_skb);
+
+	out_hdr = (struct sadb_msg *) out_skb->data;
+	out_hdr->sadb_msg_version = data->hdr->sadb_msg_version;
+	out_hdr->sadb_msg_type = SADB_DUMP;
+	out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
+	out_hdr->sadb_msg_errno = 0;
+	out_hdr->sadb_msg_reserved = 0;
+	out_hdr->sadb_msg_seq = count;
+	out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid;
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk);
+	return 0;
+}
+
+static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	u8 proto;
+	struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk };
+
+	proto = pfkey_satype2proto(hdr->sadb_msg_satype);
+	if (proto == 0)
+		return -EINVAL;
+
+	return xfrm_state_walk(proto, dump_sa, &data);
+}
+
+static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	struct pfkey_opt *pfk = pfkey_sk(sk);
+	int satype = hdr->sadb_msg_satype;
+
+	if (hdr->sadb_msg_len == (sizeof(*hdr) / sizeof(uint64_t))) {
+		/* XXX we mangle packet... */
+		hdr->sadb_msg_errno = 0;
+		if (satype != 0 && satype != 1)
+			return -EINVAL;
+		pfk->promisc = satype;
+	}
+	pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, BROADCAST_ALL, NULL);
+	return 0;
+}
+
+static int
+parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
+{
+	struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr;
+	struct sockaddr_in *addr;
+
+	if (xp->xfrm_nr >= XFRM_MAX_DEPTH)
+		return -ELOOP;
+
+	if (rq->sadb_x_ipsecrequest_mode == 0)
+		return -EINVAL;
+
+	t->id.proto = rq->sadb_x_ipsecrequest_proto; /* XXX check proto */
+	t->mode = rq->sadb_x_ipsecrequest_mode-1;
+	if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE)
+		t->optional = 1;
+	t->reqid = rq->sadb_x_ipsecrequest_reqid;
+	/* addresses present only in tunnel mode */
+	if (t->mode) {
+		addr = (void*)(rq+1);
+		t->saddr.xfrm4_addr = addr->sin_addr.s_addr;
+		addr++;
+		t->id.daddr.xfrm4_addr = addr->sin_addr.s_addr;
+	}
+	/* No way to set this via kame pfkey */
+	t->aalgos = t->ealgos = t->calgos = ~0;
+	xp->xfrm_nr++;
+	return 0;
+}
+
+static int
+parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol)
+{
+	int err;
+	int len = pol->sadb_x_policy_len*8 - sizeof(struct sadb_x_policy);
+	struct sadb_x_ipsecrequest *rq = (void*)(pol+1);
+
+	while (len >= sizeof(struct sadb_x_ipsecrequest)) {
+		if ((err = parse_ipsecrequest(xp, rq)) < 0)
+			return err;
+		len -= rq->sadb_x_ipsecrequest_len;
+		rq = (void*)((u8*)rq + rq->sadb_x_ipsecrequest_len);
+	}
+	return 0;
+}
+
+static struct sk_buff * pfkey_xfrm_policy2msg(struct xfrm_policy *xp, int dir)
+{
+	struct sk_buff *skb;
+	struct sadb_msg *hdr;
+	struct sadb_address *addr;
+	struct sadb_lifetime *lifetime;
+	struct sadb_x_policy *pol;
+	struct sockaddr_in   *sin;
+	int i;
+	int size;
+
+	size = sizeof(struct sadb_msg) +
+		sizeof(struct sadb_lifetime) * 3 +
+			sizeof(struct sadb_address)*2 + 
+				sizeof(struct sockaddr_in)*2 + /* XXX */
+					sizeof(struct sadb_x_policy) +
+						xp->xfrm_nr*(sizeof(struct sadb_x_ipsecrequest) +
+							     sizeof(struct sockaddr_in)*2);
+
+	skb =  alloc_skb(size + 16, GFP_ATOMIC);
+	if (skb == NULL)
+		return ERR_PTR(-ENOBUFS);
+
+	/* call should fill header later */
+	hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
+	memset(hdr, 0, size);	/* XXX do we need this ? */
+
+	/* src address */
+	addr = (struct sadb_address*) skb_put(skb, 
+					      sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
+	addr->sadb_address_len = 
+		(sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
+			sizeof(uint64_t);
+	addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+	addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto);
+	addr->sadb_address_prefixlen = xp->selector.prefixlen_s;
+	addr->sadb_address_reserved = 0;
+	/* src address */
+	sin = (struct sockaddr_in*)(addr + 1);
+	sin->sin_family = AF_INET;
+	sin->sin_addr.s_addr = xp->selector.saddr.xfrm4_addr;
+	sin->sin_port = xp->selector.sport;
+	memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+	/* dst address */
+	addr = (struct sadb_address*) skb_put(skb, 
+					      sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
+	addr->sadb_address_len =
+		(sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
+			sizeof(uint64_t);
+	addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+	addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto);
+	addr->sadb_address_prefixlen = xp->selector.prefixlen_d; 
+	addr->sadb_address_reserved = 0;
+	sin = (struct sockaddr_in*)(addr + 1);
+	sin->sin_family = AF_INET;
+	sin->sin_addr.s_addr = xp->selector.daddr.xfrm4_addr;
+	sin->sin_port = xp->selector.dport;
+	memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+
+	/* hard time */
+	lifetime = (struct sadb_lifetime *)  skb_put(skb, 
+						     sizeof(struct sadb_lifetime));
+	lifetime->sadb_lifetime_len =
+		sizeof(struct sadb_lifetime)/sizeof(uint64_t);
+	lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD;
+	lifetime->sadb_lifetime_allocations =  _X2KEY(xp->lft.hard_packet_limit);
+	lifetime->sadb_lifetime_bytes = _X2KEY(xp->lft.hard_byte_limit);
+	lifetime->sadb_lifetime_addtime = xp->lft.hard_add_expires_seconds;
+	lifetime->sadb_lifetime_usetime = xp->lft.hard_use_expires_seconds;
+	/* soft time */
+	lifetime = (struct sadb_lifetime *)  skb_put(skb, 
+						     sizeof(struct sadb_lifetime));
+	lifetime->sadb_lifetime_len =
+		sizeof(struct sadb_lifetime)/sizeof(uint64_t);
+	lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT;
+	lifetime->sadb_lifetime_allocations =  _X2KEY(xp->lft.soft_packet_limit);
+	lifetime->sadb_lifetime_bytes = _X2KEY(xp->lft.soft_byte_limit);
+	lifetime->sadb_lifetime_addtime = xp->lft.soft_add_expires_seconds;
+	lifetime->sadb_lifetime_usetime = xp->lft.soft_use_expires_seconds;
+	/* current time */
+	lifetime = (struct sadb_lifetime *)  skb_put(skb, 
+						     sizeof(struct sadb_lifetime));
+	lifetime->sadb_lifetime_len =
+		sizeof(struct sadb_lifetime)/sizeof(uint64_t);
+	lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT;
+	lifetime->sadb_lifetime_allocations = xp->curlft.packets;
+	lifetime->sadb_lifetime_bytes = xp->curlft.bytes;
+	lifetime->sadb_lifetime_addtime = xp->curlft.add_time;
+	lifetime->sadb_lifetime_usetime = xp->curlft.use_time;
+
+	pol = (struct sadb_x_policy *)  skb_put(skb, sizeof(struct sadb_x_policy));
+	pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t);
+	pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+	pol->sadb_x_policy_type = IPSEC_POLICY_DISCARD;
+	if (xp->action == XFRM_POLICY_ALLOW) {
+		if (xp->xfrm_nr)
+			pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
+		else
+			pol->sadb_x_policy_type = IPSEC_POLICY_NONE;
+	}
+	pol->sadb_x_policy_dir = dir+1;
+	pol->sadb_x_policy_id = xp->index;
+
+	for (i=0; i<xp->xfrm_nr; i++) {
+		struct sadb_x_ipsecrequest *rq;
+		struct xfrm_tmpl *t = xp->xfrm_vec + i;
+		int req_size;
+
+		req_size = sizeof(struct sadb_x_ipsecrequest);
+		if (t->mode)
+			req_size += 2*sizeof(struct sockaddr_in);
+		else 
+			size -= 2*sizeof(struct sockaddr_in);
+		rq = (void*)skb_put(skb, req_size);
+		pol->sadb_x_policy_len += req_size/8;
+		rq->sadb_x_ipsecrequest_len = req_size;
+		rq->sadb_x_ipsecrequest_proto = t->id.proto;
+		rq->sadb_x_ipsecrequest_mode = t->mode+1;
+		rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE;
+		if (t->optional)
+			rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE;
+		rq->sadb_x_ipsecrequest_reqid = t->reqid;
+		if (t->mode) {
+			sin = (void*)(rq+1);
+			sin->sin_family = AF_INET;
+			sin->sin_addr.s_addr = t->saddr.xfrm4_addr;
+			sin->sin_port = 0;
+			memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+			sin++;
+			sin->sin_family = AF_INET;
+			sin->sin_addr.s_addr = t->id.daddr.xfrm4_addr;
+			sin->sin_port = 0;
+			memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+		}
+	}
+	hdr->sadb_msg_len = size / sizeof(uint64_t);
+	hdr->sadb_msg_reserved = atomic_read(&xp->refcnt);
+	return skb;
+}
+
+static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	int err;
+	struct sadb_lifetime *lifetime;
+	struct sadb_address *sa;
+	struct sadb_x_policy *pol;
+	struct xfrm_policy *xp;
+	struct sk_buff *out_skb;
+	struct sadb_msg *out_hdr;
+
+	if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
+				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
+	    !ext_hdrs[SADB_X_EXT_POLICY-1])
+		return -EINVAL;
+
+	pol = ext_hdrs[SADB_X_EXT_POLICY-1];
+	if (pol->sadb_x_policy_type > IPSEC_POLICY_IPSEC)
+		return -EINVAL;
+	if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX)
+		return -EINVAL;
+
+	xp = xfrm_policy_alloc(GFP_KERNEL);
+	if (xp == NULL)
+		return -ENOBUFS;
+
+	xp->index = pol->sadb_x_policy_id;
+	xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ?
+		      XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW);
+
+	sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 
+	pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.saddr);
+	xp->selector.prefixlen_s = sa->sadb_address_prefixlen;
+	xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
+	xp->selector.sport = ((struct sockaddr_in*)(sa+1))->sin_port;
+	if (xp->selector.sport)
+		xp->selector.sport_mask = ~0;
+
+	sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1], 
+	pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.daddr);
+	xp->selector.prefixlen_d = sa->sadb_address_prefixlen;
+
+	/* Amusing, we set this twice.  KAME apps appear to set same value
+	 * in both addresses.
+	 */
+	xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
+
+	xp->selector.dport = ((struct sockaddr_in*)(sa+1))->sin_port;
+	if (xp->selector.dport)
+		xp->selector.dport_mask = ~0;
+
+	xp->lft.soft_byte_limit = XFRM_INF;
+	xp->lft.hard_byte_limit = XFRM_INF;
+	xp->lft.soft_packet_limit = XFRM_INF;
+	xp->lft.hard_packet_limit = XFRM_INF;
+	if ((lifetime = ext_hdrs[SADB_EXT_LIFETIME_HARD-1]) != NULL) {
+		xp->lft.hard_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations);
+		xp->lft.hard_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes);
+		xp->lft.hard_add_expires_seconds = lifetime->sadb_lifetime_addtime;
+		xp->lft.hard_use_expires_seconds = lifetime->sadb_lifetime_usetime;
+	}
+	if ((lifetime = ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]) != NULL) {
+		xp->lft.soft_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations);
+		xp->lft.soft_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes);
+		xp->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime;
+		xp->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime;
+	}
+	xp->xfrm_nr = 0;
+	if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC &&
+	    (err = parse_ipsecrequests(xp, pol)) < 0)
+		goto out;
+
+	out_skb = pfkey_xfrm_policy2msg(xp, pol->sadb_x_policy_dir-1);
+	if (IS_ERR(out_skb)) {
+		err =  PTR_ERR(out_skb);
+		goto out;
+	}
+
+	err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp,
+				 hdr->sadb_msg_type != SADB_X_SPDUPDATE);
+	if (err) {
+		kfree_skb(out_skb);
+		goto out;
+	}
+
+	xfrm_pol_put(xp);
+
+	out_hdr = (struct sadb_msg *) out_skb->data;
+	out_hdr->sadb_msg_version = hdr->sadb_msg_version;
+	out_hdr->sadb_msg_type = hdr->sadb_msg_type;
+	out_hdr->sadb_msg_satype = 0;
+	out_hdr->sadb_msg_errno = 0;
+	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
+	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+	return 0;
+
+out:
+	kfree(xp);
+	return err;
+}
+
+static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	int err;
+	struct sadb_address *sa;
+	struct sadb_x_policy *pol;
+	struct xfrm_policy *xp;
+	struct sk_buff *out_skb;
+	struct sadb_msg *out_hdr;
+	struct xfrm_selector sel;
+
+	if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
+				     ext_hdrs[SADB_EXT_ADDRESS_DST-1]) ||
+	    !ext_hdrs[SADB_X_EXT_POLICY-1])
+		return -EINVAL;
+
+	pol = ext_hdrs[SADB_X_EXT_POLICY-1];
+	if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX)
+		return -EINVAL;
+
+	memset(&sel, 0, sizeof(sel));
+
+	sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 
+	pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr);
+	sel.prefixlen_s = sa->sadb_address_prefixlen;
+	sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
+	sel.sport = ((struct sockaddr_in*)(sa+1))->sin_port;
+	if (sel.sport)
+		sel.sport_mask = ~0;
+
+	sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1], 
+	pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr);
+	sel.prefixlen_d = sa->sadb_address_prefixlen;
+	sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto);
+	sel.dport = ((struct sockaddr_in*)(sa+1))->sin_port;
+	if (sel.dport)
+		sel.dport_mask = ~0;
+
+	xp = xfrm_policy_delete(pol->sadb_x_policy_dir-1, &sel);
+	if (xp == NULL)
+		return -ENOENT;
+
+	err = 0;
+
+	out_skb = pfkey_xfrm_policy2msg(xp, pol->sadb_x_policy_dir-1);
+	if (IS_ERR(out_skb)) {
+		err =  PTR_ERR(out_skb);
+		goto out;
+	}
+
+	out_hdr = (struct sadb_msg *) out_skb->data;
+	out_hdr->sadb_msg_version = hdr->sadb_msg_version;
+	out_hdr->sadb_msg_type = SADB_X_SPDDELETE;
+	out_hdr->sadb_msg_satype = 0;
+	out_hdr->sadb_msg_errno = 0;
+	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
+	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+	err = 0;
+
+out:
+	if (xp) {
+		xfrm_policy_kill(xp);
+		xfrm_pol_put(xp);
+	}
+	return err;
+}
+
+static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	int err;
+	struct sadb_x_policy *pol;
+	struct xfrm_policy *xp;
+	struct sk_buff *out_skb;
+	struct sadb_msg *out_hdr;
+
+	if (!ext_hdrs[SADB_X_EXT_POLICY-1])
+		return -EINVAL;
+
+	pol = ext_hdrs[SADB_X_EXT_POLICY-1];
+	if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX)
+		return -EINVAL;
+
+	xp = xfrm_policy_byid(pol->sadb_x_policy_dir-1, pol->sadb_x_policy_id,
+			      hdr->sadb_msg_type == SADB_X_SPDDELETE2);
+	if (xp == NULL)
+		return -ENOENT;
+
+	err = 0;
+
+	out_skb = pfkey_xfrm_policy2msg(xp, pol->sadb_x_policy_dir-1);
+	if (IS_ERR(out_skb)) {
+		err =  PTR_ERR(out_skb);
+		goto out;
+	}
+
+	out_hdr = (struct sadb_msg *) out_skb->data;
+	out_hdr->sadb_msg_version = hdr->sadb_msg_version;
+	out_hdr->sadb_msg_type = hdr->sadb_msg_type;
+	out_hdr->sadb_msg_satype = 0;
+	out_hdr->sadb_msg_errno = 0;
+	out_hdr->sadb_msg_seq = hdr->sadb_msg_seq;
+	out_hdr->sadb_msg_pid = hdr->sadb_msg_pid;
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
+	err = 0;
+
+out:
+	if (xp) {
+		if (hdr->sadb_msg_type == SADB_X_SPDDELETE2)
+			xfrm_policy_kill(xp);
+		xfrm_pol_put(xp);
+	}
+	return err;
+}
+
+static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
+{
+	struct pfkey_dump_data *data = ptr;
+	struct sk_buff *out_skb;
+	struct sadb_msg *out_hdr;
+
+	out_skb = pfkey_xfrm_policy2msg(xp, dir);
+	if (IS_ERR(out_skb))
+		return PTR_ERR(out_skb);
+
+	out_hdr = (struct sadb_msg *) out_skb->data;
+	out_hdr->sadb_msg_version = data->hdr->sadb_msg_version;
+	out_hdr->sadb_msg_type = SADB_X_SPDDUMP;
+	out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
+	out_hdr->sadb_msg_errno = 0;
+	out_hdr->sadb_msg_seq = count;
+	out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid;
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk);
+	return 0;
+}
+
+static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk };
+
+	return xfrm_policy_walk(dump_sp, &data);
+}
+
+static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
+{
+	struct sk_buff *skb_out;
+	struct sadb_msg *hdr_out;
+
+	skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL);
+	if (!skb_out)
+		return -ENOBUFS;
+
+	xfrm_policy_flush();
+
+	hdr_out = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg));
+	pfkey_hdr_dup(hdr_out, hdr);
+	hdr_out->sadb_msg_errno = (uint8_t) 0;
+	hdr_out->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t));
+	pfkey_broadcast(skb_out, GFP_KERNEL, BROADCAST_ALL, NULL);
+
+	return 0;
+}
+
+
+typedef int (*pfkey_handler)(struct sock *sk, struct sk_buff *skb,
+			     struct sadb_msg *hdr, void **ext_hdrs);
+static pfkey_handler pfkey_funcs[SADB_MAX + 1] = {
+	[SADB_RESERVED]		= pfkey_reserved,
+	[SADB_GETSPI]		= pfkey_getspi,
+	[SADB_UPDATE]		= pfkey_add,
+	[SADB_ADD]		= pfkey_add,
+	[SADB_DELETE]		= pfkey_delete,
+	[SADB_GET]		= pfkey_get,
+	[SADB_ACQUIRE]		= pfkey_acquire,
+	[SADB_REGISTER]		= pfkey_register,
+	[SADB_EXPIRE]		= NULL,
+	[SADB_FLUSH]		= pfkey_flush,
+	[SADB_DUMP]		= pfkey_dump,
+	[SADB_X_PROMISC]	= pfkey_promisc,
+	[SADB_X_PCHANGE]	= NULL,
+	[SADB_X_SPDUPDATE]	= pfkey_spdadd,
+	[SADB_X_SPDADD]		= pfkey_spdadd,
+	[SADB_X_SPDDELETE]	= pfkey_spddelete,
+	[SADB_X_SPDGET]		= pfkey_spdget,
+	[SADB_X_SPDACQUIRE]	= NULL,
+	[SADB_X_SPDDUMP]	= pfkey_spddump,
+	[SADB_X_SPDFLUSH]	= pfkey_spdflush,
+	[SADB_X_SPDSETIDX]	= pfkey_spdadd,
+	[SADB_X_SPDDELETE2]	= pfkey_spdget,
+};
+
+static int pfkey_process(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr)
+{
+	void *ext_hdrs[SADB_EXT_MAX];
+	int err;
+
+	pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL,
+			BROADCAST_PROMISC_ONLY, NULL);
+
+	memset(ext_hdrs, 0, sizeof(ext_hdrs));
+	err = parse_exthdrs(skb, hdr, ext_hdrs);
+	if (!err) {
+		err = -EOPNOTSUPP;
+		if (pfkey_funcs[hdr->sadb_msg_type])
+			err = pfkey_funcs[hdr->sadb_msg_type](sk, skb, hdr, ext_hdrs);
+	}
+	return err;
+}
+
+static struct sadb_msg *pfkey_get_base_msg(struct sk_buff *skb, int *errp)
+{
+	struct sadb_msg *hdr = NULL;
+
+	if (skb->len < sizeof(*hdr)) {
+		*errp = -EMSGSIZE;
+	} else {
+		hdr = (struct sadb_msg *) skb->data;
+		if (hdr->sadb_msg_version != PF_KEY_V2 ||
+		    hdr->sadb_msg_reserved != 0 ||
+		    (hdr->sadb_msg_type <= SADB_RESERVED ||
+		     hdr->sadb_msg_type > SADB_MAX)) {
+			hdr = NULL;
+			*errp = -EINVAL;
+		} else if (hdr->sadb_msg_len != (skb->len /
+						 sizeof(uint64_t)) ||
+			   hdr->sadb_msg_len < (sizeof(struct sadb_msg) /
+						sizeof(uint64_t))) {
+			hdr = NULL;
+			*errp = -EMSGSIZE;
+		} else {
+			*errp = 0;
+		}
+	}
+	return hdr;
+}
+
+int count_ah_combs(struct xfrm_tmpl *t)
+{
+	int sz = 0;
+	int i;
+
+	for (i=1; i<sizeof(aalg_list)/sizeof(aalg_list[0]); i++) {
+		if (t->aalgos&(1<<aalg_list[i].desc.sadb_alg_id))
+			sz += sizeof(struct sadb_comb);
+	}
+	return sz + sizeof(struct sadb_prop);
+}
+
+int count_esp_combs(struct xfrm_tmpl *t)
+{
+	int sz = 0;
+	int i, k;
+
+	for (i=1; i<sizeof(ealg_list)/sizeof(ealg_list[0]); i++) {
+		if (!(t->ealgos&(1<<ealg_list[i].desc.sadb_alg_id)))
+			continue;
+		for (k=1; k<sizeof(aalg_list)/sizeof(aalg_list[0]); k++) {
+			if (t->aalgos&(1<<aalg_list[i].desc.sadb_alg_id))
+				sz += sizeof(struct sadb_comb);
+		}
+	}
+	return sz + sizeof(struct sadb_prop);
+}
+
+void dump_ah_combs(struct sk_buff *skb, struct xfrm_tmpl *t)
+{
+	struct sadb_prop *p;
+	int i;
+
+	p = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop));
+	p->sadb_prop_len = sizeof(struct sadb_prop)/8;
+	p->sadb_prop_exttype = SADB_EXT_PROPOSAL;
+	p->sadb_prop_replay = 32;
+
+	for (i=1; i<sizeof(aalg_list)/sizeof(aalg_list[0]); i++) {
+		if (t->aalgos&(1<<aalg_list[i].desc.sadb_alg_id)) {
+			struct sadb_comb *c;
+			c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb));
+			memset(c, 0, sizeof(*c));
+			p->sadb_prop_len += sizeof(struct sadb_comb)/8;
+			c->sadb_comb_auth = aalg_list[i].desc.sadb_alg_id;
+			c->sadb_comb_auth_minbits = aalg_list[i].desc.sadb_alg_minbits;
+			c->sadb_comb_auth_maxbits = aalg_list[i].desc.sadb_alg_maxbits;
+			c->sadb_comb_hard_addtime = 24*60*60;
+			c->sadb_comb_soft_addtime = 20*60*60;
+			c->sadb_comb_hard_usetime = 8*60*60;
+			c->sadb_comb_soft_usetime = 7*60*60;
+		}
+	}
+}
+
+void dump_esp_combs(struct sk_buff *skb, struct xfrm_tmpl *t)
+{
+	struct sadb_prop *p;
+	int i, k;
+
+	p = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop));
+	p->sadb_prop_len = sizeof(struct sadb_prop)/8;
+	p->sadb_prop_exttype = SADB_EXT_PROPOSAL;
+	p->sadb_prop_replay = 32;
+
+	for (i=1; i<sizeof(ealg_list)/sizeof(ealg_list[0]); i++) {
+		if (!(t->ealgos&(1<<ealg_list[i].desc.sadb_alg_id)))
+			continue;
+		for (k=1; k<sizeof(aalg_list)/sizeof(aalg_list[0]); k++) {
+			struct sadb_comb *c;
+			if (!(t->aalgos&(1<<aalg_list[i].desc.sadb_alg_id)))
+				continue;
+			c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb));
+			memset(c, 0, sizeof(*c));
+			p->sadb_prop_len += sizeof(struct sadb_comb)/8;
+			c->sadb_comb_auth = aalg_list[k].desc.sadb_alg_id;
+			c->sadb_comb_auth_minbits = aalg_list[k].desc.sadb_alg_minbits;
+			c->sadb_comb_auth_maxbits = aalg_list[k].desc.sadb_alg_maxbits;
+			c->sadb_comb_encrypt = ealg_list[i].desc.sadb_alg_id;
+			c->sadb_comb_encrypt_minbits = ealg_list[i].desc.sadb_alg_minbits;
+			c->sadb_comb_encrypt_maxbits = ealg_list[i].desc.sadb_alg_maxbits;
+			c->sadb_comb_hard_addtime = 24*60*60;
+			c->sadb_comb_soft_addtime = 20*60*60;
+			c->sadb_comb_hard_usetime = 8*60*60;
+			c->sadb_comb_soft_usetime = 7*60*60;
+		}
+	}
+}
+
+static int pfkey_send_notify(struct xfrm_state *x, int hard)
+{
+	struct sk_buff *out_skb;
+	struct sadb_msg *out_hdr;
+	int hsc = (hard ? 2 : 1);
+
+	out_skb = pfkey_xfrm_state2msg(x, 0, hsc);
+	if (IS_ERR(out_skb))
+		return PTR_ERR(out_skb);
+
+	out_hdr = (struct sadb_msg *) out_skb->data;
+	out_hdr->sadb_msg_version = PF_KEY_V2;
+	out_hdr->sadb_msg_type = SADB_EXPIRE;
+	out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
+	out_hdr->sadb_msg_errno = 0;
+	out_hdr->sadb_msg_reserved = 0;
+	out_hdr->sadb_msg_seq = 0;
+	out_hdr->sadb_msg_pid = 0;
+
+	pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
+	return 0;
+}
+
+static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp, int dir)
+{
+	struct sk_buff *skb;
+	struct sadb_msg *hdr;
+	struct sadb_address *addr;
+	struct sadb_x_policy *pol;
+	int size;
+	static u32 acqseq;
+	
+	size = sizeof(struct sadb_msg) +
+		sizeof(struct sadb_address)*2 + 
+			sizeof(struct sockaddr_in)*2 +   /* XXX */
+				sizeof(struct sadb_x_policy);
+	
+	if (x->id.proto == IPPROTO_AH)
+		size += count_ah_combs(t);
+	else if (x->id.proto == IPPROTO_ESP)
+		size += count_esp_combs(t);
+
+	skb =  alloc_skb(size + 16, GFP_ATOMIC);
+	if (skb == NULL)
+		return -ENOMEM;
+	
+	hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg));
+	hdr->sadb_msg_version = PF_KEY_V2;
+	hdr->sadb_msg_type = SADB_ACQUIRE;
+	hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
+	hdr->sadb_msg_len = size / sizeof(uint64_t);
+	hdr->sadb_msg_errno = 0;
+	hdr->sadb_msg_reserved = 0;
+	hdr->sadb_msg_seq = (++acqseq ? : ++acqseq);
+	x->km.seq = acqseq;
+	hdr->sadb_msg_pid = 0;
+	
+	/* src address */
+	addr = (struct sadb_address*) skb_put(skb, 
+					      sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
+	addr->sadb_address_len = 
+		(sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
+			sizeof(uint64_t);
+	addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC;
+	addr->sadb_address_proto = 0;
+	addr->sadb_address_prefixlen = 32;
+	addr->sadb_address_reserved = 0;
+	((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET;
+	((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr = 
+		x->props.saddr.xfrm4_addr;
+	((struct sockaddr_in*)(addr + 1))->sin_port = 0;
+	
+	/* dst address */
+	addr = (struct sadb_address*) skb_put(skb, 
+					      sizeof(struct sadb_address)+sizeof(struct sockaddr_in));
+	addr->sadb_address_len =
+		(sizeof(struct sadb_address)+sizeof(struct sockaddr_in))/
+			sizeof(uint64_t);
+	addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST;
+	addr->sadb_address_proto = 0;
+	addr->sadb_address_prefixlen = 32; 
+	addr->sadb_address_reserved = 0;
+	((struct sockaddr_in*)(addr + 1))->sin_family = AF_INET;
+	((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr = 
+		x->id.daddr.xfrm4_addr;
+	((struct sockaddr_in*)(addr + 1))->sin_port = 0;
+	
+	pol = (struct sadb_x_policy *)  skb_put(skb, sizeof(struct sadb_x_policy));
+	pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t);
+	pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY;
+	pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC;
+	pol->sadb_x_policy_dir = dir+1;
+	pol->sadb_x_policy_id = xp->index;
+
+	/* Set sadb_comb's. */
+	if (x->id.proto == IPPROTO_AH)
+		dump_ah_combs(skb, t);
+	else if (x->id.proto == IPPROTO_ESP)
+		dump_esp_combs(skb, t);
+
+	pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL);
+
+	return 0;
+}
+
+static struct xfrm_policy *pfkey_compile_policy(int opt, u8 *data, int len, int *dir)
+{
+	struct xfrm_policy *xp;
+	struct sadb_x_policy *pol = (struct sadb_x_policy*)data;
+
+	if (opt != IP_IPSEC_POLICY) {
+		*dir = -EOPNOTSUPP;
+		return NULL;
+	}
+
+	*dir = -EINVAL;
+
+	if (len < sizeof(struct sadb_x_policy) ||
+	    pol->sadb_x_policy_len*8 > len ||
+	    pol->sadb_x_policy_type > IPSEC_POLICY_BYPASS ||
+	    (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir > IPSEC_DIR_OUTBOUND))
+		return NULL;
+
+	xp = xfrm_policy_alloc(GFP_KERNEL);
+	if (xp == NULL) {
+		*dir = -ENOBUFS;
+		return NULL;
+	}
+
+	xp->index = pol->sadb_x_policy_id;
+	xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ?
+		      XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW);
+
+	xp->lft.soft_byte_limit = XFRM_INF;
+	xp->lft.hard_byte_limit = XFRM_INF;
+	xp->lft.soft_packet_limit = XFRM_INF;
+	xp->lft.hard_packet_limit = XFRM_INF;
+
+	xp->xfrm_nr = 0;
+	if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC &&
+	    (*dir = parse_ipsecrequests(xp, pol)) < 0)
+		goto out;
+
+	*dir = pol->sadb_x_policy_dir-1;
+	return xp;
+
+out:
+	kfree(xp);
+	return NULL;
+}
+
+static int pfkey_sendmsg(struct kiocb *kiocb,
+			 struct socket *sock, struct msghdr *msg, int len,
+			 struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct sk_buff *skb = NULL;
+	struct sadb_msg *hdr = NULL;
+	int err;
+
+	err = -EOPNOTSUPP;
+	if (msg->msg_flags & MSG_OOB)
+		goto out;
+
+	err = -EMSGSIZE;
+	if ((unsigned)len > sk->sndbuf-32)
+		goto out;
+
+	err = -ENOBUFS;
+	skb = alloc_skb(len, GFP_KERNEL);
+	if (skb == NULL)
+		goto out;
+
+	err = -EFAULT;
+	if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len))
+		goto out;
+
+	hdr = pfkey_get_base_msg(skb, &err);
+	if (!hdr)
+		goto out;
+
+	err = pfkey_process(sk, skb, hdr);
+
+out:
+	if (err && hdr && pfkey_error(hdr, err, sk) == 0)
+		err = 0;
+	if (skb)
+		kfree_skb(skb);
+
+	return err;
+}
+
+static int pfkey_recvmsg(struct kiocb *kiocb,
+			 struct socket *sock, struct msghdr *msg, int len,
+			 int flags, struct scm_cookie *scm)
+{
+	struct sock *sk = sock->sk;
+	struct sk_buff *skb;
+	int copied, err;
+
+	err = -EINVAL;
+	if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC))
+		goto out;
+
+	msg->msg_namelen = 0;
+	skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err);
+	if (skb == NULL)
+		goto out;
+
+	copied = skb->len;
+	if (copied > len) {
+		msg->msg_flags |= MSG_TRUNC;
+		copied = len;
+	}
+
+	skb->h.raw = skb->data;
+	err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+	if (err)
+		goto out_free;
+
+	sock_recv_timestamp(msg, sk, skb);
+
+	err = (flags & MSG_TRUNC) ? skb->len : copied;
+
+out_free:
+	skb_free_datagram(sk, skb);
+out:
+	return err;
+}
+
+static struct proto_ops pfkey_ops = {
+	.family		=	PF_KEY,
+
+	/* Operations that make no sense on pfkey sockets. */
+	.bind		=	sock_no_bind,
+	.connect	=	sock_no_connect,
+	.socketpair	=	sock_no_socketpair,
+	.accept		=	sock_no_accept,
+	.getname	=	sock_no_getname,
+	.ioctl		=	sock_no_ioctl,
+	.listen		=	sock_no_listen,
+	.shutdown	=	sock_no_shutdown,
+	.setsockopt	=	sock_no_setsockopt,
+	.getsockopt	=	sock_no_getsockopt,
+	.mmap		=	sock_no_mmap,
+	.sendpage	=	sock_no_sendpage,
+
+	/* Now the operations that really occur. */
+	.release	=	pfkey_release,
+	.poll		=	datagram_poll,
+	.sendmsg	=	pfkey_sendmsg,
+	.recvmsg	=	pfkey_recvmsg,
+};
+
+static struct net_proto_family pfkey_family_ops = {
+	.family	=	PF_KEY,
+	.create	=	pfkey_create,
+};
+
+#ifdef CONFIG_PROC_FS
+static int pfkey_read_proc(char *buffer, char **start, off_t offset,
+			   int length, int *eof, void *data)
+{
+	off_t pos = 0;
+	off_t begin = 0;
+	int len = 0;
+	struct sock *s;
+
+	len += sprintf(buffer,"sk       RefCnt Rmem   Wmem   User   Inode\n");
+
+	read_lock(&pfkey_table_lock);
+
+	for (s = pfkey_table; s; s = s->next) {
+		len += sprintf(buffer+len,"%p %-6d %-6u %-6u %-6u %-6lu",
+			       s,
+			       atomic_read(&s->refcnt),
+			       atomic_read(&s->rmem_alloc),
+			       atomic_read(&s->wmem_alloc),
+			       sock_i_uid(s),
+			       sock_i_ino(s)
+			       );
+
+		buffer[len++] = '\n';
+		
+		pos = begin + len;
+		if (pos < offset) {
+			len = 0;
+			begin = pos;
+		}
+		if(pos > offset + length)
+			goto done;
+	}
+	*eof = 1;
+
+done:
+	read_unlock(&pfkey_table_lock);
+
+	*start = buffer + (offset - begin);
+	len -= (offset - begin);
+
+	if (len > length)
+		len = length;
+	if (len < 0)
+		len = 0;
+
+	return len;
+}
+#endif
+
+static struct xfrm_mgr pfkeyv2_mgr =
+{
+	.id		= "pfkeyv2",
+	.notify		= pfkey_send_notify,
+	.acquire	= pfkey_send_acquire,
+	.compile_policy	= pfkey_compile_policy,
+};
+
+static void __exit ipsec_pfkey_exit(void)
+{
+	xfrm_unregister_km(&pfkeyv2_mgr);
+	remove_proc_entry("net/pfkey", 0);
+	sock_unregister(PF_KEY);
+}
+
+static int __init ipsec_pfkey_init(void)
+{
+	sock_register(&pfkey_family_ops);
+#ifdef CONFIG_PROC_FS
+	create_proc_read_entry("net/pfkey", 0, 0, pfkey_read_proc, NULL);
+#endif
+	xfrm_register_km(&pfkeyv2_mgr);
+	return 0;
+}
+
+module_init(ipsec_pfkey_init);
+module_exit(ipsec_pfkey_exit);
+MODULE_LICENSE("GPL");
diff -Nru a/net/netsyms.c b/net/netsyms.c
--- a/net/netsyms.c	Sun Nov 10 19:28:39 2002
+++ b/net/netsyms.c	Sun Nov 10 19:28:39 2002
@@ -53,6 +53,7 @@
 #include <linux/inet.h>
 #include <linux/mroute.h>
 #include <linux/igmp.h>
+#include <net/xfrm.h>
 
 extern struct net_proto_family inet_family_ops;
 
@@ -281,6 +282,43 @@
 extern int (*dlci_ioctl_hook)(unsigned int, void *);
 EXPORT_SYMBOL(dlci_ioctl_hook);
 #endif
+
+EXPORT_SYMBOL(xfrm_policy_alloc);
+EXPORT_SYMBOL(__xfrm_policy_destroy);
+EXPORT_SYMBOL(xfrm_policy_lookup);
+EXPORT_SYMBOL(xfrm_lookup);
+EXPORT_SYMBOL(__xfrm_policy_check);
+EXPORT_SYMBOL(__xfrm_route_forward);
+EXPORT_SYMBOL(xfrm_state_alloc);
+EXPORT_SYMBOL(__xfrm_state_destroy);
+EXPORT_SYMBOL(xfrm_state_find);
+EXPORT_SYMBOL(xfrm_state_insert);
+EXPORT_SYMBOL(xfrm_state_check_expire);
+EXPORT_SYMBOL(xfrm_state_check_space);
+EXPORT_SYMBOL(xfrm_state_lookup);
+EXPORT_SYMBOL(xfrm_replay_check);
+EXPORT_SYMBOL(xfrm_replay_advance);
+EXPORT_SYMBOL(xfrm_check_selectors);
+EXPORT_SYMBOL(xfrm4_rcv);
+EXPORT_SYMBOL(xfrm_register_type);
+EXPORT_SYMBOL(xfrm_unregister_type);
+EXPORT_SYMBOL(xfrm_get_type);
+EXPORT_SYMBOL(inet_peer_idlock);
+EXPORT_SYMBOL(xfrm_register_km);
+EXPORT_SYMBOL(xfrm_unregister_km);
+EXPORT_SYMBOL(xfrm_state_delete);
+EXPORT_SYMBOL(xfrm_state_walk);
+EXPORT_SYMBOL(xfrm_find_acq_byseq);
+EXPORT_SYMBOL(xfrm_find_acq);
+EXPORT_SYMBOL(xfrm_alloc_spi);
+EXPORT_SYMBOL(xfrm_state_flush);
+EXPORT_SYMBOL(xfrm_policy_kill);
+EXPORT_SYMBOL(xfrm_policy_delete);
+EXPORT_SYMBOL(xfrm_policy_insert);
+EXPORT_SYMBOL(xfrm_policy_walk);
+EXPORT_SYMBOL(xfrm_policy_flush);
+EXPORT_SYMBOL(xfrm_policy_byid);
+EXPORT_SYMBOL(xfrm_policy_list);
 
 
 #if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_IP_SCTP_MODULE)
diff -Nru a/net/packet/af_packet.c b/net/packet/af_packet.c
--- a/net/packet/af_packet.c	Sun Nov 10 19:28:40 2002
+++ b/net/packet/af_packet.c	Sun Nov 10 19:28:40 2002
@@ -1432,8 +1432,7 @@
 {
 	struct sock *sk = sock->sk;
 
-	switch(cmd) 
-	{
+	switch(cmd) {
 		case SIOCOUTQ:
 		{
 			int amount = atomic_read(&sk->wmem_alloc);
@@ -1452,35 +1451,12 @@
 			return put_user(amount, (int *)arg);
 		}
 		case SIOCGSTAMP:
-			if(sk->stamp.tv_sec==0)
+			if (sk->stamp.tv_sec==0)
 				return -ENOENT;
 			if (copy_to_user((void *)arg, &sk->stamp,
 					 sizeof(struct timeval)))
 				return -EFAULT;
 			break;
-		case SIOCGIFFLAGS:
-#ifndef CONFIG_INET
-		case SIOCSIFFLAGS:
-#endif
-		case SIOCGIFCONF:
-		case SIOCGIFMETRIC:
-		case SIOCSIFMETRIC:
-		case SIOCGIFMEM:
-		case SIOCSIFMEM:
-		case SIOCGIFMTU:
-		case SIOCSIFMTU:
-		case SIOCSIFLINK:
-		case SIOCGIFHWADDR:
-		case SIOCSIFHWADDR:
-		case SIOCSIFMAP:
-		case SIOCGIFMAP:
-		case SIOCSIFSLAVE:
-		case SIOCGIFSLAVE:
-		case SIOCGIFINDEX:
-		case SIOCGIFNAME:
-		case SIOCGIFCOUNT:
-		case SIOCSIFHWBROADCAST:
-			return(dev_ioctl(cmd,(void *) arg));
 
 #ifdef CONFIG_INET
 		case SIOCADDRT:
@@ -1501,7 +1477,7 @@
 #endif
 
 		default:
-			return -EOPNOTSUPP;
+			return dev_ioctl(cmd, (void *)arg);
 	}
 	return 0;
 }
diff -Nru a/net/rxrpc/main.c b/net/rxrpc/main.c
--- a/net/rxrpc/main.c	Sun Nov 10 19:28:41 2002
+++ b/net/rxrpc/main.c	Sun Nov 10 19:28:41 2002
@@ -97,7 +97,7 @@
 /*
  * clean up the Rx module
  */
-static void rxrpc_cleanup(void)
+static void __exit rxrpc_cleanup(void)
 {
 	kenter("");
 
diff -Nru a/net/sched/sch_api.c b/net/sched/sch_api.c
--- a/net/sched/sch_api.c	Sun Nov 10 19:28:39 2002
+++ b/net/sched/sch_api.c	Sun Nov 10 19:28:39 2002
@@ -1105,8 +1105,7 @@
 
 static void psched_tick(unsigned long);
 
-static struct timer_list psched_timer =
-	{ function: psched_tick };
+static struct timer_list psched_timer = TIMER_INITIALIZER(psched_tick, 0, 0);
 
 static void psched_tick(unsigned long dummy)
 {
diff -Nru a/net/sctp/associola.c b/net/sctp/associola.c
--- a/net/sctp/associola.c	Sun Nov 10 19:28:36 2002
+++ b/net/sctp/associola.c	Sun Nov 10 19:28:36 2002
@@ -52,7 +52,6 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 
-#include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/in.h>
 #include <net/ipv6.h>
@@ -208,7 +207,7 @@
 
 	asoc->ctsn_ack_point = asoc->next_tsn - 1;
 	asoc->highest_sacked = asoc->ctsn_ack_point;
-
+	asoc->last_cwr_tsn = asoc->ctsn_ack_point;
 	asoc->unack_data = 0;
 
 	SCTP_DEBUG_PRINTK("myctsnap for %s INIT as 0x%x.\n",
@@ -403,6 +402,9 @@
 		return NULL;
 
 	sctp_transport_set_owner(peer, asoc);
+
+	/* Cache a route for the transport. */
+	sctp_transport_route(peer, NULL);
 
 	/* If this is the first transport addr on this association,
 	 * initialize the association PMTU to the peer's PMTU.
diff -Nru a/net/sctp/input.c b/net/sctp/input.c
--- a/net/sctp/input.c	Sun Nov 10 19:28:36 2002
+++ b/net/sctp/input.c	Sun Nov 10 19:28:36 2002
@@ -41,6 +41,7 @@
  *    Jon Grimm <jgrimm@us.ibm.com>
  *    Hui Huang <hui.huang@nokia.com>
  *    Daisy Chang <daisyc@us.ibm.com>
+ *    Sridhar Samudrala <sri@us.ibm.com>
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -52,7 +53,7 @@
 #include <linux/ip.h>
 #include <linux/time.h> /* For struct timeval */
 #include <net/sock.h>
-#include <linux/ipsec.h>
+#include <net/xfrm.h>
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
@@ -201,7 +202,7 @@
 	rcvr = asoc ? &asoc->base : &ep->base;
 	sk = rcvr->sk;
 
-	if (!ipsec_sk_policy(sk, skb))
+	if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb))
 		goto discard_release;
 
 	/* Create an SCTP packet structure. */
@@ -217,8 +218,8 @@
 	/* Remember the SCTP header. */
 	chunk->sctp_hdr = sh;
 
-	/* Set the source address.  */
-	sctp_init_source(chunk);
+	/* Set the source and destination addresses of the incoming chunk.  */
+	sctp_init_addrs(chunk);
 
 	/* Remember where we came from.  */
 	chunk->transport = transport;
diff -Nru a/net/sctp/ipv6.c b/net/sctp/ipv6.c
--- a/net/sctp/ipv6.c	Sun Nov 10 19:28:40 2002
+++ b/net/sctp/ipv6.c	Sun Nov 10 19:28:40 2002
@@ -158,35 +158,60 @@
 }
 #endif /* TEST_FRAME */
 
-/* Returns the mtu for the given v6 destination address. */
-int sctp_v6_get_dst_mtu(const sockaddr_storage_t *address)
+/* FIXME: This macro needs to be moved to a common header file. */
+#define NIP6(addr) \
+        ntohs((addr)->s6_addr16[0]), \
+        ntohs((addr)->s6_addr16[1]), \
+        ntohs((addr)->s6_addr16[2]), \
+        ntohs((addr)->s6_addr16[3]), \
+        ntohs((addr)->s6_addr16[4]), \
+        ntohs((addr)->s6_addr16[5]), \
+        ntohs((addr)->s6_addr16[6]), \
+        ntohs((addr)->s6_addr16[7])
+
+/* Returns the dst cache entry for the given source and destination ip
+ * addresses.
+ */
+struct dst_entry *sctp_v6_get_dst(sockaddr_storage_t *daddr,
+				  sockaddr_storage_t *saddr)
 {
 	struct dst_entry *dst;
-	struct flowi fl;
-	int dst_mtu = SCTP_DEFAULT_MAXSEGMENT;
+	struct flowi fl = { .nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr,
+					       } } };
 
-	fl.proto = 0;
-	fl.fl6_dst = (struct in6_addr *)&address->v6.sin6_addr;
-	fl.fl6_src = NULL;
-	fl.fl6_flowlabel = 0;
-	fl.oif = 0;
-	fl.uli_u.ports.sport = 0;
-	fl.uli_u.ports.dport = 0;
+
+	SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
+			  __FUNCTION__, NIP6(fl.fl6_dst)); 
+
+	if (saddr) {
+		fl.fl6_src = &saddr->v6.sin6_addr;
+		SCTP_DEBUG_PRINTK(
+			"SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x - ",
+			NIP6(fl.fl6_src));
+	}
 
 	dst = ip6_route_output(NULL, &fl);
 	if (dst) {
-		dst_mtu = dst_pmtu(dst);
-		SCTP_DEBUG_PRINTK("sctp_v6_get_dst_mtu: "
-				  "ip6_route_output: dev:%s pmtu:%d\n",
-				  dst->dev->name, dst_mtu);
-		dst_release(dst);
+		struct rt6_info *rt;
+		rt = (struct rt6_info *)dst;
+		SCTP_DEBUG_PRINTK(
+			"rt6_dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
+			"rt6_src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+			NIP6(&rt->rt6i_dst.addr), NIP6(&rt->rt6i_src.addr));
 	} else {
-		SCTP_DEBUG_PRINTK("sctp_v6_get_dst_mtu: "
-				  "ip6_route_output failed, returning "
-				  "%d as dst_mtu\n", dst_mtu);
+		SCTP_DEBUG_PRINTK("NO ROUTE\n");
+		return NULL;
 	}
 
-	return dst_mtu;
+	return dst;
+}
+
+/* Check if the dst entry's source addr matches the given source addr. */
+int sctp_v6_cmp_saddr(struct dst_entry *dst, sockaddr_storage_t *saddr)
+{
+	struct rt6_info *rt = (struct rt6_info *)dst;
+
+	return ipv6_addr_cmp(&rt->rt6i_src.addr, &saddr->v6.sin6_addr); 
 }
 
 /* Initialize a PF_INET6 socket msg_name. */
@@ -301,7 +326,8 @@
 	.queue_xmit      = sctp_v6_xmit,
 	.setsockopt      = ipv6_setsockopt,
 	.getsockopt      = ipv6_getsockopt,
-	.get_dst_mtu     = sctp_v6_get_dst_mtu,
+	.get_dst	 = sctp_v6_get_dst,
+	.cmp_saddr	 = sctp_v6_cmp_saddr,
 	.net_header_len  = sizeof(struct ipv6hdr),
 	.sockaddr_len    = sizeof(struct sockaddr_in6),
 	.sa_family       = AF_INET6,
diff -Nru a/net/sctp/output.c b/net/sctp/output.c
--- a/net/sctp/output.c	Sun Nov 10 19:28:37 2002
+++ b/net/sctp/output.c	Sun Nov 10 19:28:37 2002
@@ -245,6 +245,7 @@
 	int err = 0;
 	int padding;		/* How much padding do we need?  */
 	__u8 packet_has_data = 0;
+	struct dst_entry *dst;
 
 	/* Do NOT generate a chunkless packet... */
 	if (skb_queue_empty(&packet->chunks))
@@ -410,13 +411,6 @@
 		asoc->peer.last_sent_to = transport;
 	}
 
-	/* Hey, before Linux changes, here's what we have to
-	 * do to force IP routing to recognize the change of
-	 * dest addr.				--xguo
-	 */
-	if (sk->dst_cache)
-		sk->dst_cache->obsolete = 1;
-
 	if (packet_has_data) {
 		struct timer_list *timer;
 		unsigned long timeout;
@@ -433,6 +427,13 @@
 				sctp_association_hold(asoc);
 		}
 	}
+
+	dst = transport->dst;
+	if (!dst || dst->obsolete) {
+		sctp_transport_route(transport, NULL);
+	}
+
+	nskb->dst = dst_clone(transport->dst);
 
 	SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n",
 			  nskb->len);
diff -Nru a/net/sctp/outqueue.c b/net/sctp/outqueue.c
--- a/net/sctp/outqueue.c	Sun Nov 10 19:28:38 2002
+++ b/net/sctp/outqueue.c	Sun Nov 10 19:28:38 2002
@@ -204,18 +204,43 @@
 	return error;
 }
 
+/* Insert a chunk into the retransmit queue.  Chunks on the retransmit
+ * queue are kept in order, based on the TSNs.
+ */
+void sctp_retransmit_insert(struct list_head *tlchunk, sctp_outqueue_t *q)
+{
+	struct list_head *rlchunk;
+	sctp_chunk_t *tchunk, *rchunk;
+	__u32 ttsn, rtsn;
+	int done = 0;
+
+	tchunk = list_entry(tlchunk, sctp_chunk_t, transmitted_list);
+	ttsn = ntohl(tchunk->subh.data_hdr->tsn);
+
+	list_for_each(rlchunk, &q->retransmit) {
+		rchunk = list_entry(rlchunk, sctp_chunk_t, transmitted_list);
+		rtsn = ntohl(rchunk->subh.data_hdr->tsn);
+		if (TSN_lt(ttsn, rtsn)) {
+			list_add(tlchunk, rlchunk->prev);
+			done = 1;
+			break;
+		}
+	}
+	if (!done) {
+		list_add_tail(tlchunk, &q->retransmit);
+	}
+}
+			
 /* Mark all the eligible packets on a transport for retransmission.  */
 void sctp_retransmit_mark(sctp_outqueue_t *q, sctp_transport_t *transport,
 			  __u8 fast_retransmit)
 {
-	struct list_head *lchunk;
+	struct list_head *lchunk, *ltemp;
 	sctp_chunk_t *chunk;
-	struct list_head tlist;
 
-	INIT_LIST_HEAD(&tlist);
 
-	while (!list_empty(&transport->transmitted)) {
-		lchunk = sctp_list_dequeue(&transport->transmitted);
+	/* Walk through the specified transmitted queue.  */
+	list_for_each_safe(lchunk, ltemp, &transport->transmitted) {
 		chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
 
 		/* If we are doing retransmission due to a fast retransmit,
@@ -224,10 +249,8 @@
 		 * retransmission due to a timeout, only the chunks that are
 		 * not yet acked should be added to the retransmit queue.
 		 */
-		if ((fast_retransmit && !chunk->fast_retransmit) ||
-		    (!fast_retransmit && chunk->tsn_gap_acked)) {
-			list_add_tail(lchunk, &tlist);
-		} else {
+		if ((fast_retransmit && chunk->fast_retransmit) ||
+		   (!fast_retransmit && !chunk->tsn_gap_acked)) {
 			/* RFC 2960 6.2.1 Processing a Received SACK
 			 *
 			 * C) Any time a DATA chunk is marked for
@@ -257,15 +280,14 @@
 				chunk->rtt_in_progress = 0;
 				transport->rto_pending = 0;
 			}
-			list_add_tail(lchunk, &q->retransmit);
+
+			/* Move the chunk to the retransmit queue. The chunks
+			 * on the retransmit queue is always kept in order.
+			 */
+			list_del(lchunk);
+			sctp_retransmit_insert(lchunk, q);
 		}
 	}
-
-	/* Reconstruct the transmitted queue with chunks that are not
-	 * eligible for retransmission.
-	 */
-	while (NULL != (lchunk = sctp_list_dequeue(&tlist)))
-		list_add_tail(lchunk, &transport->transmitted);
 
 	SCTP_DEBUG_PRINTK("%s: transport: %p, fast_retransmit: %d, "
 			  "cwnd: %d, ssthresh: %d, flight_size: %d, "
diff -Nru a/net/sctp/protocol.c b/net/sctp/protocol.c
--- a/net/sctp/protocol.c	Sun Nov 10 19:28:40 2002
+++ b/net/sctp/protocol.c	Sun Nov 10 19:28:40 2002
@@ -59,6 +59,7 @@
 /* Global data structures. */
 sctp_protocol_t sctp_proto;
 struct proc_dir_entry	*proc_net_sctp;
+struct sctp_mib sctp_statistics[NR_CPUS * 2];
 
 /* This is the global socket data structure used for responding to
  * the Out-of-the-blue (OOTB) packets.  A control sock will be created
@@ -255,27 +256,41 @@
 	return error;
 }
 
-/* Returns the mtu for the given v4 destination address.  */
-int sctp_v4_get_dst_mtu(const sockaddr_storage_t *address)
+/* Returns the dst cache entry for the given source and destination ip
+ * addresses.
+ */
+struct dst_entry *sctp_v4_get_dst(sockaddr_storage_t *daddr,
+				  sockaddr_storage_t *saddr)
 {
-	int dst_mtu = SCTP_DEFAULT_MAXSEGMENT;
 	struct rtable *rt;
-	struct flowi fl = { .nl_u = { .ip4_u =
-				      { .daddr = address->v4.sin_addr.s_addr } } };
+	struct flowi fl = { .nl_u = { .ip4_u = { .daddr =
+						    daddr->v4.sin_addr.s_addr,
+					       } } };
+
+	if (saddr)
+		fl.fl4_src = saddr->v4.sin_addr.s_addr;
+
+	SCTP_DEBUG_PRINTK("%s: DST:%u.%u.%u.%u, SRC:%u.%u.%u.%u - ",
+			  __FUNCTION__, NIPQUAD(fl.fl4_dst),
+			  NIPQUAD(fl.fl4_src));
 
 	if (ip_route_output_key(&rt, &fl)) {
-		SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu:ip_route_output_key"
-				  " failed, returning %d as dst_mtu\n",
-				  dst_mtu);
-	} else {
-		dst_mtu = dst_pmtu(&rt->u.dst);
-		SCTP_DEBUG_PRINTK("sctp_v4_get_dst_mtu: "
-				  "ip_route_output_key: dev:%s pmtu:%d\n",
-				  rt->u.dst.dev->name, dst_mtu);
-		ip_rt_put(rt);
+		SCTP_DEBUG_PRINTK("NO ROUTE\n");
+		return NULL;
 	}
 
-	return dst_mtu;
+	SCTP_DEBUG_PRINTK("rt_dst:%u.%u.%u.%u, rt_src:%u.%u.%u.%u\n",
+			  NIPQUAD(rt->rt_src), NIPQUAD(rt->rt_dst));
+
+	return &rt->u.dst;
+}
+
+/* Check if the dst entry's source addr matches the given source addr. */
+int sctp_v4_cmp_saddr(struct dst_entry *dst, sockaddr_storage_t *saddr)
+{
+	struct rtable *rt = (struct rtable *)dst;
+
+	return (rt->rt_src == saddr->v4.sin_addr.s_addr); 
 }
 
 /* Event handler for inet device events.
@@ -437,7 +452,8 @@
 	.queue_xmit     = ip_queue_xmit,
 	.setsockopt     = ip_setsockopt,
 	.getsockopt     = ip_getsockopt,
-	.get_dst_mtu    = sctp_v4_get_dst_mtu,
+	.get_dst	= sctp_v4_get_dst,
+	.cmp_saddr	= sctp_v4_cmp_saddr,
 	.net_header_len = sizeof(struct iphdr),
 	.sockaddr_len   = sizeof(struct sockaddr_in),
 	.sa_family      = AF_INET,
diff -Nru a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
--- a/net/sctp/sm_make_chunk.c	Sun Nov 10 19:28:37 2002
+++ b/net/sctp/sm_make_chunk.c	Sun Nov 10 19:28:37 2002
@@ -47,6 +47,7 @@
  *    Dajiang Zhang	    <dajiang.zhang@nokia.com>
  *    Sridhar Samudrala	    <sri@us.ibm.com>
  *    Daisy Chang	    <daisyc@us.ibm.com>
+ *    Ardelle Fan	    <ardelle.fan@intel.com>
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -838,6 +839,53 @@
 	return retval;
 }
 
+/* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error.  */
+sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *asoc,
+				   const sctp_chunk_t *chunk,
+				   const struct msghdr *msg)
+{
+	sctp_chunk_t *retval;
+	void *payload = NULL, *payoff;
+	size_t paylen;
+	struct iovec *iov = msg->msg_iov;
+	int iovlen = msg->msg_iovlen;
+
+	paylen = get_user_iov_size(iov, iovlen);
+	retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen);
+	if (!retval)
+		goto err_chunk;
+
+	if (paylen) {
+		/* Put the msg_iov together into payload.  */
+		payload = kmalloc(paylen, GFP_ATOMIC);
+		if (!payload)
+			goto err_payload;
+		payoff = payload;
+
+		for (; iovlen > 0; --iovlen) {
+			if (copy_from_user(payoff, iov->iov_base, iov->iov_len))
+				goto err_copy;
+			payoff += iov->iov_len;
+			iov++;
+		}
+	}
+
+	sctp_init_cause(retval, SCTP_ERROR_USER_ABORT, payload, paylen);
+
+	if (paylen)
+		kfree(payload);
+
+	return retval;
+
+err_copy:
+	kfree(payload);
+err_payload:
+	sctp_free_chunk(retval);
+	retval = NULL;
+err_chunk:
+	return retval;
+}
+
 /* Make a HEARTBEAT chunk.  */
 sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *asoc,
 				  const sctp_transport_t *transport,
@@ -982,16 +1030,17 @@
 	return retval;
 }
 
-/* Set chunk->source based on the IP header in chunk->skb.  */
-void sctp_init_source(sctp_chunk_t *chunk)
+/* Set chunk->source and dest based on the IP header in chunk->skb.  */
+void sctp_init_addrs(sctp_chunk_t *chunk)
 {
-	sockaddr_storage_t *source;
+	sockaddr_storage_t *source, *dest;
 	struct sk_buff *skb;
 	struct sctphdr *sh;
 	struct iphdr *ih4;
 	struct ipv6hdr *ih6;
 
 	source = &chunk->source;
+	dest = &chunk->dest;
 	skb = chunk->skb;
 	ih4 = skb->nh.iph;
 	ih6 = skb->nh.ipv6h;
@@ -1002,6 +1051,9 @@
 		source->v4.sin_family = AF_INET;
 		source->v4.sin_port = ntohs(sh->source);
 		source->v4.sin_addr.s_addr = ih4->saddr;
+		dest->v4.sin_family = AF_INET;
+		dest->v4.sin_port = ntohs(sh->dest);
+		dest->v4.sin_addr.s_addr = ih4->daddr;
 		break;
 
 	case 6:
@@ -1009,6 +1061,9 @@
 			source->v6.sin6_family = AF_INET6;
 			source->v6.sin6_port = ntohs(sh->source);
 			source->v6.sin6_addr = ih6->saddr;
+			dest->v6.sin6_family = AF_INET6;
+			dest->v6.sin6_port = ntohs(sh->dest);
+			dest->v6.sin6_addr = ih6->daddr;
 			/* FIXME:  What do we do with scope, etc. ? */
 			break;
 		)
diff -Nru a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
--- a/net/sctp/sm_sideeffect.c	Sun Nov 10 19:28:40 2002
+++ b/net/sctp/sm_sideeffect.c	Sun Nov 10 19:28:40 2002
@@ -66,7 +66,8 @@
 static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
 					 sctp_transport_t *transport);
 static void sctp_cmd_init_failed(sctp_cmd_seq_t *, sctp_association_t *asoc);
-static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc);
+static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *, sctp_association_t *asoc,
+				  sctp_event_t event_type, sctp_chunk_t *chunk);
 static void sctp_cmd_process_init(sctp_cmd_seq_t *, sctp_association_t *asoc,
 				  sctp_chunk_t *chunk,
 				  sctp_init_chunk_t *peer_init,
@@ -251,7 +252,7 @@
 	int force;
 	sctp_cmd_t *command;
 	sctp_chunk_t *new_obj;
-	sctp_chunk_t *chunk;
+	sctp_chunk_t *chunk = NULL;
 	sctp_packet_t *packet;
 	struct list_head *pos;
 	struct timer_list *timer;
@@ -259,7 +260,8 @@
 	sctp_transport_t *t;
 	sctp_sackhdr_t sackh;
 
-	chunk = (sctp_chunk_t *) event_arg;
+	if(SCTP_EVENT_T_TIMEOUT != event_type)
+		chunk = (sctp_chunk_t *) event_arg;
 
 	/* Note:  This whole file is a huge candidate for rework.
 	 * For example, each command could either have its own handler, so
@@ -504,7 +506,8 @@
 			break;
 
 		case SCTP_CMD_ASSOC_FAILED:
-			sctp_cmd_assoc_failed(commands, asoc);
+			sctp_cmd_assoc_failed(commands, asoc, event_type,
+					      chunk);
 			break;
 
 		case SCTP_CMD_COUNTER_INC:
@@ -595,10 +598,7 @@
 /* A helper function for delayed processing of INET ECN CE bit. */
 static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn)
 {
-	/*
-	 * Save the TSN away for comparison when we receive CWR
-	 * Note: dp->TSN is expected in host endian
-	 */
+	/* Save the TSN away for comparison when we receive CWR */
 
 	asoc->last_ecne_tsn = lowest_tsn;
 	asoc->need_ecne = 1;
@@ -621,7 +621,6 @@
 					   sctp_chunk_t *chunk)
 {
 	sctp_chunk_t *repl;
-	sctp_transport_t *transport;
 
 	/* Our previously transmitted packet ran into some congestion
 	 * so we should take action by reducing cwnd and ssthresh
@@ -629,43 +628,28 @@
 	 * sending a CWR.
 	 */
 
-	/* Find which transport's congestion variables
-	 * need to be adjusted.
+	/* First, try to determine if we want to actually lower
+	 * our cwnd variables.  Only lower them if the ECNE looks more
+	 * recent than the last response.
 	 */
+	if (TSN_lt(asoc->last_cwr_tsn, lowest_tsn)) {
+		sctp_transport_t *transport;
 
-	transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn);
+		/* Find which transport's congestion variables
+		 * need to be adjusted.
+		 */
+		transport = sctp_assoc_lookup_tsn(asoc, lowest_tsn);
 
-	/* Update the congestion variables. */
-	if (transport)
-		sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_ECNE);
-
-	/* Save away a rough idea of when we last sent out a CWR.
-	 * We compare against this value (see above) to decide if
-	 * this is a fairly new request.
-	 * Note that this is not a perfect solution.  We may
-	 * have moved beyond the window (several times) by the
-	 * next time we get an ECNE.  However, it is cute.  This idea
-	 * came from Randy's reference code.
-	 *
-	 * Here's what RFC 2960 has to say about CWR.  This is NOT
-	 * what we do.
-	 *
-	 * RFC 2960 Appendix A
-	 *
-	 *    CWR:
-	 *
-	 *    RFC 2481 details a specific bit for a sender to send in
-	 *    the header of its next outbound TCP segment to indicate
-	 *    to its peer that it has reduced its congestion window.
-	 *    This is termed the CWR bit.  For SCTP the same
-	 *    indication is made by including the CWR chunk.  This
-	 *    chunk contains one data element, i.e. the TSN number
-	 *    that was sent in the ECNE chunk.  This element
-	 *    represents the lowest TSN number in the datagram that
-	 *    was originally marked with the CE bit.
-	 */
-	asoc->last_cwr_tsn = asoc->next_tsn - 1;
+		/* Update the congestion variables. */
+		if (transport)
+			sctp_transport_lower_cwnd(transport,
+						  SCTP_LOWER_CWND_ECNE);
+		asoc->last_cwr_tsn = lowest_tsn;
+	}
 
+	/* Always try to quiet the other end.  In case of lost CWR,
+	 * resend last_cwr_tsn.  
+	 */
 	repl = sctp_make_cwr(asoc, asoc->last_cwr_tsn, chunk);
 
 	/* If we run out of memory, it will look like a lost CWR.  We'll
@@ -1038,14 +1022,26 @@
 
 /* Worker routine to handle SCTP_CMD_ASSOC_FAILED.  */
 static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
-				  sctp_association_t *asoc)
+				  sctp_association_t *asoc,
+				  sctp_event_t event_type,
+				  sctp_chunk_t *chunk)
 {
 	sctp_ulpevent_t *event;
+	__u16 error = 0;
+
+	if (event_type == SCTP_EVENT_T_PRIMITIVE)
+		error = SCTP_ERROR_USER_ABORT;
+
+	if (chunk && (SCTP_CID_ABORT == chunk->chunk_hdr->type) &&
+	    (ntohs(chunk->chunk_hdr->length) >= (sizeof(struct sctp_chunkhdr) +
+				 		 sizeof(struct sctp_errhdr)))) {
+		error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
+	}
 
 	event = sctp_ulpevent_make_assoc_change(asoc,
 						0,
 						SCTP_COMM_LOST,
-						0, 0, 0,
+						error, 0, 0,
 						GFP_ATOMIC);
 
 	if (event)
diff -Nru a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
--- a/net/sctp/sm_statefuns.c	Sun Nov 10 19:28:36 2002
+++ b/net/sctp/sm_statefuns.c	Sun Nov 10 19:28:37 2002
@@ -43,6 +43,7 @@
  *    Hui Huang 	    <hui.huang@nokia.com>
  *    Dajiang Zhang 	    <dajiang.zhang@nokia.com>
  *    Daisy Chang	    <daisyc@us.ibm.com>
+ *    Ardelle Fan	    <ardelle.fan@intel.com>
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -865,9 +866,9 @@
 /* Helper function to send out an abort for the restart
  * condition.
  */
-static int sctp_sf_send_restart_abort(sockaddr_storage_t *ssa, 
+static int sctp_sf_send_restart_abort(sockaddr_storage_t *ssa,
 				      sctp_chunk_t *init,
-				      sctp_cmd_seq_t *commands) 
+				      sctp_cmd_seq_t *commands)
 {
 	int len;
 	sctp_packet_t *pkt;
@@ -881,7 +882,7 @@
 	 */
 	errhdr = (sctp_errhdr_t *)buffer;
 	addrparm = (sctp_addr_param_t *)errhdr->variable;
-	
+
 	/* Copy into a parm format. */
 	len = sockaddr2sctp_addr(ssa, addrparm);
 	len += sizeof(sctp_errhdr_t);
@@ -897,7 +898,7 @@
 	 */
 	pkt = sctp_abort_pkt_new(ep, NULL, init, errhdr, len);
 
-	if (!pkt) 
+	if (!pkt)
 		goto out;
 	sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT, SCTP_PACKET(pkt));
 
@@ -906,18 +907,18 @@
 
 out:
 	/* Even if there is no memory, treat as a failure so
-	 * the packet will get dropped. 
+	 * the packet will get dropped.
 	 */
 	return 0;
 }
 
-/* A restart is occuring, check to make sure no new addresses 
+/* A restart is occuring, check to make sure no new addresses
  * are being added as we may be under a takeover attack.
  */
 static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc,
 				       const sctp_association_t *asoc,
 				       sctp_chunk_t *init,
-				       sctp_cmd_seq_t *commands) 
+				       sctp_cmd_seq_t *commands)
 {
 	sctp_transport_t *new_addr, *addr;
 	struct list_head *pos, *pos2;
@@ -956,8 +957,8 @@
 	if (!found && new_addr) {
 		sctp_sf_send_restart_abort(&new_addr->ipaddr, init, commands);
 	}
-	
-	/* Return success if all addresses were found. */   
+
+	/* Return success if all addresses were found. */
 	return found;
 }
 
@@ -1053,7 +1054,7 @@
  */
 static sctp_disposition_t sctp_sf_do_unexpected_init(
 	const sctp_endpoint_t *ep,
-	const sctp_association_t *asoc, 
+	const sctp_association_t *asoc,
 	const sctp_subtype_t type,
 	void *arg, sctp_cmd_seq_t *commands)
 {
@@ -1130,10 +1131,10 @@
 	/* Make sure no new addresses are being added during the
 	 * restart.   Do not do this check for COOKIE-WAIT state,
 	 * since there are no peer addresses to check against.
-	 * Upon return an ABORT will have been sent if needed.  
+	 * Upon return an ABORT will have been sent if needed.
 	 */
 	if (asoc->state != SCTP_STATE_COOKIE_WAIT) {
-		if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, 
+		if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk,
 						 commands)) {
 			retval = SCTP_DISPOSITION_CONSUME;
 			goto cleanup_asoc;
@@ -1333,9 +1334,9 @@
 	 * since you'd have to get inside the cookie.
 	 */
 	if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) {
-		printk("cookie echo check\n"); 
+		printk("cookie echo check\n");
 		return SCTP_DISPOSITION_CONSUME;
-	}	
+	}
 
 	/* For now, fail any unsent/unacked data.  Consider the optional
 	 * choice of resending of this data.
@@ -1542,7 +1543,7 @@
 	 * are in good shape.
 	 */
         chunk->subh.cookie_hdr = (sctp_signed_cookie_t *)chunk->skb->data;
-	skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - 
+	skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) -
 		 sizeof(sctp_chunkhdr_t));
 
 	/* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie
@@ -2098,18 +2099,11 @@
 
 	ecne = (sctp_ecnehdr_t *) chunk->skb->data;
 	skb_pull(chunk->skb, sizeof(sctp_ecnehdr_t));
-	ecne->lowest_tsn = ntohl(ecne->lowest_tsn);
-
-	/* Casting away the const, as we are just modifying the spinlock,
-	 * not the association itself.   This should go away in the near
-	 * future when we move to an endpoint based lock.
-	 */
 
 	/* If this is a newer ECNE than the last CWR packet we sent out */
-	if (TSN_lt(asoc->last_cwr_tsn, ecne->lowest_tsn)) {
-		sctp_add_cmd_sf(commands, SCTP_CMD_ECN_ECNE,
-				SCTP_U32(ecne->lowest_tsn));
-	}
+	sctp_add_cmd_sf(commands, SCTP_CMD_ECN_ECNE,
+			SCTP_U32(ntohl(ecne->lowest_tsn)));
+
 	return SCTP_DISPOSITION_CONSUME;
 }
 
@@ -2641,7 +2635,7 @@
 	sctp_ulpevent_t *ev;
 
 	while (chunk->chunk_end > chunk->skb->data) {
-		ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0, 
+		ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
 						     GFP_ATOMIC);
 		if (!ev)
 			goto nomem;
@@ -3401,13 +3395,14 @@
 	 * from its upper layer, but retransmits data to the far end
 	 * if necessary to fill gaps.
 	 */
+	struct msghdr *msg = arg;
 	sctp_chunk_t *abort;
 	sctp_disposition_t retval;
 
 	retval = SCTP_DISPOSITION_CONSUME;
 
 	/* Generate ABORT chunk to send the peer.  */
-	abort = sctp_make_abort(asoc, NULL, 0);
+	abort = sctp_make_abort_user(asoc, NULL, msg);
 	if (!abort)
 		retval = SCTP_DISPOSITION_NOMEM;
 	else
@@ -3525,6 +3520,7 @@
 					void *arg,
 					sctp_cmd_seq_t *commands)
 {
+	struct msghdr *msg = arg;
 	sctp_chunk_t *abort;
 	sctp_disposition_t retval;
 
@@ -3534,7 +3530,7 @@
 	retval = SCTP_DISPOSITION_CONSUME;
 
 	/* Generate ABORT chunk to send the peer */
-	abort = sctp_make_abort(asoc, NULL, 0);
+	abort = sctp_make_abort_user(asoc, NULL, msg);
 	if (!abort)
 		retval = SCTP_DISPOSITION_NOMEM;
 	else
@@ -4257,6 +4253,11 @@
 	packet = t_new(sctp_packet_t, GFP_ATOMIC);
 	if (!packet)
 		goto nomem_packet;
+
+	/* Cache a route for the transport with the chunk's destination as
+	 * the source address.
+	 */
+	sctp_transport_route(transport, (sockaddr_storage_t *)&chunk->dest);
 
 	packet = sctp_packet_init(packet, transport, sport, dport);
 	packet = sctp_packet_config(packet, vtag, 0, NULL);
diff -Nru a/net/sctp/socket.c b/net/sctp/socket.c
--- a/net/sctp/socket.c	Sun Nov 10 19:28:41 2002
+++ b/net/sctp/socket.c	Sun Nov 10 19:28:41 2002
@@ -804,10 +804,12 @@
 	SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n",
 			  msg_len, sinfo_flags);
 
-	/* If MSG_EOF|MSG_ABORT is set, no data can be sent.  Disallow
-	 * sending 0-length messages when MSG_EOF|MSG_ABORT is not set.
-	 */
-	if (((sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len > 0)) ||
+	/* If MSG_EOF is set, no data can be sent. Disallow sending zero
+	 * length messages when MSG_EOF|MSG_ABORT is not set.
+	 * If MSG_ABORT is set, the message length could be non zero with
+	 * the msg_iov set to the user abort reason.
+ 	 */
+	if (((sinfo_flags & MSG_EOF) && (msg_len > 0)) ||
 	    (!(sinfo_flags & (MSG_EOF|MSG_ABORT)) && (msg_len == 0))) {
 		err = -EINVAL;
 		goto out_nounlock;
@@ -879,7 +881,7 @@
 		}
 		if (sinfo_flags & MSG_ABORT) {
 			SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc);
-			sctp_primitive_ABORT(asoc, NULL);
+			sctp_primitive_ABORT(asoc, msg);
 			err = 0;
 			goto out_unlock;
 		}
@@ -1238,6 +1240,9 @@
 {
 	sctp_opt_t *sp = sctp_sk(sk);
 
+	/* Applicable to UDP-style socket only */
+	if (SCTP_SOCKET_TCP == sp->type)
+		return -EOPNOTSUPP;
 	if (optlen != sizeof(int))
 		return -EINVAL;
 	if (copy_from_user(&sp->autoclose, optval, optlen))
@@ -1593,6 +1598,9 @@
 
 static inline int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen)
 {
+	/* Applicable to UDP-style socket only */
+	if (SCTP_SOCKET_TCP == sctp_sk(sk)->type)
+		return -EOPNOTSUPP;
 	if (len != sizeof(int))
 		return -EINVAL;
 	if (copy_to_user(optval, &sctp_sk(sk)->autoclose, len))
@@ -1614,10 +1622,10 @@
 	int err = 0;
 
 	/* An association cannot be branched off from an already peeled-off
-	 * socket.
+	 * socket, nor is this supported for tcp style sockets.
 	 */
-	if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sctp_sk(oldsk)->type)
-		return -EINVAL;
+	if (SCTP_SOCKET_UDP != sctp_sk(oldsk)->type)
+		return -EOPNOTSUPP;
 
 	/* Create a new socket.  */
 	err = sock_create(PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, &tmpsock);
diff -Nru a/net/sctp/transport.c b/net/sctp/transport.c
--- a/net/sctp/transport.c	Sun Nov 10 19:28:37 2002
+++ b/net/sctp/transport.c	Sun Nov 10 19:28:37 2002
@@ -87,7 +87,6 @@
 	peer->ipaddr = *addr;
 	peer->af_specific = sctp_get_af_specific(addr);
 	peer->asoc = NULL;
-	peer->pmtu = peer->af_specific->get_dst_mtu(addr);
 
 	/* From 6.3.1 RTO Calculation:
 	 *
@@ -161,6 +160,7 @@
 	if (transport->asoc)
 		sctp_association_put(transport->asoc);
 
+	dst_release(transport->dst);
 	kfree(transport);
 	SCTP_DBG_OBJCNT_DEC(transport);
 }
@@ -198,6 +198,78 @@
 {
 	transport->asoc = asoc;
 	sctp_association_hold(asoc);
+}
+
+/* Caches the dst entry for a transport's destination address and an optional
+ * souce address.
+ */ 
+void sctp_transport_route(sctp_transport_t *transport,
+			  sockaddr_storage_t *saddr)
+{
+	sctp_association_t *asoc = transport->asoc;
+	sctp_func_t *af = transport->af_specific;
+	sockaddr_storage_t *daddr = &transport->ipaddr;
+	sctp_bind_addr_t *bp;
+	rwlock_t *addr_lock;
+	struct sockaddr_storage_list *laddr;
+	struct list_head *pos;
+	struct dst_entry *dst;
+
+	dst = af->get_dst(daddr, saddr);
+
+	/* If there is no association or if a source address is passed,
+	 * no more validation is required.
+	 */
+	if (!asoc || saddr)
+		goto out;
+
+	if (SCTP_STATE_ESTABLISHED == asoc->state) {
+		bp = &asoc->base.bind_addr;
+		addr_lock = &asoc->base.addr_lock;
+	} else {
+		bp = &asoc->ep->base.bind_addr;
+		addr_lock = &asoc->ep->base.addr_lock;
+	}
+
+	if (dst) {
+		/* Walk through the bind address list and look for a bind
+		 * address that matches the source address of the returned dst.
+		 */
+		sctp_read_lock(addr_lock);
+		list_for_each(pos, &bp->address_list) {
+			laddr = list_entry(pos, struct sockaddr_storage_list,
+					   list);
+			if (af->cmp_saddr(dst, &laddr->a))
+				goto out_unlock;
+		}
+		sctp_read_unlock(addr_lock);
+	
+		/* None of the bound addresses match the source address of the
+		 * dst. So release it.
+		 */	
+		dst_release(dst);
+	}
+
+	/* Walk through the bind address list and try to get a dst that
+	 * matches a bind address as the source address.
+	 */
+	sctp_read_lock(addr_lock);
+	list_for_each(pos, &bp->address_list) {
+		laddr = list_entry(pos, struct sockaddr_storage_list, list);
+
+		dst = af->get_dst(daddr, &laddr->a);
+		if (dst)
+			goto out_unlock;
+	}
+
+out_unlock:
+	sctp_read_unlock(addr_lock);
+out:
+	transport->dst = dst;
+	if (dst)
+		transport->pmtu = dst_pmtu(dst);
+	else
+		transport->pmtu = SCTP_DEFAULT_MAXSEGMENT;
 }
 
 /* Hold a reference to a transport.  */
diff -Nru a/net/socket.c b/net/socket.c
--- a/net/socket.c	Sun Nov 10 19:28:39 2002
+++ b/net/socket.c	Sun Nov 10 19:28:39 2002
@@ -1389,7 +1389,7 @@
 		flags |= MSG_DONTWAIT;
 	err=sock_recvmsg(sock, &msg, size, flags);
 
-	if(err >= 0 && addr != NULL && msg.msg_namelen)
+	if(err >= 0 && addr != NULL)
 	{
 		err2=move_addr_to_user(address, msg.msg_namelen, addr, addr_len);
 		if(err2<0)
@@ -1613,7 +1613,7 @@
 		goto out_freeiov;
 	len = err;
 
-	if (uaddr != NULL && msg_sys.msg_namelen) {
+	if (uaddr != NULL) {
 		err = move_addr_to_user(addr, msg_sys.msg_namelen, uaddr, uaddr_len);
 		if (err < 0)
 			goto out_freeiov;
diff -Nru a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
--- a/net/sunrpc/auth_null.c	Sun Nov 10 19:28:41 2002
+++ b/net/sunrpc/auth_null.c	Sun Nov 10 19:28:41 2002
@@ -25,7 +25,7 @@
 	struct rpc_auth	*auth;
 
 	dprintk("RPC: creating NULL authenticator for client %p\n", clnt);
-	if (!(auth = (struct rpc_auth *) rpc_allocate(0, sizeof(*auth))))
+	if (!(auth = (struct rpc_auth *) kmalloc(sizeof(*auth),GFP_KERNEL)))
 		return NULL;
 	auth->au_cslack = 4;
 	auth->au_rslack = 2;
@@ -41,7 +41,7 @@
 {
 	dprintk("RPC: destroying NULL authenticator %p\n", auth);
 	rpcauth_free_credcache(auth);
-	rpc_free(auth);
+	kfree(auth);
 }
 
 /*
@@ -52,7 +52,7 @@
 {
 	struct rpc_cred	*cred;
 
-	if (!(cred = (struct rpc_cred *) rpc_allocate(flags, sizeof(*cred))))
+	if (!(cred = (struct rpc_cred *) kmalloc(sizeof(*cred),GFP_KERNEL)))
 		return NULL;
 	atomic_set(&cred->cr_count, 0);
 	cred->cr_flags = RPCAUTH_CRED_UPTODATE;
@@ -68,7 +68,7 @@
 static void
 nul_destroy_cred(struct rpc_cred *cred)
 {
-	rpc_free(cred);
+	kfree(cred);
 }
 
 /*
diff -Nru a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
--- a/net/sunrpc/auth_unix.c	Sun Nov 10 19:28:40 2002
+++ b/net/sunrpc/auth_unix.c	Sun Nov 10 19:28:40 2002
@@ -41,7 +41,7 @@
 	struct rpc_auth	*auth;
 
 	dprintk("RPC: creating UNIX authenticator for client %p\n", clnt);
-	if (!(auth = (struct rpc_auth *) rpc_allocate(0, sizeof(*auth))))
+	if (!(auth = (struct rpc_auth *) kmalloc(sizeof(*auth), GFP_KERNEL)))
 		return NULL;
 	auth->au_cslack = UNX_WRITESLACK;
 	auth->au_rslack = 2;	/* assume AUTH_NULL verf */
@@ -58,7 +58,7 @@
 {
 	dprintk("RPC: destroying UNIX authenticator %p\n", auth);
 	rpcauth_free_credcache(auth);
-	rpc_free(auth);
+	kfree(auth);
 }
 
 static struct rpc_cred *
@@ -70,7 +70,7 @@
 	dprintk("RPC:      allocating UNIX cred for uid %d gid %d\n",
 				current->uid, current->gid);
 
-	if (!(cred = (struct unx_cred *) rpc_allocate(flags, sizeof(*cred))))
+	if (!(cred = (struct unx_cred *) kmalloc(sizeof(*cred), GFP_KERNEL)))
 		return NULL;
 
 	atomic_set(&cred->uc_count, 0);
@@ -98,32 +98,10 @@
 	return (struct rpc_cred *) cred;
 }
 
-struct rpc_cred *
-authunix_fake_cred(struct rpc_task *task, uid_t uid, gid_t gid)
-{
-	struct unx_cred	*cred;
-
-	dprintk("RPC:      allocating fake UNIX cred for uid %d gid %d\n",
-				uid, gid);
-
-	if (!(cred = (struct unx_cred *) rpc_malloc(task, sizeof(*cred))))
-		return NULL;
-
-	atomic_set(&cred->uc_count, 1);
-	cred->uc_flags = RPCAUTH_CRED_DEAD|RPCAUTH_CRED_UPTODATE;
-	cred->uc_uid   = uid;
-	cred->uc_gid   = gid;
-	cred->uc_fsuid = uid;
-	cred->uc_fsgid = gid;
-	cred->uc_gids[0] = (gid_t) NOGROUP;
-
-	return task->tk_msg.rpc_cred = (struct rpc_cred *) cred;
-}
-
 static void
 unx_destroy_cred(struct rpc_cred *cred)
 {
-	rpc_free(cred);
+	kfree(cred);
 }
 
 /*
diff -Nru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
--- a/net/sunrpc/clnt.c	Sun Nov 10 19:28:39 2002
+++ b/net/sunrpc/clnt.c	Sun Nov 10 19:28:39 2002
@@ -85,7 +85,7 @@
 	if (vers >= program->nrvers || !(version = program->version[vers]))
 		goto out;
 
-	clnt = (struct rpc_clnt *) rpc_allocate(0, sizeof(*clnt));
+	clnt = (struct rpc_clnt *) kmalloc(sizeof(*clnt), GFP_KERNEL);
 	if (!clnt)
 		goto out_no_clnt;
 	memset(clnt, 0, sizeof(*clnt));
@@ -125,7 +125,7 @@
 out_no_auth:
 	printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %u)\n",
 		flavor);
-	rpc_free(clnt);
+	kfree(clnt);
 	clnt = NULL;
 	goto out;
 }
@@ -180,7 +180,7 @@
 		xprt_destroy(clnt->cl_xprt);
 		clnt->cl_xprt = NULL;
 	}
-	rpc_free(clnt);
+	kfree(clnt);
 	return 0;
 }
 
@@ -487,7 +487,7 @@
 	 * auth->au_wslack */
 	bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc) + RPC_SLACK_SPACE;
 
-	if ((task->tk_buffer = rpc_malloc(task, bufsiz << 1)) != NULL)
+	if (rpc_malloc(task, bufsiz << 1) != NULL)
 		return;
 	printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); 
 
@@ -522,7 +522,7 @@
 	task->tk_action = call_bind;
 
 	/* Default buffer setup */
-	bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc)+RPC_SLACK_SPACE;
+	bufsiz = task->tk_bufsize >> 1;
 	sndbuf->head[0].iov_base = (void *)task->tk_buffer;
 	sndbuf->head[0].iov_len  = bufsiz;
 	sndbuf->tail[0].iov_len  = 0;
diff -Nru a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
--- a/net/sunrpc/pmap_clnt.c	Sun Nov 10 19:28:39 2002
+++ b/net/sunrpc/pmap_clnt.c	Sun Nov 10 19:28:39 2002
@@ -42,7 +42,12 @@
 {
 	struct rpc_portmap *map = &clnt->cl_pmap;
 	struct sockaddr_in *sap = &clnt->cl_xprt->addr;
-	struct rpc_message msg = { PMAP_GETPORT, map, &clnt->cl_port, NULL };
+	struct rpc_message msg = {
+		.rpc_proc	= PMAP_GETPORT,
+		.rpc_argp	= map,
+		.rpc_resp	= &clnt->cl_port,
+		.rpc_cred	= NULL
+	};
 	struct rpc_clnt	*pmap_clnt;
 	struct rpc_task	*child;
 
@@ -90,7 +95,12 @@
 int
 rpc_getport_external(struct sockaddr_in *sin, __u32 prog, __u32 vers, int prot)
 {
-	struct rpc_portmap map = { prog, vers, prot, 0 };
+	struct rpc_portmap map = {
+		.pm_prog	= prog,
+		.pm_vers	= vers,
+		.pm_prot	= prot,
+		.pm_port	= 0
+	};
 	struct rpc_clnt	*pmap_clnt;
 	char		hostname[32];
 	int		status;
diff -Nru a/net/sunrpc/sched.c b/net/sunrpc/sched.c
--- a/net/sunrpc/sched.c	Sun Nov 10 19:28:40 2002
+++ b/net/sunrpc/sched.c	Sun Nov 10 19:28:40 2002
@@ -15,6 +15,7 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
+#include <linux/mempool.h>
 #include <linux/unistd.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
@@ -29,9 +30,15 @@
 #endif
 
 /*
- * We give RPC the same get_free_pages priority as NFS
+ * RPC slabs and memory pools
  */
-#define GFP_RPC			GFP_NOFS
+#define RPC_BUFFER_MAXSIZE	(2048)
+#define RPC_BUFFER_POOLSIZE	(8)
+#define RPC_TASK_POOLSIZE	(8)
+static kmem_cache_t	*rpc_task_slabp;
+static kmem_cache_t	*rpc_buffer_slabp;
+static mempool_t	*rpc_task_mempool;
+static mempool_t	*rpc_buffer_mempool;
 
 static void			__rpc_default_timer(struct rpc_task *task);
 static void			rpciod_killall(void);
@@ -80,24 +87,6 @@
 static spinlock_t rpc_sched_lock = SPIN_LOCK_UNLOCKED;
 
 /*
- * This is the last-ditch buffer for NFS swap requests
- */
-static u32			swap_buffer[PAGE_SIZE >> 2];
-static long			swap_buffer_used;
-
-/*
- * Make allocation of the swap_buffer SMP-safe
- */
-static __inline__ int rpc_lock_swapbuf(void)
-{
-	return !test_and_set_bit(1, &swap_buffer_used);
-}
-static __inline__ void rpc_unlock_swapbuf(void)
-{
-	clear_bit(1, &swap_buffer_used);
-}
-
-/*
  * Disable the timer for a given RPC task. Should be called with
  * rpc_queue_lock and bh_disabled in order to avoid races within
  * rpc_run_timer().
@@ -592,10 +581,7 @@
 				/* Release RPC slot and buffer memory */
 				if (task->tk_rqstp)
 					xprt_release(task);
-				if (task->tk_buffer) {
-					rpc_free(task->tk_buffer);
-					task->tk_buffer = NULL;
-				}
+				rpc_free(task);
 				goto restarted;
 			}
 			printk(KERN_ERR "RPC: dead task tries to walk away.\n");
@@ -676,63 +662,46 @@
 }
 
 /*
- * Allocate memory for RPC purpose.
+ * Allocate memory for RPC purposes.
  *
- * This is yet another tricky issue: For sync requests issued by
- * a user process, we want to make kmalloc sleep if there isn't
- * enough memory. Async requests should not sleep too excessively
- * because that will block rpciod (but that's not dramatic when
- * it's starved of memory anyway). Finally, swapout requests should
- * never sleep at all, and should not trigger another swap_out
- * request through kmalloc which would just increase memory contention.
- *
- * I hope the following gets it right, which gives async requests
- * a slight advantage over sync requests (good for writeback, debatable
- * for readahead):
- *
- *   sync user requests:	GFP_KERNEL
- *   async requests:		GFP_RPC		(== GFP_NOFS)
- *   swap requests:		GFP_ATOMIC	(or new GFP_SWAPPER)
+ * We try to ensure that some NFS reads and writes can always proceed
+ * by using a mempool when allocating 'small' buffers.
+ * In order to avoid memory starvation triggering more writebacks of
+ * NFS requests, we use GFP_NOFS rather than GFP_KERNEL.
  */
 void *
-rpc_allocate(unsigned int flags, unsigned int size)
+rpc_malloc(struct rpc_task *task, size_t size)
 {
-	u32	*buffer;
 	int	gfp;
 
-	if (flags & RPC_TASK_SWAPPER)
+	if (task->tk_flags & RPC_TASK_SWAPPER)
 		gfp = GFP_ATOMIC;
-	else if (flags & RPC_TASK_ASYNC)
-		gfp = GFP_RPC;
 	else
-		gfp = GFP_KERNEL;
-
-	do {
-		if ((buffer = (u32 *) kmalloc(size, gfp)) != NULL) {
-			dprintk("RPC:      allocated buffer %p\n", buffer);
-			return buffer;
-		}
-		if ((flags & RPC_TASK_SWAPPER) && size <= sizeof(swap_buffer)
-		    && rpc_lock_swapbuf()) {
-			dprintk("RPC:      used last-ditch swap buffer\n");
-			return swap_buffer;
-		}
-		if (flags & RPC_TASK_ASYNC)
-			return NULL;
-		yield();
-	} while (!signalled());
+		gfp = GFP_NOFS;
 
-	return NULL;
+	if (size > RPC_BUFFER_MAXSIZE) {
+		task->tk_buffer =  kmalloc(size, gfp);
+		if (task->tk_buffer)
+			task->tk_bufsize = size;
+	} else {
+		task->tk_buffer =  mempool_alloc(rpc_buffer_mempool, gfp);
+		if (task->tk_buffer)
+			task->tk_bufsize = RPC_BUFFER_MAXSIZE;
+	}
+	return task->tk_buffer;
 }
 
 void
-rpc_free(void *buffer)
+rpc_free(struct rpc_task *task)
 {
-	if (buffer != swap_buffer) {
-		kfree(buffer);
-		return;
+	if (task->tk_buffer) {
+		if (task->tk_bufsize == RPC_BUFFER_MAXSIZE)
+			mempool_free(task->tk_buffer, rpc_buffer_mempool);
+		else
+			kfree(task->tk_buffer);
+		task->tk_buffer = NULL;
+		task->tk_bufsize = 0;
 	}
-	rpc_unlock_swapbuf();
 }
 
 /*
@@ -774,11 +743,17 @@
 				current->pid);
 }
 
+static struct rpc_task *
+rpc_alloc_task(void)
+{
+	return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS);
+}
+
 static void
 rpc_default_free_task(struct rpc_task *task)
 {
 	dprintk("RPC: %4d freeing task\n", task->tk_pid);
-	rpc_free(task);
+	mempool_free(task, rpc_task_mempool);
 }
 
 /*
@@ -791,7 +766,7 @@
 {
 	struct rpc_task	*task;
 
-	task = (struct rpc_task *) rpc_allocate(flags, sizeof(*task));
+	task = rpc_alloc_task();
 	if (!task)
 		goto cleanup;
 
@@ -856,10 +831,7 @@
 		xprt_release(task);
 	if (task->tk_msg.rpc_cred)
 		rpcauth_unbindcred(task);
-	if (task->tk_buffer) {
-		rpc_free(task->tk_buffer);
-		task->tk_buffer = NULL;
-	}
+	rpc_free(task);
 	if (task->tk_client) {
 		rpc_release_client(task->tk_client);
 		task->tk_client = NULL;
@@ -1159,3 +1131,49 @@
 	spin_unlock(&rpc_sched_lock);
 }
 #endif
+
+void
+rpc_destroy_mempool(void)
+{
+	if (rpc_buffer_mempool)
+		mempool_destroy(rpc_buffer_mempool);
+	if (rpc_task_mempool)
+		mempool_destroy(rpc_task_mempool);
+	if (rpc_task_slabp && kmem_cache_destroy(rpc_task_slabp))
+		printk(KERN_INFO "rpc_task: not all structures were freed\n");
+	if (rpc_buffer_slabp && kmem_cache_destroy(rpc_buffer_slabp))
+		printk(KERN_INFO "rpc_buffers: not all structures were freed\n");
+}
+
+int
+rpc_init_mempool(void)
+{
+	rpc_task_slabp = kmem_cache_create("rpc_tasks",
+					     sizeof(struct rpc_task),
+					     0, SLAB_HWCACHE_ALIGN,
+					     NULL, NULL);
+	if (!rpc_task_slabp)
+		goto err_nomem;
+	rpc_buffer_slabp = kmem_cache_create("rpc_buffers",
+					     RPC_BUFFER_MAXSIZE,
+					     0, SLAB_HWCACHE_ALIGN,
+					     NULL, NULL);
+	if (!rpc_buffer_slabp)
+		goto err_nomem;
+	rpc_task_mempool = mempool_create(RPC_TASK_POOLSIZE,
+					    mempool_alloc_slab,
+					    mempool_free_slab,
+					    rpc_task_slabp);
+	if (!rpc_task_mempool)
+		goto err_nomem;
+	rpc_buffer_mempool = mempool_create(RPC_BUFFER_POOLSIZE,
+					    mempool_alloc_slab,
+					    mempool_free_slab,
+					    rpc_buffer_slabp);
+	if (!rpc_buffer_mempool)
+		goto err_nomem;
+	return 0;
+err_nomem:
+	rpc_destroy_mempool();
+	return -ENOMEM;
+}
diff -Nru a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
--- a/net/sunrpc/sunrpc_syms.c	Sun Nov 10 19:28:41 2002
+++ b/net/sunrpc/sunrpc_syms.c	Sun Nov 10 19:28:41 2002
@@ -25,8 +25,6 @@
 
 
 /* RPC scheduler */
-EXPORT_SYMBOL(rpc_allocate);
-EXPORT_SYMBOL(rpc_free);
 EXPORT_SYMBOL(rpc_execute);
 EXPORT_SYMBOL(rpc_init_task);
 EXPORT_SYMBOL(rpc_sleep_on);
@@ -134,6 +132,8 @@
 static int __init
 init_sunrpc(void)
 {
+	if (rpc_init_mempool() != 0)
+		return -ENOMEM;
 #ifdef RPC_DEBUG
 	rpc_register_sysctl();
 #endif
@@ -148,6 +148,7 @@
 static void __exit
 cleanup_sunrpc(void)
 {
+	rpc_destroy_mempool();
 	cache_unregister(&auth_domain_cache);
 	cache_unregister(&ip_map_cache);
 #ifdef RPC_DEBUG
diff -Nru a/net/sunrpc/svc.c b/net/sunrpc/svc.c
--- a/net/sunrpc/svc.c	Sun Nov 10 19:28:41 2002
+++ b/net/sunrpc/svc.c	Sun Nov 10 19:28:41 2002
@@ -138,8 +138,11 @@
 {
 	while (rqstp->rq_arghi)
 		put_page(rqstp->rq_argpages[--rqstp->rq_arghi]);
-	while (rqstp->rq_resused)
-		put_page(rqstp->rq_respages[--rqstp->rq_resused]);
+	while (rqstp->rq_resused) {
+		if (rqstp->rq_respages[--rqstp->rq_resused] == NULL)
+			continue;
+		put_page(rqstp->rq_respages[rqstp->rq_resused]);
+	}
 	rqstp->rq_argused = 0;
 }
 
@@ -264,13 +267,14 @@
 	/* setup response xdr_buf.
 	 * Initially it has just one page 
 	 */
-	take_page(rqstp); /* must succeed */
+	svc_take_page(rqstp); /* must succeed */
 	resv->iov_base = page_address(rqstp->rq_respages[0]);
 	resv->iov_len = 0;
 	rqstp->rq_res.pages = rqstp->rq_respages+1;
 	rqstp->rq_res.len = 0;
 	rqstp->rq_res.page_base = 0;
 	rqstp->rq_res.page_len = 0;
+	rqstp->rq_res.tail[0].iov_len = 0;
 	/* tcp needs a space for the record length... */
 	if (rqstp->rq_prot == IPPROTO_TCP)
 		svc_putu32(resv, 0);
@@ -362,8 +366,12 @@
 		}
 	} else {
 		dprintk("svc: calling dispatcher\n");
-		if (!versp->vs_dispatch(rqstp, statp))
+		if (!versp->vs_dispatch(rqstp, statp)) {
+			/* Release reply info */
+			if (procp->pc_release)
+				procp->pc_release(rqstp, NULL, rqstp->rq_resp);
 			goto dropit;
+		}
 	}
 
 	/* Check RPC status result */
diff -Nru a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
--- a/net/sunrpc/svcsock.c	Sun Nov 10 19:28:37 2002
+++ b/net/sunrpc/svcsock.c	Sun Nov 10 19:28:37 2002
@@ -273,6 +273,11 @@
 
 	svc_release_skb(rqstp);
 
+	svc_free_allpages(rqstp);
+	rqstp->rq_res.page_len = 0;
+	rqstp->rq_res.page_base = 0;
+
+
 	/* Reset response buffer and release
 	 * the reservation.
 	 * But first, check that enough space was reserved
@@ -317,38 +322,82 @@
  * Generic sendto routine
  */
 static int
-svc_sendto(struct svc_rqst *rqstp, struct iovec *iov, int nr)
+svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
 {
 	mm_segment_t	oldfs;
 	struct svc_sock	*svsk = rqstp->rq_sock;
 	struct socket	*sock = svsk->sk_sock;
 	struct msghdr	msg;
-	int		i, buflen, len;
+	int		slen;
+	int		len = 0;
+	int		result;
+	int		size;
+	struct page	**ppage = xdr->pages;
+	size_t		base = xdr->page_base;
+	unsigned int	pglen = xdr->page_len;
+	unsigned int	flags = MSG_MORE;
 
-	for (i = buflen = 0; i < nr; i++)
-		buflen += iov[i].iov_len;
+	slen = xdr->len;
 
 	msg.msg_name    = &rqstp->rq_addr;
 	msg.msg_namelen = sizeof(rqstp->rq_addr);
-	msg.msg_iov     = iov;
-	msg.msg_iovlen  = nr;
+	msg.msg_iov     = NULL;
+	msg.msg_iovlen  = 0;
 	msg.msg_control = NULL;
 	msg.msg_controllen = 0;
+	msg.msg_flags	= MSG_MORE;
 
-	/* 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;
+	/* Grab svsk->sk_sem to serialize outgoing data. */
+	down(&svsk->sk_sem);
 
+	/* set the destination */
 	oldfs = get_fs(); set_fs(KERNEL_DS);
-	len = sock_sendmsg(sock, &msg, buflen);
+	len = sock_sendmsg(sock, &msg, 0);
 	set_fs(oldfs);
+	if (len < 0)
+		goto out;
+
+	/* send head */
+	if (slen == xdr->head[0].iov_len)
+		flags = 0;
+	len = sock->ops->sendpage(sock, rqstp->rq_respages[0], 0, xdr->head[0].iov_len, flags);
+	if (len != xdr->head[0].iov_len)
+		goto out;
+	slen -= xdr->head[0].iov_len;
+	if (slen == 0)
+		goto out;
+
+	/* send page data */
+	size = PAGE_SIZE - base < pglen ? PAGE_SIZE - base : pglen;
+	while (pglen > 0) {
+		if (slen == size)
+			flags = 0;
+		result = sock->ops->sendpage(sock, *ppage, base, size, flags);
+		if (result > 0)
+			len += result;
+		if (result != size)
+			goto out;
+		slen -= size;
+		pglen -= size;
+		size = PAGE_SIZE < pglen ? PAGE_SIZE : pglen;
+		base = 0;
+		ppage++;
+	}
+	/* send tail */
+	if (xdr->tail[0].iov_len) {
+		/* The tail *will* be in respages[0]; */
+		result = sock->ops->sendpage(sock, rqstp->rq_respages[0], 
+					     ((unsigned long)xdr->tail[0].iov_base)& (PAGE_SIZE-1),
+					     xdr->tail[0].iov_len, 0);
+
+		if (result > 0)
+			len += result;
+	}
+out:
+	up(&svsk->sk_sem);
 
-	dprintk("svc: socket %p sendto([%p %Zu... ], %d, %d) = %d (addr %x)\n",
-			rqstp->rq_sock, iov[0].iov_base, iov[0].iov_len, nr, buflen, len,
+	dprintk("svc: socket %p sendto([%p %Zu... ], %d) = %d (addr %x)\n",
+			rqstp->rq_sock, xdr->head[0].iov_base, xdr->head[0].iov_len, xdr->len, len,
 		rqstp->rq_addr.sin_addr.s_addr);
 
 	return len;
@@ -550,35 +599,11 @@
 svc_udp_sendto(struct svc_rqst *rqstp)
 {
 	int		error;
-	struct iovec vec[RPCSVC_MAXPAGES];
-	int v;
-	int base, len;
 
-	/* Set up the first element of the reply iovec.
-	 * Any other iovecs that may be in use have been taken
-	 * care of by the server implementation itself.
-	 */
-	vec[0] = rqstp->rq_res.head[0];
-	v=1;
-	base=rqstp->rq_res.page_base;
-	len = rqstp->rq_res.page_len;
-	while (len) {
-		vec[v].iov_base = page_address(rqstp->rq_res.pages[v-1]) + base;
-		vec[v].iov_len = PAGE_SIZE-base;
-		if (len <= vec[v].iov_len)
-			vec[v].iov_len = len;
-		len -= vec[v].iov_len;
-		base = 0;
-		v++;
-	}
-	if (rqstp->rq_res.tail[0].iov_len) {
-		vec[v] = rqstp->rq_res.tail[0];
-		v++;
-	}
-	error = svc_sendto(rqstp, vec, v);
+	error = svc_sendto(rqstp, &rqstp->rq_res);
 	if (error == -ECONNREFUSED)
 		/* ICMP error on earlier request. */
-		error = svc_sendto(rqstp, vec, v);
+		error = svc_sendto(rqstp, &rqstp->rq_res);
 
 	return error;
 }
@@ -940,9 +965,6 @@
 svc_tcp_sendto(struct svc_rqst *rqstp)
 {
 	struct xdr_buf	*xbufp = &rqstp->rq_res;
-	struct iovec vec[RPCSVC_MAXPAGES];
-	int v;
-	int base, len;
 	int sent;
 	u32 reclen;
 
@@ -953,25 +975,7 @@
 	reclen = htonl(0x80000000|((xbufp->len ) - 4));
 	memcpy(xbufp->head[0].iov_base, &reclen, 4);
 
-	vec[0] = rqstp->rq_res.head[0];
-	v=1;
-	base= xbufp->page_base;
-	len = xbufp->page_len;
-	while (len) {
-		vec[v].iov_base = page_address(xbufp->pages[v-1]) + base;
-		vec[v].iov_len = PAGE_SIZE-base;
-		if (len <= vec[v].iov_len)
-			vec[v].iov_len = len;
-		len -= vec[v].iov_len;
-		base = 0;
-		v++;
-	}
-	if (xbufp->tail[0].iov_len) {
-		vec[v] = xbufp->tail[0];
-		v++;
-	}
-
-	sent = svc_sendto(rqstp, vec, v);
+	sent = svc_sendto(rqstp, &rqstp->rq_res);
 	if (sent != xbufp->len) {
 		printk(KERN_NOTICE "rpc-srv/tcp: %s: %s %d when sending %d bytes - shutting down socket\n",
 		       rqstp->rq_sock->sk_server->sv_name,
@@ -1066,9 +1070,8 @@
 
 	/* Initialize the buffers */
 	/* first reclaim pages that were moved to response list */
-	while (rqstp->rq_resused) 
-		rqstp->rq_argpages[rqstp->rq_arghi++] =
-			rqstp->rq_respages[--rqstp->rq_resused];
+	svc_pushback_allpages(rqstp);
+
 	/* now allocate needed pages.  If we get a failure, sleep briefly */
 	pages = 2 + (serv->sv_bufsz + PAGE_SIZE -1) / PAGE_SIZE;
 	while (rqstp->rq_arghi < pages) {
@@ -1192,6 +1195,7 @@
 {
 	struct svc_sock	*svsk;
 	int		len;
+	struct xdr_buf	*xb;
 
 	if ((svsk = rqstp->rq_sock) == NULL) {
 		printk(KERN_WARNING "NULL socket pointer in %s:%d\n",
@@ -1202,6 +1206,12 @@
 	/* release the receive skb before sending the reply */
 	svc_release_skb(rqstp);
 
+	/* calculate over-all length */
+	xb = & rqstp->rq_res;
+	xb->len = xb->head[0].iov_len +
+		xb->page_len +
+		xb->tail[0].iov_len;
+
 	len = svsk->sk_sendto(rqstp);
 	svc_sock_release(rqstp);
 
@@ -1238,6 +1248,7 @@
 	svsk->sk_server = serv;
 	svsk->sk_lastrecv = CURRENT_TIME;
 	INIT_LIST_HEAD(&svsk->sk_deferred);
+	sema_init(&svsk->sk_sem, 1);
 
 	/* Initialize the socket */
 	if (sock->type == SOCK_DGRAM)
diff -Nru a/net/sunrpc/timer.c b/net/sunrpc/timer.c
--- a/net/sunrpc/timer.c	Sun Nov 10 19:28:41 2002
+++ b/net/sunrpc/timer.c	Sun Nov 10 19:28:41 2002
@@ -1,3 +1,20 @@
+/*
+ * linux/net/sunrpc/timer.c
+ *
+ * Estimate RPC request round trip time.
+ *
+ * Based on packet round-trip and variance estimator algorithms described
+ * in appendix A of "Congestion Avoidance and Control" by Van Jacobson
+ * and Michael J. Karels (ACM Computer Communication Review; Proceedings
+ * of the Sigcomm '88 Symposium in Stanford, CA, August, 1988).
+ *
+ * This RTT estimator is used only for RPC over datagram protocols.
+ *
+ * Copyright (C) 2002 Trond Myklebust <trond.myklebust@fys.uio.no>
+ */
+
+#include <asm/param.h>
+
 #include <linux/version.h>
 #include <linux/types.h>
 #include <linux/unistd.h>
@@ -11,38 +28,53 @@
 #define RPC_RTO_MIN (2)
 
 void
-rpc_init_rtt(struct rpc_rtt *rt, long timeo)
+rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo)
 {
-	long t = (timeo - RPC_RTO_INIT) << 3;
-	int i;
+	unsigned long init = 0;
+	unsigned i;
+
 	rt->timeo = timeo;
-	if (t < 0)
-		t = 0;
+
+	if (timeo > RPC_RTO_INIT)
+		init = (timeo - RPC_RTO_INIT) << 3;
 	for (i = 0; i < 5; i++) {
-		rt->srtt[i] = t;
+		rt->srtt[i] = init;
 		rt->sdrtt[i] = RPC_RTO_INIT;
 	}
+
 	atomic_set(&rt->ntimeouts, 0);
 }
 
+/*
+ * NB: When computing the smoothed RTT and standard deviation,
+ *     be careful not to produce negative intermediate results.
+ */
 void
-rpc_update_rtt(struct rpc_rtt *rt, int timer, long m)
+rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m)
 {
-	long *srtt, *sdrtt;
+	unsigned long *srtt, *sdrtt;
 
 	if (timer-- == 0)
 		return;
 
+	/* jiffies wrapped; ignore this one */
+	if (m < 0)
+		return;
+
 	if (m == 0)
-		m = 1;
+		m = 1L;
+
 	srtt = &rt->srtt[timer];
 	m -= *srtt >> 3;
 	*srtt += m;
+
 	if (m < 0)
 		m = -m;
+
 	sdrtt = &rt->sdrtt[timer];
 	m -= *sdrtt >> 2;
 	*sdrtt += m;
+
 	/* Set lower bound on the variance */
 	if (*sdrtt < RPC_RTO_MIN)
 		*sdrtt = RPC_RTO_MIN;
@@ -61,14 +93,17 @@
  * other                   - timeo
  */
 
-long
-rpc_calc_rto(struct rpc_rtt *rt, int timer)
+unsigned long
+rpc_calc_rto(struct rpc_rtt *rt, unsigned timer)
 {
-	long res;
+	unsigned long res;
+
 	if (timer-- == 0)
 		return rt->timeo;
+
 	res = (rt->srtt[timer] >> 3) + rt->sdrtt[timer];
 	if (res > RPC_RTO_MAX)
 		res = RPC_RTO_MAX;
+
 	return res;
 }
diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
--- a/net/sunrpc/xprt.c	Sun Nov 10 19:28:40 2002
+++ b/net/sunrpc/xprt.c	Sun Nov 10 19:28:40 2002
@@ -389,12 +389,6 @@
 	sk->no_check	 = 0;
 
 	sock_release(sock);
-	/*
-	 *	TCP doesn't require the rpciod now - other things may
-	 *	but rpciod handles that not us.
-	 */
-	if(xprt->stream)
-		rpciod_down();
 }
 
 /*
@@ -590,9 +584,11 @@
 		xprt_adjust_cwnd(xprt, copied);
 		__xprt_put_cong(xprt, req);
 	       	if (!req->rq_nresend) {
-			int timer = rpcproc_timer(clnt, task->tk_msg.rpc_proc);
+			unsigned timer =
+				rpcproc_timer(clnt, task->tk_msg.rpc_proc);
 			if (timer)
-				rpc_update_rtt(&clnt->cl_rtt, timer, (long)jiffies - req->rq_xtime);
+				rpc_update_rtt(&clnt->cl_rtt, timer,
+						(long)jiffies - req->rq_xtime);
 		}
 		rpc_clear_timeo(&clnt->cl_rtt);
 	}
@@ -911,7 +907,12 @@
 		unsigned int offset, size_t len)
 {
 	struct rpc_xprt *xprt = (struct rpc_xprt *)rd_desc->buf;
-	skb_reader_t desc = { skb, offset, len };
+	skb_reader_t desc = {
+		.skb	= skb,
+		.offset	= offset,
+		.count	= len,
+		.csum	= 0
+       	};
 
 	dprintk("RPC:      tcp_data_recv\n");
 	do {
@@ -1457,11 +1458,6 @@
 	/* Reset to new socket */
 	xprt->sock = sock;
 	xprt->inet = sk;
-	/*
-	 *	TCP requires the rpc I/O daemon is present
-	 */
-	if(xprt->stream)
-		rpciod_up();
 
 	return;
 }
@@ -1547,7 +1543,7 @@
  out_bad:
 	dprintk("RPC:      xprt_create_proto failed\n");
 	if (xprt)
-		rpc_free(xprt);
+		kfree(xprt);
 	return NULL;
 }
 
@@ -1586,7 +1582,7 @@
 	dprintk("RPC:      destroying transport %p\n", xprt);
 	xprt_shutdown(xprt);
 	xprt_close(xprt);
-	rpc_free(xprt);
+	kfree(xprt);
 
 	return 0;
 }
diff -Nru a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c
--- a/net/wanrouter/af_wanpipe.c	Sun Nov 10 19:28:41 2002
+++ b/net/wanrouter/af_wanpipe.c	Sun Nov 10 19:28:41 2002
@@ -512,6 +512,7 @@
 
 	/* Use timer to send data to the driver. This will act
          * as a BH handler for sendmsg functions */
+	init_timer(&wan_opt->tx_timer);
 	wan_opt->tx_timer.data	   = (unsigned long)sk;
 	wan_opt->tx_timer.function = wanpipe_delayed_transmit;
 
@@ -1922,30 +1923,6 @@
 			sock->file->f_flags |= O_NONBLOCK;
 			return 0;
 	
-		case SIOCGIFFLAGS:
-#ifndef CONFIG_INET
-		case SIOCSIFFLAGS:
-#endif
-		case SIOCGIFCONF:
-		case SIOCGIFMETRIC:
-		case SIOCSIFMETRIC:
-		case SIOCGIFMEM:
-		case SIOCSIFMEM:
-		case SIOCGIFMTU:
-		case SIOCSIFMTU:
-		case SIOCSIFLINK:
-		case SIOCGIFHWADDR:
-		case SIOCSIFHWADDR:
-		case SIOCSIFMAP:
-		case SIOCGIFMAP:
-		case SIOCSIFSLAVE:
-		case SIOCGIFSLAVE:
-		case SIOCGIFINDEX:
-		case SIOCGIFNAME:
-		case SIOCGIFCOUNT:
-		case SIOCSIFHWBROADCAST:
-			return(dev_ioctl(cmd,(void *) arg));
-
 #ifdef CONFIG_INET
 		case SIOCADDRT:
 		case SIOCDELRT:
@@ -1968,7 +1945,7 @@
 #endif
 
 		default:
-			return -EOPNOTSUPP;
+			return dev_ioctl(cmd,(void *) arg);
 	}
 	/*NOTREACHED*/
 }
diff -Nru a/scripts/Configure b/scripts/Configure
--- a/scripts/Configure	Sun Nov 10 19:28:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,688 +0,0 @@
-#! /bin/sh
-#
-# This script is used to configure the Linux kernel.
-#
-# It was inspired by the challenge in the original Configure script
-# to ``do something better'', combined with the actual need to ``do
-# something better'' because the old configure script wasn't flexible
-# enough.
-#
-# Raymond Chen was the original author of Configure.
-# Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
-#
-# 050793 - use IFS='@' to get around a bug in a pre-version of bash-1.13
-# with an empty IFS.
-#
-# 030995 (storner@osiris.ping.dk) - added support for tri-state answers,
-# for selecting modules to compile.
-#
-# 180995 Bernhard Kaindl (bkaindl@ping.at) - added dummy functions for
-# use with a config.in modified for make menuconfig.
-#
-# 301195 (boldt@math.ucsb.edu) - added help text support
-#
-# 281295 Paul Gortmaker - make tri_state functions collapse to boolean
-# if module support is not enabled.
-#
-# 010296 Aaron Ucko (ucko@vax1.rockhurst.edu) - fix int and hex to accept
-# arbitrary ranges
-#
-# 150296 Dick Streefland (dicks@tasking.nl) - report new configuration
-# items and ask for a value even when doing a "make oldconfig"
-#
-# 200396 Tom Dyas (tdyas@eden.rutgers.edu) - when the module option is
-# chosen for an item, define the macro <option_name>_MODULE
-#
-# 090397 Axel Boldt (boldt@math.ucsb.edu) - avoid ? and + in regular 
-# expressions for GNU expr since version 1.15 and up use \? and \+.
-#
-# 300397 Phil Blundell (pjb27@cam.ac.uk) - added support for min/max 
-# arguments to "int", allow dep_tristate to take a list of dependencies
-# rather than just one.
-#
-# 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
-# texts.
-#
-# 102598 Michael Chastain (mec@shout.net) - put temporary files in
-# current directory, not in /tmp.
-#
-# 24 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
-# - Improve the exit message (Jeff Ronne).
-#
-# 7 October 2000, Ghozlane Toumi, <gtoumi@messel.emse.fr>
-# added switches for "random" , "all yes" and "all modules"
-#
-
-#
-# Make sure we're really running bash.
-#
-# I would really have preferred to write this script in a language with
-# better string handling, but alas, bash is the only scripting language
-# that I can be reasonable sure everybody has on their linux machine.
-#
-[ -z "$BASH" ] && { echo "Configure requires bash" 1>&2; exit 1; }
-
-# Disable filename globbing once and for all.
-# Enable function cacheing.
-set -f -h
-
-#
-# Dummy functions for use with a config.in modified for menuconf
-#
-function mainmenu_option () {
-	:
-}
-function mainmenu_name () {
-	:
-}
-function endmenu () {
-	:
-}
-
-#
-# returns a random number between 1 and $1
-#
-function rnd () {
-	rnd=$[ $RANDOM  %  $1 + 1 ]
-}
-
-#
-# randomly chose a number in a config list (LIST_CONFIG_NAME)
-# or in a range ( MIN_CONFIG_NAME MAX_CONFIG_NAME )
-# ONLY if there is no forced default (and we are in an "auto" mode)
-# we are limited by the range of values taken by  "$RANDOM"
-#
-#       rndval CONFIG_NAME
-#
-
-function rndval () {
-	[ "$AUTO" != "yes" -o -n "$old" ] && return
-	def_list=$(eval echo "\${LIST_$1}")
-	def_min=$(eval echo "\${MIN_$1}")
-	def_max=$(eval echo "\${MAX_$1}")
-
-	if [ -n "$def_list" ]; then
-	  set -- $(echo $def_list | sed 's/,/ /g')
-	  rnd $#
-	  while [ $rnd -le $# ] ; do
-	    def=$1
-	    shift
-	  done
-	  return
-	fi
-	if [ -n "$def_min" -a -n "$def_max" ]; then
-	  rnd $[ $def_max - $def_min ]
-	  def=$[ $def_min + $rnd ]
-	fi
-}
-
-#
-# help prints the corresponding help text from Configure.help to stdout
-#
-#       help variable
-#
-function help () {
-   #first escape regexp special characters in the argument:
-   var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
-   #now pick out the right help text:
-   text=$(cat /dev/null $(find . -name Config.help) |
-	sed -n "/^$var[ 	]*\$/,\${
-			/^$var[ 	]*\$/c\\
-${var}:\\
-
-			/^#/b
-			/^[^ 	]/q
-			/<file:\\([^>]*\\)>/s//\\1/g
-			p
-		    }")
-   if [ -z "$text" ]
-   then
-	echo; echo "  Sorry, no help available for this option yet.";echo
-   else
-	(echo; echo "$text"; echo) | ${PAGER:-more}
-   fi
-}
-
-
-#
-# readln reads a line into $ans.
-#
-#	readln prompt default oldval
-#
-function readln () {
-	if [ "$AUTO" = "yes" ]; then 
-		echo -n "$1"
-		ans=$2
-		echo $ans
-	elif [ "$DEFAULT" = "-d" -a -n "$3" ]; then
-		echo "$1"
-		ans=$2
-	else
-		echo -n "$1"
-		[ -z "$3" ] && echo -n "(NEW) "
-		IFS='@' read ans || exit 1
-		[ -z "$ans" ] && ans=$2
-	fi
-}
-
-#
-# comment does some pretty-printing
-#
-#	comment 'xxx'
-# 
-function comment () {
-	echo "*"; echo "* $1" ; echo "*"
-	(echo "" ; echo "#"; echo "# $1" ; echo "#") >>$CONFIG
-	(echo "" ; echo "/*"; echo " * $1" ; echo " */") >>$CONFIG_H
-}
-
-#
-# define_bool sets the value of a boolean argument
-#
-#	define_bool define value
-#
-function define_bool () {
-	define_tristate $1 $2
-}
-
-function define_tristate () {
-	case "$2" in
-	 "y")
-		echo "$1=y" >>$CONFIG
-		echo "#define $1 1" >>$CONFIG_H
-		;;
-
-	 "m")
-		echo "$1=m" >>$CONFIG
-		echo "#undef  $1" >>$CONFIG_H
-		echo "#define $1_MODULE 1" >>$CONFIG_H
-		;;
-
-	 "n")
-		echo "# $1 is not set" >>$CONFIG
-		echo "#undef  $1" >>$CONFIG_H
-		;;
-	esac
-	eval "$1=$2"
-}
-
-#
-# bool processes a boolean argument
-#
-#	bool question define
-#
-function bool () {
-	old=$(eval echo "\${$2}")
-	def=${old:-'n'}
-	if [ "$AUTO" = "yes" -a -z "$old" ]; then
-	  if [ "$RND" = "-r" ]; then
-	    rnd 2
-	    case $rnd in
-	      "1") def="y" ;;
-	      "2") def="n" ;;
-	    esac
-	  else
-	    def=$DEF_ANS;
-	  fi
-	fi
-	case "$def" in
-	 "y" | "m") defprompt="Y/n/?"
-	      def="y"
-	      ;;
-	 "n") defprompt="N/y/?"
-	      ;;
-	esac
-	while :; do
-	  readln "$1 ($2) [$defprompt] " "$def" "$old"
-	  case "$ans" in
-	    [yY] | [yY]es ) define_bool "$2" "y"
-			    break;;
-	    [nN] | [nN]o )  define_bool "$2" "n"
-			    break;;
-	    * )             help "$2"
-			    ;;
-	  esac
-	done
-}
-
-#
-# tristate processes a tristate argument
-#
-#	tristate question define
-#
-function tristate () {
-	if [ "$CONFIG_MODULES" != "y" ]; then
-	  bool "$1" "$2"
-	else 
-	  old=$(eval echo "\${$2}")
-	  def=${old:-'n'}
-	  if [ "$AUTO" = "yes" -a -z "$old" ]; then
-	     if [ "$RND" = "-r" ]; then 
-	      rnd 3
-	      case $rnd in
-	        "1") def="y" ;;
-	        "2") def="n" ;;
-	        "3") def="m" ;;
-	      esac
-	    else
-	      def=$DEF_ANS
-	    fi
-	  fi
-	  case "$def" in
-	   "y") defprompt="Y/m/n/?"
-		;;
-	   "m") defprompt="M/n/y/?"
-		;;
-	   "n") defprompt="N/y/m/?"
-		;;
-	  esac
-	  while :; do
-	    readln "$1 ($2) [$defprompt] " "$def" "$old"
-	    case "$ans" in
-	      [yY] | [yY]es ) define_tristate "$2" "y"
-			      break ;;
-	      [nN] | [nN]o )  define_tristate "$2" "n"
-			      break ;;
-	      [mM] )          define_tristate "$2" "m"
-			      break ;;
-	      * )             help "$2"
-			      ;;
-	    esac
-	  done
-	fi
-}
-
-#
-# dep_tristate processes a tristate argument that depends upon
-# another option or options.  If any of the options we depend upon is a
-# module, then the only allowable options are M or N.  If all are Y, then
-# this is a normal tristate.  This is used in cases where modules
-# are nested, and one module requires the presence of something
-# else in the kernel.
-#
-#	dep_tristate question define default ...
-#
-function dep_tristate () {
-	old=$(eval echo "\${$2}")
-	def=${old:-'n'}
-	ques=$1
-	var=$2
-	need_module=0
-	shift 2
-	while [ $# -gt 0 ]; do
-	  case "$1" in
- 	    n)
-	      define_tristate "$var" "n"
-	      return
-	      ;;
-	    m)
-	      need_module=1
-	      ;;
-	  esac
-	  shift
-	done
-
-	if [ $need_module = 1 ]; then
-	   if [ "$CONFIG_MODULES" = "y" ]; then
-		if [ "$AUTO" = "yes" -a -z "$old" ]; then
-		   if [ "$RND" = "-r" ]; then
-		      rnd 2
-		      case $rnd in
-			"1") def="m" ;;
-			"2") def="n" ;;
-		      esac
-		   else
-		      def=$DEF_ANS
-		   fi
-		fi
-		case "$def" in
-		 "y" | "m") defprompt="M/n/?"
-		      def="m"
-		      ;;
-		 "n") defprompt="N/m/?"
-		      ;;
-		esac
-		while :; do
-		  readln "$ques ($var) [$defprompt] " "$def" "$old"
-		  case "$ans" in
-		      [nN] | [nN]o )  define_tristate "$var" "n"
-				      break ;;
-		      [mM] )          define_tristate "$var" "m"
-				      break ;;
-		      [yY] | [yY]es ) echo 
-   echo "  This answer is not allowed, because it is not consistent with"
-   echo "  your other choices."
-   echo "  This driver depends on another one which you chose to compile"
-   echo "  as a module. This means that you can either compile this one"
-   echo "  as a module as well (with M) or leave it out altogether (N)."
-				      echo
-				      ;;
-		      * )             help "$var"
-				      ;;
-		  esac
-		done
-	   fi
-	else
-	   tristate "$ques" "$var"
-	fi
-}
-
-function dep_bool () {
-	ques=$1
-	var=$2
-	shift 2
-	while [ $# -gt 0 ]; do
-	  case "$1" in
-	    m | n)
-	      define_bool "$var" "n"
-	      return
-	      ;;
-	  esac
-	  shift
-	done
-
-	bool "$ques" "$var"
-}
-
-function dep_mbool () {
-	ques=$1
-	var=$2
-	shift 2
-	while [ $# -gt 0 ]; do
-	  case "$1" in
-	    n)
-	      define_bool "$var" "n"
-	      return
-	      ;;
-	  esac
-	  shift
-	done
-
-	bool "$ques" "$var"
-}
-
-#
-# define_int sets the value of a integer argument
-#
-#	define_int define value
-#
-function define_int () {
-	echo "$1=$2" >>$CONFIG
-	echo "#define $1 ($2)" >>$CONFIG_H
-	eval "$1=$2"
-}
-
-#
-# int processes an integer argument with optional limits
-#
-#	int question define default
-#
-function int () {
-	old=$(eval echo "\${$2}")
-	def=${old:-$3}
-	rndval $2
-	while :; do
-	  readln "$1 ($2) [$def] " "$def" "$old"
-	  if expr "$ans" : '[0-9]*$' > /dev/null; then
-            define_int "$2" "$ans"
-	    break
-          else
-	    help "$2"
-          fi
-	done
-}
-
-#
-# define_hex sets the value of a hexadecimal argument
-#
-#	define_hex define value
-#
-function define_hex () {
-	echo "$1=$2" >>$CONFIG
-	echo "#define $1 0x${2#*[x,X]}" >>$CONFIG_H
-	eval "$1=$2"
-}
-
-#
-# hex processes an hexadecimal argument
-#
-#	hex question define default
-#
-function hex () {
-	old=$(eval echo "\${$2}")
-	def=${old:-$3}
-	def=${def#*[x,X]}
-	rndval $2
-	while :; do
-	  readln "$1 ($2) [$def] " "$def" "$old"
-	  ans=${ans#*[x,X]}
-	  if expr "$ans" : '[0-9a-fA-F][0-9a-fA-F]*$' > /dev/null; then
-	    define_hex "$2" "$ans"
-	    break
-	  else
-	    help "$2"
-	  fi
-	done
-}
-
-#
-# define_string sets the value of a string argument
-#
-#	define_string define value
-#
-function define_string () {
-	echo "$1=\"$2\"" >>$CONFIG
-	echo "#define $1 \"$2\"" >>$CONFIG_H
-	eval "$1=\"$2\""
-}
-
-#
-# string processes a string argument
-#
-#	string question define default
-#
-function string () {
-	old=$(eval echo "\${$2}")
-	def=${old:-$3}
-	while :; do
-          if [ "$old" = "?" ]; then
-             readln "$1 ($2) [$def] " "$def" ""
-          else
-	     readln "$1 ($2) [$def] " "$def" "$old"
-          fi
-	  if [ "$ans" = "?" ]; then
-	    help "$2"
-	  else
-	    break
-	  fi
-	done
-	define_string "$2" "$ans"
-}
-#
-# choice processes a choice list (1-out-of-n)
-#
-#	choice question choice-list default
-#
-# The choice list has a syntax of:
-#	NAME WHITESPACE VALUE { WHITESPACE NAME WHITESPACE VALUE }
-# The user may enter any unique prefix of one of the NAMEs and
-# choice will define VALUE as if it were a boolean option.
-# VALUE must be in all uppercase.  Normally, VALUE is of the
-# form CONFIG_<something>.  Thus, if the user selects <something>,
-# the CPP symbol CONFIG_<something> will be defined and the
-# shell variable CONFIG_<something> will be set to "y".
-#
-function choice () {
-	question="$1"
-	choices="$2"
-	old=
-	def=$3
-
-	# determine default answer:
-	names=""
-	set -- $choices
-	firstvar=$2
-	while [ -n "$2" ]; do
-		if [ -n "$names" ]; then
-			names="$names, $1"
-		else
-			names="$1"
-		fi
-		if [ "$(eval echo \"\${$2}\")" = "y" ]; then
-			old=$1
-			def=$1
-		fi
-		shift; shift
-	done
-
-	if [ "$RND" = "-r" -a -z "$old" ] ; then 
-	  set -- $choices
-	  rnd $#
-	  while [ $rnd -le $# ] ; do 
-	    def=$1
-	    shift ; shift
-	  done
-	fi
-
-	val=""
-	while [ -z "$val" ]; do
-		ambg=n
-		readln "$question ($names) [$def] " "$def" "$old"
-		ans=$(echo $ans | tr a-z A-Z)
-		set -- $choices
-		while [ -n "$1" ]; do
-			name=$(echo $1 | tr a-z A-Z)
-			case "$name" in
-				"$ans"* | */"$ans"* )
-					case "$name" in
-						"$ans" | */"$ans"/* | \
-						"$ans"/* | */"$ans" )
-							val="$2"
-							break # exact match
-						;;
-					esac
-					if [ -n "$val" ]; then
-						echo;echo \
-		"  Sorry, \"$ans\" is ambiguous; please enter a longer string."
-						echo
-						val=""
-						ambg=y
-						break
-					else
-						val="$2"
-					fi;;
-			esac
-			shift; shift
-		done
-		if [ "$val" = "" -a "$ambg" = "n" ]; then
-			help "$firstvar"
-		fi
-	done
-	set -- $choices
-	while [ -n "$2" ]; do
-		if [ "$2" = "$val" ]; then
-			echo "  defined $val"
-			define_bool "$2" "y"
-		else
-			define_bool "$2" "n"
-		fi
-		shift; shift
-	done
-}
-
-CONFIG=.tmpconfig
-CONFIG_H=.tmpconfig.h
-FORCE_DEFAULT=.force_default
-trap "rm -f $CONFIG $CONFIG_H ; exit 1" 1 2
-
-#
-# Make sure we start out with a clean slate.
-#
-echo "#" > $CONFIG
-echo "# Automatically generated make config: don't edit" >> $CONFIG
-echo "#" >> $CONFIG
-
-echo "/*" > $CONFIG_H
-echo " * Automatically generated C config: don't edit" >> $CONFIG_H
-echo " */" >> $CONFIG_H
-echo "#define AUTOCONF_INCLUDED" >> $CONFIG_H
-
-DEFAULT=""
-if [ "$1" = "-d" ] ; then
-	DEFAULT="-d"
-	shift
-fi
-
-RND=""
-DEF_ANS=""
-AUTO=""
-case "$1" in 
-	-r) RND="-r" ; AUTO="yes" ; shift ;;
-	-y) DEF_ANS="y" ; AUTO="yes" ; shift ;;
-	-m) DEF_ANS="m" ; AUTO="yes" ; shift ;;
-	-n) DEF_ANS="n" ; AUTO="yes" ; shift ;;
-esac
-
-CONFIG_IN=./config.in
-if [ "$1" != "" ] ; then
-	CONFIG_IN=$1
-fi
-
-for DEFAULTS in .config /lib/modules/`uname -r`/.config /etc/kernel-config /boot/config-`uname -r` arch/$ARCH/defconfig
-do
-  [ -r $DEFAULTS ] && break
-done
-
-if [ "$AUTO" != "yes" ]; then
-  if [ -f $DEFAULTS ]; then
-    echo "#"
-    echo "# Using defaults found in" $DEFAULTS
-    echo "#"
-    . $DEFAULTS
-    sed -e 's/# \(CONFIG_[^ ]*\) is not.*/\1=n/' <$DEFAULTS >.config-is-not.$$
-    . .config-is-not.$$
-    rm .config-is-not.$$
-  else
-    echo "#"
-    echo "# No defaults found"
-    echo "#"
-  fi
-else
-  if [ -f $FORCE_DEFAULT ]; then
-    echo "#"
-    echo "# Forcing defaults found in $FORCE_DEFAULT"
-    echo "#"
-    sed -e '
-s/# \(CONFIG_[^ ]*\) is not.*/\1=n/;
-s/# range \(CONFIG_[^ ]*\) \([^ ][^ ]*\) \([^ ][^ ]*\)/MIN_\1=\2; MAX_\1=\3/;
-s/# list \(CONFIG_[^ ]*\) \([^ ][^ ]*\)/LIST_\1=\2/
-' <$FORCE_DEFAULT >.default_val.$$
-    . .default_val.$$
-    rm .default_val.$$
-  else
-    echo "#"
-    echo "# No defaults found"
-    echo "#"
-  fi 
-fi
-
-. $CONFIG_IN
-
-rm -f .config.old
-if [ -f .config ]; then
-	mv .config .config.old
-fi
-mv .tmpconfig .config
-mv .tmpconfig.h include/linux/autoconf.h
-
-echo
-echo "*** End of Linux kernel configuration."
-echo "*** Check the top-level Makefile for additional configuration."
-if [ ! -f .hdepend -o "$CONFIG_MODVERSIONS" = "y" ] ; then
-    echo "*** Next, you must run 'make dep'."
-else
-    echo "*** Next, you may run 'make bzImage', 'make bzdisk', or 'make install'."
-fi
-echo
-
-exit 0
diff -Nru a/scripts/Makefile b/scripts/Makefile
--- a/scripts/Makefile	Sun Nov 10 19:28:40 2002
+++ b/scripts/Makefile	Sun Nov 10 19:28:40 2002
@@ -7,7 +7,6 @@
 #                include/config/...
 # docproc: 	 Preprocess .tmpl file in order to generate .sgml documentation
 # conmakehash:	 Create arrays for initializing the kernel console tables
-# tkparse: 	 Used by xconfig
 
 EXTRA_TARGETS := fixdep split-include docproc conmakehash
 
@@ -23,33 +22,10 @@
 # can't do it
 # ---------------------------------------------------------------------------
 
-host-progs := fixdep split-include conmakehash docproc tkparse
-tkparse-objs := tkparse.o tkcond.o tkgen.o
-
-clean-files := kconfig.tk
+host-progs := fixdep split-include conmakehash docproc
 
 include $(TOPDIR)/Rules.make
 
-# In reality kconfig.tk should depend on all Config.in files,
-# but it is not worth the effort to generate the dependencies.
-# The alternative solution to always generate it is fairly fast.
-# FORCE it to remake
-$(obj)/kconfig.tk: $(srctree)/arch/$(ARCH)/config.in $(obj)/tkparse FORCE
-	@echo '  Generating $@'
-	@(                                                      \
-	if [ -f /usr/local/bin/wish ];        then              \
-		echo '#!'"/usr/local/bin/wish -f";              \
-	else                                                    \
-		echo '#!'"/usr/bin/wish -f";                    \
-	fi;                                                     \
-	cat $(src)/header.tk;                                   \
-	$(obj)/tkparse < $<;                                    \
-	echo "set defaults \"arch/${ARCH}/defconfig\"";         \
-	echo "set ARCH \"${ARCH}\"";                            \
-	cat $(src)/tail.tk;                                     \
-	) > $@
-	@chmod 755 $@
-
 
 # ---------------------------------------------------------------------------
 # Targets hardcoded and wellknow in top-level makefile
@@ -58,5 +34,5 @@
 	$(call descend,scripts/lxdialog,)
 
 # fixdep is needed to compile other host programs
-$(obj)/split-include $(obj)/docproc $(addprefix $(obj)/,$(tkparse-objs)) \
+$(obj)/split-include $(obj)/docproc \
 $(obj)/conmakehash lxdialog: $(obj)/fixdep
diff -Nru a/scripts/Menuconfig b/scripts/Menuconfig
--- a/scripts/Menuconfig	Sun Nov 10 19:28:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1469 +0,0 @@
-#! /bin/sh
-#
-# This script is used to configure the linux kernel.
-#
-# It was inspired by a desire to not have to hit <enter> 9 million times
-# or startup the X server just to change a single kernel parameter.  
-#
-# This script attempts to parse the configuration files, which are
-# scattered throughout the kernel source tree, and creates a temporary
-# set of mini scripts which are in turn used to create nested menus and
-# radiolists.
-#
-# It uses a very modified/mutilated version of the "dialog" utility
-# written by Savio Lam (lam836@cs.cuhk.hk). Savio is not responsible
-# for this script or the version of dialog used by this script.
-# Please do not contact him with questions. The official version of 
-# dialog is available at sunsite.unc.edu or a sunsite mirror.
-#
-# Portions of this script were borrowed from the original Configure
-# script.
-#
-# William Roadcap was the original author of Menuconfig.
-# Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
-#
-# 070497 Bernhard Kaindl (bkaindl@netway.at) - get default values for
-# new bool, tristate and dep_tristate parameters from the defconfig file.
-# new configuration parameters are marked with '(NEW)' as in make config.
-#
-# 180697 Bernhard Kaindl (bkaindl@netway.at) - added the needed support
-# for string options. They are handled like the int and hex options.
-#
-# 081297 Pavel Machek (pavel@atrey.karlin.mff.cuni.cz) - better error 
-# handling
-#
-# 131197 Michael Chastain (mec@shout.net) - output all lines for a
-# choice list, not just the selected one.  This makes the output
-# the same as Configure output, which is important for smart config
-# dependencies.
-#
-# 101297 Michael Chastain (mec@shout.net) - remove sound driver cruft.
-#
-# 221297 Michael Chastain (mec@shout.net) - make define_bool actually
-# define its arguments so that later tests on them work right.
-#
-# 160198 Michael Chastain (mec@shout.net) - fix bug with 'c' command
-# (complement existing value) when used on virgin uninitialized variables.
-#
-# 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
-# texts.
-#
-# 12 Dec 1998, Michael Elizabeth Chastain (mec@shout.net)
-# Remove a /tmp security hole in get_def (also makes it faster).
-# Give uninitialized variables canonical values rather than null value.
-# Change a lot of places to call set_x_info uniformly.
-# Take out message about preparing version (old sound driver cruft).
-#
-# 13 Dec 1998, Riley H Williams <rhw@memalpha.cx>
-# When an error occurs, actually display the error message as well as
-# our comments thereon.
-#
-# 31 Dec 1998, Michael Elizabeth Chastain (mec@shout.net)
-# Fix mod_bool to honor $CONFIG_MODULES.
-# Fix dep_tristate to call define_bool when dependency is "n".
-#
-# 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
-# Blow away lxdialog.scrltmp on entry to activate_menu.  This protects
-# against people who use commands like ' ' to select menus.
-#
-# 24 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
-# - Improve the exit message (Jeff Ronne).
-#
-# 06 July 1999, Andrzej M. Krzysztofowicz, <ankry@mif.pg.gda.pl>
-# - Support for multiple conditions in dep_tristate().
-# - Implemented new functions: define_tristate(), define_int(), define_hex(),
-#   define_string(), dep_bool().
-#
-# 12 November 2001, Keith Owens <kaos@ocs.com.au>
-# Escape double quotes on eval so the quotes are still there on the second
-# evaluation, required to handle strings with special characters.
-# 
-
-
-#
-# Change this to TRUE if you prefer all kernel options listed
-# in a single menu rather than the standard menu hierarchy.
-#
-single_menu_mode=
-
-#
-# Make sure we're really running bash.
-#
-[ -z "$BASH" ] && { echo "Menuconfig requires bash" 1>&2; exit 1; }
-
-#
-# Cache function definitions, turn off posix compliance
-#
-set -h +o posix
-
-
-
-# Given a configuration variable, set the global variable $x to its value,
-# and the global variable $info to the string " (NEW)" if this is a new
-# variable.
-#
-# This function looks for: (1) the current value, or (2) the default value
-# from the arch-dependent defconfig file, or (3) a default passed by the caller.
-
-function set_x_info () {
-    eval x=\$$1
-    if [ -z "$x" ]; then
-	eval `sed -n -e 's/# \(.*\) is not set.*/\1=n/' -e "/^$1=/p" arch/$ARCH/defconfig`
-	eval x=\${$1:-\"$2\"}
-	eval $1=$x
-	eval INFO_$1="' (NEW)'"
-    fi
-    eval info=\"\$INFO_$1\"
-}
-
-#
-# Load the functions used by the config.in files.
-#
-# I do this because these functions must be redefined depending
-# on whether they are being called for interactive use or for
-# saving a configuration to a file.
-#
-# Thank the heavens bash supports nesting function definitions.
-#
-load_functions () {
-
-#
-# Additional comments
-#
-function comment () {
-	comment_ctr=$[ comment_ctr + 1 ]
-	echo -ne "': $comment_ctr' '--- $1' " >>MCmenu
-}
-
-#
-# Define a boolean to a specific value.
-#
-function define_bool () {
-	eval $1=$2
-}
-
-function define_tristate () {
-	eval $1=$2
-}
-
-function define_hex () {
-	eval $1=$2
-}
-
-function define_int () {
-	eval $1=$2
-}
-
-function define_string () {
-	eval $1=\"$2\"
-}
-
-#
-# Create a boolean (Yes/No) function for our current menu
-# which calls our local bool function.
-#
-function bool () {
-	set_x_info "$2" "n"
-
-	case $x in
-	y|m)	flag="*" ;;
-	n)	flag=" " ;;
-	esac
-
-	echo -ne "'$2' '[$flag] $1$info' " >>MCmenu
-
-	echo -e "function $2 () { l_bool '$2' \"\$1\" ;}\n" >>MCradiolists
-}
-
-#
-# Create a tristate (Yes/No/Module) radiolist function
-# which calls our local tristate function.
-#
-# Collapses to a boolean (Yes/No) if module support is disabled.
-#
-function tristate () {
-	if [ "$CONFIG_MODULES" != "y" ]
-	then
-		bool "$1" "$2"
-	else
-		set_x_info "$2" "n"
-	
-		case $x in
-		y) flag="*" ;;
-		m) flag="M" ;;
-		*) flag=" " ;;
-		esac
-	
-		echo -ne "'$2' '<$flag> $1$info' " >>MCmenu
-	
-		echo -e "
-		function $2 () { l_tristate '$2' \"\$1\" ;}" >>MCradiolists
-	fi
-}
-
-#
-# Create a tristate radiolist function which is dependent on
-# another kernel configuration option.
-#
-# Quote from the original configure script:
-#
-#       If the option we depend upon is a module,
-#       then the only allowable options are M or N.  If Y, then
-#       this is a normal tristate.  This is used in cases where modules
-#       are nested, and one module requires the presence of something
-#       else in the kernel.
-#
-function dep_tristate () {
-	ques="$1"
-	var="$2"
-	dep=y
-	shift 2
-	while [ $# -gt 0 ]; do
-		if   [ "$1" = y ]; then
-			shift
-		elif [ "$1" = m ]; then
-			dep=m
-			shift
-		else
-			dep=n
-			shift $#
-		fi
-	done
-	if [ "$dep" = y ]; then
-	    tristate "$ques" "$var"
-	elif [ "$dep" = m ]; then
-	    mod_bool "$ques" "$var"
-	else 
-	    define_tristate "$var" n
-	fi
-}
-
-#
-#   Same as above, but now only Y and N are allowed as dependency
-#   (i.e. third and next arguments).
-#
-function dep_bool () {
-	ques="$1"
-	var="$2"
-	dep=y
-	shift 2
-	while [ $# -gt 0 ]; do
-		if [ "$1" = y ]; then
-			shift
-		else
-			dep=n
-			shift $#
-		fi
-	done
-	if [ "$dep" = y ]; then
-	    bool "$ques" "$var"
-	else 
-	    define_bool "$var" n
-	fi
-}
-
-function dep_mbool () {
-	ques="$1"
-	var="$2"
-	dep=y
-	shift 2
-	while [ $# -gt 0 ]; do
-		if [ "$1" = y -o "$1" = m ]; then
-			shift
-		else
-			dep=n
-			shift $#
-		fi
-	done
-	if [ "$dep" = y ]; then
-	    bool "$ques" "$var"
-	else 
-	    define_bool "$var" n
-	fi
-}
-
-#
-# Add a menu item which will call our local int function.
-# 
-function int () {
-	set_x_info "$2" "$3"
-
-	echo -ne "'$2' '($x) $1$info' " >>MCmenu
-
-	echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' ;}" >>MCradiolists
-}
-
-#
-# Add a menu item which will call our local hex function.
-# 
-function hex () {
-	set_x_info "$2" "$3"
-	x=${x##*[x,X]}
-
-	echo -ne "'$2' '($x) $1$info' " >>MCmenu
-
-	echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' ;}" >>MCradiolists
-}
-
-#
-# Add a menu item which will call our local string function.
-# 
-function string () {
-	set_x_info "$2" "$3"
-
-	echo -ne "'$2' '     $1: \"$x\"$info' " >>MCmenu
-
-	echo -e "function $2 () { l_string '$1' '$2' '$3' '$x' ;}" >>MCradiolists
-}
-
-#
-# Add a menu item which will call our local One-of-Many choice list.
-#
-function choice () {
-	#
-	# Need to remember params cause they're gonna get reset.
-	#
-	title=$1
-	choices=$2
-	default=$3
-	current=
-
-	#
-	# Find out if one of the choices is already set.
-	# If it's not then make it the default.
-	#
-	set -- $choices
-	firstchoice=$2
-
-	while [ -n "$2" ]
-	do
-		if eval [ \"_\$$2\" = \"_y\" ]
-		then
-			current=$1
-			break
-		fi
-		shift ; shift
-	done
-
-	: ${current:=$default}
-
-	echo -ne "'$firstchoice' '($current) $title' " >>MCmenu
-
-	echo -e "
-	function $firstchoice () \
-		{ l_choice '$title' \"$choices\" \"$current\" ;}" >>MCradiolists
-}
-
-} # END load_functions()
-
-
-
-
-
-#
-# Extract available help for an option from Config.help
-# and send it to standard output.
-#
-# Most of this function was borrowed from the original kernel
-# Configure script.
-#
-function extract_help () {
-   #first escape regexp special characters in the argument:
-   var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
-   #now pick out the right help text:
-   text=$(cat /dev/null $(find . -name Config.help) |
-          sed -n "/^$var[ 	]*\$/,\${
-                        /^$var[ 	]*\$/c\\
-${var}:\\
-
-                        /^#/b
-                        /^[^ 	]/q
-                        s/^  //
-			/<file:\\([^>]*\\)>/s//\\1/g
-                        p
-                    }")
-
-   if [ -z "$text" ]
-   then
-        echo "There is no help available for this kernel option."
-        return 1
-   else
-	echo "$text"
-   fi
-}
-
-#
-# Activate a help dialog.
-#
-function help () {
-	if extract_help $1 >help.out
-	then
-		$DIALOG	--backtitle "$backtitle" --title "$2"\
-			--textbox help.out $ROWS $COLS
-	else
-		$DIALOG	--backtitle "$backtitle" \
-			--textbox help.out $ROWS $COLS
-	fi
-	rm -f help.out
-}
-
-#
-# Show the README file.
-#
-function show_readme () {
-	$DIALOG --backtitle "$backtitle" \
-		--textbox scripts/README.Menuconfig $ROWS $COLS
-}
-
-#
-# Begin building the dialog menu command and Initialize the 
-# Radiolist function file.
-#
-function menu_name () {
-	echo -ne "$DIALOG --title '$1'\
-			--backtitle '$backtitle' \
-			--menu '$menu_instructions' \
-			$ROWS $COLS $((ROWS-10)) \
-			'$default' " >MCmenu
-	>MCradiolists
-}
-
-#
-# Add a submenu option to the menu currently under construction.
-#
-function submenu () {
-	echo -ne "'activate_menu $2' '$1  --->' " >>MCmenu
-}
-
-#
-# Handle a boolean (Yes/No) option.
-#
-function l_bool () {
-	if [ -n "$2" ]
-	then
-		case "$2" in
-		y|m)	eval $1=y ;;
-		c)	eval x=\$$1
-		   	case $x in
-		   	y) eval $1=n ;;
-		   	n) eval $1=y ;;
-			*) eval $1=y ;;
-		   	esac ;;
-		*)	eval $1=n ;;
-		esac
-	else
-		echo -ne "\007"
-	fi
-}
-
-#
-# Same as bool() except options are (Module/No)
-#
-function mod_bool () {
-	if [ "$CONFIG_MODULES" != "y" ]; then
-	    define_bool "$2" "n"
-	else
-	    set_x_info "$2" "n"
- 
-	    case $x in
-	    y|m) flag='M' ;;
-	    *)   flag=' ' ;;
-	    esac
- 
-	    echo -ne "'$2' '<$flag> $1$info' " >>MCmenu
- 
-	    echo -e "function $2 () { l_mod_bool '$2' \"\$1\" ;}" >>MCradiolists
-	fi
-}
-
-#
-# Same as l_bool() except options are (Module/No)
-#
-function l_mod_bool() {
-	if [ -n "$2" ]
-	then
-		case "$2" in
-		y)	echo -en "\007"
-			${DIALOG} --backtitle "$backtitle" \
-				  --infobox "\
-This feature depends on another which has been configured as a module.  \
-As a result, this feature will be built as a module." 4 70
-			sleep 5
-			eval $1=m ;;
-		m)	eval $1=m ;;
-		c)	eval x=\$$1
-			case $x in
-			m) eval $1=n ;;
-			n) eval $1=m ;;
-			*) eval $1=m ;;
-			esac ;;
-		*)	eval $1=n ;;
-		esac
-	else
-		echo -ne "\007"
-	fi
-}
-
-#
-# Handle a tristate (Yes/No/Module) option.
-#
-function l_tristate () {
-	if [ -n "$2" ]
-	then
-		eval x=\$$1
-
-		case "$2" in
-		y) eval $1=y ;;
-		m) eval $1=m ;;
-		c) eval x=\$$1
-		   case $x in
-		   y) eval $1=n ;;
-		   n) eval $1=m ;;
-		   m) eval $1=y ;;
-		   *) eval $1=y ;;
-		   esac ;;
-		*) eval $1=n ;;
-		esac
-	else
-		echo -ne "\007"
-	fi
-}
-
-#
-# Create a dialog for entering an integer into a kernel option.
-#
-function l_int () {
-	while true
-	do
-		if $DIALOG --title "$1" \
-			--backtitle "$backtitle" \
-			--inputbox "$inputbox_instructions_int" \
-			10 75 "$4" 2>MCdialog.out
-		then
-			answer="`cat MCdialog.out`"
-			answer="${answer:-$3}"
-
-			# Semantics of + and ? in GNU expr changed, so
-			# we avoid them:
-			if expr "$answer" : '0$' '|' "$answer" : '[1-9][0-9]*$' '|' "$answer" : '-[1-9][0-9]*$' >/dev/null
-			then
-				eval $2=\"$answer\"
-			else
-				eval $2=\"$3\"
-				echo -en "\007"
-				${DIALOG} --backtitle "$backtitle" \
-					--infobox "You have made an invalid entry." 3 43
-				sleep 2
-			fi
-
-			break
-		fi
-
-		help "$2" "$1"
-	done
-}
-
-#
-# Create a dialog for entering a hexadecimal into a kernel option.
-#
-function l_hex () {
-	while true
-	do
-		if $DIALOG --title "$1" \
-			--backtitle "$backtitle" \
-			--inputbox "$inputbox_instructions_hex" \
-			10 75 "$4" 2>MCdialog.out
-		then
-			answer="`cat MCdialog.out`"
-			answer="${answer:-$3}"
-			answer="${answer##*[x,X]}"
-
-			if expr "$answer" : '[0-9a-fA-F][0-9a-fA-F]*$' >/dev/null
-			then
-				eval $2=\"$answer\"
-			else
-				eval $2=\"$3\"
-				echo -en "\007"
-				${DIALOG} --backtitle "$backtitle" \
-					--infobox "You have made an invalid entry." 3 43
-				sleep 2
-			fi
-
-			break
-		fi
-
-		help "$2" "$1"
-	done
-}
-
-#
-# Create a dialog for entering a string into a kernel option.
-#
-function l_string () {
-	while true
-	do
-		if $DIALOG --title "$1" \
-			--backtitle "$backtitle" \
-			--inputbox "$inputbox_instructions_string" \
-			10 75 "$4" 2>MCdialog.out
-		then
-			answer="`cat MCdialog.out`"
-			answer="${answer:-$3}"
-
-			#
-			# Someone may add a nice check for the entered
-			# string here...
-			#
-			eval $2=\"$answer\"
-
-			break
-		fi
-
-		help "$2" "$1"
-	done
-}
-
-
-#
-# Handle a one-of-many choice list.
-#
-function l_choice () {
-	#
-	# Need to remember params cause they're gonna get reset.
-	#
-	title="$1"
-	choices="$2"
-	current="$3"
-        chosen=
-
-	#
-	# Scan current value of choices and set radiolist switches.
-	#
-	list=
-	set -- $choices
-	firstchoice=$2
-	while [ -n "$2" ]
-	do
-		case "$1" in
-		"$current"*)	if [ -z "$chosen" ]; then
-					list="$list $2 $1 ON "
-					chosen=1
-				else
-					list="$list $2 $1 OFF "
-				fi  ;;
-		*)		list="$list $2 $1 OFF " ;;
-		esac
-			
-		shift ; shift
-	done
-
-	while true
-	do
-		if $DIALOG --title "$title" \
-			--backtitle "$backtitle" \
-			--radiolist "$radiolist_instructions" \
-			15 70 6 $list 2>MCdialog.out
-		then
-			choice=`cat MCdialog.out`
-			break
-		fi
-
-		help "$firstchoice" "$title"
-	done
-
-	#
-	# Now set the boolean value of each option based on
-	# the selection made from the radiolist.
-	#
-	set -- $choices
-	while [ -n "$2" ]
-	do
-		if [ "$2" = "$choice" ]
-		then
-			eval $2=\"y\"
-		else
-			eval $2=\"n\"
-		fi
-		
-		shift ; shift
-	done
-}
-
-#
-# Call awk, and watch for error codes, etc.
-#
-function callawk () {
-awk "$1" || { echo "Awk died with error code $?. Giving up."; exit 1; }
-}
-
-#
-# A faster awk based recursive parser. (I hope)
-#
-function parser1 () {
-callawk '
-BEGIN {
-	menu_no = 0
-	comment_is_option = 0
-	parser("'$CONFIG_IN'","MCmenu0")
-}
-
-function parser(ifile,menu) {
-
-	while (getline <ifile) {
-		if ($1 == "mainmenu_option") {
-			comment_is_option = "1"
-		}
-		else if ($1 == "comment" && comment_is_option == "1") {
-			comment_is_option= "0"
-			sub($1,"",$0)
-			++menu_no
-
-			printf("submenu %s MCmenu%s\n", $0, menu_no) >>menu
-
-			newmenu = sprintf("MCmenu%d", menu_no);
-			printf( "function MCmenu%s () {\n"\
-				"default=$1\n"\
-				"menu_name %s\n",\
-				 menu_no, $0) >newmenu
-
-			parser(ifile, newmenu)
-		}
-		else if ($0 ~ /^#|\$MAKE|mainmenu_name/) {
-			printf("") >>menu
-		}
-		else if ($1 ~ "endmenu") {
-			printf("}\n") >>menu
-			return
-		} 
-		else if ($1 == "source") {
-			parser($2,menu)
-		}
-		else {
-			print >>menu
-		}
-	}
-}'
-}
-
-#
-# Secondary parser for single menu mode.
-#
-function parser2 () {
-callawk '
-BEGIN {
-	parser("'$CONFIG_IN'","MCmenu0")
-}
-
-function parser(ifile,menu) {
-
-	while (getline <ifile) {
-		if ($0 ~ /^#|$MAKE|mainmenu_name/) {
-			printf("") >>menu
-		}
-		else if ($1 ~ /mainmenu_option|endmenu/) {
-			printf("") >>menu
-		} 
-		else if ($1 == "source") {
-			parser($2,menu)
-		}
-		else {
-			print >>menu
-		}
-	}
-}'
-}
-
-#
-# Parse all the config.in files into mini scripts.
-#
-function parse_config_files () {
-	rm -f MCmenu*
-
-	echo "function MCmenu0 () {" >MCmenu0
-	echo 'default=$1' >>MCmenu0
-	echo "menu_name 'Main Menu'" >>MCmenu0
-
-	if [ "_$single_menu_mode" = "_TRUE" ]
-	then
-		parser2
-	else
-		parser1
-	fi
-
-	echo "comment ''"	>>MCmenu0
-	echo "g_alt_config" 	>>MCmenu0
-	echo "s_alt_config" 	>>MCmenu0
-
-	echo "}" >>MCmenu0
-
-	#
-	# These mini scripts must be sourced into the current
-	# environment in order for all of this to work.  Leaving
-	# them on the disk as executables screws up the recursion
-	# in activate_menu(), among other things.  Once they are
-	# sourced we can discard them.
-	#
-	for i in MCmenu*
-	do
-		echo -n "."
-		source ./$i
-	done
-	rm -f MCmenu*
-}
-
-#
-# This is the menu tree's bootstrap.
-#
-# Executes the parsed menus on demand and creates a set of functions,
-# one per configuration option.  These functions will in turn execute
-# dialog commands or recursively call other menus.
-#
-function activate_menu () {
-	rm -f lxdialog.scrltmp
-	while true
-	do
-		comment_ctr=0		#So comment lines get unique tags
-
-		$1 "$default" 2> MCerror #Create the lxdialog menu & functions
-
-		if [ "$?" != "0" ]
-		then
-			clear
-			cat <<EOM
-
-Menuconfig has encountered a possible error in one of the kernel's
-configuration files and is unable to continue.  Here is the error
-report:
-
-EOM
-			sed 's/^/ Q> /' MCerror
-			cat <<EOM
-
-Please report this to the maintainer <mec@shout.net>.  You may also
-send a problem report to <linux-kernel@vger.kernel.org>.
-
-Please indicate the kernel version you are trying to configure and
-which menu you were trying to enter when this error occurred.
-
-EOM
-			cleanup
-			exit 1
-		fi
-		rm -f MCerror
-
-		. ./MCradiolists		#Source the menu's functions
-
-		. ./MCmenu 2>MCdialog.out	#Activate the lxdialog menu
-		ret=$?
-
-		read selection <MCdialog.out
-
-		case "$ret" in
-		0|3|4|5|6)
-			defaults="$selection$defaults"  #pseudo stack
-			case "$ret" in
-			0) eval $selection   ;;
-			3) eval $selection y ;;
-			4) eval $selection n ;;
-			5) eval $selection m ;;
-			6) eval $selection c ;;
-			esac
-			default="${defaults%%*}" defaults="${defaults#*}"
-			;;
-		2)	
-			default="${selection%%\ *}"
-
-			case "$selection" in
-			*"-->"*|*"alt_config"*)
-				show_readme ;;
-			*)
-				eval help $selection ;;
-			esac
-			;;
-		255|1)
-			break
-			;;
-		139)
-			stty sane
-			clear
-			cat <<EOM
-
-There seems to be a problem with the lxdialog companion utility which is
-built prior to running Menuconfig.  Usually this is an indicator that you
-have upgraded/downgraded your ncurses libraries and did not remove the 
-old ncurses header file(s) in /usr/include or /usr/include/ncurses.
-
-It is VERY important that you have only one set of ncurses header files
-and that those files are properly version matched to the ncurses libraries 
-installed on your machine.
-
-You may also need to rebuild lxdialog.  This can be done by moving to
-the /usr/src/linux/scripts/lxdialog directory and issuing the 
-"make clean all" command.
-
-If you have verified that your ncurses install is correct, you may email
-the maintainer <mec@shout.net> or post a message to
-<linux-kernel@vger.kernel.org> for additional assistance. 
-
-EOM
-			cleanup
-			exit 139
-			;;
-		esac
-	done
-}
-
-#
-# Create a menu item to load an alternate configuration file.
-#
-g_alt_config () {
-	echo -n "get_alt_config 'Load an Alternate Configuration File' "\
-		>>MCmenu
-}
-
-#
-# Get alternate config file name and load the 
-# configuration from it.
-#
-get_alt_config () {
-	set -f ## Switch file expansion OFF
-
-	while true
-	do
-		ALT_CONFIG="${ALT_CONFIG:-$DEFAULTS}"
-
-		$DIALOG --backtitle "$backtitle" \
-			--inputbox "\
-Enter the name of the configuration file you wish to load.  \
-Accept the name shown to restore the configuration you \
-last retrieved.  Leave blank to abort."\
-			11 55 "$ALT_CONFIG" 2>MCdialog.out
-
-		if [ "$?" = "0" ]
-		then
-			ALT_CONFIG=`cat MCdialog.out`
-
-			[ "_" = "_$ALT_CONFIG" ] && break
-
-			if eval [ -r \"$ALT_CONFIG\" ]
-			then
-				eval load_config_file \"$ALT_CONFIG\"
-				break
-			else
-				echo -ne "\007"
-				$DIALOG	--backtitle "$backtitle" \
-					--infobox "File does not exist!"  3 38
-				sleep 2
-			fi
-		else
-			cat <<EOM >help.out
-
-For various reasons, one may wish to keep several different kernel
-configurations available on a single machine.  
-
-If you have saved a previous configuration in a file other than the
-kernel's default, entering the name of the file here will allow you
-to modify that configuration.
-
-If you are uncertain, then you have probably never used alternate 
-configuration files.  You should therefor leave this blank to abort.
-
-EOM
-			$DIALOG	--backtitle "$backtitle"\
-				--title "Load Alternate Configuration"\
-				--textbox help.out $ROWS $COLS
-		fi
-	done
-
-	set +f ## Switch file expansion ON
-	rm -f help.out MCdialog.out
-}
-
-#
-# Create a menu item to store an alternate config file.
-#
-s_alt_config () {
-	echo -n "save_alt_config 'Save Configuration to an Alternate File' "\
-		 >>MCmenu
-}
-
-#
-# Get an alternate config file name and save the current
-# configuration to it.
-#
-save_alt_config () {
-	set -f  ## Switch file expansion OFF
-			
-	while true
-	do
-		$DIALOG --backtitle "$backtitle" \
-			--inputbox "\
-Enter a filename to which this configuration should be saved \
-as an alternate.  Leave blank to abort."\
-			10 55 "$ALT_CONFIG" 2>MCdialog.out
-
-		if [ "$?" = "0" ]
-		then
-			ALT_CONFIG=`cat MCdialog.out`
-
-			[ "_" = "_$ALT_CONFIG" ] && break
-
-			if eval touch $ALT_CONFIG 2>/dev/null
-			then
-				eval save_configuration $ALT_CONFIG
-				load_functions  ## RELOAD
-				break
-			else
-				echo -ne "\007"
-				$DIALOG	--backtitle "$backtitle" \
-					--infobox "Can't create file!  Probably a nonexistent directory." 3 60
-				sleep 2
-			fi
-		else
-			cat <<EOM >help.out
-
-For various reasons, one may wish to keep different kernel
-configurations available on a single machine.  
-
-Entering a file name here will allow you to later retrieve, modify
-and use the current configuration as an alternate to whatever 
-configuration options you have selected at that time.
-
-If you are uncertain what all this means then you should probably
-leave this blank.
-EOM
-			$DIALOG	--backtitle "$backtitle"\
-				--title "Save Alternate Configuration"\
-				--textbox help.out $ROWS $COLS
-		fi
-	done
-
-	set +f  ## Switch file expansion ON
-	rm -f help.out MCdialog.out
-}
-
-#
-# Load config options from a file.
-# Converts all "# OPTION is not set" lines to "OPTION=n" lines
-#
-function load_config_file () {
-	awk '
-	  /# .* is not set.*/ { printf("%s=n\n", $2) }
-	! /# .* is not set.*/ { print }
-	' $1 >.tmpconfig
-
-	source ./.tmpconfig
-	rm -f .tmpconfig
-}
-
-#
-# Just what it says.
-#
-save_configuration () {
-        echo
-	echo -n "Saving your kernel configuration."
-
-	#
-	# Now, let's redefine the configuration functions for final
-	# output to the config files.
-	#
-	# Nested function definitions, YIPEE!
-	#
-	function bool () {
-		set_x_info "$2" "n"
-		eval define_bool \"$2\" \"$x\"
-	}
-
-	function tristate () {
-		set_x_info "$2" "n"
-		eval define_tristate \"$2\" \"$x\"
-	}
-
-	function dep_tristate () {
-		set_x_info "$2" "n"
-		var="$2"
-		shift 2
-		while [ $# -gt 0 ]; do
-			if   [ "$1" = y ]; then
-				shift
-			elif [ "$1" = m -a "$x" != n ]; then
-				x=m; shift
-			else 
-				x=n; shift $#
-			fi
-		done
-		define_tristate "$var" "$x"
-	}
-
-	function dep_bool () {
-		set_x_info "$2" "n"
-		var="$2"
-		shift 2
-		while [ $# -gt 0 ]; do
-			if   [ "$1" = y ]; then
-				shift
-			else 
-				x=n; shift $#
-			fi
-		done
-		define_bool "$var" "$x"
-	}
-
-	function dep_mbool () {
-		set_x_info "$2" "n"
-		var="$2"
-		shift 2
-		while [ $# -gt 0 ]; do
-			if   [ "$1" = y -o "$1" = m ]; then
-				shift
-			else 
-				x=n; shift $#
-			fi
-		done
-		define_bool "$var" "$x"
-	}
-
-	function int () {
-		set_x_info "$2" "$3"
-		echo "$2=$x" 		>>$CONFIG
-		echo "#define $2 ($x)"	>>$CONFIG_H
-	}
-
-	function hex () {
-		set_x_info "$2" "$3"
-		echo "$2=$x" 			 >>$CONFIG
-		echo "#define $2 0x${x##*[x,X]}" >>$CONFIG_H
-	}
-
-	function string () {
-		set_x_info "$2" "$3"
-		echo "$2=\"$x\"" 			 >>$CONFIG
-		echo "#define $2 \"$x\""	>>$CONFIG_H
-	}
-
-	function define_hex () {
-		eval $1=\"$2\"
-               	echo "$1=$2"			>>$CONFIG
-		echo "#define $1 0x${2##*[x,X]}"	>>$CONFIG_H
-	}
-
-	function define_int () {
-		eval $1=\"$2\"
-		echo "$1=$2" 			>>$CONFIG
-		echo "#define $1 ($2)"		>>$CONFIG_H
-	}
-
-	function define_string () {
-		eval $1=\"$2\"
-		echo "$1=\"$2\""		>>$CONFIG
-		echo "#define $1 \"$2\""	>>$CONFIG_H
-	}
-
-	function define_bool () {
-		define_tristate "$1" "$2"
-	}
-
-	function define_tristate () {
-		eval $1=\"$2\"
-
-   		case "$2" in
-         	y)
-                	echo "$1=y" 		>>$CONFIG
-                	echo "#define $1 1"	>>$CONFIG_H
-                	;;
-
-         	m)
-			if [ "$CONFIG_MODULES" = "y" ]
-			then
-                		echo "$1=m"		   >>$CONFIG
-                		echo "#undef  $1"	   >>$CONFIG_H
-                		echo "#define $1_MODULE 1" >>$CONFIG_H
-			else
-                		echo "$1=y" 		>>$CONFIG
-                		echo "#define $1 1"	>>$CONFIG_H
-			fi
-                	;;
-
-         	n)
-			echo "# $1 is not set"	>>$CONFIG
-                	echo "#undef  $1"	>>$CONFIG_H
-                	;;
-        	esac
-	}
-
-	function choice () {
-		#
-		# Find the first choice that's already set to 'y'
-		#
-		choices="$2"
-		default="$3"
-		current=
-		chosen=
-
-		set -- $choices
-		while [ -n "$2" ]
-		do
-			if eval [ \"_\$$2\" = \"_y\" ]
-			then
-				current=$1
-				break
-			fi
-			shift ; shift
-		done
-
-		#
-		# Use the default if none were set.  
-		#
-		: ${current:=$default}
-
-		#
-		# Output all choices (to be compatible with other configs).
-		#
-		set -- $choices
-		while [ -n "$2" ]
-		do
-			case "$1" in
-			"$current"*)	if [ -z "$chosen" ]; then
-						define_bool "$2" "y"
-						chosen=1
-					else
-						define_bool "$2" "n"
-					fi ;;
-			*)		define_bool "$2" "n" ;;
-			esac
-			shift ; shift
-		done
-	}
-
-	function mainmenu_name () {
-		:
-	}
-
-	function mainmenu_option () {
-		comment_is_option=TRUE
-	}
-
-	function endmenu () {
-		:
-	}
-
-	function comment () {
-		if [ "$comment_is_option" ]
-		then
-			comment_is_option=
-			echo        >>$CONFIG
-			echo "#"    >>$CONFIG
-			echo "# $1" >>$CONFIG
-			echo "#"    >>$CONFIG
-
-			echo         >>$CONFIG_H
-			echo "/*"    >>$CONFIG_H
-			echo " * $1" >>$CONFIG_H
-			echo " */"   >>$CONFIG_H
-		fi
-	}
-
-	echo -n "."
-
-	DEF_CONFIG="${1:-.config}"
-	DEF_CONFIG_H="include/linux/autoconf.h"
-
-	CONFIG=.tmpconfig
-	CONFIG_H=.tmpconfig.h
-
-	echo "#" >$CONFIG
-	echo "# Automatically generated by make menuconfig: don't edit" >>$CONFIG
-	echo "#" >>$CONFIG
-
-	echo "/*" >$CONFIG_H
-	echo " * Automatically generated by make menuconfig: don't edit" >>$CONFIG_H
-	echo " */" >>$CONFIG_H
-	echo "#define AUTOCONF_INCLUDED" >> $CONFIG_H
-
-	echo -n "."
-	if . $CONFIG_IN >>.menuconfig.log 2>&1
-	then
-		if [ "$DEF_CONFIG" = ".config" ]
-		then
-			mv $CONFIG_H $DEF_CONFIG_H
-		fi
-
-		if [ -f "$DEF_CONFIG" ]
-		then
-			rm -f ${DEF_CONFIG}.old
-			mv $DEF_CONFIG ${DEF_CONFIG}.old
-		fi
-
-		mv $CONFIG $DEF_CONFIG
-			
-		return 0
-	else
-		return 1
-	fi
-}
-
-#
-# Remove temporary files
-#
-cleanup () {
-	cleanup1
-	cleanup2
-}
-
-cleanup1 () {
-	rm -f MCmenu* MCradiolists MCdialog.out help.out
-}
-
-cleanup2 () {
-	rm -f .tmpconfig .tmpconfig.h
-}
-
-set_geometry () {
-	# Some distributions export these with incorrect values
-	# which can really screw up some ncurses programs.
-	LINES=  COLUMNS=
-
-	ROWS=${1:-24}  COLS=${2:-80} 
-
-	# Just in case the nasty rlogin bug returns.
-	#
-	[ $ROWS = 0 ] && ROWS=24
-	[ $COLS = 0 ] && COLS=80
-
-	if [ $ROWS -lt 19 -o $COLS -lt 80 ]
-	then
-		echo -e "\n\007Your display is too small to run Menuconfig!"
-		echo "It must be at least 19 lines by 80 columns."
-		exit 1
-	fi 
-
-	ROWS=$((ROWS-4))  COLS=$((COLS-5))
-}
-
-
-set_geometry `stty size 2>/dev/null`
-
-menu_instructions="\
-Arrow keys navigate the menu.  \
-<Enter> selects submenus --->.  \
-Highlighted letters are hotkeys.  \
-Pressing <Y> includes, <N> excludes, <M> modularizes features.  \
-Press <Esc><Esc> to exit, <?> for Help.  \
-Legend: [*] built-in  [ ] excluded  <M> module  < > module capable"
-
-radiolist_instructions="\
-Use the arrow keys to navigate this window or \
-press the hotkey of the item you wish to select \
-followed by the <SPACE BAR>.
-Press <?> for additional information about this option."
-
-inputbox_instructions_int="\
-Please enter a decimal value. \
-Fractions will not be accepted.  \
-Use the <TAB> key to move from the input field to the buttons below it."
-
-inputbox_instructions_hex="\
-Please enter a hexadecimal value. \
-Use the <TAB> key to move from the input field to the buttons below it."
-
-inputbox_instructions_string="\
-Please enter a string value. \
-Use the <TAB> key to move from the input field to the buttons below it."
-
-DIALOG="./scripts/lxdialog/lxdialog"
-
-kernel_version="${VERSION}.${PATCHLEVEL}.${SUBLEVEL}${EXTRAVERSION}"
-
-backtitle="Linux Kernel v$kernel_version Configuration"
-
-trap "cleanup ; exit 1" 1 2 15
-
-
-#
-# Locate default files.
-#
-CONFIG_IN=./config.in
-if [ "$1" != "" ] ; then
-	CONFIG_IN=$1
-fi
-
-DEFAULTS=arch/$ARCH/defconfig
-if [ -f .config ]; then
-  DEFAULTS=.config
-fi
-
-if [ -f $DEFAULTS ]
-then
-  echo "Using defaults found in" $DEFAULTS
-  load_config_file $DEFAULTS
-else
-  echo "No defaults found"
-fi
-
-
-# Fresh new log.
->.menuconfig.log
-
-# Load the functions used by the config.in files.
-echo -n "Preparing scripts: functions" 
-load_functions
-
-if [ ! -e $CONFIG_IN ]
-then
-	echo "Your main config.in file ($CONFIG_IN) does not exist"
-	exit 1
-fi
-
-if [ ! -x $DIALOG ]
-then
-	echo "Your lxdialog utility does not exist"
-	exit 1
-fi
-
-#
-# Read config.in files and parse them into one shell function per menu.
-#
-echo -n ", parsing"
-parse_config_files $CONFIG_IN
-
-echo "done."
-#
-# Start the ball rolling from the top.
-#
-activate_menu MCmenu0
-
-#
-# All done!
-#
-cleanup1
-
-#
-# Confirm and Save
-#
-if $DIALOG --backtitle "$backtitle" \
-	   --yesno "Do you wish to save your new kernel configuration?" 5 60
-then
-	save_configuration
-	echo
-	echo
-	echo "*** End of Linux kernel configuration."
-	echo "*** Check the top-level Makefile for additional configuration."
-	if [ ! -f .hdepend -o "$CONFIG_MODVERSIONS" = "y" ] ; then
-	    echo "*** Next, you must run 'make dep'."
-	else
-	    echo "*** Next, you may run 'make bzImage', 'make bzdisk', or 'make install'."
-	fi
-	echo
-else
-	echo
-    	echo 
-	echo Your kernel configuration changes were NOT saved.
-	echo
-fi
-
-# Remove log if empty.
-if [ ! -s .menuconfig.log ] ; then
-	rm -f .menuconfig.log
-fi
-
-exit 0
diff -Nru a/scripts/README.Menuconfig b/scripts/README.Menuconfig
--- a/scripts/README.Menuconfig	Sun Nov 10 19:28:39 2002
+++ b/scripts/README.Menuconfig	Sun Nov 10 19:28:39 2002
@@ -1,7 +1,8 @@
 Menuconfig gives the Linux kernel configuration a long needed face
 lift.  Featuring text based color menus and dialogs, it does not
-require X Windows.  With this utility you can easily select a kernel
-option to modify without sifting through 100 other options.
+require X Windows (however, you need ncurses in order to use it).
+With this utility you can easily select a kernel option to modify
+without sifting through 100 other options.
 
 Overview
 --------
@@ -172,11 +173,17 @@
 ******** IMPORTANT, OPTIONAL ALTERNATE PERSONALITY AVAILABLE ********
 ********                                                     ********
 If you prefer to have all of the kernel options listed in a single
-menu, rather than the default multimenu hierarchy, you may edit the
-Menuconfig script and change the line "single_menu_mode="  to 
-"single_menu_mode=TRUE".
+menu, rather than the default multimenu hierarchy, run the menuconfig
+with MENUCONFIG_MODE environment variable set to single_menu. Example:
 
-This mode is not recommended unless you have a fairly fast machine.
+make menuconfig MENUCONFIG_MODE=single_menu
+
+<Enter> will then unroll the appropriate category, or enfold it if it
+is already unrolled.
+
+Note that this mode can eventually be a little more CPU expensive
+(especially with a larger number of unrolled categories) than the
+default mode.
 *********************************************************************
 
 
diff -Nru a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
--- a/scripts/kconfig/conf.c	Sun Nov 10 19:28:41 2002
+++ b/scripts/kconfig/conf.c	Sun Nov 10 19:28:41 2002
@@ -115,6 +115,7 @@
 			exit(1);
 		}
 	case ask_all:
+		fflush(stdout);
 		fgets(line, 128, stdin);
 		return;
 	case set_default:
@@ -366,7 +367,7 @@
 			for (cmenu = menu->list; cmenu; cmenu = cmenu->next) {
 				if (!cmenu->sym || !menu_is_visible(cmenu))
 					continue;
-				if (!strncmp(line, menu_get_prompt(cmenu), len)) {
+				if (!strncasecmp(line, menu_get_prompt(cmenu), len)) {
 					def_menu = cmenu;
 					break;
 				}
diff -Nru a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
--- a/scripts/kconfig/confdata.c	Sun Nov 10 19:28:41 2002
+++ b/scripts/kconfig/confdata.c	Sun Nov 10 19:28:41 2002
@@ -4,7 +4,6 @@
  */
 
 #include <ctype.h>
-#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -14,7 +13,6 @@
 #include "lkc.h"
 
 const char conf_def_filename[] = ".config";
-char conf_filename[PATH_MAX+1];
 
 const char conf_defname[] = "arch/$ARCH/defconfig";
 
@@ -61,7 +59,7 @@
 int conf_read(const char *name)
 {
 	FILE *in = NULL;
-	char line[128];
+	char line[1024];
 	char *p, *p2;
 	int lineno = 0;
 	struct symbol *sym;
@@ -71,8 +69,6 @@
 
 	if (name) {
 		in = fopen(name, "r");
-		if (in)
-			strcpy(conf_filename, name);
 	} else {
 		const char **names = conf_confnames;
 		while ((name = *names++)) {
@@ -91,21 +87,21 @@
 		return 1;
 
 	for_all_symbols(i, sym) {
-		sym->flags |= SYMBOL_NEW;
+		sym->flags |= SYMBOL_NEW | SYMBOL_CHANGED;
+		sym->flags &= ~SYMBOL_VALID;
 		switch (sym->type) {
 		case S_INT:
 		case S_HEX:
 		case S_STRING:
-			if (S_VAL(sym->def)) {
+			if (S_VAL(sym->def))
 				free(S_VAL(sym->def));
-				S_VAL(sym->def) = NULL;
-			}
 		default:
-			;
+			S_VAL(sym->def) = NULL;
+			S_TRI(sym->def) = no;
 		}
 	}
 
-	while (fgets(line, 128, in)) {
+	while (fgets(line, sizeof(line), in)) {
 		lineno++;
 		switch (line[0]) {
 		case '#':
@@ -117,7 +113,6 @@
 			*p++ = 0;
 			if (strncmp(p, "is not set", 10))
 				continue;
-			//printf("%s -> n\n", line + 9);
 			sym = sym_lookup(line + 9, 0);
 			switch (sym->type) {
 			case S_BOOLEAN:
@@ -139,23 +134,29 @@
 			p2 = strchr(p, '\n');
 			if (p2)
 				*p2 = 0;
-			//printf("%s -> %s\n", line + 7, p);
 			sym = sym_find(line + 7);
 			if (!sym) {
 				fprintf(stderr, "%s:%d: trying to assign nonexistent symbol %s\n", name, lineno, line + 7);
 				break;
 			}
 			switch (sym->type) {
-			case S_BOOLEAN:
-				sym->def = symbol_yes.curr;
-				sym->flags &= ~SYMBOL_NEW;
-				break;
 			case S_TRISTATE:
-				if (p[0] == 'm')
-					sym->def = symbol_mod.curr;
-				else
-					sym->def = symbol_yes.curr;
-				sym->flags &= ~SYMBOL_NEW;
+				if (p[0] == 'm') {
+					S_TRI(sym->def) = mod;
+					sym->flags &= ~SYMBOL_NEW;
+					break;
+				}
+			case S_BOOLEAN:
+				if (p[0] == 'y') {
+					S_TRI(sym->def) = yes;
+					sym->flags &= ~SYMBOL_NEW;
+					break;
+				}
+				if (p[0] == 'n') {
+					S_TRI(sym->def) = no;
+					sym->flags &= ~SYMBOL_NEW;
+					break;
+				}
 				break;
 			case S_STRING:
 				if (*p++ != '"')
@@ -167,13 +168,19 @@
 					}
 					memmove(p2, p2 + 1, strlen(p2));
 				}
+				if (!p2) {
+					fprintf(stderr, "%s:%d: invalid string found\n", name, lineno);
+					exit(1);
+				}
 			case S_INT:
 			case S_HEX:
 				if (sym_string_valid(sym, p)) {
 					S_VAL(sym->def) = strdup(p);
 					sym->flags &= ~SYMBOL_NEW;
-				} else
-					fprintf(stderr, "%s:%d:symbol value '%s' invalid for %s\n", name, lineno, p, sym->name);
+				} else {
+					fprintf(stderr, "%s:%d: symbol value '%s' invalid for %s\n", name, lineno, p, sym->name);
+					exit(1);
+				}
 				break;
 			default:
 				;
@@ -352,7 +359,6 @@
 	rename(name, oldname);
 	if (rename(".tmpconfig", name))
 		return 1;
-	strcpy(conf_filename, name);
 
 	sym_change_count = 0;
 
diff -Nru a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h
--- a/scripts/kconfig/expr.h	Sun Nov 10 19:28:40 2002
+++ b/scripts/kconfig/expr.h	Sun Nov 10 19:28:40 2002
@@ -169,7 +169,7 @@
 	//char *help;
 	struct file *file;
 	int lineno;
-	//void *data;
+	void *data;
 };
 
 #ifndef SWIG
diff -Nru a/scripts/kconfig/lex.zconf.c_shipped b/scripts/kconfig/lex.zconf.c_shipped
--- a/scripts/kconfig/lex.zconf.c_shipped	Sun Nov 10 19:28:41 2002
+++ b/scripts/kconfig/lex.zconf.c_shipped	Sun Nov 10 19:28:41 2002
@@ -542,7 +542,7 @@
     },
 
     {
-       11,   77,   77,  -34,   77,  -34,   77,   77,  -34,   77,
+       11,   77,   77,   78,   77,  -34,   77,   77,  -34,   77,
        77,   77,   77,   77,   77,  -34,   77,   77,   77,   77,
        77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
        77,   77,   77,   77,   77,   77,   77
@@ -564,11 +564,11 @@
     },
 
     {
-       11,   78,   79,   80,   78,   78,   78,   78,   78,   78,
-       78,   78,   78,   78,   78,   78,   78,   78,   78,   78,
+       11,   79,   79,   80,   79,   79,   79,   79,   79,   79,
+       79,   79,   79,   79,   79,   79,   79,   79,   79,   79,
 
-       78,   78,   78,   78,   78,   78,   78,   78,   78,   78,
-       78,   78,   78,   78,   78,   78,   78
+       79,   79,   79,   79,   79,   79,   79,   79,   79,   79,
+       79,   79,   79,   79,   79,   79,   79
     },
 
     {
@@ -860,7 +860,7 @@
     },
 
     {
-       11,   77,   77,  -77,   77,  -77,   77,   77,  -77,   77,
+       11,   77,   77,   78,   77,  -77,   77,   77,  -77,   77,
        77,   77,   77,   77,   77,  -77,   77,   77,   77,   77,
 
        77,   77,   77,   77,   77,   77,   77,   77,   77,   77,
@@ -875,7 +875,7 @@
     },
 
     {
-       11,  -79,  106,   80,  -79,  -79,  -79,  -79,  -79,  -79,
+       11,  -79,  -79,   80,  -79,  -79,  -79,  -79,  -79,  -79,
       -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,
       -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,  -79,
       -79,  -79,  -79,  -79,  -79,  -79,  -79
@@ -906,7 +906,7 @@
 
     {
        11,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,  -83,
-      -83,  107,   84,   84,  -83,  -83,   84,   84,   84,   84,
+      -83,  106,   84,   84,  -83,  -83,   84,   84,   84,   84,
        84,   84,   84,   84,   84,   84,   84,   84,   84,   84,
        84,   84,   84,   84,   84,   84,  -83
     },
@@ -944,14 +944,14 @@
     {
        11,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,  -88,
       -88,  -88,  -88,   56,  -88,  -88,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,  108,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,  107,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,  -88
     },
 
     {
        11,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,  -89,
       -89,  -89,  -89,   56,  -89,  -89,   56,   56,   56,   56,
-       56,   56,   56,   56,  109,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,  108,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,  -89
 
     },
@@ -959,20 +959,20 @@
     {
        11,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,  -90,
       -90,  -90,  -90,   56,  -90,  -90,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,  110,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,  109,   56,   56,   56,
        56,   56,   56,   56,   56,   56,  -90
     },
 
     {
        11,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,  -91,
       -91,  -91,  -91,   56,  -91,  -91,   56,   56,   56,   56,
-       56,  111,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,  110,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,  -91
     },
 
     {
        11,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,  -92,
-      -92,  -92,  -92,   56,  -92,  -92,  112,   56,   56,   56,
+      -92,  -92,  -92,   56,  -92,  -92,  111,   56,   56,   56,
 
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,  -92
@@ -981,14 +981,14 @@
     {
        11,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,  -93,
       -93,  -93,  -93,   56,  -93,  -93,   56,   56,   56,   56,
-      113,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+      112,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,  -93
     },
 
     {
        11,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,  -94,
-      -94,  -94,  -94,   56,  -94,  -94,   56,   56,  114,   56,
-       56,   56,   56,   56,  115,   56,  116,   56,   56,   56,
+      -94,  -94,  -94,   56,  -94,  -94,   56,   56,  113,   56,
+       56,   56,   56,   56,  114,   56,  115,   56,   56,   56,
        56,   56,   56,   56,   56,   56,  -94
 
     },
@@ -996,7 +996,7 @@
     {
        11,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,  -95,
       -95,  -95,  -95,   56,  -95,  -95,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,  117,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,  116,
        56,   56,   56,   56,   56,   56,  -95
     },
 
@@ -1018,7 +1018,7 @@
     {
        11,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,  -98,
       -98,  -98,  -98,   56,  -98,  -98,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,  118,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,  117,   56,   56,
        56,   56,   56,   56,   56,   56,  -98
     },
 
@@ -1026,21 +1026,21 @@
        11,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,  -99,
       -99,  -99,  -99,   56,  -99,  -99,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,  119,   56,  -99
+       56,   56,   56,   56,  118,   56,  -99
 
     },
 
     {
        11, -100, -100, -100, -100, -100, -100, -100, -100, -100,
      -100, -100, -100,   56, -100, -100,   56,   56,   56,   56,
-       56,   56,   56,   56,  120,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,  119,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -100
     },
 
     {
        11, -101, -101, -101, -101, -101, -101, -101, -101, -101,
      -101, -101, -101,   56, -101, -101,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,  121,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,  120,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -101
     },
 
@@ -1049,20 +1049,20 @@
      -102, -102, -102,   56, -102, -102,   56,   56,   56,   56,
 
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,  122,   56, -102
+       56,   56,   56,   56,  121,   56, -102
     },
 
     {
        11, -103, -103, -103, -103, -103, -103, -103, -103, -103,
      -103, -103, -103,   56, -103, -103,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,  123,   56,   56,   56,   56, -103
+       56,  122,   56,   56,   56,   56, -103
     },
 
     {
        11, -104, -104, -104, -104, -104, -104, -104, -104, -104,
      -104, -104, -104,   56, -104, -104,   56,   56,   56,   56,
-       56,   56,   56,   56,  124,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,  123,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -104
 
     },
@@ -1071,35 +1071,35 @@
        11, -105, -105, -105, -105, -105, -105, -105, -105, -105,
      -105, -105, -105,   56, -105, -105,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,  125,   56,   56,   56, -105
+       56,   56,  124,   56,   56,   56, -105
     },
 
     {
-       11, -106,  106,   80, -106, -106, -106, -106, -106, -106,
-     -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
-     -106, -106, -106, -106, -106, -106, -106, -106, -106, -106,
-     -106, -106, -106, -106, -106, -106, -106
+       11, -106, -106, -106, -106, -106, -106, -106, -106, -106,
+     -106,   84,   84,   84, -106, -106,   84,   84,   84,   84,
+       84,   84,   84,   84,   84,   84,   84,   84,   84,   84,
+       84,   84,   84,   84,   84,   84, -106
     },
 
     {
        11, -107, -107, -107, -107, -107, -107, -107, -107, -107,
-     -107,   84,   84,   84, -107, -107,   84,   84,   84,   84,
+     -107, -107, -107,   56, -107, -107,   56,   56,   56,   56,
 
-       84,   84,   84,   84,   84,   84,   84,   84,   84,   84,
-       84,   84,   84,   84,   84,   84, -107
+      125,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56, -107
     },
 
     {
        11, -108, -108, -108, -108, -108, -108, -108, -108, -108,
-     -108, -108, -108,   56, -108, -108,   56,   56,   56,   56,
-      126,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+     -108, -108, -108,   56, -108, -108,   56,   56,  126,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -108
     },
 
     {
        11, -109, -109, -109, -109, -109, -109, -109, -109, -109,
-     -109, -109, -109,   56, -109, -109,   56,   56,  127,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+     -109, -109, -109,   56, -109, -109,   56,   56,   56,   56,
+      127,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -109
 
     },
@@ -1107,36 +1107,36 @@
     {
        11, -110, -110, -110, -110, -110, -110, -110, -110, -110,
      -110, -110, -110,   56, -110, -110,   56,   56,   56,   56,
-      128,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,  128,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -110
     },
 
     {
        11, -111, -111, -111, -111, -111, -111, -111, -111, -111,
      -111, -111, -111,   56, -111, -111,   56,   56,   56,   56,
-       56,   56,   56,   56,  129,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56, -111
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,  129,   56, -111
     },
 
     {
        11, -112, -112, -112, -112, -112, -112, -112, -112, -112,
      -112, -112, -112,   56, -112, -112,   56,   56,   56,   56,
 
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,  130,   56, -112
+       56,   56,   56,   56,   56,   56,   56,  130,   56,   56,
+       56,   56,   56,   56,   56,   56, -112
     },
 
     {
        11, -113, -113, -113, -113, -113, -113, -113, -113, -113,
      -113, -113, -113,   56, -113, -113,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,  131,   56,   56,
+       56,   56,   56,  131,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -113
     },
 
     {
        11, -114, -114, -114, -114, -114, -114, -114, -114, -114,
      -114, -114, -114,   56, -114, -114,   56,   56,   56,   56,
-       56,   56,   56,  132,   56,   56,   56,   56,   56,   56,
+       56,  132,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -114
 
     },
@@ -1144,14 +1144,14 @@
     {
        11, -115, -115, -115, -115, -115, -115, -115, -115, -115,
      -115, -115, -115,   56, -115, -115,   56,   56,   56,   56,
-       56,  133,   56,   56,   56,   56,   56,   56,   56,   56,
+      133,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -115
     },
 
     {
        11, -116, -116, -116, -116, -116, -116, -116, -116, -116,
      -116, -116, -116,   56, -116, -116,   56,   56,   56,   56,
-      134,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -116
     },
 
@@ -1159,21 +1159,21 @@
        11, -117, -117, -117, -117, -117, -117, -117, -117, -117,
      -117, -117, -117,   56, -117, -117,   56,   56,   56,   56,
 
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,  134,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -117
     },
 
     {
        11, -118, -118, -118, -118, -118, -118, -118, -118, -118,
      -118, -118, -118,   56, -118, -118,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,  135,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -118
     },
 
     {
        11, -119, -119, -119, -119, -119, -119, -119, -119, -119,
      -119, -119, -119,   56, -119, -119,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,  135,   56,
        56,   56,   56,   56,   56,   56, -119
 
     },
@@ -1181,51 +1181,51 @@
     {
        11, -120, -120, -120, -120, -120, -120, -120, -120, -120,
      -120, -120, -120,   56, -120, -120,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,  136,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,  136,
        56,   56,   56,   56,   56,   56, -120
     },
 
     {
        11, -121, -121, -121, -121, -121, -121, -121, -121, -121,
      -121, -121, -121,   56, -121, -121,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,  137,
+       56,   56,   56,   56,  137,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -121
     },
 
     {
        11, -122, -122, -122, -122, -122, -122, -122, -122, -122,
-     -122, -122, -122,   56, -122, -122,   56,   56,   56,   56,
+     -122, -122, -122,   56, -122, -122,   56,   56,  138,   56,
 
-       56,   56,   56,   56,  138,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -122
     },
 
     {
        11, -123, -123, -123, -123, -123, -123, -123, -123, -123,
-     -123, -123, -123,   56, -123, -123,   56,   56,  139,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+     -123, -123, -123,   56, -123, -123,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,  139,   56,   56,
        56,   56,   56,   56,   56,   56, -123
     },
 
     {
        11, -124, -124, -124, -124, -124, -124, -124, -124, -124,
      -124, -124, -124,   56, -124, -124,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,  140,   56,   56,
-       56,   56,   56,   56,   56,   56, -124
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,  140,   56,   56, -124
 
     },
 
     {
        11, -125, -125, -125, -125, -125, -125, -125, -125, -125,
-     -125, -125, -125,   56, -125, -125,   56,   56,   56,   56,
+     -125, -125, -125,   56, -125, -125,  141,   56,   56,   56,
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,  141,   56,   56, -125
+       56,   56,   56,   56,   56,   56, -125
     },
 
     {
        11, -126, -126, -126, -126, -126, -126, -126, -126, -126,
-     -126, -126, -126,   56, -126, -126,  142,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+     -126, -126, -126,   56, -126, -126,   56,   56,   56,   56,
+      142,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -126
     },
 
@@ -1233,36 +1233,36 @@
        11, -127, -127, -127, -127, -127, -127, -127, -127, -127,
      -127, -127, -127,   56, -127, -127,   56,   56,   56,   56,
 
-      143,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,  143,   56,   56,
        56,   56,   56,   56,   56,   56, -127
     },
 
     {
        11, -128, -128, -128, -128, -128, -128, -128, -128, -128,
      -128, -128, -128,   56, -128, -128,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,  144,   56,   56,
+       56,   56,  144,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -128
     },
 
     {
        11, -129, -129, -129, -129, -129, -129, -129, -129, -129,
      -129, -129, -129,   56, -129, -129,   56,   56,   56,   56,
-       56,   56,  145,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,  145,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -129
 
     },
 
     {
        11, -130, -130, -130, -130, -130, -130, -130, -130, -130,
-     -130, -130, -130,   56, -130, -130,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,  146,   56,   56,   56,   56,
+     -130, -130, -130,   56, -130, -130,   56,   56,   56,  146,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -130
     },
 
     {
        11, -131, -131, -131, -131, -131, -131, -131, -131, -131,
-     -131, -131, -131,   56, -131, -131,   56,   56,   56,  147,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+     -131, -131, -131,   56, -131, -131,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,  147,   56,
        56,   56,   56,   56,   56,   56, -131
     },
 
@@ -1270,21 +1270,21 @@
        11, -132, -132, -132, -132, -132, -132, -132, -132, -132,
      -132, -132, -132,   56, -132, -132,   56,   56,   56,   56,
 
-       56,   56,   56,   56,   56,   56,   56,   56,  148,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -132
     },
 
     {
        11, -133, -133, -133, -133, -133, -133, -133, -133, -133,
      -133, -133, -133,   56, -133, -133,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,  148,   56,   56,
        56,   56,   56,   56,   56,   56, -133
     },
 
     {
        11, -134, -134, -134, -134, -134, -134, -134, -134, -134,
      -134, -134, -134,   56, -134, -134,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,  149,   56,   56,
+      149,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -134
 
     },
@@ -1292,15 +1292,15 @@
     {
        11, -135, -135, -135, -135, -135, -135, -135, -135, -135,
      -135, -135, -135,   56, -135, -135,   56,   56,   56,   56,
-      150,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,  150,   56,   56,
        56,   56,   56,   56,   56,   56, -135
     },
 
     {
        11, -136, -136, -136, -136, -136, -136, -136, -136, -136,
      -136, -136, -136,   56, -136, -136,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,  151,   56,   56,
-       56,   56,   56,   56,   56,   56, -136
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,  151,   56,   56, -136
     },
 
     {
@@ -1308,35 +1308,35 @@
      -137, -137, -137,   56, -137, -137,   56,   56,   56,   56,
 
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,  152,   56,   56, -137
+       56,  152,   56,   56,   56,   56, -137
     },
 
     {
        11, -138, -138, -138, -138, -138, -138, -138, -138, -138,
      -138, -138, -138,   56, -138, -138,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,  153,   56,   56,   56,   56, -138
+      153,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56, -138
     },
 
     {
        11, -139, -139, -139, -139, -139, -139, -139, -139, -139,
      -139, -139, -139,   56, -139, -139,   56,   56,   56,   56,
-      154,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,  154,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -139
 
     },
 
     {
        11, -140, -140, -140, -140, -140, -140, -140, -140, -140,
-     -140, -140, -140,   56, -140, -140,   56,   56,   56,   56,
-       56,   56,  155,   56,   56,   56,   56,   56,   56,   56,
+     -140, -140, -140,   56, -140, -140,  155,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -140
     },
 
     {
        11, -141, -141, -141, -141, -141, -141, -141, -141, -141,
-     -141, -141, -141,   56, -141, -141,  156,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+     -141, -141, -141,   56, -141, -141,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,  156,   56,   56,
        56,   56,   56,   56,   56,   56, -141
     },
 
@@ -1344,7 +1344,7 @@
        11, -142, -142, -142, -142, -142, -142, -142, -142, -142,
      -142, -142, -142,   56, -142, -142,   56,   56,   56,   56,
 
-       56,   56,   56,   56,   56,   56,   56,  157,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -142
     },
 
@@ -1352,14 +1352,14 @@
        11, -143, -143, -143, -143, -143, -143, -143, -143, -143,
      -143, -143, -143,   56, -143, -143,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56, -143
+       56,   56,   56,  157,   56,   56, -143
     },
 
     {
        11, -144, -144, -144, -144, -144, -144, -144, -144, -144,
      -144, -144, -144,   56, -144, -144,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,  158,   56,   56, -144
+       56,   56,   56,   56,   56,   56, -144
 
     },
 
@@ -1367,49 +1367,49 @@
        11, -145, -145, -145, -145, -145, -145, -145, -145, -145,
      -145, -145, -145,   56, -145, -145,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56, -145
+       56,   56,   56,  158,   56,   56, -145
     },
 
     {
        11, -146, -146, -146, -146, -146, -146, -146, -146, -146,
      -146, -146, -146,   56, -146, -146,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,  159,   56,   56, -146
+       56,   56,  159,   56,   56,   56, -146
     },
 
     {
        11, -147, -147, -147, -147, -147, -147, -147, -147, -147,
      -147, -147, -147,   56, -147, -147,   56,   56,   56,   56,
 
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,  160,   56,   56,   56, -147
+       56,   56,   56,   56,  160,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56, -147
     },
 
     {
        11, -148, -148, -148, -148, -148, -148, -148, -148, -148,
      -148, -148, -148,   56, -148, -148,   56,   56,   56,   56,
-       56,   56,   56,   56,  161,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56, -148
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,  161,   56, -148
     },
 
     {
        11, -149, -149, -149, -149, -149, -149, -149, -149, -149,
      -149, -149, -149,   56, -149, -149,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,  162,   56, -149
+       56,   56,   56,   56,   56,   56,   56,  162,   56,   56,
+       56,   56,   56,   56,   56,   56, -149
 
     },
 
     {
        11, -150, -150, -150, -150, -150, -150, -150, -150, -150,
-     -150, -150, -150,   56, -150, -150,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,  163,   56,   56,
+     -150, -150, -150,   56, -150, -150,  163,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -150
     },
 
     {
        11, -151, -151, -151, -151, -151, -151, -151, -151, -151,
-     -151, -151, -151,   56, -151, -151,  164,   56,   56,   56,
+     -151, -151, -151,   56, -151, -151,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -151
     },
@@ -1418,14 +1418,14 @@
        11, -152, -152, -152, -152, -152, -152, -152, -152, -152,
      -152, -152, -152,   56, -152, -152,   56,   56,   56,   56,
 
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+      164,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -152
     },
 
     {
        11, -153, -153, -153, -153, -153, -153, -153, -153, -153,
      -153, -153, -153,   56, -153, -153,   56,   56,   56,   56,
-      165,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -153
     },
 
@@ -1441,14 +1441,14 @@
        11, -155, -155, -155, -155, -155, -155, -155, -155, -155,
      -155, -155, -155,   56, -155, -155,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56, -155
+       56,   56,   56,  165,   56,   56, -155
     },
 
     {
        11, -156, -156, -156, -156, -156, -156, -156, -156, -156,
      -156, -156, -156,   56, -156, -156,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,  166,   56,   56, -156
+       56,   56,   56,   56,   56,   56, -156
     },
 
     {
@@ -1476,14 +1476,14 @@
 
     {
        11, -160, -160, -160, -160, -160, -160, -160, -160, -160,
-     -160, -160, -160,   56, -160, -160,   56,   56,   56,   56,
+     -160, -160, -160,   56, -160, -160,   56,   56,  166,   56,
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -160
     },
 
     {
        11, -161, -161, -161, -161, -161, -161, -161, -161, -161,
-     -161, -161, -161,   56, -161, -161,   56,   56,  167,   56,
+     -161, -161, -161,   56, -161, -161,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -161
     },
@@ -1493,29 +1493,29 @@
      -162, -162, -162,   56, -162, -162,   56,   56,   56,   56,
 
        56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56, -162
+       56,   56,   56,   56,  167,   56, -162
     },
 
     {
        11, -163, -163, -163, -163, -163, -163, -163, -163, -163,
      -163, -163, -163,   56, -163, -163,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,  168,   56, -163
+       56,   56,   56,   56,   56,  168,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56, -163
     },
 
     {
        11, -164, -164, -164, -164, -164, -164, -164, -164, -164,
      -164, -164, -164,   56, -164, -164,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,  169,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56, -164
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,  169,   56,   56,   56, -164
 
     },
 
     {
        11, -165, -165, -165, -165, -165, -165, -165, -165, -165,
      -165, -165, -165,   56, -165, -165,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,  170,   56,   56,   56, -165
+      170,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56, -165
     },
 
     {
@@ -1529,7 +1529,7 @@
        11, -167, -167, -167, -167, -167, -167, -167, -167, -167,
      -167, -167, -167,   56, -167, -167,   56,   56,   56,   56,
 
-      172,   56,   56,   56,   56,   56,   56,   56,   56,   56,
+       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
        56,   56,   56,   56,   56,   56, -167
     },
 
@@ -1562,14 +1562,6 @@
        56,   56,   56,   56,   56,   56, -171
     },
 
-    {
-       11, -172, -172, -172, -172, -172, -172, -172, -172, -172,
-     -172, -172, -172,   56, -172, -172,   56,   56,   56,   56,
-
-       56,   56,   56,   56,   56,   56,   56,   56,   56,   56,
-       56,   56,   56,   56,   56,   56, -172
-    },
-
     } ;
 
 
@@ -1590,27 +1582,27 @@
 
 #define YY_NUM_RULES 55
 #define YY_END_OF_BUFFER 56
-static yyconst short int yy_accept[173] =
+static yyconst short int yy_accept[172] =
     {   0,
         0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
        56,    5,    4,    3,    2,   29,   30,   28,   28,   28,
        28,   28,   28,   28,   28,   28,   28,   28,   28,   28,
-       54,   51,   53,   45,   50,   46,   48,   44,   41,   35,
+       54,   51,   53,   46,   50,   49,   48,   44,   41,   35,
        40,   44,   33,   34,   43,   43,   36,   43,   43,   44,
         4,    3,    2,    2,    1,   28,   28,   28,   28,   28,
        28,   28,   15,   28,   28,   28,   28,   28,   28,   28,
-       28,   28,   54,   51,   53,   52,   45,   49,   48,   47,
+       28,   28,   54,   51,   53,   52,   46,   45,   48,   47,
        37,   31,   43,   43,   38,   39,   32,   28,   28,   28,
        28,   28,   28,   28,   28,   26,   25,   28,   28,   28,
 
-       28,   28,   28,   28,   28,   48,   42,   23,   28,   28,
-       28,   28,   28,   28,   28,   28,   14,   28,    7,   28,
+       28,   28,   28,   28,   28,   42,   23,   28,   28,   28,
+       28,   28,   28,   28,   28,   14,   28,    7,   28,   28,
        28,   28,   28,   28,   28,   28,   28,   28,   28,   28,
-       28,   28,   16,   28,   28,   28,   28,   28,   28,   28,
-       28,   28,   10,   28,   13,   28,   28,   28,   28,   28,
-       28,   21,   28,    9,   27,   28,   24,   12,   20,   17,
-       28,    8,   28,   28,   28,   28,   28,    6,   19,   18,
-       22,   11
+       28,   16,   28,   28,   28,   28,   28,   28,   28,   28,
+       28,   10,   28,   13,   28,   28,   28,   28,   28,   28,
+       21,   28,    9,   27,   28,   24,   12,   20,   17,   28,
+        8,   28,   28,   28,   28,   28,    6,   19,   18,   22,
+       11
     } ;
 
 static yyconst int yy_ec[256] =
@@ -1655,6 +1647,7 @@
 char *yytext;
 #line 1 "zconf.l"
 #define INITIAL 0
+#define YY_NEVER_INTERACTIVE 1
 #define COMMAND 1
 #define HELP 2
 #define STRING 3
@@ -1722,7 +1715,7 @@
 	memcpy(text, str, size);
 	text[size] = 0;
 }
-#line 1726 "lex.zconf.c"
+#line 1719 "lex.zconf.c"
 
 /* Macros after this point can all be overridden by user definitions in
  * section 1.
@@ -1874,7 +1867,7 @@
 	int str = 0;
 	int ts, i;
 
-#line 1878 "lex.zconf.c"
+#line 1871 "lex.zconf.c"
 
 	if ( yy_init )
 		{
@@ -1957,125 +1950,123 @@
 #line 84 "zconf.l"
 {
 	unput(yytext[0]);
-	//printf("new config: ");
-	//symbol_end(NULL);
 	BEGIN(COMMAND);
 }
 	YY_BREAK
 
 case 6:
 YY_RULE_SETUP
-#line 93 "zconf.l"
+#line 91 "zconf.l"
 BEGIN(PARAM); return T_MAINMENU;
 	YY_BREAK
 case 7:
 YY_RULE_SETUP
-#line 94 "zconf.l"
+#line 92 "zconf.l"
 BEGIN(PARAM); return T_MENU;
 	YY_BREAK
 case 8:
 YY_RULE_SETUP
-#line 95 "zconf.l"
+#line 93 "zconf.l"
 BEGIN(PARAM); return T_ENDMENU;
 	YY_BREAK
 case 9:
 YY_RULE_SETUP
-#line 96 "zconf.l"
+#line 94 "zconf.l"
 BEGIN(PARAM); return T_SOURCE;
 	YY_BREAK
 case 10:
 YY_RULE_SETUP
-#line 97 "zconf.l"
+#line 95 "zconf.l"
 BEGIN(PARAM); return T_CHOICE;
 	YY_BREAK
 case 11:
 YY_RULE_SETUP
-#line 98 "zconf.l"
+#line 96 "zconf.l"
 BEGIN(PARAM); return T_ENDCHOICE;
 	YY_BREAK
 case 12:
 YY_RULE_SETUP
-#line 99 "zconf.l"
+#line 97 "zconf.l"
 BEGIN(PARAM); return T_COMMENT;
 	YY_BREAK
 case 13:
 YY_RULE_SETUP
-#line 100 "zconf.l"
+#line 98 "zconf.l"
 BEGIN(PARAM); return T_CONFIG;
 	YY_BREAK
 case 14:
 YY_RULE_SETUP
-#line 101 "zconf.l"
+#line 99 "zconf.l"
 BEGIN(PARAM); return T_HELP;
 	YY_BREAK
 case 15:
 YY_RULE_SETUP
-#line 102 "zconf.l"
+#line 100 "zconf.l"
 BEGIN(PARAM); return T_IF;
 	YY_BREAK
 case 16:
 YY_RULE_SETUP
-#line 103 "zconf.l"
+#line 101 "zconf.l"
 BEGIN(PARAM); return T_ENDIF;
 	YY_BREAK
 case 17:
 YY_RULE_SETUP
-#line 104 "zconf.l"
+#line 102 "zconf.l"
 BEGIN(PARAM); return T_DEPENDS;
 	YY_BREAK
 case 18:
 YY_RULE_SETUP
-#line 105 "zconf.l"
+#line 103 "zconf.l"
 BEGIN(PARAM); return T_REQUIRES;
 	YY_BREAK
 case 19:
 YY_RULE_SETUP
-#line 106 "zconf.l"
+#line 104 "zconf.l"
 BEGIN(PARAM); return T_OPTIONAL;
 	YY_BREAK
 case 20:
 YY_RULE_SETUP
-#line 107 "zconf.l"
+#line 105 "zconf.l"
 BEGIN(PARAM); return T_DEFAULT;
 	YY_BREAK
 case 21:
 YY_RULE_SETUP
-#line 108 "zconf.l"
+#line 106 "zconf.l"
 BEGIN(PARAM); return T_PROMPT;
 	YY_BREAK
 case 22:
 YY_RULE_SETUP
-#line 109 "zconf.l"
+#line 107 "zconf.l"
 BEGIN(PARAM); return T_TRISTATE;
 	YY_BREAK
 case 23:
 YY_RULE_SETUP
-#line 110 "zconf.l"
+#line 108 "zconf.l"
 BEGIN(PARAM); return T_BOOLEAN;
 	YY_BREAK
 case 24:
 YY_RULE_SETUP
-#line 111 "zconf.l"
+#line 109 "zconf.l"
 BEGIN(PARAM); return T_BOOLEAN;
 	YY_BREAK
 case 25:
 YY_RULE_SETUP
-#line 112 "zconf.l"
+#line 110 "zconf.l"
 BEGIN(PARAM); return T_INT;
 	YY_BREAK
 case 26:
 YY_RULE_SETUP
-#line 113 "zconf.l"
+#line 111 "zconf.l"
 BEGIN(PARAM); return T_HEX;
 	YY_BREAK
 case 27:
 YY_RULE_SETUP
-#line 114 "zconf.l"
+#line 112 "zconf.l"
 BEGIN(PARAM); return T_STRING;
 	YY_BREAK
 case 28:
 YY_RULE_SETUP
-#line 115 "zconf.l"
+#line 113 "zconf.l"
 {
 		alloc_string(yytext, yyleng);
 		zconflval.string = text;
@@ -2084,64 +2075,64 @@
 	YY_BREAK
 case 29:
 YY_RULE_SETUP
-#line 120 "zconf.l"
+#line 118 "zconf.l"
 
 	YY_BREAK
 case 30:
 YY_RULE_SETUP
-#line 121 "zconf.l"
+#line 119 "zconf.l"
 current_file->lineno++; BEGIN(INITIAL);
 	YY_BREAK
 
 
 case 31:
 YY_RULE_SETUP
-#line 125 "zconf.l"
+#line 123 "zconf.l"
 return T_AND;
 	YY_BREAK
 case 32:
 YY_RULE_SETUP
-#line 126 "zconf.l"
+#line 124 "zconf.l"
 return T_OR;
 	YY_BREAK
 case 33:
 YY_RULE_SETUP
-#line 127 "zconf.l"
+#line 125 "zconf.l"
 return T_OPEN_PAREN;
 	YY_BREAK
 case 34:
 YY_RULE_SETUP
-#line 128 "zconf.l"
+#line 126 "zconf.l"
 return T_CLOSE_PAREN;
 	YY_BREAK
 case 35:
 YY_RULE_SETUP
-#line 129 "zconf.l"
+#line 127 "zconf.l"
 return T_NOT;
 	YY_BREAK
 case 36:
 YY_RULE_SETUP
-#line 130 "zconf.l"
+#line 128 "zconf.l"
 return T_EQUAL;
 	YY_BREAK
 case 37:
 YY_RULE_SETUP
-#line 131 "zconf.l"
+#line 129 "zconf.l"
 return T_UNEQUAL;
 	YY_BREAK
 case 38:
 YY_RULE_SETUP
-#line 132 "zconf.l"
+#line 130 "zconf.l"
 return T_IF;
 	YY_BREAK
 case 39:
 YY_RULE_SETUP
-#line 133 "zconf.l"
+#line 131 "zconf.l"
 return T_ON;
 	YY_BREAK
 case 40:
 YY_RULE_SETUP
-#line 134 "zconf.l"
+#line 132 "zconf.l"
 {
 		str = yytext[0];
 		new_string();
@@ -2150,17 +2141,17 @@
 	YY_BREAK
 case 41:
 YY_RULE_SETUP
-#line 139 "zconf.l"
+#line 137 "zconf.l"
 BEGIN(INITIAL); current_file->lineno++; return T_EOL;
 	YY_BREAK
 case 42:
 YY_RULE_SETUP
-#line 140 "zconf.l"
+#line 138 "zconf.l"
 /* ignore */
 	YY_BREAK
 case 43:
 YY_RULE_SETUP
-#line 141 "zconf.l"
+#line 139 "zconf.l"
 {
 		alloc_string(yytext, yyleng);
 		zconflval.string = text;
@@ -2169,66 +2160,87 @@
 	YY_BREAK
 case 44:
 YY_RULE_SETUP
-#line 146 "zconf.l"
+#line 144 "zconf.l"
 
 	YY_BREAK
+case YY_STATE_EOF(PARAM):
+#line 145 "zconf.l"
+{
+		BEGIN(INITIAL);
+	}
+	YY_BREAK
 
 
 case 45:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 150 "zconf.l"
+#line 151 "zconf.l"
 {
 		append_string(yytext, yyleng);
+		zconflval.string = text;
+		return T_STRING;
 	}
 	YY_BREAK
 case 46:
 YY_RULE_SETUP
-#line 153 "zconf.l"
+#line 156 "zconf.l"
 {
-		if (str == yytext[0]) {
-			BEGIN(PARAM);
-			zconflval.string = text;
-			//printf("s:%s\n", text);
-			return T_STRING;
-		} else
-			append_string(yytext, 1);
+		append_string(yytext, yyleng);
 	}
 	YY_BREAK
 case 47:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 162 "zconf.l"
-append_string(yytext+yyleng-1, 1); current_file->lineno++;
+#line 159 "zconf.l"
+{
+		append_string(yytext+1, yyleng);
+		zconflval.string = text;
+		return T_STRING;
+	}
 	YY_BREAK
 case 48:
 YY_RULE_SETUP
-#line 163 "zconf.l"
-append_string(yytext+1, yyleng-1);
+#line 164 "zconf.l"
+{
+		append_string(yytext+1, yyleng - 1);
+	}
 	YY_BREAK
 case 49:
 YY_RULE_SETUP
-#line 164 "zconf.l"
-append_string(yytext+1, 1);
+#line 167 "zconf.l"
+{
+		if (str == yytext[0]) {
+			BEGIN(PARAM);
+			zconflval.string = text;
+			return T_STRING;
+		} else
+			append_string(yytext, 1);
+	}
 	YY_BREAK
 case 50:
 YY_RULE_SETUP
-#line 165 "zconf.l"
+#line 175 "zconf.l"
 {
-		//printf(":%d: open string!\n", current_file->lineno+1);
-		exit(0);
+		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+		BEGIN(INITIAL);
+		return T_EOL;
 	}
 	YY_BREAK
 case YY_STATE_EOF(STRING):
-#line 169 "zconf.l"
+#line 180 "zconf.l"
 {
-		//printf(":%d: open string!\n", current_file->lineno+1);
-		exit(0);
+		BEGIN(INITIAL);
 	}
 	YY_BREAK
 
 
 case 51:
 YY_RULE_SETUP
-#line 176 "zconf.l"
+#line 186 "zconf.l"
 {
 		ts = 0;
 		for (i = 0; i < yyleng; i++) {
@@ -2258,7 +2270,7 @@
 yy_c_buf_p = yy_cp = yy_bp + 1;
 YY_DO_BEFORE_ACTION; /* set up yytext again */
 YY_RULE_SETUP
-#line 199 "zconf.l"
+#line 209 "zconf.l"
 {
 		current_file->lineno++;
 		zconf_endhelp();
@@ -2267,7 +2279,7 @@
 	YY_BREAK
 case 53:
 YY_RULE_SETUP
-#line 204 "zconf.l"
+#line 214 "zconf.l"
 {
 		current_file->lineno++;
 		append_string("\n", 1);
@@ -2275,7 +2287,7 @@
 	YY_BREAK
 case 54:
 YY_RULE_SETUP
-#line 208 "zconf.l"
+#line 218 "zconf.l"
 {
 		append_string(yytext, yyleng);
 		if (!first_ts)
@@ -2283,7 +2295,7 @@
 	}
 	YY_BREAK
 case YY_STATE_EOF(HELP):
-#line 213 "zconf.l"
+#line 223 "zconf.l"
 {
 		zconf_endhelp();
 		return T_HELPTEXT;
@@ -2292,22 +2304,22 @@
 
 case YY_STATE_EOF(INITIAL):
 case YY_STATE_EOF(COMMAND):
-case YY_STATE_EOF(PARAM):
-#line 219 "zconf.l"
+#line 229 "zconf.l"
 {
 	if (current_buf) {
 		zconf_endfile();
 		return T_EOF;
 	}
+	fclose(yyin);
 	yyterminate();
 }
 	YY_BREAK
 case 55:
 YY_RULE_SETUP
-#line 227 "zconf.l"
+#line 238 "zconf.l"
 YY_FATAL_ERROR( "flex scanner jammed" );
 	YY_BREAK
-#line 2311 "lex.zconf.c"
+#line 2323 "lex.zconf.c"
 
 	case YY_END_OF_BUFFER:
 		{
@@ -3170,7 +3182,7 @@
 	return 0;
 	}
 #endif
-#line 227 "zconf.l"
+#line 238 "zconf.l"
 
 void zconf_starthelp(void)
 {
@@ -3192,7 +3204,6 @@
 		printf("can't find file %s\n", name);
 		exit(1);
 	}
-	//fprintf(stderr, "zconf_initscan: %s\n", name);
 
 	current_buf = malloc(sizeof(*current_buf));
 	memset(current_buf, 0, sizeof(*current_buf));
@@ -3218,8 +3229,6 @@
 	buf->parent = current_buf;
 	current_buf = buf;
 
-	//fprintf(stderr, "zconf_nextfile: %s\n", name);
-
 	if (file->flags & FILE_BUSY) {
 		printf("recursive scan (%s)?\n", name);
 		exit(1);
@@ -3244,6 +3253,7 @@
 
 	parent = current_buf->parent;
 	if (parent) {
+		fclose(yyin);
 		yy_delete_buffer(YY_CURRENT_BUFFER);
 		yy_switch_to_buffer(parent->state);
 	}
diff -Nru a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
--- a/scripts/kconfig/mconf.c	Sun Nov 10 19:28:38 2002
+++ b/scripts/kconfig/mconf.c	Sun Nov 10 19:28:38 2002
@@ -1,6 +1,9 @@
 /*
  * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org>
  * Released under the terms of the GNU GPL v2.0.
+ *
+ * Introduced single menu mode (show all sub-menus in one large tree).
+ * 2002-11-06 Petr Baudis <pasky@ucw.cz>
  */
 
 #include <sys/ioctl.h>
@@ -8,10 +11,12 @@
 #include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <string.h>
+#include <termios.h>
 #include <unistd.h>
 
 #define LKC_DIRECT_LINK
@@ -78,12 +83,15 @@
 
 static char buf[4096], *bufptr = buf;
 static char input_buf[4096];
+static char filename[PATH_MAX+1] = ".config";
 static char *args[1024], **argptr = args;
 static int indent = 0;
+static struct termios ios_org;
 static int rows, cols;
 static struct menu *current_menu;
 static int child_count;
 static int do_resize;
+static int single_menu_mode;
 
 static void conf(struct menu *menu);
 static void conf_choice(struct menu *menu);
@@ -274,10 +282,20 @@
 			case P_MENU:
 				child_count++;
 				cprint("m%p", menu);
-				if (menu->parent != &rootmenu)
-					cprint1("   %*c", indent + 1, ' ');
-				cprint1("%s  --->", prompt);
+
+				if (single_menu_mode) {
+					cprint1("%s%*c%s",
+						menu->data ? "-->" : "++>",
+						indent + 1, ' ', prompt);
+				} else {
+					if (menu->parent != &rootmenu)
+						cprint1("   %*c", indent + 1, ' ');
+					cprint1("%s  --->", prompt);
+				}
+
 				cprint_done();
+				if (single_menu_mode && menu->data)
+					goto conf_childs;
 				return;
 			default:
 				if (prompt) {
@@ -392,6 +410,7 @@
 	char active_entry[40];
 	int stat, type, i;
 
+	unlink("lxdialog.scrltmp");
 	active_entry[0] = 0;
 	while (1) {
 		cprint_init();
@@ -442,7 +461,10 @@
 		case 0:
 			switch (type) {
 			case 'm':
-				conf(submenu);
+				if (single_menu_mode)
+					submenu->data = (void *) !submenu->data;
+				else
+					conf(submenu);
 				break;
 			case 't':
 				if (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)
@@ -484,6 +506,8 @@
 		case 6:
 			if (type == 't')
 				sym_toggle_tristate_value(sym);
+			else if (type == 'm')
+				conf(submenu);
 			break;
 		}
 	}
@@ -518,11 +542,19 @@
 static void show_help(struct menu *menu)
 {
 	const char *help;
+	char *helptext;
+	struct symbol *sym = menu->sym;
 
-	help = menu->sym->help;
+	help = sym->help;
 	if (!help)
 		help = nohelp_text;
-	show_helptext(menu_get_prompt(menu), help);
+	if (sym->name) {
+		helptext = malloc(strlen(sym->name) + strlen(help) + 16);
+		sprintf(helptext, "CONFIG_%s:\n\n%s", sym->name, help);
+		show_helptext(menu_get_prompt(menu), helptext);
+		free(helptext);
+	} else
+		show_helptext(menu_get_prompt(menu), help);
 }
 
 static void show_readme(void)
@@ -631,7 +663,7 @@
 		cprint(load_config_text);
 		cprint("11");
 		cprint("55");
-		cprint("%s", conf_filename);
+		cprint("%s", filename);
 		stat = exec_conf();
 		switch(stat) {
 		case 0:
@@ -660,7 +692,7 @@
 		cprint(save_config_text);
 		cprint("11");
 		cprint("55");
-		cprint("%s", conf_filename);
+		cprint("%s", filename);
 		stat = exec_conf();
 		switch(stat) {
 		case 0:
@@ -679,16 +711,35 @@
 	}
 }
 
+static void conf_cleanup(void)
+{
+	tcsetattr(1, TCSAFLUSH, &ios_org);
+	unlink(".help.tmp");
+	unlink("lxdialog.scrltmp");
+}
+
 int main(int ac, char **av)
 {
+	struct symbol *sym;
+	char *mode;
 	int stat;
+
 	conf_parse(av[1]);
 	conf_read(NULL);
 
-	sprintf(menu_backtitle, "Linux Kernel v%s.%s.%s%s Configuration",
-		getenv("VERSION"), getenv("PATCHLEVEL"),
-		getenv("SUBLEVEL"), getenv("EXTRAVERSION"));
+	sym = sym_lookup("KERNELRELEASE", 0);
+	sym_calc_value(sym);
+	sprintf(menu_backtitle, "Linux Kernel v%s Configuration",
+		sym_get_string_value(sym));
+
+	mode = getenv("MENUCONFIG_MODE");
+	if (mode) {
+		if (!strcasecmp(mode, "single_menu"))
+			single_menu_mode = 1;
+	}
 
+	tcgetattr(1, &ios_org);
+	atexit(conf_cleanup);
 	init_wsize();
 	conf(&rootmenu);
 
diff -Nru a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c
--- a/scripts/kconfig/menu.c	Sun Nov 10 19:28:41 2002
+++ b/scripts/kconfig/menu.c	Sun Nov 10 19:28:41 2002
@@ -290,7 +290,7 @@
 	FILE *out;
 
 	if (!name)
-		name = "..config.cmd";
+		name = ".config.cmd";
 	out = fopen("..config.tmp", "w");
 	if (!out)
 		return 1;
diff -Nru a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc
--- a/scripts/kconfig/qconf.cc	Sun Nov 10 19:28:36 2002
+++ b/scripts/kconfig/qconf.cc	Sun Nov 10 19:28:36 2002
@@ -17,6 +17,10 @@
 #include <qheader.h>
 #include <qfiledialog.h>
 #include <qregexp.h>
+#if QT_VERSION >= 300
+#include <qsettings.h>
+#endif
+
 #include <stdlib.h>
 
 #include "lkc.h"
@@ -26,6 +30,9 @@
 #include "images.c"
 
 static QApplication *configApp;
+#if QT_VERSION >= 300
+static QSettings *configSettings;
+#endif
 
 /*
  * update all the children of a menu entry
@@ -613,6 +620,25 @@
 	QMenuBar* menu;
 	QSplitter* split1;
 	QSplitter* split2;
+	bool ok;
+	int x, y, width, height;
+
+	QWidget *d = configApp->desktop();
+
+#if QT_VERSION >= 300
+	width = configSettings->readNumEntry("/kconfig/qconf/window width", d->width() - 64);
+	height = configSettings->readNumEntry("/kconfig/qconf/window height", d->height() - 64);
+	resize(width, height);
+	x = configSettings->readNumEntry("/kconfig/qconf/window x", 0, &ok);
+	if (ok)
+		y = configSettings->readNumEntry("/kconfig/qconf/window y", 0, &ok);
+	if (ok)
+		move(x, y);
+#else
+	width = d->width() - 64;
+	height = d->height() - 64;
+	resize(width, height);
+#endif
 
 	showDebug = false;
 
@@ -864,6 +890,8 @@
 		return;
 	if (conf_read(s.latin1()))
 		QMessageBox::information(this, "qconf", "Unable to load configuration!");
+	configList->updateListAll();
+	menuList->updateListAll();
 }
 
 void ConfigView::saveConfig(void)
@@ -1046,6 +1074,9 @@
 #endif
 
 	configApp = new QApplication(ac, av);
+#if QT_VERSION >= 300
+	configSettings = new QSettings;
+#endif
 	if (ac > 1 && av[1][0] == '-') {
 		switch (av[1][1]) {
 		case 'a':
@@ -1063,11 +1094,20 @@
 	fixup_rootmenu(&rootmenu);
 	conf_read(NULL);
 	//zconfdump(stdout);
+
 	v = new ConfigView();
 
 	//zconfdump(stdout);
 	v->show();
 	configApp->connect(configApp, SIGNAL(lastWindowClosed()), SLOT(quit()));
 	configApp->exec();
+
+#if QT_VERSION >= 300
+	configSettings->writeEntry("/kconfig/qconf/window x", v->pos().x());
+	configSettings->writeEntry("/kconfig/qconf/window y", v->pos().y());
+	configSettings->writeEntry("/kconfig/qconf/window width", v->size().width());
+	configSettings->writeEntry("/kconfig/qconf/window height", v->size().height());
+	delete configSettings;
+#endif
 	return 0;
 }
diff -Nru a/scripts/kconfig/zconf.l b/scripts/kconfig/zconf.l
--- a/scripts/kconfig/zconf.l	Sun Nov 10 19:28:40 2002
+++ b/scripts/kconfig/zconf.l	Sun Nov 10 19:28:40 2002
@@ -1,4 +1,4 @@
-%option backup nostdinit noyywrap full ecs
+%option backup nostdinit noyywrap never-interactive full ecs
 %option 8bit backup nodefault perf-report perf-report
 %x COMMAND HELP STRING PARAM
 %{
@@ -83,8 +83,6 @@
 
 .	{
 	unput(yytext[0]);
-	//printf("new config: ");
-	//symbol_end(NULL);
 	BEGIN(COMMAND);
 }
 
@@ -144,31 +142,43 @@
 		return T_WORD;
 	}
 	.
+	<<EOF>> {
+		BEGIN(INITIAL);
+	}
 }
 
 <STRING>{
-	[^'"\n\\]+	{
+	[^'"\\\n]+/\n	{
+		append_string(yytext, yyleng);
+		zconflval.string = text;
+		return T_STRING;
+	}
+	[^'"\\\n]+	{
 		append_string(yytext, yyleng);
 	}
+	\\.?/\n	{
+		append_string(yytext+1, yyleng);
+		zconflval.string = text;
+		return T_STRING;
+	}
+	\\.?	{
+		append_string(yytext+1, yyleng - 1);
+	}
 	\'|\"	{
 		if (str == yytext[0]) {
 			BEGIN(PARAM);
 			zconflval.string = text;
-			//printf("s:%s\n", text);
 			return T_STRING;
 		} else
 			append_string(yytext, 1);
 	}
-	\\[ \t]*\n	append_string(yytext+yyleng-1, 1); current_file->lineno++;
-	\\[ \t]*	append_string(yytext+1, yyleng-1);
-	\\.		append_string(yytext+1, 1);
 	\n	{
-		//printf(":%d: open string!\n", current_file->lineno+1);
-		exit(0);
+		printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno());
+		BEGIN(INITIAL);
+		return T_EOL;
 	}
 	<<EOF>>	{
-		//printf(":%d: open string!\n", current_file->lineno+1);
-		exit(0);
+		BEGIN(INITIAL);
 	}
 }
 
@@ -221,6 +231,7 @@
 		zconf_endfile();
 		return T_EOF;
 	}
+	fclose(yyin);
 	yyterminate();
 }
 
@@ -245,7 +256,6 @@
 		printf("can't find file %s\n", name);
 		exit(1);
 	}
-	//fprintf(stderr, "zconf_initscan: %s\n", name);
 
 	current_buf = malloc(sizeof(*current_buf));
 	memset(current_buf, 0, sizeof(*current_buf));
@@ -271,8 +281,6 @@
 	buf->parent = current_buf;
 	current_buf = buf;
 
-	//fprintf(stderr, "zconf_nextfile: %s\n", name);
-
 	if (file->flags & FILE_BUSY) {
 		printf("recursive scan (%s)?\n", name);
 		exit(1);
@@ -297,6 +305,7 @@
 
 	parent = current_buf->parent;
 	if (parent) {
+		fclose(yyin);
 		yy_delete_buffer(YY_CURRENT_BUFFER);
 		yy_switch_to_buffer(parent->state);
 	}
diff -Nru a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped
--- a/scripts/kconfig/zconf.tab.c_shipped	Sun Nov 10 19:28:38 2002
+++ b/scripts/kconfig/zconf.tab.c_shipped	Sun Nov 10 19:28:38 2002
@@ -1,49 +1,137 @@
-/* A Bison parser, made from zconf.y
-   by GNU bison 1.35.  */
+/* A Bison parser, made from zconf.y, by GNU bison 1.75.  */
 
-#define YYBISON 1  /* Identify Bison output.  */
+/* Skeleton parser for Yacc-like parsing with Bison,
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, 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, 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.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
+/* Written by Richard Stallman by simplifying the original so called
+   ``semantic'' parser.  */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+   infringing on user name space.  This should be done even for local
+   variables, as they might otherwise be expanded by user macros.
+   There are some unavoidable exceptions within include files to
+   define necessary library symbols; they are noted "INFRINGES ON
+   USER NAME SPACE" below.  */
+
+/* Identify Bison output.  */
+#define YYBISON	1
+
+/* Pure parsers.  */
+#define YYPURE	0
+
+/* Using locations.  */
+#define YYLSP_NEEDED 0
+
+/* If NAME_PREFIX is specified substitute the variables and functions
+   names.  */
 #define yyparse zconfparse
-#define yylex zconflex
+#define yylex   zconflex
 #define yyerror zconferror
-#define yylval zconflval
-#define yychar zconfchar
+#define yylval  zconflval
+#define yychar  zconfchar
 #define yydebug zconfdebug
 #define yynerrs zconfnerrs
-# define	T_MAINMENU	257
-# define	T_MENU	258
-# define	T_ENDMENU	259
-# define	T_SOURCE	260
-# define	T_CHOICE	261
-# define	T_ENDCHOICE	262
-# define	T_COMMENT	263
-# define	T_CONFIG	264
-# define	T_HELP	265
-# define	T_HELPTEXT	266
-# define	T_IF	267
-# define	T_ENDIF	268
-# define	T_DEPENDS	269
-# define	T_REQUIRES	270
-# define	T_OPTIONAL	271
-# define	T_PROMPT	272
-# define	T_DEFAULT	273
-# define	T_TRISTATE	274
-# define	T_BOOLEAN	275
-# define	T_INT	276
-# define	T_HEX	277
-# define	T_WORD	278
-# define	T_STRING	279
-# define	T_UNEQUAL	280
-# define	T_EOF	281
-# define	T_EOL	282
-# define	T_CLOSE_PAREN	283
-# define	T_OPEN_PAREN	284
-# define	T_ON	285
-# define	T_OR	286
-# define	T_AND	287
-# define	T_EQUAL	288
-# define	T_NOT	289
 
+
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     T_MAINMENU = 258,
+     T_MENU = 259,
+     T_ENDMENU = 260,
+     T_SOURCE = 261,
+     T_CHOICE = 262,
+     T_ENDCHOICE = 263,
+     T_COMMENT = 264,
+     T_CONFIG = 265,
+     T_HELP = 266,
+     T_HELPTEXT = 267,
+     T_IF = 268,
+     T_ENDIF = 269,
+     T_DEPENDS = 270,
+     T_REQUIRES = 271,
+     T_OPTIONAL = 272,
+     T_PROMPT = 273,
+     T_DEFAULT = 274,
+     T_TRISTATE = 275,
+     T_BOOLEAN = 276,
+     T_INT = 277,
+     T_HEX = 278,
+     T_WORD = 279,
+     T_STRING = 280,
+     T_UNEQUAL = 281,
+     T_EOF = 282,
+     T_EOL = 283,
+     T_CLOSE_PAREN = 284,
+     T_OPEN_PAREN = 285,
+     T_ON = 286,
+     T_OR = 287,
+     T_AND = 288,
+     T_EQUAL = 289,
+     T_NOT = 290
+   };
+#endif
+#define T_MAINMENU 258
+#define T_MENU 259
+#define T_ENDMENU 260
+#define T_SOURCE 261
+#define T_CHOICE 262
+#define T_ENDCHOICE 263
+#define T_COMMENT 264
+#define T_CONFIG 265
+#define T_HELP 266
+#define T_HELPTEXT 267
+#define T_IF 268
+#define T_ENDIF 269
+#define T_DEPENDS 270
+#define T_REQUIRES 271
+#define T_OPTIONAL 272
+#define T_PROMPT 273
+#define T_DEFAULT 274
+#define T_TRISTATE 275
+#define T_BOOLEAN 276
+#define T_INT 277
+#define T_HEX 278
+#define T_WORD 279
+#define T_STRING 280
+#define T_UNEQUAL 281
+#define T_EOF 282
+#define T_EOL 283
+#define T_CLOSE_PAREN 284
+#define T_OPEN_PAREN 285
+#define T_ON 286
+#define T_OR 287
+#define T_AND 288
+#define T_EQUAL 289
+#define T_NOT 290
+
+
+
+
+/* Copy the first part of user declarations.  */
 #line 1 "zconf.y"
 
 /*
@@ -74,328 +162,58 @@
 
 #define YYERROR_VERBOSE
 
-#line 32 "zconf.y"
+
+/* Enabling traces.  */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+
+/* Enabling verbose error messages.  */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
 #ifndef YYSTYPE
-typedef union
-{
+#line 33 "zconf.y"
+typedef union {
 	int token;
 	char *string;
 	struct symbol *symbol;
 	struct expr *expr;
 	struct menu *menu;
 } yystype;
+/* Line 193 of /usr/share/bison/yacc.c.  */
+#line 190 "zconf.tab.c"
 # define YYSTYPE yystype
 # define YYSTYPE_IS_TRIVIAL 1
 #endif
-#line 83 "zconf.y"
-
-#define LKC_DIRECT_LINK
-#include "lkc.h"
-#ifndef YYDEBUG
-# define YYDEBUG 1
-#endif
-
 
-
-#define	YYFINAL		145
-#define	YYFLAG		-32768
-#define	YYNTBASE	36
-
-/* YYTRANSLATE(YYLEX) -- Bison token number corresponding to YYLEX. */
-#define YYTRANSLATE(x) ((unsigned)(x) <= 289 ? yytranslate[x] : 74)
-
-/* YYTRANSLATE[YYLEX] -- Bison token number corresponding to YYLEX. */
-static const char yytranslate[] =
+#ifndef YYLTYPE
+typedef struct yyltype
 {
-       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     1,     3,     4,     5,
-       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
-      16,    17,    18,    19,    20,    21,    22,    23,    24,    25,
-      26,    27,    28,    29,    30,    31,    32,    33,    34,    35
-};
-
-#if YYDEBUG
-static const short yyprhs[] =
-{
-       0,     0,     1,     4,     6,     8,    10,    14,    16,    18,
-      20,    23,    25,    27,    29,    31,    33,    36,    40,    41,
-      45,    49,    52,    55,    58,    61,    64,    67,    70,    74,
-      78,    80,    84,    86,    91,    94,    95,    99,   103,   106,
-     109,   113,   115,   118,   119,   122,   125,   127,   133,   137,
-     138,   141,   144,   147,   150,   154,   156,   161,   164,   165,
-     168,   171,   174,   178,   181,   184,   187,   191,   194,   197,
-     198,   202,   205,   209,   212,   215,   216,   218,   222,   224,
-     226,   228,   230,   232,   234,   236,   237,   240,   242,   246,
-     250,   254,   257,   261,   265,   267
-};
-static const short yyrhs[] =
-{
-      -1,    36,    37,     0,    38,     0,    46,     0,    57,     0,
-       3,    68,    70,     0,     5,     0,    14,     0,     8,     0,
-       1,    70,     0,    52,     0,    62,     0,    40,     0,    60,
-       0,    70,     0,    10,    24,     0,    39,    28,    41,     0,
-       0,    41,    42,    28,     0,    41,    66,    28,     0,    41,
-      64,     0,    41,    28,     0,    20,    67,     0,    21,    67,
-       0,    22,    67,     0,    23,    67,     0,    25,    67,     0,
-      18,    68,    71,     0,    19,    73,    71,     0,     7,     0,
-      43,    28,    47,     0,    69,     0,    44,    49,    45,    28,
-       0,    44,    49,     0,     0,    47,    48,    28,     0,    47,
-      66,    28,     0,    47,    64,     0,    47,    28,     0,    18,
-      68,    71,     0,    17,     0,    19,    73,     0,     0,    49,
-      38,     0,    13,    72,     0,    69,     0,    50,    28,    53,
-      51,    28,     0,    50,    28,    53,     0,     0,    53,    38,
-       0,    53,    57,     0,    53,    46,     0,     4,    68,     0,
-      54,    28,    65,     0,    69,     0,    55,    58,    56,    28,
-       0,    55,    58,     0,     0,    58,    38,     0,    58,    57,
-       0,    58,    46,     0,    58,     1,    28,     0,     6,    68,
-       0,    59,    28,     0,     9,    68,     0,    61,    28,    65,
-       0,    11,    28,     0,    63,    12,     0,     0,    65,    66,
-      28,     0,    65,    28,     0,    15,    31,    72,     0,    15,
-      72,     0,    16,    72,     0,     0,    68,     0,    68,    13,
-      72,     0,    24,     0,    25,     0,     5,     0,     8,     0,
-      14,     0,    28,     0,    27,     0,     0,    13,    72,     0,
-      73,     0,    73,    34,    73,     0,    73,    26,    73,     0,
-      30,    72,    29,     0,    35,    72,     0,    72,    32,    72,
-       0,    72,    33,    72,     0,    24,     0,    25,     0
-};
-
+  int first_line;
+  int first_column;
+  int last_line;
+  int last_column;
+} yyltype;
+# define YYLTYPE yyltype
+# define YYLTYPE_IS_TRIVIAL 1
 #endif
 
-#if YYDEBUG
-/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
-static const short yyrline[] =
-{
-       0,    88,    89,    92,    93,    94,    95,    96,    97,    98,
-      99,   102,   104,   105,   106,   107,   113,   121,   127,   129,
-     130,   131,   132,   135,   141,   147,   153,   159,   165,   171,
-     179,   188,   194,   202,   204,   210,   212,   213,   214,   215,
-     218,   224,   230,   237,   239,   244,   254,   262,   264,   270,
-     272,   273,   274,   279,   286,   292,   300,   302,   308,   310,
-     311,   312,   313,   316,   322,   329,   336,   343,   349,   356,
-     357,   358,   361,   366,   371,   379,   381,   385,   390,   391,
-     394,   395,   396,   399,   400,   402,   403,   406,   407,   408,
-     409,   410,   411,   412,   415,   416
-};
-#endif
-
-
-#if (YYDEBUG) || defined YYERROR_VERBOSE
-
-/* YYTNAME[TOKEN_NUM] -- String name of the token TOKEN_NUM. */
-static const char *const yytname[] =
-{
-  "$", "error", "$undefined.", "T_MAINMENU", "T_MENU", "T_ENDMENU", 
-  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", 
-  "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", "T_REQUIRES", 
-  "T_OPTIONAL", "T_PROMPT", "T_DEFAULT", "T_TRISTATE", "T_BOOLEAN", 
-  "T_INT", "T_HEX", "T_WORD", "T_STRING", "T_UNEQUAL", "T_EOF", "T_EOL", 
-  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_ON", "T_OR", "T_AND", "T_EQUAL", 
-  "T_NOT", "input", "block", "common_block", "config_entry_start", 
-  "config_stmt", "config_option_list", "config_option", "choice", 
-  "choice_entry", "choice_end", "choice_stmt", "choice_option_list", 
-  "choice_option", "choice_block", "if", "if_end", "if_stmt", "if_block", 
-  "menu", "menu_entry", "menu_end", "menu_stmt", "menu_block", "source", 
-  "source_stmt", "comment", "comment_stmt", "help_start", "help", 
-  "depends_list", "depends", "prompt_stmt_opt", "prompt", "end", 
-  "nl_or_eof", "if_expr", "expr", "symbol", 0
-};
-#endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
-static const short yyr1[] =
-{
-       0,    36,    36,    37,    37,    37,    37,    37,    37,    37,
-      37,    38,    38,    38,    38,    38,    39,    40,    41,    41,
-      41,    41,    41,    42,    42,    42,    42,    42,    42,    42,
-      43,    44,    45,    46,    46,    47,    47,    47,    47,    47,
-      48,    48,    48,    49,    49,    50,    51,    52,    52,    53,
-      53,    53,    53,    54,    55,    56,    57,    57,    58,    58,
-      58,    58,    58,    59,    60,    61,    62,    63,    64,    65,
-      65,    65,    66,    66,    66,    67,    67,    67,    68,    68,
-      69,    69,    69,    70,    70,    71,    71,    72,    72,    72,
-      72,    72,    72,    72,    73,    73
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
-static const short yyr2[] =
-{
-       0,     0,     2,     1,     1,     1,     3,     1,     1,     1,
-       2,     1,     1,     1,     1,     1,     2,     3,     0,     3,
-       3,     2,     2,     2,     2,     2,     2,     2,     3,     3,
-       1,     3,     1,     4,     2,     0,     3,     3,     2,     2,
-       3,     1,     2,     0,     2,     2,     1,     5,     3,     0,
-       2,     2,     2,     2,     3,     1,     4,     2,     0,     2,
-       2,     2,     3,     2,     2,     2,     3,     2,     2,     0,
-       3,     2,     3,     2,     2,     0,     1,     3,     1,     1,
-       1,     1,     1,     1,     1,     0,     2,     1,     3,     3,
-       3,     2,     3,     3,     1,     1
-};
-
-/* YYDEFACT[S] -- default rule to reduce with in state S when YYTABLE
-   doesn't specify something else to do.  Zero means the default is an
-   error. */
-static const short yydefact[] =
-{
-       1,     0,     0,     0,     0,     7,     0,    30,     9,     0,
-       0,     0,     8,    84,    83,     2,     3,     0,    13,     0,
-      43,     4,     0,    11,     0,    58,     5,     0,    14,     0,
-      12,    15,    10,    78,    79,     0,    53,    63,    65,    16,
-      94,    95,     0,     0,    45,    87,    18,    35,    34,    49,
-      69,     0,    64,    69,     6,     0,    91,     0,     0,     0,
-       0,    17,    31,    80,    81,    82,    44,     0,    32,    48,
-      54,     0,    59,    61,     0,    60,    55,    66,    90,    92,
-      93,    89,    88,     0,     0,     0,     0,     0,    75,    75,
-      75,    75,    75,    22,     0,     0,    21,     0,    41,     0,
-       0,    39,     0,    38,     0,    33,    50,    52,     0,    51,
-      46,    71,     0,    62,    56,    67,     0,    73,    74,    85,
-      85,    23,    76,    24,    25,    26,    27,    19,    68,    20,
-      85,    42,    36,    37,    47,    70,    72,     0,    28,    29,
-       0,    40,    86,    77,     0,     0
-};
-
-static const short yydefgoto[] =
-{
-       1,    15,    16,    17,    18,    61,    94,    19,    20,    67,
-      21,    62,   102,    48,    22,   108,    23,    69,    24,    25,
-      74,    26,    51,    27,    28,    29,    30,    95,    96,    70,
-     112,   121,   122,    68,    31,   138,    44,    45
-};
-
-static const short yypact[] =
-{
-  -32768,    17,    41,    65,    65,-32768,    65,-32768,-32768,    65,
-     -11,    40,-32768,-32768,-32768,-32768,-32768,    13,-32768,    23,
-  -32768,-32768,    66,-32768,    72,-32768,-32768,    77,-32768,    81,
-  -32768,-32768,-32768,-32768,-32768,    41,-32768,-32768,-32768,-32768,
-  -32768,-32768,    40,    40,    64,    59,-32768,-32768,    98,-32768,
-  -32768,    49,-32768,-32768,-32768,     7,-32768,    40,    40,    67,
-      67,    99,   117,-32768,-32768,-32768,-32768,    85,-32768,    74,
-      18,    88,-32768,-32768,    95,-32768,-32768,    18,-32768,    96,
-  -32768,-32768,-32768,   102,    36,    40,    65,    67,    65,    65,
-      65,    65,    65,-32768,   103,   129,-32768,   114,-32768,    65,
-      67,-32768,   115,-32768,   116,-32768,-32768,-32768,   118,-32768,
-  -32768,-32768,   119,-32768,-32768,-32768,    40,    64,    64,   135,
-     135,-32768,   136,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
-     135,-32768,-32768,-32768,-32768,-32768,    64,    40,-32768,-32768,
-      40,-32768,    64,    64,   150,-32768
-};
-
-static const short yypgoto[] =
-{
-  -32768,-32768,   -37,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
-     -41,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,
-  -32768,   -32,-32768,-32768,-32768,-32768,-32768,-32768,    89,   100,
-      11,    48,     0,   -22,     3,  -118,   -42,   -52
-};
-
-
-#define	YYLAST		153
-
-
-static const short yytable[] =
-{
-      55,    56,   139,    35,    36,    32,    37,    81,    82,    38,
-      73,    66,   141,    39,    72,    79,    80,   144,     2,    75,
-       3,     4,     5,     6,     7,     8,     9,    10,   107,    76,
-      11,    12,   106,    84,    85,   120,    78,   109,    54,    57,
-      58,    46,   117,   118,    13,    14,   111,   110,   131,   -57,
-      71,    47,   -57,     4,    63,     6,     7,    64,     9,    10,
-      40,    41,    11,    65,    40,    41,    42,   116,    13,    14,
-      42,    43,    97,   104,   136,    43,    13,    14,     4,    63,
-       6,     7,    64,     9,    10,    59,   119,    11,    65,    33,
-      34,    40,    41,    60,    49,   142,    57,    58,   143,   130,
-      50,    13,    14,    63,     6,    52,    64,     9,    10,    53,
-      83,    11,    65,   105,    84,    85,   113,    86,    87,    88,
-      89,    90,    91,   114,    92,    13,    14,    93,    83,    58,
-     115,   127,    84,    85,    98,    99,   100,   123,   124,   125,
-     126,   128,   129,   132,   133,   101,   134,   135,   137,   140,
-     145,   103,     0,    77
-};
-
-static const short yycheck[] =
-{
-      42,    43,   120,     3,     4,     2,     6,    59,    60,     9,
-      51,    48,   130,    24,    51,    57,    58,     0,     1,    51,
-       3,     4,     5,     6,     7,     8,     9,    10,    69,    51,
-      13,    14,    69,    15,    16,    87,    29,    69,    35,    32,
-      33,    28,    84,    85,    27,    28,    28,    69,   100,     0,
-       1,    28,     3,     4,     5,     6,     7,     8,     9,    10,
-      24,    25,    13,    14,    24,    25,    30,    31,    27,    28,
-      30,    35,    61,    62,   116,    35,    27,    28,     4,     5,
-       6,     7,     8,     9,    10,    26,    86,    13,    14,    24,
-      25,    24,    25,    34,    28,   137,    32,    33,   140,    99,
-      28,    27,    28,     5,     6,    28,     8,     9,    10,    28,
-      11,    13,    14,    28,    15,    16,    28,    18,    19,    20,
-      21,    22,    23,    28,    25,    27,    28,    28,    11,    33,
-      28,    28,    15,    16,    17,    18,    19,    89,    90,    91,
-      92,    12,    28,    28,    28,    28,    28,    28,    13,    13,
-       0,    62,    -1,    53
-};
-/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
-#line 3 "/usr/share/bison/bison.simple"
-
-/* Skeleton output parser for bison,
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software
-   Foundation, 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, 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.  */
+/* Copy the second part of user declarations.  */
+#line 83 "zconf.y"
 
-/* As a special exception, when this file is copied by Bison into a
-   Bison output file, you may use that output file without restriction.
-   This special exception was added by the Free Software Foundation
-   in version 1.24 of Bison.  */
+#define LKC_DIRECT_LINK
+#include "lkc.h"
 
-/* This is the parser code that is written into each bison parser when
-   the %semantic_parser declaration is not specified in the grammar.
-   It was written by Richard Stallman by simplifying the hairy parser
-   used when %semantic_parser is specified.  */
 
-/* All symbols defined below should begin with yy or YY, to avoid
-   infringing on user name space.  This should be done even for local
-   variables, as they might otherwise be expanded by user macros.
-   There are some unavoidable exceptions within include files to
-   define necessary library symbols; they are noted "INFRINGES ON
-   USER NAME SPACE" below.  */
+/* Line 213 of /usr/share/bison/yacc.c.  */
+#line 215 "zconf.tab.c"
 
-#if ! defined (yyoverflow) || defined (YYERROR_VERBOSE)
+#if ! defined (yyoverflow) || YYERROR_VERBOSE
 
 /* The parser invokes alloca or malloc; define the necessary symbols.  */
 
@@ -424,7 +242,7 @@
 #  define YYSTACK_ALLOC malloc
 #  define YYSTACK_FREE free
 # endif
-#endif /* ! defined (yyoverflow) || defined (YYERROR_VERBOSE) */
+#endif /* ! defined (yyoverflow) || YYERROR_VERBOSE */
 
 
 #if (! defined (yyoverflow) \
@@ -436,25 +254,16 @@
 {
   short yyss;
   YYSTYPE yyvs;
-# if YYLSP_NEEDED
-  YYLTYPE yyls;
-# endif
-};
+  };
 
 /* The size of the maximum gap between one aligned stack and the next.  */
 # define YYSTACK_GAP_MAX (sizeof (union yyalloc) - 1)
 
 /* The size of an array large to enough to hold all stacks, each with
    N elements.  */
-# if YYLSP_NEEDED
-#  define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (short) + sizeof (YYSTYPE) + sizeof (YYLTYPE))	\
-      + 2 * YYSTACK_GAP_MAX)
-# else
-#  define YYSTACK_BYTES(N) \
+# define YYSTACK_BYTES(N) \
      ((N) * (sizeof (short) + sizeof (YYSTYPE))				\
       + YYSTACK_GAP_MAX)
-# endif
 
 /* Copy COUNT objects from FROM to TO.  The source and destination do
    not overlap.  */
@@ -468,7 +277,7 @@
 	{					\
 	  register YYSIZE_T yyi;		\
 	  for (yyi = 0; yyi < (Count); yyi++)	\
-	    (To)[yyi] = (From)[yyi];		\
+	    (To)[yyi] = (From)[yyi];	\
 	}					\
       while (0)
 #  endif
@@ -492,6 +301,324 @@
 
 #endif
 
+#if defined (__STDC__) || defined (__cplusplus)
+   typedef signed char yysigned_char;
+#else
+   typedef short yysigned_char;
+#endif
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL  2
+#define YYLAST   151
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS  36
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS  39
+/* YYNRULES -- Number of rules. */
+#define YYNRULES  96
+/* YYNRULES -- Number of states. */
+#define YYNSTATES  145
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
+#define YYUNDEFTOK  2
+#define YYMAXUTOK   290
+
+#define YYTRANSLATE(X) \
+  ((unsigned)(X) <= YYMAXUTOK ? yytranslate[X] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
+static const unsigned char yytranslate[] =
+{
+       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
+       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
+       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
+      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
+      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
+      35
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+   YYRHS.  */
+static const unsigned short yyprhs[] =
+{
+       0,     0,     3,     4,     7,     9,    11,    13,    17,    19,
+      21,    23,    26,    28,    30,    32,    34,    36,    39,    43,
+      44,    48,    52,    55,    58,    61,    64,    67,    70,    73,
+      77,    81,    83,    87,    89,    94,    97,    98,   102,   106,
+     109,   112,   116,   118,   121,   122,   125,   128,   130,   136,
+     140,   141,   144,   147,   150,   153,   157,   159,   164,   167,
+     168,   171,   174,   177,   181,   184,   187,   190,   194,   197,
+     200,   201,   205,   208,   212,   215,   218,   219,   221,   225,
+     227,   229,   231,   233,   235,   237,   239,   240,   243,   245,
+     249,   253,   257,   260,   264,   268,   270
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yysigned_char yyrhs[] =
+{
+      37,     0,    -1,    -1,    37,    38,    -1,    39,    -1,    47,
+      -1,    58,    -1,     3,    69,    71,    -1,     5,    -1,    14,
+      -1,     8,    -1,     1,    71,    -1,    53,    -1,    63,    -1,
+      41,    -1,    61,    -1,    71,    -1,    10,    24,    -1,    40,
+      28,    42,    -1,    -1,    42,    43,    28,    -1,    42,    67,
+      28,    -1,    42,    65,    -1,    42,    28,    -1,    20,    68,
+      -1,    21,    68,    -1,    22,    68,    -1,    23,    68,    -1,
+      25,    68,    -1,    18,    69,    72,    -1,    19,    74,    72,
+      -1,     7,    -1,    44,    28,    48,    -1,    70,    -1,    45,
+      50,    46,    28,    -1,    45,    50,    -1,    -1,    48,    49,
+      28,    -1,    48,    67,    28,    -1,    48,    65,    -1,    48,
+      28,    -1,    18,    69,    72,    -1,    17,    -1,    19,    74,
+      -1,    -1,    50,    39,    -1,    13,    73,    -1,    70,    -1,
+      51,    28,    54,    52,    28,    -1,    51,    28,    54,    -1,
+      -1,    54,    39,    -1,    54,    58,    -1,    54,    47,    -1,
+       4,    69,    -1,    55,    28,    66,    -1,    70,    -1,    56,
+      59,    57,    28,    -1,    56,    59,    -1,    -1,    59,    39,
+      -1,    59,    58,    -1,    59,    47,    -1,    59,     1,    28,
+      -1,     6,    69,    -1,    60,    28,    -1,     9,    69,    -1,
+      62,    28,    66,    -1,    11,    28,    -1,    64,    12,    -1,
+      -1,    66,    67,    28,    -1,    66,    28,    -1,    15,    31,
+      73,    -1,    15,    73,    -1,    16,    73,    -1,    -1,    69,
+      -1,    69,    13,    73,    -1,    24,    -1,    25,    -1,     5,
+      -1,     8,    -1,    14,    -1,    28,    -1,    27,    -1,    -1,
+      13,    73,    -1,    74,    -1,    74,    34,    74,    -1,    74,
+      26,    74,    -1,    30,    73,    29,    -1,    35,    73,    -1,
+      73,    32,    73,    -1,    73,    33,    73,    -1,    24,    -1,
+      25,    -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
+static const unsigned short yyrline[] =
+{
+       0,    88,    88,    89,    92,    93,    94,    95,    96,    97,
+      98,    99,   102,   104,   105,   106,   107,   113,   121,   127,
+     129,   130,   131,   132,   135,   141,   147,   153,   159,   165,
+     171,   179,   188,   194,   202,   204,   210,   212,   213,   214,
+     215,   218,   224,   230,   237,   239,   244,   254,   262,   264,
+     270,   272,   273,   274,   279,   286,   292,   300,   302,   308,
+     310,   311,   312,   313,   316,   322,   329,   336,   343,   349,
+     356,   357,   358,   361,   366,   371,   379,   381,   385,   390,
+     391,   394,   395,   396,   399,   400,   402,   403,   406,   407,
+     408,   409,   410,   411,   412,   415,   416
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE
+/* YYTNME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+   First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+  "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU", 
+  "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", 
+  "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", "T_REQUIRES", 
+  "T_OPTIONAL", "T_PROMPT", "T_DEFAULT", "T_TRISTATE", "T_BOOLEAN", 
+  "T_INT", "T_HEX", "T_WORD", "T_STRING", "T_UNEQUAL", "T_EOF", "T_EOL", 
+  "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_ON", "T_OR", "T_AND", "T_EQUAL", 
+  "T_NOT", "$accept", "input", "block", "common_block", 
+  "config_entry_start", "config_stmt", "config_option_list", 
+  "config_option", "choice", "choice_entry", "choice_end", "choice_stmt", 
+  "choice_option_list", "choice_option", "choice_block", "if", "if_end", 
+  "if_stmt", "if_block", "menu", "menu_entry", "menu_end", "menu_stmt", 
+  "menu_block", "source", "source_stmt", "comment", "comment_stmt", 
+  "help_start", "help", "depends_list", "depends", "prompt_stmt_opt", 
+  "prompt", "end", "nl_or_eof", "if_expr", "expr", "symbol", 0
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+   token YYLEX-NUM.  */
+static const unsigned short yytoknum[] =
+{
+       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
+     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
+     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
+     285,   286,   287,   288,   289,   290
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
+static const unsigned char yyr1[] =
+{
+       0,    36,    37,    37,    38,    38,    38,    38,    38,    38,
+      38,    38,    39,    39,    39,    39,    39,    40,    41,    42,
+      42,    42,    42,    42,    43,    43,    43,    43,    43,    43,
+      43,    44,    45,    46,    47,    47,    48,    48,    48,    48,
+      48,    49,    49,    49,    50,    50,    51,    52,    53,    53,
+      54,    54,    54,    54,    55,    56,    57,    58,    58,    59,
+      59,    59,    59,    59,    60,    61,    62,    63,    64,    65,
+      66,    66,    66,    67,    67,    67,    68,    68,    68,    69,
+      69,    70,    70,    70,    71,    71,    72,    72,    73,    73,
+      73,    73,    73,    73,    73,    74,    74
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
+static const unsigned char yyr2[] =
+{
+       0,     2,     0,     2,     1,     1,     1,     3,     1,     1,
+       1,     2,     1,     1,     1,     1,     1,     2,     3,     0,
+       3,     3,     2,     2,     2,     2,     2,     2,     2,     3,
+       3,     1,     3,     1,     4,     2,     0,     3,     3,     2,
+       2,     3,     1,     2,     0,     2,     2,     1,     5,     3,
+       0,     2,     2,     2,     2,     3,     1,     4,     2,     0,
+       2,     2,     2,     3,     2,     2,     2,     3,     2,     2,
+       0,     3,     2,     3,     2,     2,     0,     1,     3,     1,
+       1,     1,     1,     1,     1,     1,     0,     2,     1,     3,
+       3,     3,     2,     3,     3,     1,     1
+};
+
+/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
+   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
+   means the default is an error.  */
+static const unsigned char yydefact[] =
+{
+       2,     0,     1,     0,     0,     0,     8,     0,    31,    10,
+       0,     0,     0,     9,    85,    84,     3,     4,     0,    14,
+       0,    44,     5,     0,    12,     0,    59,     6,     0,    15,
+       0,    13,    16,    11,    79,    80,     0,    54,    64,    66,
+      17,    95,    96,     0,     0,    46,    88,    19,    36,    35,
+      50,    70,     0,    65,    70,     7,     0,    92,     0,     0,
+       0,     0,    18,    32,    81,    82,    83,    45,     0,    33,
+      49,    55,     0,    60,    62,     0,    61,    56,    67,    91,
+      93,    94,    90,    89,     0,     0,     0,     0,     0,    76,
+      76,    76,    76,    76,    23,     0,     0,    22,     0,    42,
+       0,     0,    40,     0,    39,     0,    34,    51,    53,     0,
+      52,    47,    72,     0,    63,    57,    68,     0,    74,    75,
+      86,    86,    24,    77,    25,    26,    27,    28,    20,    69,
+      21,    86,    43,    37,    38,    48,    71,    73,     0,    29,
+      30,     0,    41,    87,    78
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const short yydefgoto[] =
+{
+      -1,     1,    16,    17,    18,    19,    62,    95,    20,    21,
+      68,    22,    63,   103,    49,    23,   109,    24,    70,    25,
+      26,    75,    27,    52,    28,    29,    30,    31,    96,    97,
+      71,   113,   122,   123,    69,    32,   139,    45,    46
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+   STATE-NUM.  */
+#define YYPACT_NINF -120
+static const short yypact[] =
+{
+    -120,    17,  -120,    41,    48,    48,  -120,    48,  -120,  -120,
+      48,   -11,    40,  -120,  -120,  -120,  -120,  -120,    13,  -120,
+      23,  -120,  -120,    66,  -120,    72,  -120,  -120,    77,  -120,
+      81,  -120,  -120,  -120,  -120,  -120,    41,  -120,  -120,  -120,
+    -120,  -120,  -120,    40,    40,    57,    59,  -120,  -120,    98,
+    -120,  -120,    49,  -120,  -120,  -120,     7,  -120,    40,    40,
+      67,    67,    99,   117,  -120,  -120,  -120,  -120,    85,  -120,
+      74,    18,    88,  -120,  -120,    95,  -120,  -120,    18,  -120,
+      96,  -120,  -120,  -120,   102,    36,    40,    48,    67,    48,
+      48,    48,    48,    48,  -120,   103,   129,  -120,   114,  -120,
+      48,    67,  -120,   115,  -120,   116,  -120,  -120,  -120,   118,
+    -120,  -120,  -120,   119,  -120,  -120,  -120,    40,    57,    57,
+     135,   135,  -120,   136,  -120,  -120,  -120,  -120,  -120,  -120,
+    -120,   135,  -120,  -120,  -120,  -120,  -120,    57,    40,  -120,
+    -120,    40,  -120,    57,    57
+};
+
+/* YYPGOTO[NTERM-NUM].  */
+static const yysigned_char yypgoto[] =
+{
+    -120,  -120,  -120,   -38,  -120,  -120,  -120,  -120,  -120,  -120,
+    -120,   -42,  -120,  -120,  -120,  -120,  -120,  -120,  -120,  -120,
+    -120,  -120,   -33,  -120,  -120,  -120,  -120,  -120,  -120,    87,
+      97,    34,    47,    -1,   -23,     2,  -119,   -43,   -53
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
+   positive, shift that token.  If negative, reduce the rule which
+   number is the opposite.  If zero, do what YYDEFACT says.
+   If YYTABLE_NINF, parse error.  */
+#define YYTABLE_NINF -59
+static const short yytable[] =
+{
+      56,    57,   140,    36,    37,    33,    38,    82,    83,    39,
+      74,    67,   142,    40,    73,    80,    81,     2,     3,    76,
+       4,     5,     6,     7,     8,     9,    10,    11,   108,    77,
+      12,    13,   107,    85,    86,   121,    79,   110,    55,    58,
+      59,    47,   118,   119,    14,    15,   112,   111,   132,   -58,
+      72,    48,   -58,     5,    64,     7,     8,    65,    10,    11,
+      41,    42,    12,    66,    41,    42,    43,   117,    14,    15,
+      43,    44,    34,    35,   137,    44,    14,    15,     5,    64,
+       7,     8,    65,    10,    11,    60,   120,    12,    66,    58,
+      59,    41,    42,    61,    50,   143,    98,   105,   144,   131,
+      51,    14,    15,    64,     7,    53,    65,    10,    11,    54,
+      84,    12,    66,   106,    85,    86,   114,    87,    88,    89,
+      90,    91,    92,   115,    93,    14,    15,    94,    84,    59,
+     116,   128,    85,    86,    99,   100,   101,   124,   125,   126,
+     127,   129,   130,   133,   134,   102,   135,   136,   138,   141,
+     104,    78
+};
+
+static const unsigned char yycheck[] =
+{
+      43,    44,   121,     4,     5,     3,     7,    60,    61,    10,
+      52,    49,   131,    24,    52,    58,    59,     0,     1,    52,
+       3,     4,     5,     6,     7,     8,     9,    10,    70,    52,
+      13,    14,    70,    15,    16,    88,    29,    70,    36,    32,
+      33,    28,    85,    86,    27,    28,    28,    70,   101,     0,
+       1,    28,     3,     4,     5,     6,     7,     8,     9,    10,
+      24,    25,    13,    14,    24,    25,    30,    31,    27,    28,
+      30,    35,    24,    25,   117,    35,    27,    28,     4,     5,
+       6,     7,     8,     9,    10,    26,    87,    13,    14,    32,
+      33,    24,    25,    34,    28,   138,    62,    63,   141,   100,
+      28,    27,    28,     5,     6,    28,     8,     9,    10,    28,
+      11,    13,    14,    28,    15,    16,    28,    18,    19,    20,
+      21,    22,    23,    28,    25,    27,    28,    28,    11,    33,
+      28,    28,    15,    16,    17,    18,    19,    90,    91,    92,
+      93,    12,    28,    28,    28,    28,    28,    28,    13,    13,
+      63,    54
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+   symbol of state STATE-NUM.  */
+static const unsigned char yystos[] =
+{
+       0,    37,     0,     1,     3,     4,     5,     6,     7,     8,
+       9,    10,    13,    14,    27,    28,    38,    39,    40,    41,
+      44,    45,    47,    51,    53,    55,    56,    58,    60,    61,
+      62,    63,    71,    71,    24,    25,    69,    69,    69,    69,
+      24,    24,    25,    30,    35,    73,    74,    28,    28,    50,
+      28,    28,    59,    28,    28,    71,    73,    73,    32,    33,
+      26,    34,    42,    48,     5,     8,    14,    39,    46,    70,
+      54,    66,     1,    39,    47,    57,    58,    70,    66,    29,
+      73,    73,    74,    74,    11,    15,    16,    18,    19,    20,
+      21,    22,    23,    25,    28,    43,    64,    65,    67,    17,
+      18,    19,    28,    49,    65,    67,    28,    39,    47,    52,
+      58,    70,    28,    67,    28,    28,    28,    31,    73,    73,
+      69,    74,    68,    69,    68,    68,    68,    68,    28,    12,
+      28,    69,    74,    28,    28,    28,    28,    73,    13,    72,
+      72,    13,    72,    73,    73
+};
 
 #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__)
 # define YYSIZE_T __SIZE_TYPE__
@@ -513,14 +640,19 @@
 #define yyclearin	(yychar = YYEMPTY)
 #define YYEMPTY		-2
 #define YYEOF		0
+
 #define YYACCEPT	goto yyacceptlab
-#define YYABORT 	goto yyabortlab
+#define YYABORT		goto yyabortlab
 #define YYERROR		goto yyerrlab1
+
 /* Like YYERROR except do call yyerror.  This remains here temporarily
    to ease the transition to the new meaning of YYERROR, for GCC.
    Once GCC version 2 has supplanted version 1, this can go.  */
+
 #define YYFAIL		goto yyerrlab
+
 #define YYRECOVERING()  (!!yyerrstatus)
+
 #define YYBACKUP(Token, Value)					\
 do								\
   if (yychar == YYEMPTY && yylen == 1)				\
@@ -541,41 +673,20 @@
 #define YYTERROR	1
 #define YYERRCODE	256
 
-
 /* YYLLOC_DEFAULT -- Compute the default location (before the actions
-   are run).
-
-   When YYLLOC_DEFAULT is run, CURRENT is set the location of the
-   first token.  By default, to implement support for ranges, extend
-   its range to the last symbol.  */
+   are run).  */
 
 #ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)       	\
-   Current.last_line   = Rhs[N].last_line;	\
-   Current.last_column = Rhs[N].last_column;
+# define YYLLOC_DEFAULT(Current, Rhs, N)           \
+  Current.first_line   = Rhs[1].first_line;      \
+  Current.first_column = Rhs[1].first_column;    \
+  Current.last_line    = Rhs[N].last_line;       \
+  Current.last_column  = Rhs[N].last_column;
 #endif
 
-
 /* YYLEX -- calling `yylex' with the right arguments.  */
 
-#if YYPURE
-# if YYLSP_NEEDED
-#  ifdef YYLEX_PARAM
-#   define YYLEX		yylex (&yylval, &yylloc, YYLEX_PARAM)
-#  else
-#   define YYLEX		yylex (&yylval, &yylloc)
-#  endif
-# else /* !YYLSP_NEEDED */
-#  ifdef YYLEX_PARAM
-#   define YYLEX		yylex (&yylval, YYLEX_PARAM)
-#  else
-#   define YYLEX		yylex (&yylval)
-#  endif
-# endif /* !YYLSP_NEEDED */
-#else /* !YYPURE */
-# define YYLEX			yylex ()
-#endif /* !YYPURE */
-
+#define YYLEX	yylex ()
 
 /* Enable debugging if requested.  */
 #if YYDEBUG
@@ -590,11 +701,17 @@
   if (yydebug)					\
     YYFPRINTF Args;				\
 } while (0)
+# define YYDSYMPRINT(Args)			\
+do {						\
+  if (yydebug)					\
+    yysymprint Args;				\
+} while (0)
 /* Nonzero means print parse trace.  It is left uninitialized so that
    multiple parsers can coexist.  */
 int yydebug;
 #else /* !YYDEBUG */
 # define YYDPRINTF(Args)
+# define YYDSYMPRINT(Args)
 #endif /* !YYDEBUG */
 
 /* YYINITDEPTH -- initial size of the parser's stacks.  */
@@ -616,8 +733,10 @@
 #ifndef YYMAXDEPTH
 # define YYMAXDEPTH 10000
 #endif
+
 
-#ifdef YYERROR_VERBOSE
+
+#if YYERROR_VERBOSE
 
 # ifndef yystrlen
 #  if defined (__GLIBC__) && defined (_STRING_H)
@@ -667,11 +786,74 @@
 }
 #  endif
 # endif
-#endif
+
+#endif /* !YYERROR_VERBOSE */
+
 
-#line 315 "/usr/share/bison/bison.simple"
+
+#if YYDEBUG
+/*-----------------------------.
+| Print this symbol on YYOUT.  |
+`-----------------------------*/
+
+static void
+#if defined (__STDC__) || defined (__cplusplus)
+yysymprint (FILE* yyout, int yytype, YYSTYPE yyvalue)
+#else
+yysymprint (yyout, yytype, yyvalue)
+    FILE* yyout;
+    int yytype;
+    YYSTYPE yyvalue;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvalue;
+
+  if (yytype < YYNTOKENS)
+    {
+      YYFPRINTF (yyout, "token %s (", yytname[yytype]);
+# ifdef YYPRINT
+      YYPRINT (yyout, yytoknum[yytype], yyvalue);
+# endif
+    }
+  else
+    YYFPRINTF (yyout, "nterm %s (", yytname[yytype]);
+
+  switch (yytype)
+    {
+      default:
+        break;
+    }
+  YYFPRINTF (yyout, ")");
+}
+#endif /* YYDEBUG. */
 
 
+/*-----------------------------------------------.
+| Release the memory associated to this symbol.  |
+`-----------------------------------------------*/
+
+static void
+#if defined (__STDC__) || defined (__cplusplus)
+yydestruct (int yytype, YYSTYPE yyvalue)
+#else
+yydestruct (yytype, yyvalue)
+    int yytype;
+    YYSTYPE yyvalue;
+#endif
+{
+  /* Pacify ``unused variable'' warnings.  */
+  (void) yyvalue;
+
+  switch (yytype)
+    {
+      default:
+        break;
+    }
+}
+
+
+
 /* The user can define YYPARSE_PARAM as the name of an argument to be passed
    into yyparse.  The argument should have type void *.
    It should actually point to an object.
@@ -700,46 +882,22 @@
 # endif
 #endif
 
-/* YY_DECL_VARIABLES -- depending whether we use a pure parser,
-   variables are global, or local to YYPARSE.  */
 
-#define YY_DECL_NON_LSP_VARIABLES			\
-/* The lookahead symbol.  */				\
-int yychar;						\
-							\
-/* The semantic value of the lookahead symbol. */	\
-YYSTYPE yylval;						\
-							\
-/* Number of parse errors so far.  */			\
-int yynerrs;
+/* The lookahead symbol.  */
+int yychar;
 
-#if YYLSP_NEEDED
-# define YY_DECL_VARIABLES			\
-YY_DECL_NON_LSP_VARIABLES			\
-						\
-/* Location data for the lookahead symbol.  */	\
-YYLTYPE yylloc;
-#else
-# define YY_DECL_VARIABLES			\
-YY_DECL_NON_LSP_VARIABLES
-#endif
+/* The semantic value of the lookahead symbol.  */
+YYSTYPE yylval;
 
+/* Number of parse errors so far.  */
+int yynerrs;
 
-/* If nonreentrant, generate the variables here. */
-
-#if !YYPURE
-YY_DECL_VARIABLES
-#endif  /* !YYPURE */
 
 int
 yyparse (YYPARSE_PARAM_ARG)
      YYPARSE_PARAM_DECL
 {
-  /* If reentrant, generate the variables here. */
-#if YYPURE
-  YY_DECL_VARIABLES
-#endif  /* !YYPURE */
-
+  
   register int yystate;
   register int yyn;
   int yyresult;
@@ -756,7 +914,7 @@
      Refer to the stacks thru separate pointers, to allow yyoverflow
      to reallocate them elsewhere.  */
 
-  /* The state stack. */
+  /* The state stack.  */
   short	yyssa[YYINITDEPTH];
   short *yyss = yyssa;
   register short *yyssp;
@@ -766,31 +924,19 @@
   YYSTYPE *yyvs = yyvsa;
   register YYSTYPE *yyvsp;
 
-#if YYLSP_NEEDED
-  /* The location stack.  */
-  YYLTYPE yylsa[YYINITDEPTH];
-  YYLTYPE *yyls = yylsa;
-  YYLTYPE *yylsp;
-#endif
 
-#if YYLSP_NEEDED
-# define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
-#else
-# define YYPOPSTACK   (yyvsp--, yyssp--)
-#endif
 
-  YYSIZE_T yystacksize = YYINITDEPTH;
+#define YYPOPSTACK   (yyvsp--, yyssp--)
 
+  YYSIZE_T yystacksize = YYINITDEPTH;
 
   /* The variables used to return semantic value and location from the
      action routines.  */
   YYSTYPE yyval;
-#if YYLSP_NEEDED
-  YYLTYPE yyloc;
-#endif
+
 
   /* When reducing, the number of symbols on the RHS of the reduced
-     rule. */
+     rule.  */
   int yylen;
 
   YYDPRINTF ((stderr, "Starting parse\n"));
@@ -807,9 +953,7 @@
 
   yyssp = yyss;
   yyvsp = yyvs;
-#if YYLSP_NEEDED
-  yylsp = yyls;
-#endif
+
   goto yysetstate;
 
 /*------------------------------------------------------------.
@@ -837,24 +981,17 @@
 	YYSTYPE *yyvs1 = yyvs;
 	short *yyss1 = yyss;
 
+
 	/* Each stack pointer address is followed by the size of the
-	   data in use in that stack, in bytes.  */
-# if YYLSP_NEEDED
-	YYLTYPE *yyls1 = yyls;
-	/* This used to be a conditional around just the two extra args,
-	   but that might be undefined if yyoverflow is a macro.  */
-	yyoverflow ("parser stack overflow",
-		    &yyss1, yysize * sizeof (*yyssp),
-		    &yyvs1, yysize * sizeof (*yyvsp),
-		    &yyls1, yysize * sizeof (*yylsp),
-		    &yystacksize);
-	yyls = yyls1;
-# else
+	   data in use in that stack, in bytes.  This used to be a
+	   conditional around just the two extra args, but that might
+	   be undefined if yyoverflow is a macro.  */
 	yyoverflow ("parser stack overflow",
 		    &yyss1, yysize * sizeof (*yyssp),
 		    &yyvs1, yysize * sizeof (*yyvsp),
+
 		    &yystacksize);
-# endif
+
 	yyss = yyss1;
 	yyvs = yyvs1;
       }
@@ -877,10 +1014,8 @@
 	  goto yyoverflowlab;
 	YYSTACK_RELOCATE (yyss);
 	YYSTACK_RELOCATE (yyvs);
-# if YYLSP_NEEDED
-	YYSTACK_RELOCATE (yyls);
-# endif
-# undef YYSTACK_RELOCATE
+
+#  undef YYSTACK_RELOCATE
 	if (yyss1 != yyssa)
 	  YYSTACK_FREE (yyss1);
       }
@@ -889,9 +1024,7 @@
 
       yyssp = yyss + yysize - 1;
       yyvsp = yyvs + yysize - 1;
-#if YYLSP_NEEDED
-      yylsp = yyls + yysize - 1;
-#endif
+
 
       YYDPRINTF ((stderr, "Stack size increased to %lu\n",
 		  (unsigned long int) yystacksize));
@@ -904,7 +1037,6 @@
 
   goto yybackup;
 
-
 /*-----------.
 | yybackup.  |
 `-----------*/
@@ -917,7 +1049,7 @@
   /* First try to decide what to do without reference to lookahead token.  */
 
   yyn = yypact[yystate];
-  if (yyn == YYFLAG)
+  if (yyn == YYPACT_NINF)
     goto yydefault;
 
   /* Not known => get a lookahead token if don't already have one.  */
@@ -931,12 +1063,12 @@
       yychar = YYLEX;
     }
 
-  /* Convert token to internal form (in yychar1) for indexing tables with */
+  /* Convert token to internal form (in yychar1) for indexing tables with.  */
 
-  if (yychar <= 0)		/* This means end of input. */
+  if (yychar <= 0)		/* This means end of input.  */
     {
       yychar1 = 0;
-      yychar = YYEOF;		/* Don't call YYLEX any more */
+      yychar = YYEOF;		/* Don't call YYLEX any more.  */
 
       YYDPRINTF ((stderr, "Now at end of input.\n"));
     }
@@ -944,45 +1076,26 @@
     {
       yychar1 = YYTRANSLATE (yychar);
 
-#if YYDEBUG
-     /* We have to keep this `#if YYDEBUG', since we use variables
-	which are defined only if `YYDEBUG' is set.  */
-      if (yydebug)
-	{
-	  YYFPRINTF (stderr, "Next token is %d (%s",
-		     yychar, yytname[yychar1]);
-	  /* Give the individual parser a way to print the precise
-	     meaning of a token, for further debugging info.  */
-# ifdef YYPRINT
-	  YYPRINT (stderr, yychar, yylval);
-# endif
-	  YYFPRINTF (stderr, ")\n");
-	}
-#endif
+      /* We have to keep this `#if YYDEBUG', since we use variables
+	 which are defined only if `YYDEBUG' is set.  */
+      YYDPRINTF ((stderr, "Next token is "));
+      YYDSYMPRINT ((stderr, yychar1, yylval));
+      YYDPRINTF ((stderr, "\n"));
     }
 
+  /* If the proper action on seeing token YYCHAR1 is to reduce or to
+     detect an error, take that action.  */
   yyn += yychar1;
-  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
+  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yychar1)
     goto yydefault;
-
   yyn = yytable[yyn];
-
-  /* yyn is what to do for this token type in this state.
-     Negative => reduce, -yyn is rule number.
-     Positive => shift, yyn is new state.
-       New state is final state => don't bother to shift,
-       just return success.
-     0, or most negative number => error.  */
-
-  if (yyn < 0)
+  if (yyn <= 0)
     {
-      if (yyn == YYFLAG)
+      if (yyn == 0 || yyn == YYTABLE_NINF)
 	goto yyerrlab;
       yyn = -yyn;
       goto yyreduce;
     }
-  else if (yyn == 0)
-    goto yyerrlab;
 
   if (yyn == YYFINAL)
     YYACCEPT;
@@ -996,9 +1109,7 @@
     yychar = YYEMPTY;
 
   *++yyvsp = yylval;
-#if YYLSP_NEEDED
-  *++yylsp = yylloc;
-#endif
+
 
   /* Count tokens shifted since error; after three, turn off error
      status.  */
@@ -1029,19 +1140,14 @@
   /* If YYLEN is nonzero, implement the default value of the action:
      `$$ = $1'.
 
-     Otherwise, the following line sets YYVAL to the semantic value of
-     the lookahead token.  This behavior is undocumented and Bison
+     Otherwise, the following line sets YYVAL to garbage.
+     This behavior is undocumented and Bison
      users should not rely upon it.  Assigning to YYVAL
      unconditionally makes the parser a bit smaller, and it avoids a
      GCC warning that YYVAL may be used uninitialized.  */
   yyval = yyvsp[1-yylen];
 
-#if YYLSP_NEEDED
-  /* Similarly for the default location.  Let the user run additional
-     commands if for instance locations are ranges.  */
-  yyloc = yylsp[1-yylen];
-  YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen);
-#endif
+
 
 #if YYDEBUG
   /* We have to keep this `#if YYDEBUG', since we use variables which
@@ -1051,362 +1157,415 @@
       int yyi;
 
       YYFPRINTF (stderr, "Reducing via rule %d (line %d), ",
-		 yyn, yyrline[yyn]);
+		 yyn - 1, yyrline[yyn]);
 
       /* Print the symbols being reduced, and their result.  */
-      for (yyi = yyprhs[yyn]; yyrhs[yyi] > 0; yyi++)
+      for (yyi = yyprhs[yyn]; yyrhs[yyi] >= 0; yyi++)
 	YYFPRINTF (stderr, "%s ", yytname[yyrhs[yyi]]);
       YYFPRINTF (stderr, " -> %s\n", yytname[yyr1[yyn]]);
     }
 #endif
-
-  switch (yyn) {
-
-case 7:
+  switch (yyn)
+    {
+        case 8:
 #line 96 "zconf.y"
-{ zconfprint("unexpected 'endmenu' statement"); ;
-    break;}
-case 8:
+    { zconfprint("unexpected 'endmenu' statement"); }
+    break;
+
+  case 9:
 #line 97 "zconf.y"
-{ zconfprint("unexpected 'endif' statement"); ;
-    break;}
-case 9:
+    { zconfprint("unexpected 'endif' statement"); }
+    break;
+
+  case 10:
 #line 98 "zconf.y"
-{ zconfprint("unexpected 'endchoice' statement"); ;
-    break;}
-case 10:
+    { zconfprint("unexpected 'endchoice' statement"); }
+    break;
+
+  case 11:
 #line 99 "zconf.y"
-{ zconfprint("syntax error"); yyerrok; ;
-    break;}
-case 16:
+    { zconfprint("syntax error"); yyerrok; }
+    break;
+
+  case 17:
 #line 114 "zconf.y"
-{
+    {
 	struct symbol *sym = sym_lookup(yyvsp[0].string, 0);
 	sym->flags |= SYMBOL_OPTIONAL;
 	menu_add_entry(sym);
 	printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), yyvsp[0].string);
-;
-    break;}
-case 17:
+}
+    break;
+
+  case 18:
 #line 122 "zconf.y"
-{
+    {
 	menu_end_entry();
 	printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 22:
+}
+    break;
+
+  case 23:
 #line 133 "zconf.y"
-{ ;
-    break;}
-case 23:
+    { }
+    break;
+
+  case 24:
 #line 136 "zconf.y"
-{
+    {
 	menu_set_type(S_TRISTATE);
 	printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 24:
+}
+    break;
+
+  case 25:
 #line 142 "zconf.y"
-{
+    {
 	menu_set_type(S_BOOLEAN);
 	printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 25:
+}
+    break;
+
+  case 26:
 #line 148 "zconf.y"
-{
+    {
 	menu_set_type(S_INT);
 	printd(DEBUG_PARSE, "%s:%d:int\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 26:
+}
+    break;
+
+  case 27:
 #line 154 "zconf.y"
-{
+    {
 	menu_set_type(S_HEX);
 	printd(DEBUG_PARSE, "%s:%d:hex\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 27:
+}
+    break;
+
+  case 28:
 #line 160 "zconf.y"
-{
+    {
 	menu_set_type(S_STRING);
 	printd(DEBUG_PARSE, "%s:%d:string\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 28:
+}
+    break;
+
+  case 29:
 #line 166 "zconf.y"
-{
+    {
 	menu_add_prop(P_PROMPT, yyvsp[-1].string, NULL, yyvsp[0].expr);
 	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 29:
+}
+    break;
+
+  case 30:
 #line 172 "zconf.y"
-{
+    {
 	menu_add_prop(P_DEFAULT, NULL, yyvsp[-1].symbol, yyvsp[0].expr);
 	printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 30:
+}
+    break;
+
+  case 31:
 #line 180 "zconf.y"
-{
+    {
 	struct symbol *sym = sym_lookup(NULL, 0);
 	sym->flags |= SYMBOL_CHOICE;
 	menu_add_entry(sym);
 	menu_add_prop(P_CHOICE, NULL, NULL, NULL);
 	printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 31:
+}
+    break;
+
+  case 32:
 #line 189 "zconf.y"
-{
+    {
 	menu_end_entry();
 	menu_add_menu();
-;
-    break;}
-case 32:
+}
+    break;
+
+  case 33:
 #line 195 "zconf.y"
-{
+    {
 	if (zconf_endtoken(yyvsp[0].token, T_CHOICE, T_ENDCHOICE)) {
 		menu_end_menu();
 		printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno());
 	}
-;
-    break;}
-case 34:
+}
+    break;
+
+  case 35:
 #line 205 "zconf.y"
-{
+    {
 	printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno);
 	zconfnerrs++;
-;
-    break;}
-case 40:
+}
+    break;
+
+  case 41:
 #line 219 "zconf.y"
-{
+    {
 	menu_add_prop(P_PROMPT, yyvsp[-1].string, NULL, yyvsp[0].expr);
 	printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 41:
+}
+    break;
+
+  case 42:
 #line 225 "zconf.y"
-{
+    {
 	current_entry->sym->flags |= SYMBOL_OPTIONAL;
 	printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 42:
+}
+    break;
+
+  case 43:
 #line 231 "zconf.y"
-{
+    {
 	menu_add_prop(P_DEFAULT, NULL, yyvsp[0].symbol, NULL);
-	//current_choice->prop->def = $2;
+	//current_choice->prop->def = ;
 	printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 45:
+}
+    break;
+
+  case 46:
 #line 245 "zconf.y"
-{
+    {
 	printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno());
 	menu_add_entry(NULL);
-	//current_entry->prompt = menu_add_prop(T_IF, NULL, NULL, $2);
+	//current_entry->prompt = menu_add_prop(T_IF, NULL, NULL, );
 	menu_add_dep(yyvsp[0].expr);
 	menu_end_entry();
 	menu_add_menu();
-;
-    break;}
-case 46:
+}
+    break;
+
+  case 47:
 #line 255 "zconf.y"
-{
+    {
 	if (zconf_endtoken(yyvsp[0].token, T_IF, T_ENDIF)) {
 		menu_end_menu();
 		printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno());
 	}
-;
-    break;}
-case 48:
+}
+    break;
+
+  case 49:
 #line 265 "zconf.y"
-{
+    {
 	printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno);
 	zconfnerrs++;
-;
-    break;}
-case 53:
+}
+    break;
+
+  case 54:
 #line 280 "zconf.y"
-{
+    {
 	menu_add_entry(NULL);
 	menu_add_prop(P_MENU, yyvsp[0].string, NULL, NULL);
 	printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 54:
+}
+    break;
+
+  case 55:
 #line 287 "zconf.y"
-{
+    {
 	menu_end_entry();
 	menu_add_menu();
-;
-    break;}
-case 55:
+}
+    break;
+
+  case 56:
 #line 293 "zconf.y"
-{
+    {
 	if (zconf_endtoken(yyvsp[0].token, T_MENU, T_ENDMENU)) {
 		menu_end_menu();
 		printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno());
 	}
-;
-    break;}
-case 57:
+}
+    break;
+
+  case 58:
 #line 303 "zconf.y"
-{
+    {
 	printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno);
 	zconfnerrs++;
-;
-    break;}
-case 62:
+}
+    break;
+
+  case 63:
 #line 313 "zconf.y"
-{ zconfprint("invalid menu option"); yyerrok; ;
-    break;}
-case 63:
+    { zconfprint("invalid menu option"); yyerrok; }
+    break;
+
+  case 64:
 #line 317 "zconf.y"
-{
+    {
 	yyval.string = yyvsp[0].string;
 	printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), yyvsp[0].string);
-;
-    break;}
-case 64:
+}
+    break;
+
+  case 65:
 #line 323 "zconf.y"
-{
+    {
 	zconf_nextfile(yyvsp[-1].string);
-;
-    break;}
-case 65:
+}
+    break;
+
+  case 66:
 #line 330 "zconf.y"
-{
+    {
 	menu_add_entry(NULL);
 	menu_add_prop(P_COMMENT, yyvsp[0].string, NULL, NULL);
 	printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 66:
+}
+    break;
+
+  case 67:
 #line 337 "zconf.y"
-{
+    {
 	menu_end_entry();
-;
-    break;}
-case 67:
+}
+    break;
+
+  case 68:
 #line 344 "zconf.y"
-{
+    {
 	printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno());
 	zconf_starthelp();
-;
-    break;}
-case 68:
+}
+    break;
+
+  case 69:
 #line 350 "zconf.y"
-{
+    {
 	current_entry->sym->help = yyvsp[0].string;
-;
-    break;}
-case 71:
+}
+    break;
+
+  case 72:
 #line 359 "zconf.y"
-{ ;
-    break;}
-case 72:
+    { }
+    break;
+
+  case 73:
 #line 362 "zconf.y"
-{
+    {
 	menu_add_dep(yyvsp[0].expr);
 	printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 73:
+}
+    break;
+
+  case 74:
 #line 367 "zconf.y"
-{
+    {
 	menu_add_dep(yyvsp[0].expr);
 	printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 74:
+}
+    break;
+
+  case 75:
 #line 372 "zconf.y"
-{
+    {
 	menu_add_dep(yyvsp[0].expr);
 	printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno());
-;
-    break;}
-case 76:
+}
+    break;
+
+  case 77:
 #line 382 "zconf.y"
-{
+    {
 	menu_add_prop(P_PROMPT, yyvsp[0].string, NULL, NULL);
-;
-    break;}
-case 77:
+}
+    break;
+
+  case 78:
 #line 386 "zconf.y"
-{
+    {
 	menu_add_prop(P_PROMPT, yyvsp[-2].string, NULL, yyvsp[0].expr);
-;
-    break;}
-case 80:
+}
+    break;
+
+  case 81:
 #line 394 "zconf.y"
-{ yyval.token = T_ENDMENU; ;
-    break;}
-case 81:
+    { yyval.token = T_ENDMENU; }
+    break;
+
+  case 82:
 #line 395 "zconf.y"
-{ yyval.token = T_ENDCHOICE; ;
-    break;}
-case 82:
+    { yyval.token = T_ENDCHOICE; }
+    break;
+
+  case 83:
 #line 396 "zconf.y"
-{ yyval.token = T_ENDIF; ;
-    break;}
-case 85:
+    { yyval.token = T_ENDIF; }
+    break;
+
+  case 86:
 #line 402 "zconf.y"
-{ yyval.expr = NULL; ;
-    break;}
-case 86:
+    { yyval.expr = NULL; }
+    break;
+
+  case 87:
 #line 403 "zconf.y"
-{ yyval.expr = yyvsp[0].expr; ;
-    break;}
-case 87:
+    { yyval.expr = yyvsp[0].expr; }
+    break;
+
+  case 88:
 #line 406 "zconf.y"
-{ yyval.expr = expr_alloc_symbol(yyvsp[0].symbol); ;
-    break;}
-case 88:
+    { yyval.expr = expr_alloc_symbol(yyvsp[0].symbol); }
+    break;
+
+  case 89:
 #line 407 "zconf.y"
-{ yyval.expr = expr_alloc_comp(E_EQUAL, yyvsp[-2].symbol, yyvsp[0].symbol); ;
-    break;}
-case 89:
+    { yyval.expr = expr_alloc_comp(E_EQUAL, yyvsp[-2].symbol, yyvsp[0].symbol); }
+    break;
+
+  case 90:
 #line 408 "zconf.y"
-{ yyval.expr = expr_alloc_comp(E_UNEQUAL, yyvsp[-2].symbol, yyvsp[0].symbol); ;
-    break;}
-case 90:
+    { yyval.expr = expr_alloc_comp(E_UNEQUAL, yyvsp[-2].symbol, yyvsp[0].symbol); }
+    break;
+
+  case 91:
 #line 409 "zconf.y"
-{ yyval.expr = yyvsp[-1].expr; ;
-    break;}
-case 91:
+    { yyval.expr = yyvsp[-1].expr; }
+    break;
+
+  case 92:
 #line 410 "zconf.y"
-{ yyval.expr = expr_alloc_one(E_NOT, yyvsp[0].expr); ;
-    break;}
-case 92:
+    { yyval.expr = expr_alloc_one(E_NOT, yyvsp[0].expr); }
+    break;
+
+  case 93:
 #line 411 "zconf.y"
-{ yyval.expr = expr_alloc_two(E_OR, yyvsp[-2].expr, yyvsp[0].expr); ;
-    break;}
-case 93:
+    { yyval.expr = expr_alloc_two(E_OR, yyvsp[-2].expr, yyvsp[0].expr); }
+    break;
+
+  case 94:
 #line 412 "zconf.y"
-{ yyval.expr = expr_alloc_two(E_AND, yyvsp[-2].expr, yyvsp[0].expr); ;
-    break;}
-case 94:
+    { yyval.expr = expr_alloc_two(E_AND, yyvsp[-2].expr, yyvsp[0].expr); }
+    break;
+
+  case 95:
 #line 415 "zconf.y"
-{ yyval.symbol = sym_lookup(yyvsp[0].string, 0); free(yyvsp[0].string); ;
-    break;}
-case 95:
+    { yyval.symbol = sym_lookup(yyvsp[0].string, 0); free(yyvsp[0].string); }
+    break;
+
+  case 96:
 #line 416 "zconf.y"
-{ yyval.symbol = sym_lookup(yyvsp[0].string, 1); free(yyvsp[0].string); ;
-    break;}
-}
+    { yyval.symbol = sym_lookup(yyvsp[0].string, 1); free(yyvsp[0].string); }
+    break;
+
 
-#line 705 "/usr/share/bison/bison.simple"
+    }
 
+/* Line 1016 of /usr/share/bison/yacc.c.  */
+#line 1565 "zconf.tab.c"
 
   yyvsp -= yylen;
   yyssp -= yylen;
-#if YYLSP_NEEDED
-  yylsp -= yylen;
-#endif
+
 
 #if YYDEBUG
   if (yydebug)
@@ -1420,9 +1579,7 @@
 #endif
 
   *++yyvsp = yyval;
-#if YYLSP_NEEDED
-  *++yylsp = yyloc;
-#endif
+
 
   /* Now `shift' the result of the reduction.  Determine what state
      that goes to, based on the state we popped back to and the rule
@@ -1430,11 +1587,11 @@
 
   yyn = yyr1[yyn];
 
-  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
-  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
     yystate = yytable[yystate];
   else
-    yystate = yydefgoto[yyn - YYNTBASE];
+    yystate = yydefgoto[yyn - YYNTOKENS];
 
   goto yynewstate;
 
@@ -1447,13 +1604,13 @@
   if (!yyerrstatus)
     {
       ++yynerrs;
-
-#ifdef YYERROR_VERBOSE
+#if YYERROR_VERBOSE
       yyn = yypact[yystate];
 
-      if (yyn > YYFLAG && yyn < YYLAST)
+      if (YYPACT_NINF < yyn && yyn < YYLAST)
 	{
 	  YYSIZE_T yysize = 0;
+	  int yytype = YYTRANSLATE (yychar);
 	  char *yymsg;
 	  int yyx, yycount;
 
@@ -1462,15 +1619,15 @@
 	     YYCHECK.  */
 	  for (yyx = yyn < 0 ? -yyn : 0;
 	       yyx < (int) (sizeof (yytname) / sizeof (char *)); yyx++)
-	    if (yycheck[yyx + yyn] == yyx)
+	    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
 	      yysize += yystrlen (yytname[yyx]) + 15, yycount++;
 	  yysize += yystrlen ("parse error, unexpected ") + 1;
-	  yysize += yystrlen (yytname[YYTRANSLATE (yychar)]);
+	  yysize += yystrlen (yytname[yytype]);
 	  yymsg = (char *) YYSTACK_ALLOC (yysize);
 	  if (yymsg != 0)
 	    {
 	      char *yyp = yystpcpy (yymsg, "parse error, unexpected ");
-	      yyp = yystpcpy (yyp, yytname[YYTRANSLATE (yychar)]);
+	      yyp = yystpcpy (yyp, yytname[yytype]);
 
 	      if (yycount < 5)
 		{
@@ -1478,7 +1635,7 @@
 		  for (yyx = yyn < 0 ? -yyn : 0;
 		       yyx < (int) (sizeof (yytname) / sizeof (char *));
 		       yyx++)
-		    if (yycheck[yyx + yyn] == yyx)
+		    if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
 		      {
 			const char *yyq = ! yycount ? ", expecting " : " or ";
 			yyp = yystpcpy (yyp, yyq);
@@ -1493,99 +1650,90 @@
 	    yyerror ("parse error; also virtual memory exhausted");
 	}
       else
-#endif /* defined (YYERROR_VERBOSE) */
+#endif /* YYERROR_VERBOSE */
 	yyerror ("parse error");
     }
   goto yyerrlab1;
 
 
-/*--------------------------------------------------.
-| yyerrlab1 -- error raised explicitly by an action |
-`--------------------------------------------------*/
+/*----------------------------------------------------.
+| yyerrlab1 -- error raised explicitly by an action.  |
+`----------------------------------------------------*/
 yyerrlab1:
   if (yyerrstatus == 3)
     {
       /* If just tried and failed to reuse lookahead token after an
 	 error, discard it.  */
 
-      /* return failure if at end of input */
+      /* Return failure if at end of input.  */
       if (yychar == YYEOF)
-	YYABORT;
+        {
+	  /* Pop the error token.  */
+          YYPOPSTACK;
+	  /* Pop the rest of the stack.  */
+	  while (yyssp > yyss)
+	    {
+	      YYDPRINTF ((stderr, "Error: popping "));
+	      YYDSYMPRINT ((stderr,
+			    yystos[*yyssp],
+			    *yyvsp));
+	      YYDPRINTF ((stderr, "\n"));
+	      yydestruct (yystos[*yyssp], *yyvsp);
+	      YYPOPSTACK;
+	    }
+	  YYABORT;
+        }
+
       YYDPRINTF ((stderr, "Discarding token %d (%s).\n",
 		  yychar, yytname[yychar1]));
+      yydestruct (yychar1, yylval);
       yychar = YYEMPTY;
     }
 
   /* Else will try to reuse lookahead token after shifting the error
      token.  */
 
-  yyerrstatus = 3;		/* Each real token shifted decrements this */
-
-  goto yyerrhandle;
+  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
 
+  for (;;)
+    {
+      yyn = yypact[yystate];
+      if (yyn != YYPACT_NINF)
+	{
+	  yyn += YYTERROR;
+	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+	    {
+	      yyn = yytable[yyn];
+	      if (0 < yyn)
+		break;
+	    }
+	}
 
-/*-------------------------------------------------------------------.
-| yyerrdefault -- current state does not do anything special for the |
-| error token.                                                       |
-`-------------------------------------------------------------------*/
-yyerrdefault:
-#if 0
-  /* This is wrong; only states that explicitly want error tokens
-     should shift them.  */
-
-  /* If its default is to accept any token, ok.  Otherwise pop it.  */
-  yyn = yydefact[yystate];
-  if (yyn)
-    goto yydefault;
-#endif
+      /* Pop the current state because it cannot handle the error token.  */
+      if (yyssp == yyss)
+	YYABORT;
 
+      YYDPRINTF ((stderr, "Error: popping "));
+      YYDSYMPRINT ((stderr,
+		    yystos[*yyssp], *yyvsp));
+      YYDPRINTF ((stderr, "\n"));
+
+      yydestruct (yystos[yystate], *yyvsp);
+      yyvsp--;
+      yystate = *--yyssp;
 
-/*---------------------------------------------------------------.
-| yyerrpop -- pop the current state because it cannot handle the |
-| error token                                                    |
-`---------------------------------------------------------------*/
-yyerrpop:
-  if (yyssp == yyss)
-    YYABORT;
-  yyvsp--;
-  yystate = *--yyssp;
-#if YYLSP_NEEDED
-  yylsp--;
-#endif
 
 #if YYDEBUG
-  if (yydebug)
-    {
-      short *yyssp1 = yyss - 1;
-      YYFPRINTF (stderr, "Error: state stack now");
-      while (yyssp1 != yyssp)
-	YYFPRINTF (stderr, " %d", *++yyssp1);
-      YYFPRINTF (stderr, "\n");
-    }
+      if (yydebug)
+	{
+	  short *yyssp1 = yyss - 1;
+	  YYFPRINTF (stderr, "Error: state stack now");
+	  while (yyssp1 != yyssp)
+	    YYFPRINTF (stderr, " %d", *++yyssp1);
+	  YYFPRINTF (stderr, "\n");
+	}
 #endif
-
-/*--------------.
-| yyerrhandle.  |
-`--------------*/
-yyerrhandle:
-  yyn = yypact[yystate];
-  if (yyn == YYFLAG)
-    goto yyerrdefault;
-
-  yyn += YYTERROR;
-  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
-    goto yyerrdefault;
-
-  yyn = yytable[yyn];
-  if (yyn < 0)
-    {
-      if (yyn == YYFLAG)
-	goto yyerrpop;
-      yyn = -yyn;
-      goto yyreduce;
     }
-  else if (yyn == 0)
-    goto yyerrpop;
 
   if (yyn == YYFINAL)
     YYACCEPT;
@@ -1593,9 +1741,7 @@
   YYDPRINTF ((stderr, "Shifting error token, "));
 
   *++yyvsp = yylval;
-#if YYLSP_NEEDED
-  *++yylsp = yylloc;
-#endif
+
 
   yystate = yyn;
   goto yynewstate;
@@ -1615,13 +1761,15 @@
   yyresult = 1;
   goto yyreturn;
 
-/*---------------------------------------------.
-| yyoverflowab -- parser overflow comes here.  |
-`---------------------------------------------*/
+#ifndef yyoverflow
+/*----------------------------------------------.
+| yyoverflowlab -- parser overflow comes here.  |
+`----------------------------------------------*/
 yyoverflowlab:
   yyerror ("parser stack overflow");
   yyresult = 2;
   /* Fall through.  */
+#endif
 
 yyreturn:
 #ifndef yyoverflow
@@ -1630,6 +1778,8 @@
 #endif
   return yyresult;
 }
+
+
 #line 419 "zconf.y"
 
 
@@ -1864,3 +2014,4 @@
 #include "expr.c"
 #include "symbol.c"
 #include "menu.c"
+
diff -Nru a/scripts/kconfig/zconf.tab.h_shipped b/scripts/kconfig/zconf.tab.h_shipped
--- a/scripts/kconfig/zconf.tab.h_shipped	Sun Nov 10 19:28:41 2002
+++ b/scripts/kconfig/zconf.tab.h_shipped	Sun Nov 10 19:28:41 2002
@@ -1,53 +1,125 @@
+/* A Bison parser, made from zconf.y, by GNU bison 1.75.  */
+
+/* Skeleton parser for Yacc-like parsing with Bison,
+   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002 Free Software Foundation, 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, 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.  */
+
+/* As a special exception, when this file is copied by Bison into a
+   Bison output file, you may use that output file without restriction.
+   This special exception was added by the Free Software Foundation
+   in version 1.24 of Bison.  */
+
 #ifndef BISON_ZCONF_TAB_H
 # define BISON_ZCONF_TAB_H
 
+/* Tokens.  */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+   /* Put the tokens into the symbol table, so that GDB and other debuggers
+      know about them.  */
+   enum yytokentype {
+     T_MAINMENU = 258,
+     T_MENU = 259,
+     T_ENDMENU = 260,
+     T_SOURCE = 261,
+     T_CHOICE = 262,
+     T_ENDCHOICE = 263,
+     T_COMMENT = 264,
+     T_CONFIG = 265,
+     T_HELP = 266,
+     T_HELPTEXT = 267,
+     T_IF = 268,
+     T_ENDIF = 269,
+     T_DEPENDS = 270,
+     T_REQUIRES = 271,
+     T_OPTIONAL = 272,
+     T_PROMPT = 273,
+     T_DEFAULT = 274,
+     T_TRISTATE = 275,
+     T_BOOLEAN = 276,
+     T_INT = 277,
+     T_HEX = 278,
+     T_WORD = 279,
+     T_STRING = 280,
+     T_UNEQUAL = 281,
+     T_EOF = 282,
+     T_EOL = 283,
+     T_CLOSE_PAREN = 284,
+     T_OPEN_PAREN = 285,
+     T_ON = 286,
+     T_OR = 287,
+     T_AND = 288,
+     T_EQUAL = 289,
+     T_NOT = 290
+   };
+#endif
+#define T_MAINMENU 258
+#define T_MENU 259
+#define T_ENDMENU 260
+#define T_SOURCE 261
+#define T_CHOICE 262
+#define T_ENDCHOICE 263
+#define T_COMMENT 264
+#define T_CONFIG 265
+#define T_HELP 266
+#define T_HELPTEXT 267
+#define T_IF 268
+#define T_ENDIF 269
+#define T_DEPENDS 270
+#define T_REQUIRES 271
+#define T_OPTIONAL 272
+#define T_PROMPT 273
+#define T_DEFAULT 274
+#define T_TRISTATE 275
+#define T_BOOLEAN 276
+#define T_INT 277
+#define T_HEX 278
+#define T_WORD 279
+#define T_STRING 280
+#define T_UNEQUAL 281
+#define T_EOF 282
+#define T_EOL 283
+#define T_CLOSE_PAREN 284
+#define T_OPEN_PAREN 285
+#define T_ON 286
+#define T_OR 287
+#define T_AND 288
+#define T_EQUAL 289
+#define T_NOT 290
+
+
+
+
 #ifndef YYSTYPE
-typedef union
-{
+#line 33 "zconf.y"
+typedef union {
 	int token;
 	char *string;
 	struct symbol *symbol;
 	struct expr *expr;
 	struct menu *menu;
 } yystype;
+/* Line 1281 of /usr/share/bison/yacc.c.  */
+#line 118 "zconf.tab.h"
 # define YYSTYPE yystype
-# define YYSTYPE_IS_TRIVIAL 1
 #endif
-# define	T_MAINMENU	257
-# define	T_MENU	258
-# define	T_ENDMENU	259
-# define	T_SOURCE	260
-# define	T_CHOICE	261
-# define	T_ENDCHOICE	262
-# define	T_COMMENT	263
-# define	T_CONFIG	264
-# define	T_HELP	265
-# define	T_HELPTEXT	266
-# define	T_IF	267
-# define	T_ENDIF	268
-# define	T_DEPENDS	269
-# define	T_REQUIRES	270
-# define	T_OPTIONAL	271
-# define	T_PROMPT	272
-# define	T_DEFAULT	273
-# define	T_TRISTATE	274
-# define	T_BOOLEAN	275
-# define	T_INT	276
-# define	T_HEX	277
-# define	T_WORD	278
-# define	T_STRING	279
-# define	T_UNEQUAL	280
-# define	T_EOF	281
-# define	T_EOL	282
-# define	T_CLOSE_PAREN	283
-# define	T_OPEN_PAREN	284
-# define	T_ON	285
-# define	T_OR	286
-# define	T_AND	287
-# define	T_EQUAL	288
-# define	T_NOT	289
-
 
 extern YYSTYPE zconflval;
 
+
 #endif /* not BISON_ZCONF_TAB_H */
+
diff -Nru a/scripts/tail.tk b/scripts/tail.tk
--- a/scripts/tail.tk	Sun Nov 10 19:28:40 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,89 +0,0 @@
-# FILE: tail.tk
-# This file is boilerplate TCL/TK function definitions for 'make xconfig'.
-#
-# CHANGES
-# =======
-#
-# 8 January 1998, Michael Elizabeth Chastain, <mec@shout.net>
-# Arrange buttons in three columns for better screen fitting.
-#
-
-#
-# Read the user's settings from .config.  These will override whatever is
-# in config.in.  Don't do this if the user specified a -D to force
-# the defaults.
-#
-if { [file readable .config] == 1} then {
-	if { $argc > 0 } then {
-		if { [lindex $argv 0] != "-D" } then {
-			read_config .config
-		}
-		else
-		{
-			read_config $defaults
-		}
-	} else {
-		read_config .config
-	}
-} else {
-	read_config $defaults
-}
-
-update_define 1 $total_menus 0
-update_mainmenu
-
-button .f0.right.save -anchor w -text "Save and Exit" -underline 0\
-    -command { catch {exec cp -f .config .config.old}; \
-		writeconfig .config include/linux/autoconf.h; wrapup .wrap }
-
-button .f0.right.quit -anchor w -text "Quit Without Saving" -underline 0\
-    -command { maybe_exit .maybe }
-
-button .f0.right.load -anchor w -text "Load Configuration from File" \
-    -command { load_configfile .load "Load Configuration from file" read_config_file
-}
-
-button .f0.right.store -anchor w -text "Store Configuration to File" \
-    -command { load_configfile .load "Store Configuration to file" write_config_file }
-
-#
-# Now pack everything.
-#
-
-pack .f0.right.store .f0.right.load .f0.right.quit .f0.right.save \
-    -padx 0 -pady 0 -side bottom -fill x
-pack .f0.left .f0.middle .f0.right -side left -padx 5 -pady 0 -fill y
-pack .f0 -padx 5 -pady 5
-
-update idletasks
-set winy [expr 10 + [winfo reqheight .f0]]
-set scry [lindex [wm maxsize .] 1]
-set winx [expr 10 + [winfo reqwidth .f0]]
-set scrx [lindex [wm maxsize .] 0]
-if {$winx < $scrx} then {set maxx -1} else {set maxx $winx}
-if {$winy < $scry} then {set maxy -1} else {set maxy $winy}
-.f0 configure -width $winx -height $winy 
-wm maxsize . $maxx $maxy
-
-#
-# If we cannot write our config files, disable the write button.
-#
-if { [file exists .config] == 1 } then {
-		if { [file writable .config] == 0 } then {
-			.f0.right.save configure -state disabled
-		}
-	} else {
-		if { [file writable .] == 0 } then {
-			.f0.right.save configure -state disabled
-		}
-	}
-
-if { [file exists include/linux/autoconf.h] == 1 } then {
-		if { [file writable include/linux/autoconf.h] == 0 } then {
-			.f0.right.save configure -state disabled
-		}
-	} else {
-		if { [file writable include/linux/] == 0 } then {
-			.f0.right.save configure -state disabled
-		}
-	}
diff -Nru a/scripts/tkcond.c b/scripts/tkcond.c
--- a/scripts/tkcond.c	Sun Nov 10 19:28:36 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,602 +0,0 @@
-/*
- * tkcond.c
- *
- * Eric Youngdale was the original author of xconfig.
- * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
- *
- * This file takes the tokenized statement list and transforms 'if ...'
- * statements.  For each simple statement, I find all of the 'if' statements
- * that enclose it, and attach the aggregate conditionals of those 'if'
- * statements to the cond list of the simple statement.
- *
- * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
- * - Steam-clean this file.  I tested this by generating kconfig.tk for
- *   every architecture and comparing it character-for-character against
- *   the output of the old tkparse.
- *
- * 07 July 1999, Andrzej M. Krzysztofowicz <ankry@mif.pg.gda.pl>
- * - kvariables removed; all variables are stored in a single table now
- * - some elimination of options non-valid for current architecture
- *   implemented.
- * - negation (!) eliminated from conditions
- *
- * TO DO:
- * - xconfig is at the end of its life cycle.  Contact <mec@shout.net> if
- *   you are interested in working on the replacement.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "tkparse.h"
-
-
-
-/*
- * Mark variables which are defined anywhere.
- */
-static void mark_variables( struct kconfig * scfg )
-{
-    struct kconfig * cfg;
-    int i;
-
-    for ( i = 1; i <= max_varnum; i++ )
-	vartable[i].defined = 0;
-    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
-    {
-	if ( cfg->token == token_bool
-	||   cfg->token == token_choice_item
-	||   cfg->token == token_define_bool
-	||   cfg->token == token_define_hex
-	||   cfg->token == token_define_int
-	||   cfg->token == token_define_string
-	||   cfg->token == token_define_tristate
-	||   cfg->token == token_dep_bool
-	||   cfg->token == token_dep_mbool
-	||   cfg->token == token_dep_tristate
-	||   cfg->token == token_hex
-	||   cfg->token == token_int
-	||   cfg->token == token_string
-	||   cfg->token == token_tristate
-	||   cfg->token == token_unset )
-	{
-	    if ( cfg->nameindex > 0 )	/* paranoid */
-	    {
-		vartable[cfg->nameindex].defined = 1;
-	    }
-	}
-    }
-}
-
-
-
-static void free_cond( struct condition *cond )
-{
-    struct condition *tmp, *tmp1;
-    for ( tmp = cond; tmp; tmp = tmp1 )
-    {
-	tmp1 = tmp->next;
-	free( (void*)tmp );
-    }
-}
-
-
-
-/*
- * Remove the bang operator from a condition to avoid priority problems.
- * "!" has different priorities as "test" command argument and in 
- * a tk script.
- */
-static struct condition * remove_bang( struct condition * condition )
-{
-    struct condition * conda, * condb, * prev = NULL;
-
-    for ( conda = condition; conda; conda = conda->next )
-    {
-	if ( conda->op == op_bang && conda->next &&
-	   ( condb = conda->next->next ) )
-	{
-	    if ( condb->op == op_eq || condb->op == op_neq )
-	    {
-		condb->op = (condb->op == op_eq) ? op_neq : op_eq;
-		conda->op = op_nuked;
-		if ( prev )
-		{
-		    prev->next = conda->next;
-		}
-		else
-		{
-		    condition = conda->next;
-		}
-		conda->next = NULL;
-		free_cond( conda );
-		conda = condb;
-	    }
-	}
-	prev = conda;
-    }
-    return condition;
-}
-
-
-
-/*
- * Make a new condition chain by joining the current condition stack with
- * the "&&" operator for glue.
- */
-static struct condition * join_condition_stack( struct condition * conditions [],
-    int depth )
-{
-    struct condition * cond_list;
-    struct condition * cond_last;
-    int i, is_first = 1;
-
-    cond_list = cond_last = NULL;
-
-    for ( i = 0; i < depth; i++ )
-    {
-	if ( conditions[i]->op == op_false )
-	{
-	    struct condition * cnew;
-
-	    /* It is always false condition */
-	    cnew = malloc( sizeof(*cnew) );
-	    memset( cnew, 0, sizeof(*cnew) );
-	    cnew->op = op_false;
-	    cond_list = cond_last = cnew;
-	    goto join_done;
-	}
-    }
-    for ( i = 0; i < depth; i++ )
-    {
-	struct condition * cond;
-	struct condition * cnew;
-	int add_paren;
-
-	/* omit always true conditions */
-	if ( conditions[i]->op == op_true )
-	    continue;
-
-	/* if i have another condition, add an '&&' operator */
-	if ( !is_first )
-	{
-	    cnew = malloc( sizeof(*cnew) );
-	    memset( cnew, 0, sizeof(*cnew) );
-	    cnew->op = op_and;
-	    cond_last->next = cnew;
-	    cond_last = cnew;
-	}
-
-	if ( conditions[i]->op != op_lparen )
-	{
-	    /* add a '(' */
-	    add_paren = 1;
-	    cnew = malloc( sizeof(*cnew) );
-	    memset( cnew, 0, sizeof(*cnew) );
-	    cnew->op = op_lparen;
-	    if ( cond_last == NULL )
-		{ cond_list = cond_last = cnew; }
-	    else
-		{ cond_last->next = cnew; cond_last = cnew; }
-	}
-	else
-	{
-	    add_paren = 0;
-	}
-
-	/* duplicate the chain */
-	for ( cond = conditions [i]; cond != NULL; cond = cond->next )
-	{
-	    cnew            = malloc( sizeof(*cnew) );
-	    cnew->next      = NULL;
-	    cnew->op        = cond->op;
-	    cnew->str       = cond->str ? strdup( cond->str ) : NULL;
-	    cnew->nameindex = cond->nameindex;
-	    if ( cond_last == NULL )
-		{ cond_list = cond_last = cnew; }
-	    else
-		{ cond_last->next = cnew; cond_last = cnew; }
-	}
-
-	if ( add_paren )
-	{
-	    /* add a ')' */
-	    cnew = malloc( sizeof(*cnew) );
-	    memset( cnew, 0, sizeof(*cnew) );
-	    cnew->op = op_rparen;
-	    cond_last->next = cnew;
-	    cond_last = cnew;
-	}
-	is_first = 0;
-    }
-
-    /*
-     * Remove duplicate conditions.
-     */
-    {
-	struct condition *cond1, *cond1b, *cond1c, *cond1d, *cond1e, *cond1f;
-
-	for ( cond1 = cond_list; cond1 != NULL; cond1 = cond1->next )
-	{
-	    if ( cond1->op == op_lparen )
-	    {
-		cond1b = cond1 ->next; if ( cond1b == NULL ) break;
-		cond1c = cond1b->next; if ( cond1c == NULL ) break;
-		cond1d = cond1c->next; if ( cond1d == NULL ) break;
-		cond1e = cond1d->next; if ( cond1e == NULL ) break;
-		cond1f = cond1e->next; if ( cond1f == NULL ) break;
-
-		if ( cond1b->op == op_variable
-		&& ( cond1c->op == op_eq || cond1c->op == op_neq )
-		&&   cond1d->op == op_constant 
-		&&   cond1e->op == op_rparen )
-		{
-		    struct condition *cond2, *cond2b, *cond2c, *cond2d, *cond2e, *cond2f;
-
-		    for ( cond2 = cond1f->next; cond2 != NULL; cond2 = cond2->next )
-		    {
-			if ( cond2->op == op_lparen )
-			{
-			    cond2b = cond2 ->next; if ( cond2b == NULL ) break;
-			    cond2c = cond2b->next; if ( cond2c == NULL ) break;
-			    cond2d = cond2c->next; if ( cond2d == NULL ) break;
-			    cond2e = cond2d->next; if ( cond2e == NULL ) break;
-			    cond2f = cond2e->next;
-
-			    /* look for match */
-			    if ( cond2b->op == op_variable
-			    &&   cond2b->nameindex == cond1b->nameindex
-			    &&   cond2c->op == cond1c->op
-			    &&   cond2d->op == op_constant
-			    &&   strcmp( cond2d->str, cond1d->str ) == 0
-			    &&   cond2e->op == op_rparen )
-			    {
-				/* one of these must be followed by && */
-				if ( cond1f->op == op_and
-				|| ( cond2f != NULL && cond2f->op == op_and ) )
-				{
-				    /* nuke the first duplicate */
-				    cond1 ->op = op_nuked;
-				    cond1b->op = op_nuked;
-				    cond1c->op = op_nuked;
-				    cond1d->op = op_nuked;
-				    cond1e->op = op_nuked;
-				    if ( cond1f->op == op_and )
-					cond1f->op = op_nuked;
-				    else
-					cond2f->op = op_nuked;
-				}
-			    }
-			}
-		    }
-		}
-	    }
-	}
-    }
-
-join_done:
-    return cond_list;
-}
-
-
-
-static char * current_arch = NULL;
-
-/*
- * Eliminating conditions with ARCH = <not current>.
- */
-static struct condition *eliminate_other_arch( struct condition *list )
-{
-    struct condition *cond1a = list, *cond1b = NULL, *cond1c = NULL, *cond1d = NULL;
-    if ( current_arch == NULL )
-	current_arch = getenv( "ARCH" );
-    if ( current_arch == NULL )
-    {
-	fprintf( stderr, "error: ARCH undefined\n" );
-	exit( 1 );
-    }
-    if ( cond1a->op == op_variable
-    && ! strcmp( vartable[cond1a->nameindex].name, "ARCH" ) )
-    {
-	cond1b = cond1a->next; if ( cond1b == NULL ) goto done;
-	cond1c = cond1b->next; if ( cond1c == NULL ) goto done;
-	cond1d = cond1c->next;
-	if ( cond1c->op == op_constant && cond1d == NULL )
-	{
-	    if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
-	    ||   (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
-	    {
-		/* This is for another architecture */ 
-		cond1a->op = op_false;
-		cond1a->next = NULL;
-		free_cond( cond1b );
-		return cond1a;
-	    }
-	    else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
-		 ||   (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
-	    {
-		/* This is for current architecture */
-		cond1a->op = op_true;
-		cond1a->next = NULL;
-		free_cond( cond1b );
-		return cond1a;
-	    }
-	}
-	else if ( cond1c->op == op_constant && cond1d->op == op_or )
-	{
-	    if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
-	    ||   (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
-	    {
-		/* This is for another architecture */ 
-		cond1b = cond1d->next;
-		cond1d->next = NULL;
-		free_cond( cond1a );
-		return eliminate_other_arch( cond1b );
-	    }
-	    else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
-		 || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
-	    {
-		/* This is for current architecture */
-		cond1a->op = op_true;
-		cond1a->next = NULL;
-		free_cond( cond1b );
-		return cond1a;
-	    }
-	}
-	else if ( cond1c->op == op_constant && cond1d->op == op_and )
-	{
-	    if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
-	    ||   (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
-	    {
-		/* This is for another architecture */
-		int l_par = 0;
-		
-		for ( cond1c = cond1d->next; cond1c; cond1c = cond1c->next )
-		{
-		    if ( cond1c->op == op_lparen )
-			l_par++;
-		    else if ( cond1c->op == op_rparen )
-			l_par--;
-		    else if ( cond1c->op == op_or && l_par == 0 )
-		    /* Expression too complex - don't touch */
-			return cond1a;
-		    else if ( l_par < 0 )
-		    {
-			fprintf( stderr, "incorrect condition: programming error ?\n" );
-			exit( 1 );
-		    }
-		}
-		cond1a->op = op_false;
-		cond1a->next = NULL;
-		free_cond( cond1b );
-		return cond1a;
-	    }
-	    else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
-		 || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
-	    {
-		/* This is for current architecture */
-		cond1b = cond1d->next;
-		cond1d->next = NULL;
-		free_cond( cond1a );
-		return eliminate_other_arch( cond1b );
-	    }
-	}
-    }
-    if ( cond1a->op == op_variable && ! vartable[cond1a->nameindex].defined )
-    {
-	cond1b = cond1a->next; if ( cond1b == NULL ) goto done;
-	cond1c = cond1b->next; if ( cond1c == NULL ) goto done;
-	cond1d = cond1c->next;
-
-	if ( cond1c->op == op_constant
-	&& ( cond1d == NULL || cond1d->op == op_and ) ) /*???*/
-	{
-	    if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
-	    {
-		cond1a->op = op_false;
-		cond1a->next = NULL;
-		free_cond( cond1b );
-		return cond1a;
-	    }
-	}
-	else if ( cond1c->op == op_constant && cond1d->op == op_or )
-	{
-	    if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
-	    {
-		cond1b = cond1d->next;
-		cond1d->next = NULL;
-		free_cond( cond1a );
-		return eliminate_other_arch( cond1b );
-	    }
-	}
-    }
-done:
-    return list;
-}
-
-
-
-/*
- * This is the main transformation function.
- */
-void fix_conditionals( struct kconfig * scfg )
-{
-    struct kconfig * cfg;
-
-    /*
-     * Transform op_variable to op_kvariable.
-     */
-    mark_variables( scfg );
-
-    /*
-     * Walk the statement list, maintaining a stack of current conditions.
-     *   token_if      push its condition onto the stack.
-     *   token_else    invert the condition on the top of the stack.
-     *   token_endif   pop the stack.
-     *
-     * For a simple statement, create a condition chain by joining together
-     * all of the conditions on the stack.
-     */
-    {
-	struct condition * cond_stack [32];
-	int depth = 0;
-	struct kconfig * prev = NULL;
-
-	for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
-	{
-	    int good = 1;
-	    switch ( cfg->token )
-	    {
-	    default:
-		break;
-
-	    case token_if:
-		cond_stack [depth++] =
-		    remove_bang( eliminate_other_arch( cfg->cond ) );
-		cfg->cond = NULL;
-		break;
-
-	    case token_else:
-		{
-		    /*
-		     * Invert the condition chain.
-		     *
-		     * Be careful to transfrom op_or to op_and1, not op_and.
-		     * I will need this later in the code that removes
-		     * duplicate conditions.
-		     */
-		    struct condition * cond;
-
-		    for ( cond  = cond_stack [depth-1];
-			  cond != NULL;
-			  cond  = cond->next )
-		    {
-			switch( cond->op )
-			{
-			default:     break;
-			case op_and: cond->op = op_or;   break;
-			case op_or:  cond->op = op_and1; break;
-			case op_neq: cond->op = op_eq;   break;
-			case op_eq:  cond->op = op_neq;  break;
-			case op_true: cond->op = op_false;break;
-			case op_false:cond->op = op_true; break;
-			}
-		    }
-		}
-		break;
-
-	    case token_fi:
-		--depth;
-		break;
-
-	    case token_bool:
-	    case token_choice_item:
-	    case token_choice_header:
-	    case token_comment:
-	    case token_define_bool:
-	    case token_define_hex:
-	    case token_define_int:
-	    case token_define_string:
-	    case token_define_tristate:
-	    case token_endmenu:
-	    case token_hex:
-	    case token_int:
-	    case token_mainmenu_option:
-	    case token_string:
-	    case token_tristate:
-	    case token_unset:
-		cfg->cond = join_condition_stack( cond_stack, depth );
-		if ( cfg->cond && cfg->cond->op == op_false )
-		{
-		    good = 0;
-		    if ( prev )
-			prev->next = cfg->next;
-		    else
-			scfg = cfg->next;
-		}
-		break;
-
-	    case token_dep_bool:
-	    case token_dep_mbool:
-	    case token_dep_tristate:
-		/*
-		 * Same as the other simple statements, plus an additional
-		 * condition for the dependency.
-		 */
-		if ( cfg->cond )
-		{
-		    cond_stack [depth] = eliminate_other_arch( cfg->cond );
-		    cfg->cond = join_condition_stack( cond_stack, depth+1 );
-		}
-		else
-		{
-		    cfg->cond = join_condition_stack( cond_stack, depth );
-		}
-		if ( cfg->cond && cfg->cond->op == op_false )
-		{
-		    good = 0;
-		    if ( prev )
-			prev->next = cfg->next;
-		    else
-			scfg = cfg->next;
-		}
-		break;
-	    }
-	    if ( good )
-		prev = cfg;
-	}
-    }
-}
-
-
-
-#if 0
-void dump_condition( struct condition *list )
-{
-    struct condition *tmp;
-    for ( tmp = list; tmp; tmp = tmp->next )
-    {
-	switch (tmp->op)
-	{
-	default:
-	    break;
-	case op_variable:
-	    printf( " %s", vartable[tmp->nameindex].name );
-	    break;
-	case op_constant: 
-	    printf( " %s", tmp->str );
-	    break;
-	case op_eq:
-	    printf( " =" );
-	    break;
-	case op_bang:
-	    printf( " !" );
-	    break;
-	case op_neq:
-	    printf( " !=" );
-	    break;
-	case op_and:
-	case op_and1:
-	    printf( " -a" );
-	    break;
-	case op_or:
-	    printf( " -o" );
-	    break;
-	case op_true:
-	    printf( " TRUE" );
-	    break;
-	case op_false:
-	    printf( " FALSE" );
-	    break;
-	case op_lparen:
-	    printf( " (" );
-	    break;
-	case op_rparen:
-	    printf( " )" );
-	    break;
-	}
-    }
-    printf( "\n" );
-}
-#endif
diff -Nru a/scripts/tkgen.c b/scripts/tkgen.c
--- a/scripts/tkgen.c	Sun Nov 10 19:28:41 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1521 +0,0 @@
-/* Generate tk script based upon config.in
- *
- * Version 1.0
- * Eric Youngdale
- * 10/95
- *
- * 1996 01 04
- * Avery Pennarun - Aesthetic improvements.
- *
- * 1996 01 24
- * Avery Pennarun - Bugfixes and more aesthetics.
- *
- * 1996 03 08
- * Avery Pennarun - The int and hex config.in commands work right.
- *                - Choice buttons are more user-friendly.
- *                - Disabling a text entry line greys it out properly.
- *                - dep_tristate now works like in Configure. (not pretty)
- *                - No warnings in gcc -Wall. (Fixed some "interesting" bugs.)
- *                - Faster/prettier "Help" lookups.
- *
- * 1996 03 15
- * Avery Pennarun - Added new sed script from Axel Boldt to make help even
- *                  faster. (Actually awk is downright slow on some machines.)
- *                - Fixed a bug I introduced into Choice dependencies.  Thanks
- *                  to Robert Krawitz for pointing this out.
- *
- * 1996 03 16
- * Avery Pennarun - basic "do_make" support added to let sound config work.
- *
- * 1996 03 25
- *     Axel Boldt - Help now works on "choice" buttons.
- *
- * 1996 04 06
- * Avery Pennarun - Improved sound config stuff. (I think it actually works
- *                  now!)
- *                - Window-resize-limits don't use ugly /usr/lib/tk4.0 hack.
- *                - int/hex work with tk3 again. (The "cget" error.)
- *                - Next/Prev buttons switch between menus.  I can't take
- *                  much credit for this; the code was already there, but
- *                  ifdef'd out for some reason.  It flickers a lot, but
- *                  I suspect there's no "easy" fix for that.
- *                - Labels no longer highlight as you move the mouse over
- *                  them (although you can still press them... oh well.)
- *                - Got rid of the last of the literal color settings, to
- *                  help out people with mono X-Windows systems. 
- *                  (Apparently there still are some out there!)
- *                - Tabstops seem sensible now.
- *
- * 1996 04 14
- * Avery Pennarun - Reduced flicker when creating windows, even with "update
- *                  idletasks" hack.
- *
- * 1997 12 08
- * Michael Chastain - Remove sound driver special cases.
- *
- * 1997 11 15
- * Michael Chastain - For choice buttons, write values for all options,
- *                    not just the single chosen one.  This is compatible
- *                    with 'make config' and 'make oldconfig', and is
- *                    needed so smart-config dependencies work if the
- *                    user switches from one configuration method to
- *                    another.
- *
- * 1998 03 09
- * Axel Boldt - Smaller layout of main menu - it's still too big for 800x600.
- *            - Display help in text window to allow for cut and paste.
- *            - Allow for empty lines in help texts.
- *            - update_define should not set all variables unconditionally to
- *              0: they may have been set to 1 elsewhere. CONFIG_NETLINK is
- *              an example.
- *
- * 1999 01 04
- * Michael Elizabeth Chastain <mec@shout.net>
- * - Call clear_globalflags when writing out update_mainmenu.
- *   This fixes the missing global/vfix lines for ARCH=alpha on 2.2.0-pre4.
- *
- * 8 January 1999, Michael Elizabeth Chastain <mec@shout.net>
- * - Emit menus_per_column
- *
- * 14 January 1999, Michael Elizabeth Chastain <mec@shout.net>
- * - Steam-clean this file.  I tested this by generating kconfig.tk for every
- *   architecture and comparing it character-for-character against the output
- *   of the old tkparse.
- * - Fix flattening of nested menus.  The old code simply assigned items to
- *   the most recent token_mainmenu_option, without paying attention to scope.
- *   For example: "menu-1 bool-a menu-2 bool-b endmenu bool-c bool-d endmenu".
- *   The old code would put bool-a in menu-1, bool-b in menu-2, and bool-c
- *   and bool-d in *menu-2*.  This hosed the nested submenus in
- *   drives/net/Config.in and other places.
- * - Fix menu line wraparound at 128 menus (some fool used a 'char' for
- *   a counter).
- *
- * 23 January 1999, Michael Elizabeth Chastain <mec@shout.net>
- * - Remove bug-compatible code.
- *
- * 07 July 1999, Andrzej M. Krzysztofowicz <ankry@mif.pg.gda.pl>
- * Some bugfixes, including
- * - disabling "m" options when CONFIG_MODULES is set to "n" as well as "y"
- *   option in dep_tristate when dependency is set to "m",
- * - deactivating choices which should not be available,
- * - basic validation for int and hex introduced if the entered one is not 
- *   valid,
- * - updates of all opened menus instead of the active only. I was afraid
- *   that it would slow down updates, but I don't even see any speed difference
- *   on my machine. If it slows you can still work with only a single menu
- *   opened,
- * - fixed error when focussing non-existent window (especially Help windows),
- * Higher level submenus implemented.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include "tkparse.h"
-
-
-/*
- * Total number of menus.
- */
-static int tot_menu_num = 0;
-
-/*
- * Pointers to mainmenu_option and endmenu of each menu.
- */
-struct kconfig * menu_first [100];
-struct kconfig * menu_last  [100];
-
-/*
- * Generate portion of wish script for the beginning of a submenu.
- * The guts get filled in with the various options.
- */
-static void start_proc( char * label, int menu_num, int toplevel )
-{
-    if ( toplevel )
-	printf( "menu_option menu%d %d \"%s\"\n", menu_num, menu_num, label );
-    printf( "proc menu%d {w title} {\n", menu_num );
-    printf( "\tset oldFocus [focus]\n" );
-    if ( menu_first[menu_num]->menu_number != 0 )
-	printf( "\tcatch {focus .menu%d}\n",
-		menu_first[menu_num]->menu_number );
-    printf( "\tcatch {destroy $w; unregister_active %d}\n", menu_num );
-    printf( "\ttoplevel $w -class Dialog\n" );
-    printf( "\twm withdraw $w\n" );
-    printf( "\tglobal active_menus\n" );
-    printf( "\tset active_menus [lsort -integer [linsert $active_menus end %d]]\n", menu_num );
-    printf( "\tmessage $w.m -width 400 -aspect 300 -text \\\n" );
-    printf( "\t\t\"%s\"  -relief raised\n", label );
-    printf( "\tpack $w.m -pady 10 -side top -padx 10\n" );
-    printf( "\twm title $w \"%s\" \n\n", label );
-
-    printf( "\tbind $w <Escape> \"catch {focus $oldFocus}; destroy $w; unregister_active %d; break\"\n", menu_num);
-
-    printf("\tset nextscript ");
-    printf("\"catch {focus $oldFocus}; " );
-    /* 
-     * We are checking which windows should be destroyed and which are 
-     * common parents with the next one. Remember that menu_num field
-     * in mainmenu_option record reports number of its *parent* menu.
-     */
-    if ( menu_num < tot_menu_num
-    && menu_first[menu_num + 1]->menu_number != menu_num )
-    {
-	int to_destr;
-
-	printf( "destroy $w; unregister_active %d; ", menu_num );
-	to_destr = menu_first[menu_num]->menu_number;
-	while ( to_destr > 0 && menu_first[menu_num + 1]->menu_number != to_destr )
-	{
-	    printf( "catch {destroy .menu%d}; unregister_active %d; ",
-		to_destr, to_destr );
-	    to_destr = menu_first[to_destr]->menu_number;
-	}
-    }
-    printf( "menu%d .menu%d \\\"$title\\\"\"\n",
-	menu_num+1, menu_num+1 );
-
-    /*
-     * Attach the "Prev", "Next" and "OK" buttons at the end of the window.
-     */
-    printf( "\tframe $w.f\n" );
-    if ( toplevel )
-	printf( "\tbutton $w.f.back -text \"Main Menu\" \\\n" );
-    else
-	printf( "\tbutton $w.f.back -text \"OK\" \\\n" );
-    printf( "\t\t-width 15 -command \"catch {focus $oldFocus}; destroy $w; unregister_active %d\"\n",
-	menu_num );
-    printf( "\tbutton $w.f.next -text \"Next\" -underline 0\\\n" );
-    printf( "\t\t-width 15 -command $nextscript\n");
-
-    if ( menu_num == tot_menu_num ) {
-      printf( "\t$w.f.next configure -state disabled\n" );
-        /* 
-         *  this is a bit hackish but Alt-n must be rebound
-         *  otherwise if the user press Alt-n on the last menu
-         *  it will give him/her the next menu of one of the 
-         *  previous options
-         */
-        printf( "\tbind all <Alt-n> \"puts \\\"no more menus\\\" \"\n");
-    }
-    else
-    {
-        /*
-         * I should be binding to $w not all - but if I do nehat I get the error "unknown path"
-         */
-        printf( "\tbind all <Alt-n> $nextscript\n");
-    }
-    printf( "\tbutton $w.f.prev -text \"Prev\" -underline 0\\\n" );
-    printf( "\t\t-width 15 -command \"catch {focus $oldFocus}; destroy $w; unregister_active %d; menu%d .menu%d \\\"$title\\\"\"\n",
-	menu_num, menu_num-1, menu_num-1 );
-    if ( menu_num == 1 ) {
-	printf( "\t$w.f.prev configure -state disabled\n" );
-    }
-    else
-    {
-        printf( "\tbind $w <Alt-p> \"catch {focus $oldFocus}; destroy $w; unregister_active %d; menu%d .menu%d \\\"$title\\\";break\"\n",
-            menu_num, menu_num-1, menu_num-1 );
-    }  
-    printf( "\tpack $w.f.back $w.f.next $w.f.prev -side left -expand on\n" );
-    printf( "\tpack $w.f -pady 10 -side bottom -anchor w -fill x\n" );
-
-    /*
-     * Lines between canvas and other areas of the window.
-     */
-    printf( "\tframe $w.topline -relief ridge -borderwidth 2 -height 2\n" );
-    printf( "\tpack $w.topline -side top -fill x\n\n" );
-    printf( "\tframe $w.botline -relief ridge -borderwidth 2 -height 2\n" );
-    printf( "\tpack $w.botline -side bottom -fill x\n\n" );
-
-    /*
-     * The "config" frame contains the canvas and a scrollbar.
-     */
-    printf( "\tframe $w.config\n" );
-    printf( "\tpack $w.config -fill y -expand on\n\n" );
-    printf( "\tscrollbar $w.config.vscroll -command \"$w.config.canvas yview\"\n" );
-    printf( "\tpack $w.config.vscroll -side right -fill y\n\n" );
-
-    /*
-     * The scrollable canvas itself, where the real work (and mess) gets done.
-     */
-    printf( "\tcanvas $w.config.canvas -height 1\\\n" );
-    printf( "\t\t-relief flat -borderwidth 0 -yscrollcommand \"$w.config.vscroll set\" \\\n" );
-    printf( "\t\t-width [expr [winfo screenwidth .] * 1 / 2] \n" );
-    printf( "\tframe $w.config.f\n" );
-    printf( "\tbind $w <Key-Down> \"$w.config.canvas yview scroll  1 unit;break;\"\n");
-    printf( "\tbind $w <Key-Up> \"$w.config.canvas yview scroll  -1 unit;break;\"\n");
-    printf( "\tbind $w <Key-Next> \"$w.config.canvas yview scroll  1 page;break;\"\n");
-    printf( "\tbind $w <Key-Prior> \"$w.config.canvas yview scroll  -1 page;break;\"\n");
-    printf( "\tbind $w <Key-Home> \"$w.config.canvas yview moveto 0;break;\"\n");
-    printf( "\tbind $w <Key-End> \"$w.config.canvas yview moveto 1 ;break;\"\n");
-    printf( "\tpack $w.config.canvas -side right -fill y\n" );
-    printf("\n\n");
-}
-
-
-
-/*
- * Each proc we create needs a global declaration for any global variables we
- * use.  To minimize the size of the file, we set a flag each time we output
- * a global declaration so we know whether we need to insert one for a
- * given function or not.
- */
-static void clear_globalflags(void)
-{
-    int i;
-    for ( i = 1; i <= max_varnum; i++ )
-	vartable[i].global_written = 0;
-}
-
-
-
-/*
- * Output a "global" line for a given variable.  Also include the
- * call to "vfix".  (If vfix is not needed, then it's fine to just printf
- * a "global" line).
- */
-void global( const char *var )
-{
-    printf( "\tglobal %s\n", var );
-}
-
-
-
-/*
- * This function walks the chain of conditions that we got from cond.c
- * and creates a TCL conditional to enable/disable a given widget.
- */
-void generate_if( struct kconfig * cfg, struct condition * ocond,
-    int menu_num, int line_num )
-{
-    struct condition * cond;
-    struct dependency * tmp;
-    struct kconfig * cfg1;
-
-    if ( line_num >= -1 )
-    {
-	if ( cfg->token == token_define_bool || cfg->token == token_define_hex
-	||   cfg->token == token_define_int || cfg->token == token_define_string
-	||   cfg->token == token_define_tristate || cfg->token == token_unset )
-	    return;
-	if ( cfg->token == token_comment && line_num == -1 )
-	    return;
-    }
-    else
-    {
-	if ( cfg->token == token_string || cfg->token == token_mainmenu_option )
-	    return;
-    }
-
-    /*
-     * First write any global declarations we need for this conditional.
-     */
-    for ( cond = ocond; cond != NULL; cond = cond->next )
-    {
-	switch ( cond->op )
-	{
-	default:
-	    break;
-
-	case op_variable:
-	    if ( ! vartable[cond->nameindex].global_written )
-	    {
-		vartable[cond->nameindex].global_written = 1;
-		global( vartable[cond->nameindex].name );
-	    }
-	    break;
-	}
-    }
-
-    /*
-     * Now write this option.
-     */
-    if ( cfg->nameindex > 0 && ! vartable[cfg->nameindex].global_written )
-    {
-	vartable[cfg->nameindex].global_written = 1;
-	global( vartable[cfg->nameindex].name );
-    }
-
-    /*
-     * Generate the body of the conditional.
-     */
-    printf( "\tif {" );
-    for ( cond = ocond; cond != NULL; cond = cond->next )
-    {
-	switch ( cond->op )
-	{
-	default:
-	    break;
-
-	case op_bang:   printf( " ! "  ); break;
-	case op_eq:     printf( " == " ); break;
-	case op_neq:    printf( " != " ); break;
-	case op_and:    printf( " && " ); break;
-	case op_and1:   printf( " && " ); break;
-	case op_or:     printf( " || " ); break;
-	case op_lparen: printf( "("    ); break;
-	case op_rparen: printf( ")"    ); break;
-
-	case op_variable:
-	    printf( "$%s", vartable[cond->nameindex].name );
-	    break;
-
-	case op_constant:
-	    if      ( strcmp( cond->str, "y" ) == 0 ) printf( "1" );
-	    else if ( strcmp( cond->str, "n" ) == 0 ) printf( "0" );
-	    else if ( strcmp( cond->str, "m" ) == 0 ) printf( "2" );
-	    else if ( strcmp( cond->str, "" ) == 0 )  printf( "4" );
-	    else
-		printf( "\"%s\"", cond->str );
-	    break;
-	}
-    }
-    printf( "} then {" );
-
-    /*
-     * Generate a procedure call to write the value.
-     * This code depends on procedures in header.tk.
-     */
-    if ( line_num >= -1 )
-    {
-	int modtoyes = 0;
-
-	switch ( cfg->token )
-	{
-	default:
-	    printf( " }\n" );
-	    break;
-
-	case token_dep_mbool:
-	    modtoyes = 1;
-	case token_dep_bool:
-	    printf( "\n" );
-	    for ( tmp = cfg->depend; tmp; tmp = tmp->next )
-		if ( ! vartable[get_varnum( tmp->name )].global_written )
-		{
-		    global( tmp->name );
-		}
-	    printf( "\tset tmpvar_dep [effective_dep [list" );
-	    for ( tmp = cfg->depend; tmp; tmp = tmp->next )
-		printf( " $%s", tmp->name );
-	    printf( "]];set %s [sync_bool $%s $tmpvar_dep %d];",
-		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name,
-		modtoyes );
-	    printf( "if {$tmpvar_dep != 1" );
-	    if (modtoyes)
-		printf( " && $tmpvar_dep != 2" );
-	    printf( "} then {configure_entry .menu%d.config.f.x%d disabled {y};",
-		menu_num, line_num );
-	    printf( "} else {" );
-	    printf( "configure_entry .menu%d.config.f.x%d normal {y};",
-		menu_num, line_num );
-	    printf( "}; " );
-	case token_bool:
-	    if ( cfg->token == token_bool )
-		printf( "\n\t" );
-	    printf( "configure_entry .menu%d.config.f.x%d normal {n l",
-		menu_num, line_num );
-	    if ( cfg->token == token_bool )
-		printf( " y" );
-	    printf( "}" );
-	    printf( "} else {");
-	    printf( "configure_entry .menu%d.config.f.x%d disabled {y n l}}\n",
-		menu_num, line_num );
-	    break;
-
-	case token_choice_header:
-	    printf( "configure_entry .menu%d.config.f.x%d normal {x l}",
-		menu_num, line_num );
-	    printf( "} else {" );
-	    printf( "configure_entry .menu%d.config.f.x%d disabled {x l}",
-		menu_num, line_num );
-	    printf( "}\n" );
-	    break;
-
-	case token_choice_item:
-	    fprintf( stderr, "Internal error on token_choice_item\n" );
-	    exit( 1 );
-
-	case token_dep_tristate:
-	    printf( "\n" );
-	    for ( tmp = cfg->depend; tmp; tmp = tmp->next )
-		if ( ! vartable[get_varnum( tmp->name )].global_written )
-		{
-		    global( tmp->name );
-		}
-	    printf( "\tset tmpvar_dep [effective_dep [list" );
-	    for ( tmp = cfg->depend; tmp; tmp = tmp->next )
-		printf( " $%s", tmp->name );
-	    printf( "]];set %s [sync_tristate $%s $tmpvar_dep];",
-		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-	    printf( "\tif {$tmpvar_dep != 1} then {" );
-	    printf( "configure_entry .menu%d.config.f.x%d disabled {y}",
-		menu_num, line_num );
-	    printf( "} else {" );
-	    printf( "configure_entry .menu%d.config.f.x%d normal {y}",
-		menu_num, line_num );
-	    printf( "}; " );
-	    printf( "if {$tmpvar_dep == 0} then {" );
-	    printf( "configure_entry .menu%d.config.f.x%d disabled {m}",
-		menu_num, line_num );
-	    printf( "} else {" );
-	    printf( "configure_entry .menu%d.config.f.x%d normal {m}",
-		menu_num, line_num );
-	    printf( "}; " );
-	case token_tristate:
-	    if ( cfg->token == token_tristate )
-	    {
-		printf( "\n\tconfigure_entry .menu%d.config.f.x%d normal {y}; ",
-		    menu_num, line_num );
-	    }
-	    printf( "if {($CONFIG_MODULES == 1)} then {" );
-	    printf( "configure_entry .menu%d.config.f.x%d normal {m}} else {",
-		menu_num, line_num );
-	    printf( "configure_entry .menu%d.config.f.x%d disabled {m}}; ",
-		menu_num, line_num );
-	    printf( "configure_entry .menu%d.config.f.x%d normal {n l}",
-		menu_num, line_num );
-
-	/*
-	 * Or in a bit to the variable - this causes all of the radiobuttons
-	 * to be deselected (i.e. not be red).
-	 */
-	    printf( "} else {" );
-	    printf( "configure_entry .menu%d.config.f.x%d disabled {y n m l}}\n",
-		menu_num, line_num );
-	    break;
-
-	case token_hex:
-	case token_int:
-	case token_string:
-	    printf( ".menu%d.config.f.x%d.x configure -state normal -foreground [ cget .ref -foreground ]; ",
-		menu_num, line_num );
-	    printf( ".menu%d.config.f.x%d.l configure -state normal; ",
-		menu_num, line_num );
-	    printf( "} else {" );
-	    printf( ".menu%d.config.f.x%d.x configure -state disabled -foreground [ cget .ref -disabledforeground ]; ",
-		menu_num, line_num );
-	    printf( ".menu%d.config.f.x%d.l configure -state disabled}\n",
-		menu_num, line_num );
-	    break;
-
-	case token_comment:
-	case token_mainmenu_option:
-	    if ( line_num >= 0 )
-	    {
-		printf( "configure_entry .menu%d.config.f.x%d normal {m}",
-		    menu_num, line_num );
-		printf( "} else {" );
-		printf( "configure_entry .menu%d.config.f.x%d disabled {m}}\n",
-		    menu_num, line_num );
-	    }
-	    else
-		printf( ".f0.x%d configure -state normal } else { .f0.x%d configure -state disabled }\n",
-		    menu_num, menu_num );
-	    break;
-	}
-    }
-    else
-    {
-	int modtoyes = 0;
-
-	switch ( cfg->token )
-	{
-	default:
-	    printf( " }\n" );
-	    break;
-
-	case token_dep_mbool:
-	    modtoyes = 1;
-	case token_dep_bool:
-	    printf( "\n" );
-	    for ( tmp = cfg->depend; tmp; tmp = tmp->next )
-		if ( ! vartable[get_varnum( tmp->name )].global_written )
-		{
-		    global( tmp->name );
-		}
-	    printf( "\tset tmpvar_dep [effective_dep [list" );
-	    for ( tmp = cfg->depend; tmp; tmp = tmp->next )
-		printf( " $%s", tmp->name );
-	    printf( "]];set %s [sync_bool $%s $tmpvar_dep %d];",
-		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name,
-		modtoyes );
-	case token_bool:
-	    if ( cfg->token == token_bool )
-		printf( "\n\t" );
-	    printf( "set %s [expr $%s&15]",
-		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-	    printf( "} else {");
-	    printf( "set %s [expr $%s|16]}\n",
-		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-	    break;
-
-	case token_choice_header:
-	    printf( "} else {" );
-	    for ( cfg1  = cfg->next;
-		  cfg1 != NULL && cfg1->token == token_choice_item;
-		  cfg1  = cfg1->next )
-		printf( "set %s 4;", vartable[cfg1->nameindex].name );
-	    printf( "}\n" );
-	    break;
-
-	case token_choice_item:
-	    fprintf( stderr, "Internal error on token_choice_item\n" );
-	    exit( 1 );
-
-	case token_define_bool:
-	case token_define_tristate:
-	    if ( ! vartable[get_varnum( cfg->value )].global_written )
-	    {
-		global( cfg->value );
-	    }
-	    printf( "set %s $%s }\n",
-		vartable[cfg->nameindex].name, cfg->value );
-	    break;
-
-	case token_define_hex:
-	case token_define_int:
-	    printf( "set %s %s }\n",
-		vartable[cfg->nameindex].name, cfg->value );
-	    break;
-
-	case token_define_string:
-	    printf( "set %s \"%s\" }\n",
-		vartable[cfg->nameindex].name, cfg->value );
-	    break;
-
-	case token_dep_tristate:
-	    printf( "\n" );
-	    for ( tmp = cfg->depend; tmp; tmp = tmp->next )
-		if ( ! vartable[get_varnum( tmp->name )].global_written )
-		{
-		    global( tmp->name );
-		}
-	    printf( "\tset tmpvar_dep [effective_dep [list" );
-	    for ( tmp = cfg->depend; tmp; tmp = tmp->next )
-		printf( " $%s", tmp->name );
-	    printf( "]]; set %s [sync_tristate $%s $tmpvar_dep]; ",
-		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-	case token_tristate:
-	    if ( cfg->token == token_tristate )
-		printf( "if {($CONFIG_MODULES == 0) && ($%s == 2)} then {set %s 1}; ",
-		    vartable[cfg->nameindex].name,
-		    vartable[cfg->nameindex].name );
-	/*
-	 * Or in a bit to the variable - this causes all of the radiobuttons
-	 * to be deselected (i.e. not be red).
-	 */
-	    printf( "set %s [expr $%s&15]",
-		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-	    printf( "} else {" );
-
-	/*
-	 * Clear the disable bit to enable the correct radiobutton.
-	 */
-	    printf( "set %s [expr $%s|16]}\n",
-		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-	    break;
-
-	case token_hex:
-	case token_int:
-	    if ( cfg->value && *cfg->value == '$' )
-	    {
-		int i = get_varnum( cfg->value+1 );
-		printf( "\n" );
-		if ( ! vartable[i].global_written )
-		{
-		    global( vartable[i].name );
-		}
-		printf( "\t" );
-	    }
-	    if ( cfg->token == token_hex )
-		printf( "validate_hex " );
-	    else if ( cfg->token == token_int )
-		printf( "validate_int " );
-	    printf( "%s \"$%s\" %s}\n",
-		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name,
-		cfg->value );
-	    break;
-
-	case token_unset:
-	    printf( "set %s 4}\n", vartable[cfg->nameindex].name );
-	    break;
-	}
-    }
-}
-
-
-/*
- * Generate a line that writes a variable to the output file.
- */
-void generate_writeconfig( struct kconfig * cfg )
-{
-    struct condition * cond;
-    struct dependency * tmp;
-    int depmod = 2;
-    
-    /*
-     * Generate global declaration for this symbol.
-     */
-    if ( cfg->token != token_comment )
-    {
-	if ( cfg->nameindex > 0 && ! vartable[cfg->nameindex].global_written )
-	{
-	    vartable[cfg->nameindex].global_written = 1;
-	    global( vartable[cfg->nameindex].name );
-	}
-	if ( cfg->token == token_define_tristate || cfg->token == token_define_bool )
-	{
-	    if ( ! vartable[get_varnum( cfg->value )].global_written )
-	    {
-		vartable[get_varnum( cfg->value )].global_written = 1;
-		global( cfg->value );
-	    }
-	}
-	else if ( cfg->nameindex <= 0 && cfg->token == token_choice_header )
-	{
-	    printf( "\tglobal tmpvar_%d\n", -(cfg->nameindex) );
-	}
-    }
-
-    /*
-     * Generate global declarations for the condition chain.
-     */
-    for ( cond = cfg->cond; cond != NULL; cond = cond->next )
-    {
-	switch( cond->op )
-	{
-	default:
-	    break;
-
-	case op_variable:
-	    if ( ! vartable[cond->nameindex].global_written )
-	    {
-		vartable[cond->nameindex].global_written = 1;
-		global( vartable[cond->nameindex].name );
-	    }
-	    break;
-	}
-    }
-
-    /*
-     * Generate indentation.
-     */
-	printf( "\t" );
-
-    /*
-     * Generate the conditional.
-     */
-    if ( cfg->cond != NULL )
-    {
-	printf( "if {" );
-	for ( cond = cfg->cond; cond != NULL; cond = cond->next )
-	{
-	    switch ( cond->op )
-	    {
-	    default:           break;
-	    case op_bang:      printf( " ! "  ); break;
-	    case op_eq:        printf( " == " ); break;
-	    case op_neq:       printf( " != " ); break;
-	    case op_and:       printf( " && " ); break;
-	    case op_and1:      printf( " && " ); break;
-	    case op_or:        printf( " || " ); break;
-	    case op_lparen:    printf( "("    ); break;
-	    case op_rparen:    printf( ")"    ); break;
-
-	    case op_variable:
-		printf( "$%s", vartable[cond->nameindex].name );
-		break;
-
-	    case op_constant:
-		if      ( strcmp( cond->str, "n" ) == 0 ) printf( "0" );
-		else if ( strcmp( cond->str, "y" ) == 0 ) printf( "1" );
-		else if ( strcmp( cond->str, "m" ) == 0 ) printf( "2" );
-		else if ( strcmp( cond->str, "" ) == 0 )  printf( "4" );
-		else
-		    printf( "\"%s\"", cond->str );
-		break;
-	    }
-	}
-	printf( "} then {" );
-    }
-
-    /*
-     * Generate a procedure call to write the value.
-     * This code depends on the write_* procedures in header.tk.
-     */
-    switch ( cfg->token )
-    {
-    default:
-	if ( cfg->cond != NULL )
-	    printf( " }" );
-	printf( "\n" );
-	break;
-
-    case token_bool:
-    case token_tristate:
-	printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2", 
-	    vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-	if ( cfg->cond != NULL )
-	    printf( " }" );
-	printf( "\n" );
-	break;
-
-    case token_choice_header:
-	/*
-	 * This is funky code -- it fails if there were any conditionals.
-	 * Fortunately all the conditionals got stripped off somewhere
-	 * else.
-	 */
-	{
-	    struct kconfig * cfg1;
-	    for ( cfg1  = cfg->next;
-		  cfg1 != NULL && cfg1->token == token_choice_item;
-		  cfg1  = cfg1->next )
-	    {
-		printf("\n\tif { $tmpvar_%d == \"%s\" } then { write_tristate $cfg $autocfg %s 1 [list $notmod] 2 } else { write_tristate $cfg $autocfg %s 0 [list $notmod] 2 }",
-		    -(cfg->nameindex), cfg1->label,
-		    vartable[cfg1->nameindex].name,
-		    vartable[cfg1->nameindex].name );
-	    }
-	}
-	if ( cfg->cond != NULL )
-	    printf( "}" );
-	printf( "\n" );
-	break;
-
-    case token_choice_item:
-	fprintf( stderr, "Internal error on token_choice_item\n" );
-	exit( 1 );
-
-    case token_comment:
-	printf( "write_comment $cfg $autocfg \"%s\"",
-	    cfg->label );
-	if ( cfg->cond != NULL )
-	    printf( "}" );
-	printf( "\n" );
-	break;
-
-    case token_define_bool:
-    case token_define_tristate:
-	if ( cfg->cond == NULL )
-	{
-	    printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2\n",
-		vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-	}
-	else
-	{
-	    printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2 }\n",
-		vartable[cfg->nameindex].name, cfg->value );
-	}
-	break;
-
-    case token_dep_mbool:
-	depmod = 1;
-    case token_dep_bool:
-    case token_dep_tristate:
-	printf( "write_tristate $cfg $autocfg %s $%s [list",
-	    vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-	for ( tmp = cfg->depend; tmp; tmp = tmp->next )
-	    printf( " $%s", tmp->name );
-	printf( "] %d", depmod );
-	if ( cfg->cond != NULL )
-	    printf( " }" );
-	printf( "\n" );
-	break;
-
-    case token_define_hex:
-	printf( "write_hex $cfg $autocfg %s %s $notmod",
-	    vartable[cfg->nameindex].name, cfg->value );
-	if ( cfg->cond != NULL )
-	    printf( " }" );
-	printf( "\n" );
-	break;
-
-    case token_define_int:
-	printf( "write_int $cfg $autocfg %s %s $notmod",
-	    vartable[cfg->nameindex].name, cfg->value );
-	if ( cfg->cond != NULL )
-	    printf( " }" );
-	printf( "\n" );
-	break;
-
-    case token_define_string:
-	printf( "write_string $cfg $autocfg %s \"%s\" $notmod",
-	    vartable[cfg->nameindex].name, cfg->value );
-	if ( cfg->cond != NULL )
-	    printf( " }" );
-	printf( "\n" );
-	break;
-
-    case token_hex:
-	printf( "write_hex $cfg $autocfg %s $%s $notmod",
-	    vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-	if ( cfg->cond != NULL )
-	    printf( " }" );
-	printf( "\n" );
-	break;
-
-    case token_int:
-	printf( "write_int $cfg $autocfg %s $%s $notmod",
-	    vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-	if ( cfg->cond != NULL )
-	    printf( " }" );
-	printf( "\n" );
-	break;
-
-    case token_string:
-	printf( "write_string $cfg $autocfg %s \"$%s\" $notmod",
-	    vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-	if ( cfg->cond != NULL )
-	    printf( " }" );
-	printf( "\n" );
-	break;
-    }
-}
-
-static void generate_update_var( struct kconfig * scfg, int menu_num )
-{
-    struct kconfig * cfg;
-
-    if ( menu_num>0 )
-    {
-	printf( "proc update_define_menu%d {} {\n", menu_num );
-	printf( "\tupdate_define_mainmenu\n" );
-    }
-    else
-	printf( "proc update_define_mainmenu {} {\n" );
-    clear_globalflags();
-    global( "CONFIG_MODULES" );
-    vartable[ get_varnum( "CONFIG_MODULES" ) ].global_written = 1;
-    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
-    {
-	if ( cfg->menu_number == menu_num && (cfg->token == token_define_bool || cfg->token == token_define_tristate
-	||   cfg->token == token_define_hex || cfg->token == token_define_int
-	||   cfg->token == token_define_string || cfg->token == token_unset 
-	||   cfg->token == token_tristate) )
-	{
-	    if ( ! vartable[cfg->nameindex].global_written )
-	    {
-		vartable[cfg->nameindex].global_written = 1;
-		global( vartable[cfg->nameindex].name );
-	    }
-	}
-    }
-
-    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
-    {
-	char tmp[20];
-	struct kconfig * cfg1;
-
-	if ( cfg->menu_number == menu_num )
-	{
-	    switch ( cfg->token )
-	    {
-	    default:
-	    case token_choice_item:
-		break;
-	    case token_choice_header:
-		sprintf( tmp, "tmpvar_%d", -(cfg->nameindex) );
-		global( tmp );
-		for ( cfg1  = cfg->next;
-		      cfg1 != NULL && cfg1->token == token_choice_item;
-		      cfg1  = cfg1->next )
-		{
-		    vartable[cfg1->nameindex].global_written = 1;
-		    global( vartable[cfg1->nameindex].name );
-		    printf( "\tif {$tmpvar_%d == \"%s\"} then {set %s 1} else {set %s 0}\n",
-			-(cfg->nameindex), cfg1->label,
-			vartable[cfg1->nameindex].name,
-			vartable[cfg1->nameindex].name );
-		}
-		break;
-	    case token_bool:
-	    case token_define_bool:
-	    case token_define_tristate:
-	    case token_define_hex:
-	    case token_define_int:
-	    case token_define_string:
-	    case token_dep_bool:
-	    case token_dep_tristate:
-	    case token_dep_mbool:
-	    case token_int:
-	    case token_hex:
-	    case token_mainmenu_option:
-	    case token_tristate:
-	    case token_unset:
-		if ( cfg->cond != NULL )
-		    generate_if( cfg, cfg->cond, menu_num, -2 );
-		else switch ( cfg->token )
-		{
-		case token_tristate:
-		    printf( "\n\tif {($CONFIG_MODULES == 0)} then {if {($%s == 2)} then {set %s 1}}\n",
-			vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
-		    break;
-		case token_define_bool:
-		case token_define_tristate:
-		    if ( ! vartable[get_varnum( cfg->value )].global_written )
-		    {
-			vartable[get_varnum( cfg->value )].global_written = 1;
-			global( cfg->value );
-		    }
-		    printf( "\tset %s $%s\n", vartable[cfg->nameindex].name,
-			cfg->value );
-		    break;
-		case token_define_hex:
-		case token_define_int:
-		    printf( "\tset %s %s\n", vartable[cfg->nameindex].name,
-			cfg->value );
-		    break;
-		case token_define_string:
-		    printf( "\tset %s \"%s\"\n", vartable[cfg->nameindex].name,
-			cfg->value );
-		    break;
-		case token_unset:
-		    printf( "\tset %s 4\n", vartable[cfg->nameindex].name );
-		default:
-		    break;
-		}
-	    }
-	}
-    }
-    printf( "}\n\n\n" );
-}
-
-
-/*
- * Generates the end of a menu procedure.
- */
-static void end_proc( struct kconfig * scfg, int menu_num )
-{
-    struct kconfig * cfg;
-
-    printf( "\n\n\n" );
-    printf( "\tfocus $w\n" );
-    printf( "\tupdate_active\n" );
-    printf( "\tglobal winx; global winy\n" );
-    if ( menu_first[menu_num]->menu_number != 0 )
-    {
-	printf( "\tif {[winfo exists .menu%d] == 0} then ",
-		menu_first[menu_num]->menu_number );
-	printf( "{menu%d .menu%d \"%s\"}\n",
-		menu_first[menu_num]->menu_number, menu_first[menu_num]->menu_number,
-		menu_first[menu_first[menu_num]->menu_number]->label );
-	printf( "\tset winx [expr [winfo x .menu%d]+30]; set winy [expr [winfo y .menu%d]+30]\n",
-		menu_first[menu_num]->menu_number, menu_first[menu_num]->menu_number );
-    }
-    else
-	printf( "\tset winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30]\n" );
-    printf( "\tif {[winfo exists $w]} then {wm geometry $w +$winx+$winy}\n" );
-
-    /*
-     * Now that the whole window is in place, we need to wait for an "update"
-     * so we can tell the canvas what its virtual size should be.
-     *
-     * Unfortunately, this causes some ugly screen-flashing because the whole
-     * window is drawn, and then it is immediately resized.  It seems
-     * unavoidable, though, since "frame" objects won't tell us their size
-     * until after an update, and "canvas" objects can't automatically pack
-     * around frames.  Sigh.
-     */
-    printf( "\tupdate idletasks\n" );
-    printf( "\tif {[winfo exists $w]} then  {$w.config.canvas create window 0 0 -anchor nw -window $w.config.f\n\n" );
-    printf( "\t$w.config.canvas configure \\\n" );
-    printf( "\t\t-width [expr [winfo reqwidth $w.config.f] + 1]\\\n" );
-    printf( "\t\t-scrollregion \"-1 -1 [expr [winfo reqwidth $w.config.f] + 1] \\\n" );
-    printf( "\t\t\t [expr [winfo reqheight $w.config.f] + 1]\"\n\n" );
-	 
-    /*
-     * If the whole canvas will fit in 3/4 of the screen height, do it;
-     * otherwise, resize to around 1/2 the screen and let us scroll.
-     */
-    printf( "\tset winy [expr [winfo reqh $w] - [winfo reqh $w.config.canvas]]\n" );
-    printf( "\tset scry [expr [winfo screenh $w] / 2]\n" );
-    printf( "\tset maxy [expr [winfo screenh $w] * 3 / 4]\n" );
-    printf( "\tset canvtotal [expr [winfo reqh $w.config.f] + 2]\n" );
-    printf( "\tif [expr $winy + $canvtotal < $maxy] {\n" );
-    printf( "\t\t$w.config.canvas configure -height $canvtotal\n" );
-    printf( "\t} else {\n" );
-    printf( "\t\t$w.config.canvas configure -height [expr $scry - $winy]\n" );
-    printf( "\t\t}\n\t}\n" );
-
-    /*
-     * Limit the min/max window size.  Height can vary, but not width,
-     * because of the limitations of canvas and our laziness.
-     */
-    printf( "\tupdate idletasks\n" );
-    printf( "\tif {[winfo exists $w]} then {\n\twm maxsize $w [winfo width $w] [winfo screenheight $w]\n" );
-    printf( "\twm minsize $w [winfo width $w] 100\n\n" );
-    printf( "\twm deiconify $w\n" );
-    printf( "}\n}\n\n" );
-
-    /*
-     * Now we generate the companion procedure for the menu we just
-     * generated.  This procedure contains all of the code to
-     * disable/enable widgets based upon the settings of the other
-     * widgets, and will be called first when the window is mapped,
-     * and each time one of the buttons in the window are clicked.
-     */
-    printf( "proc update_menu%d {} {\n", menu_num );
-
-    /*
-     * Clear all of the booleans that are defined in this menu.
-     */
-    clear_globalflags();
-    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
-    {
-	if ( cfg->menu_number == menu_num
-	&&   cfg->token != token_mainmenu_option
-	&&   cfg->token != token_choice_item )
-	{
-	    if ( cfg->cond != NULL )
-	    {
-		int i;
-		if ( (cfg->token == token_tristate || cfg->token == token_dep_tristate)
-		&& ! vartable[i = get_varnum( "CONFIG_MODULES" )].global_written )
-		{
-		    global( "CONFIG_MODULES" );
-		    vartable[i].global_written = 1;
-		}
-		generate_if( cfg, cfg->cond, cfg->menu_number, cfg->menu_line );
-	    }
-	    else
-	    {
-		if ( cfg->token == token_tristate )
-		{
-		    int i;
-		    if ( ! vartable[cfg->nameindex].global_written )
-		    {
-			vartable[cfg->nameindex].global_written = 1;
-			printf( "\tglobal %s\n", vartable[cfg->nameindex].name );
-		    }
-		    if ( ! vartable[i = get_varnum( "CONFIG_MODULES" )].global_written )
-		    {
-			global( "CONFIG_MODULES" );
-			vartable[i].global_written = 1;
-		    }
-		    printf( "\n\tif {($CONFIG_MODULES == 1)} then {configure_entry .menu%d.config.f.x%d normal {m}} else {configure_entry .menu%d.config.f.x%d disabled {m}}\n",
-			menu_num, cfg->menu_line,
-			menu_num, cfg->menu_line );
-		}
-	    }
-	}
-	else if ( cfg->token == token_mainmenu_option
-	     &&   cfg->menu_number == menu_num
-	     &&   cfg->cond != NULL )
-	{
-	    generate_if( cfg, cfg->cond, menu_num, cfg->menu_line );
-	}
-    }
-    printf("}\n\n\n");
-
-    generate_update_var( scfg, menu_num );
-}
-
-/*
- * This is the top level function for generating the tk script.
- */
-void dump_tk_script( struct kconfig * scfg )
-{
-    int menu_depth;
-    int menu_num [64];
-    int imenu, i;
-    int top_level_num = 0;
-    struct kconfig * cfg;
-    struct kconfig * cfg1 = NULL;
-    const char * name = "No Name";
-
-    /*
-     * Mark begin and end of each menu so I can omit submenus when walking
-     * over a parent menu.
-     */
-    tot_menu_num = 0;
-    menu_depth   = 0;
-    menu_num [0] = 0;
-
-    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
-    {
-	switch ( cfg->token )
-	{
-	default:
-	    break;
-
-	case token_mainmenu_name:
-	    name = cfg->label;
-	    break;
-
-	case token_mainmenu_option:
-	    if ( ++menu_depth >= 64 )
-		{ fprintf( stderr, "menus too deep\n" ); exit( 1 ); }
-	    if ( ++tot_menu_num >= 100 )
-		{ fprintf( stderr, "too many menus\n" ); exit( 1 ); }
-	    menu_num   [menu_depth]   = tot_menu_num;
-	    menu_first [tot_menu_num] = cfg;
-	    menu_last  [tot_menu_num] = cfg;
-	    /*
-	     * Note, that menu_number is set to the number of parent 
-	     * (upper level) menu.
-	     */
-	    cfg->menu_number = menu_num[menu_depth - 1];
-	    if ( menu_depth == 1 )
-		++top_level_num;
-	    break;
-
-	case token_endmenu:
-	    menu_last [menu_num [menu_depth]] = cfg;
-	    /* flatten menus with proper scoping */
-	    if ( --menu_depth < 0 )
-		{ fprintf( stderr, "unmatched endmenu\n" ); exit( 1 ); }
-	    break;
-
-	case token_bool:
-	case token_choice_header:
-	case token_choice_item:
-	case token_comment:
-	case token_dep_bool:
-	case token_dep_tristate:
-	case token_dep_mbool:
-	case token_hex:
-	case token_int:
-	case token_string:
-	case token_tristate:
-	    cfg->menu_number = menu_num[menu_depth];
-	    if ( menu_depth == 0 )
-		{ fprintf( stderr, "statement not in menu\n" ); exit( 1 ); }
-	    break;
-
-	case token_define_bool:
-	case token_define_hex:
-	case token_define_int:
-	case token_define_string:
-	case token_define_tristate:
-	case token_unset:
-	    cfg->menu_number = menu_num[menu_depth];
-	    break;
-	}
-    }
-
-    /*
-     * Generate menus per column setting.
-     * There are:
-     *   four extra buttons for save/quit/load/store;
-     *   one blank button
-     *   add two to round up for division
-     */
-    printf( "set menus_per_column %d\n", (top_level_num + 4 + 1 + 2) / 3 );
-    printf( "set total_menus %d\n\n", tot_menu_num );
-
-    printf( "proc toplevel_menu {num} {\n" );
-    for ( imenu = 1; imenu <= tot_menu_num; ++imenu )
-    {
-	int parent = 1;
-
-	if ( menu_first[imenu]->menu_number == 0 )
-	    parent = menu_first[imenu]->menu_number;
-	else
-	    printf( "\tif {$num == %d} then {return %d}\n",
-		imenu, menu_first[imenu]->menu_number );
-    }
-    printf( "\treturn $num\n}\n\n" );
-
-    /*
-     * Generate the menus.
-     */
-    printf( "mainmenu_name \"%s\"\n", name );
-    for ( imenu = 1; imenu <= tot_menu_num; ++imenu )
-    {
-	int menu_line = 0;
-	int nr_submenu = imenu;
-	int menu_name_omitted = 0;
-	int opt_count = 0;
-
-	clear_globalflags();
-	start_proc( menu_first[imenu]->label, imenu, 
-		!menu_first[imenu]->menu_number );
-
-	for ( cfg = menu_first[imenu]->next; cfg != NULL && cfg != menu_last[imenu]; cfg = cfg->next )
-	{
-	    switch ( cfg->token )
-	    {
-	    default:
-		break;
-
-	    case token_mainmenu_option:
-		while ( menu_first[++nr_submenu]->menu_number > imenu )
-		    ;
-		cfg->menu_line = menu_line++;
-		printf( "\tsubmenu $w.config.f %d %d \"%s\" %d\n",
-		    cfg->menu_number, cfg->menu_line, cfg->label, nr_submenu );
-		cfg = menu_last[nr_submenu];
-		break;
-
-	    case token_comment:
-		if ( !cfg->menu_line && !menu_name_omitted )
-		{
-		    cfg->menu_line = -1;
-		    menu_name_omitted = 1;
-		}
-		else
-		{
-		    menu_name_omitted = 1;
-		    cfg->menu_line = menu_line++;
-		    printf( "\tcomment $w.config.f %d %d \"%s\"\n",
-			cfg->menu_number, cfg->menu_line, cfg->label );
-		}
-		break;
-
-	    case token_bool:
-		cfg->menu_line = menu_line++;
-		printf( "\tbool $w.config.f %d %d \"%s\" %s\n",
-		    cfg->menu_number, cfg->menu_line, cfg->label,
-		    vartable[cfg->nameindex].name );
-		break;
-
-	    case token_choice_header:
-		/*
-		 * I need the first token_choice_item to pick out the right
-		 * help text from Documentation/Configure.help.
-		 */
-		cfg->menu_line = menu_line++;
-		printf( "\tglobal tmpvar_%d\n", -(cfg->nameindex) );
-		printf( "\tminimenu $w.config.f %d %d \"%s\" tmpvar_%d %s\n",
-		    cfg->menu_number, cfg->menu_line, cfg->label,
-		    -(cfg->nameindex), vartable[cfg->next->nameindex].name );
-		printf( "\tmenu $w.config.f.x%d.x.menu -tearoffcommand \"menutitle \\\"%s\\\"\"\n",
-		    cfg->menu_line, cfg->label );
-		cfg1 = cfg;
-		opt_count = 0;
-		break;
-
-	    case token_choice_item:
-		/* note: no menu line; uses choice header menu line */
-		printf( "\t$w.config.f.x%d.x.menu add radiobutton -label \"%s\" -variable tmpvar_%d -value \"%s\" -command \"update_active\"\n",
-		    cfg1->menu_line, cfg->label, -(cfg1->nameindex),
-		    cfg->label );
-		opt_count++;
-		if ( cfg->next && cfg->next->token != token_choice_item ) {
-		    /* last option in the menu */
-		    printf( "\tmenusplit $w $w.config.f.x%d.x.menu %d\n",
-			cfg1->menu_line, opt_count );
-		}
-		break;
-
-	    case token_dep_bool:
-	    case token_dep_mbool:
-		cfg->menu_line = menu_line++;
-		printf( "\tdep_bool $w.config.f %d %d \"%s\" %s\n",
-		    cfg->menu_number, cfg->menu_line, cfg->label,
-		    vartable[cfg->nameindex].name );
-		break;
-
-	    case token_dep_tristate:
-		cfg->menu_line = menu_line++;
-		printf( "\tdep_tristate $w.config.f %d %d \"%s\" %s\n",
-		    cfg->menu_number, cfg->menu_line, cfg->label,
-		    vartable[cfg->nameindex].name );
-		break;
-
-	    case token_hex:
-		cfg->menu_line = menu_line++;
-		printf( "\thex $w.config.f %d %d \"%s\" %s\n",
-		    cfg->menu_number, cfg->menu_line, cfg->label,
-		    vartable[cfg->nameindex].name );
-		break;
-
-	    case token_int:
-		cfg->menu_line = menu_line++;
-		printf( "\tint $w.config.f %d %d \"%s\" %s\n",
-		    cfg->menu_number, cfg->menu_line, cfg->label,
-		    vartable[cfg->nameindex].name );
-		break;
-
-	    case token_string:
-		cfg->menu_line = menu_line++;
-		printf( "\tistring $w.config.f %d %d \"%s\" %s\n",
-		    cfg->menu_number, cfg->menu_line, cfg->label,
-		    vartable[cfg->nameindex].name );
-		break;
-
-	    case token_tristate:
-		cfg->menu_line = menu_line++;
-		printf( "\ttristate $w.config.f %d %d \"%s\" %s\n",
-		    cfg->menu_number, cfg->menu_line, cfg->label,
-		    vartable[cfg->nameindex].name );
-		break;
-	    }
-	}
-
-	end_proc( scfg, imenu );
-    }
-
-    /*
-     * The top level menu also needs an update function.  When we update a
-     * submenu, we may need to disable one or more of the submenus on
-     * the top level menu, and this procedure will ensure that things are
-     * correct.
-     */
-    clear_globalflags();
-    printf( "proc update_mainmenu {}  {\n" );
-    for ( imenu = 1; imenu <= tot_menu_num; imenu++ )
-    {
-	if ( menu_first[imenu]->cond != NULL && menu_first[imenu]->menu_number == 0 )
-	    generate_if( menu_first[imenu], menu_first[imenu]->cond, imenu, -1 );
-    }
-    printf( "}\n\n\n" );
-
-    clear_globalflags();
-    /*
-     * Generate code to load the default settings into the variables.
-     * The script in tail.tk will attempt to load .config,
-     * which may override these settings, but that's OK.
-     */
-    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
-    {
-	switch ( cfg->token )
-	{
-	default:
-	    break;
-
-	case token_bool:
-	case token_choice_item:
-	case token_dep_bool:
-	case token_dep_tristate:
-	case token_dep_mbool:
-	case token_tristate:
-	    if ( ! vartable[cfg->nameindex].global_written )
-	    {
-		printf( "set %s 0\n", vartable[cfg->nameindex].name );
-		vartable[cfg->nameindex].global_written = 1;
-	    }
-	    break;
-
-	case token_choice_header:
-	    printf( "set tmpvar_%d \"(not set)\"\n", -(cfg->nameindex) );
-	    break;
-
-	case token_hex:
-	case token_int:
-	    if ( ! vartable[cfg->nameindex].global_written )
-	    {
-		printf( "set %s %s\n", vartable[cfg->nameindex].name, cfg->value ? cfg->value : "0" );
-		vartable[cfg->nameindex].global_written = 1;
-	    }
-	    break;
-
-	case token_string:
-	    if ( ! vartable[cfg->nameindex].global_written )
-	    {
-		printf( "set %s \"%s\"\n", vartable[cfg->nameindex].name, cfg->value );
-		vartable[cfg->nameindex].global_written = 1;
-	    }
-	    break;
-	}
-    }
-
-    /*
-     * Define to an empty value all other variables (which are never defined)
-     */
-    for ( i = 1; i <= max_varnum; i++ )
-    {
-	if ( ! vartable[i].global_written
-	&&   strncmp( vartable[i].name, "CONSTANT_", 9 ) )
-	    printf( "set %s 4\n", vartable[i].name );
-    }
-
-    /*
-     * Generate a function to write all of the variables to a file.
-     */
-    printf( "proc writeconfig {file1 file2} {\n" );
-    printf( "\tset cfg [open $file1 w]\n" );
-    printf( "\tset autocfg [open $file2 w]\n" );
-    printf( "\tset notmod 1\n" );
-    printf( "\tset notset 0\n" );
-    printf( "\tputs $cfg \"#\"\n");
-    printf( "\tputs $cfg \"# Automatically generated make config: don't edit\"\n");
-    printf( "\tputs $cfg \"#\"\n" );
-
-    printf( "\tputs $autocfg \"/*\"\n" );
-    printf( "\tputs $autocfg \" * Automatically generated C config: don't edit\"\n" );
-    printf( "\tputs $autocfg \" */\"\n" );
-    printf( "\tputs $autocfg \"#define AUTOCONF_INCLUDED\"\n" );
-
-    clear_globalflags();
-    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
-    {
-	switch ( cfg->token )
-	{
-	default:
-	    break;
-
-	case token_bool:
-	case token_choice_header:
-	case token_comment:
-	case token_define_bool:
-	case token_define_hex:
-	case token_define_int:
-	case token_define_string:
-	case token_define_tristate:
-	case token_dep_bool:
-	case token_dep_tristate:
-	case token_dep_mbool:
-	case token_hex:
-	case token_int:
-	case token_string:
-	case token_tristate:
-	    generate_writeconfig( cfg );
-	    break;
-	}
-    }
-    printf( "\tclose $cfg\n" );
-    printf( "\tclose $autocfg\n" );
-    printf( "}\n\n\n" );
-
-    /*
-     * Generate a simple function that updates the master choice
-     * variable depending upon what values were loaded from a .config
-     * file.  
-     */
-    printf( "proc clear_choices { } {\n" );
-    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
-    {
-	if ( cfg->token == token_choice_header )
-	{
-	    for ( cfg1  = cfg->next; 
-		  cfg1 != NULL && cfg1->token == token_choice_item;
-		  cfg1  = cfg1->next )
-	    {
-		printf( "\tglobal %s; set %s 0\n",
-		    vartable[cfg1->nameindex].name,
-		    vartable[cfg1->nameindex].name );
-	    }
-	}
-    }
-    printf( "}\n\n\n" );
-
-    printf( "proc update_choices { } {\n" );
-    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
-    {
-	if ( cfg->token == token_choice_header )
-	{
-	    printf( "\tglobal tmpvar_%d\n", -(cfg->nameindex) );
-	    printf("\tset tmpvar_%d \"%s\"\n", -(cfg->nameindex), cfg->value);
-	    for ( cfg1  = cfg->next; 
-		  cfg1 != NULL && cfg1->token == token_choice_item;
-		  cfg1  = cfg1->next )
-	    {
-		printf( "\tglobal %s\n", vartable[cfg1->nameindex].name );
-		printf( "\tif { $%s == 1 } then { set tmpvar_%d \"%s\" }\n",
-		    vartable[cfg1->nameindex].name,
-		    -(cfg->nameindex), cfg1->label );
-	    }
-	}
-    }
-    printf( "}\n\n\n" );
-
-    generate_update_var( scfg, 0 );
-
-    /*
-     * That's it.  We are done.  The output of this file will have header.tk
-     * prepended and tail.tk appended to create an executable wish script.
-     */
-}
diff -Nru a/scripts/tkparse.c b/scripts/tkparse.c
--- a/scripts/tkparse.c	Sun Nov 10 19:28:36 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,828 +0,0 @@
-/*
- * tkparse.c
- *
- * Eric Youngdale was the original author of xconfig.
- * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
- *
- * Parse a config.in file and translate it to a wish script.
- * This task has three parts:
- *
- *   tkparse.c	tokenize the input
- *   tkcond.c   transform 'if ...' statements
- *   tkgen.c    generate output
- *
- * Change History
- *
- * 7 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
- * - Teach dep_tristate about a few literals, such as:
- *     dep_tristate 'foo' CONFIG_FOO m
- *   Also have it print an error message and exit on some parse failures.
- *
- * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
- * - Don't fclose stdin.  Thanks to Tony Hoyle for nailing this one.
- *
- * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
- * - Steam-clean this file.  I tested this by generating kconfig.tk for
- *   every architecture and comparing it character-for-character against
- *   the output of the old tkparse.
- *
- * 23 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
- * - Remove bug-compatible code.
- *
- * 07 July 1999, Andrzej M. Krzysztofowicz, <ankry@mif.pg.gda.pl>
- * - Submenus implemented,
- * - plenty of option updating/displaying fixes,
- * - dep_bool, define_hex, define_int, define_string, define_tristate and
- *   undef implemented,
- * - dep_tristate fixed to support multiple dependencies,
- * - handling of variables with an empty value implemented,
- * - value checking for int and hex fields,
- * - more checking during condition parsing; choice variables are treated as
- *   all others now,
- *
- * TO DO:
- * - xconfig is at the end of its life cycle.  Contact <mec@shout.net> if
- *   you are interested in working on the replacement.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "tkparse.h"
-
-static struct kconfig * config_list = NULL;
-static struct kconfig * config_last = NULL;
-static const char * current_file = "<unknown file>";
-static int lineno = 0;
-
-static void do_source( const char * );
-
-#undef strcmp
-int my_strcmp( const char * s1, const char * s2 ) { return strcmp( s1, s2 ); }
-#define strcmp my_strcmp
-
-/*
- * Report a syntax error.
- */
-static void syntax_error( const char * msg )
-{
-    fprintf( stderr, "%s: %d: %s\n", current_file, lineno, msg );
-    exit( 1 );
-}
-
-
-
-/*
- * Find index of a specific variable in the symbol table.
- * Create a new entry if it does not exist yet.
- */
-struct variable *vartable;
-int max_varnum = 0;
-static int vartable_size = 0;
-
-int get_varnum( char * name )
-{
-    int i;
-    
-    for ( i = 1; i <= max_varnum; i++ )
-	if ( strcmp( vartable[i].name, name ) == 0 )
-	    return i;
-    while (max_varnum+1 >= vartable_size) {
-	vartable = realloc(vartable, (vartable_size += 1000)*sizeof(*vartable));
-	if (!vartable) {
-	    fprintf(stderr, "tkparse realloc vartable failed\n");
-	    exit(1);
-	}
-    }
-    vartable[++max_varnum].name = malloc( strlen( name )+1 );
-    strcpy( vartable[max_varnum].name, name );
-    return max_varnum;
-}
-
-
-
-/*
- * Get a string.
- */
-static const char * get_string( const char * pnt, char ** label )
-{
-    const char * word;
-
-    word = pnt;
-    for ( ; ; )
-    {
-	if ( *pnt == '\0' || *pnt == ' ' || *pnt == '\t' )
-	    break;
-	pnt++;
-    }
-
-    *label = malloc( pnt - word + 1 );
-    memcpy( *label, word, pnt - word );
-    (*label)[pnt - word] = '\0';
-
-    if ( *pnt != '\0' )
-	pnt++;
-    return pnt;
-}
-
-
-
-/*
- * Get a quoted string.
- * Insert a '\' before any characters that need quoting.
- */
-static const char * get_qstring( const char * pnt, char ** label )
-{
-    char quote_char;
-    char newlabel [2048];
-    char * pnt1;
-
-    /* advance to the open quote */
-    for ( ; ; )
-    {
-	if ( *pnt == '\0' )
-	    return pnt;
-	quote_char = *pnt++;
-	if ( quote_char == '"' || quote_char == '\'' )
-	    break;
-    }
-
-    /* copy into an intermediate buffer */
-    pnt1 = newlabel;
-    for ( ; ; )
-    {
-	if ( *pnt == '\0' )
-	    syntax_error( "unterminated quoted string" );
-	if ( *pnt == quote_char && pnt[-1] != '\\' )
-	    break;
-
-	/* copy the character, quoting if needed */
-	if ( *pnt == '"' || *pnt == '\'' || *pnt == '[' || *pnt == ']' )
-	    *pnt1++ = '\\';
-	*pnt1++ = *pnt++;
-    }
-
-    /* copy the label into a permanent location */
-    *pnt1++ = '\0';
-    *label = (char *) malloc( pnt1 - newlabel );
-    memcpy( *label, newlabel, pnt1 - newlabel );
-
-    /* skip over last quote and next whitespace */
-    pnt++;
-    while ( *pnt == ' ' || *pnt == '\t' )
-	pnt++;
-    return pnt;
-}
-
-
-
-/*
- * Get a quoted or unquoted string. It is recognized by the first 
- * non-white character. '"' and '"' are not allowed inside the string.
- */
-static const char * get_qnqstring( const char * pnt, char ** label )
-{
-    char quote_char;
-
-    while ( *pnt == ' ' || *pnt == '\t' )
-	pnt++;
-
-    if ( *pnt == '\0' )
-	return pnt;
-    quote_char = *pnt;
-    if ( quote_char == '"' || quote_char == '\'' )
-	return get_qstring( pnt, label );
-    else
-	return get_string( pnt, label );
-}
-
-
-
-/*
- * Tokenize an 'if' statement condition.
- */
-static struct condition * tokenize_if( const char * pnt )
-{
-    struct condition * list;
-    struct condition * last;
-    struct condition * prev;
-
-    /* eat the open bracket */
-    while ( *pnt == ' ' || *pnt == '\t' )
-	pnt++;
-    if ( *pnt != '[' )
-	syntax_error( "bad 'if' condition" );
-    pnt++;
-
-    list = last = NULL;
-    for ( ; ; )
-    {
-	struct condition * cond;
-
-	/* advance to the next token */
-	while ( *pnt == ' ' || *pnt == '\t' )
-	    pnt++;
-	if ( *pnt == '\0' )
-	    syntax_error( "unterminated 'if' condition" );
-	if ( *pnt == ']' )
-	    return list;
-
-	/* allocate a new token */
-	cond = malloc( sizeof(*cond) );
-	memset( cond, 0, sizeof(*cond) );
-	if ( last == NULL )
-	    { list = last = cond; prev = NULL; }
-	else
-	    { prev = last; last->next = cond; last = cond; }
-
-	/* determine the token value */
-	if ( *pnt == '-' && pnt[1] == 'a' )
-	{
-	    if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
-		syntax_error( "incorrect argument" );
-	    cond->op = op_and;  pnt += 2; continue;
-	}
-
-	if ( *pnt == '-' && pnt[1] == 'o' )
-	{
-	    if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
-		syntax_error( "incorrect argument" );
-	    cond->op = op_or;   pnt += 2; continue;
-	}
-
-	if ( *pnt == '!' && pnt[1] == '=' )
-	{
-	    if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
-		syntax_error( "incorrect argument" );
-	    cond->op = op_neq;  pnt += 2; continue;
-	}
-
-	if ( *pnt == '=' )
-	{
-	    if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
-		syntax_error( "incorrect argument" );
-	    cond->op = op_eq;   pnt += 1; continue;
-	}
-
-	if ( *pnt == '!' )
-	{
-	    if ( prev && ( prev->op != op_and && prev->op != op_or
-		      && prev->op != op_bang ) )
-		syntax_error( "incorrect argument" );
-	    cond->op = op_bang; pnt += 1; continue;
-	}
-
-	if ( *pnt == '"' )
-	{
-	    const char * word;
-
-	    if ( prev && ( prev->op == op_variable || prev->op == op_constant ) )
-		syntax_error( "incorrect argument" );
-	    /* advance to the word */
-	    pnt++;
-	    if ( *pnt == '$' )
-		{ cond->op = op_variable; pnt++; }
-	    else
-		{ cond->op = op_constant; }
-
-	    /* find the end of the word */
-	    word = pnt;
-	    for ( ; ; )
-	    {
-		if ( *pnt == '\0' )
-		    syntax_error( "unterminated double quote" );
-		if ( *pnt == '"' )
-		    break;
-		pnt++;
-	    }
-
-	    /* store a copy of this word */
-	    {
-		char * str = malloc( pnt - word + 1 );
-		memcpy( str, word, pnt - word );
-		str [pnt - word] = '\0';
-		if ( cond->op == op_variable )
-		{
-		    cond->nameindex = get_varnum( str );
-		    free( str );
-		}
-		else /* op_constant */
-		{
-		    cond->str = str;
-		}
-	    }
-
-	    pnt++;
-	    continue;
-	}
-
-	/* unknown token */
-	syntax_error( "bad if condition" );
-    }
-}
-
-
-
-/*
- * Tokenize a choice list.  Choices appear as pairs of strings;
- * note that I am parsing *inside* the double quotes.  Ugh.
- */
-static const char * tokenize_choices( struct kconfig * cfg_choose,
-    const char * pnt )
-{
-    int default_checked = 0;
-    for ( ; ; )
-    {
-	struct kconfig * cfg;
-	char * buffer = malloc( 64 );
-
-	/* skip whitespace */
-	while ( *pnt == ' ' || *pnt == '\t' )
-	    pnt++;
-	if ( *pnt == '\0' )
-	    return pnt;
-
-	/* allocate a new kconfig line */
-	cfg = malloc( sizeof(*cfg) );
-	memset( cfg, 0, sizeof(*cfg) );
-	if ( config_last == NULL )
-	    { config_last = config_list = cfg; }
-	else
-	    { config_last->next = cfg; config_last = cfg; }
-
-	/* fill out the line */
-	cfg->token      = token_choice_item;
-	cfg->cfg_parent = cfg_choose;
-	pnt = get_string( pnt, &cfg->label );
-	if ( ! default_checked &&
-	     ! strncmp( cfg->label, cfg_choose->value, strlen( cfg_choose->value ) ) )
-	{
-	    default_checked = 1;
-	    free( cfg_choose->value );
-	    cfg_choose->value = cfg->label;
-	}
-	while ( *pnt == ' ' || *pnt == '\t' )
-	    pnt++;
-	pnt = get_string( pnt, &buffer );
-	cfg->nameindex = get_varnum( buffer );
-    }
-    if ( ! default_checked )
-	syntax_error( "bad 'choice' default value" );
-    return pnt;
-}
-
-
-
-/*
- * Tokenize one line.
- */
-static void tokenize_line( const char * pnt )
-{
-    static struct kconfig * last_menuoption = NULL;
-    enum e_token token;
-    struct kconfig * cfg;
-    struct dependency ** dep_ptr;
-    char * buffer = malloc( 64 );
-
-    /* skip white space */
-    while ( *pnt == ' ' || *pnt == '\t' )
-	pnt++;
-
-    /*
-     * categorize the next token
-     */
-
-#define match_token(t, s) \
-    if (strncmp(pnt, s, strlen(s)) == 0) { token = t; pnt += strlen(s); break; }
-
-    token = token_UNKNOWN;
-    switch ( *pnt )
-    {
-    default:
-	break;
-
-    case '#':
-    case '\0':
-	return;
-
-    case 'b':
-	match_token( token_bool, "bool" );
-	break;
-
-    case 'c':
-	match_token( token_choice_header, "choice"  );
-	match_token( token_comment, "comment" );
-	break;
-
-    case 'd':
-	match_token( token_define_bool, "define_bool" );
-	match_token( token_define_hex, "define_hex" );
-	match_token( token_define_int, "define_int" );
-	match_token( token_define_string, "define_string" );
-	match_token( token_define_tristate, "define_tristate" );
-	match_token( token_dep_bool, "dep_bool" );
-	match_token( token_dep_mbool, "dep_mbool" );
-	match_token( token_dep_tristate, "dep_tristate" );
-	break;
-
-    case 'e':
-	match_token( token_else, "else" );
-	match_token( token_endmenu, "endmenu" );
-	break;
-
-    case 'f':
-	match_token( token_fi, "fi" );
-	break;
-
-    case 'h':
-	match_token( token_hex, "hex" );
-	break;
-
-    case 'i':
-	match_token( token_if, "if" );
-	match_token( token_int, "int" );
-	break;
-
-    case 'm':
-	match_token( token_mainmenu_name, "mainmenu_name" );
-	match_token( token_mainmenu_option, "mainmenu_option" );
-	break;
-
-    case 's':
-	match_token( token_source, "source" );
-	match_token( token_string, "string" );
-	break;
-
-    case 't':
-	match_token( token_then, "then" );
-	match_token( token_tristate, "tristate" );
-	break;
-
-    case 'u':
-	match_token( token_unset, "unset" );
-	break;
-    }
-
-#undef match_token
-
-    if ( token == token_source )
-    {
-	while ( *pnt == ' ' || *pnt == '\t' )
-	    pnt++;
-	do_source( pnt );
-	return;
-    }
-
-    if ( token == token_then )
-    {
-	if ( config_last != NULL && config_last->token == token_if )
-	    return;
-	syntax_error( "bogus 'then'" );
-    }
-
-#if 0
-    if ( token == token_unset )
-    {
-	fprintf( stderr, "Ignoring 'unset' command\n" );
-	return;
-    }
-#endif
-
-    if ( token == token_UNKNOWN )
-	syntax_error( "unknown command" );
-
-    /*
-     * Allocate an item.
-     */
-    cfg = malloc( sizeof(*cfg) );
-    memset( cfg, 0, sizeof(*cfg) );
-    if ( config_last == NULL )
-	{ config_last = config_list = cfg; }
-    else
-	{ config_last->next = cfg; config_last = cfg; }
-
-    /*
-     * Tokenize the arguments.
-     */
-    while ( *pnt == ' ' || *pnt == '\t' )
-	pnt++;
-
-    cfg->token = token;
-    switch ( token )
-    {
-    default:
-	syntax_error( "unknown token" );
-
-    case token_bool:
-    case token_tristate:
-	pnt = get_qstring ( pnt, &cfg->label );
-	pnt = get_string  ( pnt, &buffer );
-	cfg->nameindex = get_varnum( buffer );
-	break;
-
-    case token_choice_header:
-	{
-	    static int choose_number = 0;
-	    char * choice_list;
-
-	    pnt = get_qstring ( pnt, &cfg->label  );
-	    pnt = get_qstring ( pnt, &choice_list );
-	    pnt = get_string  ( pnt, &cfg->value  );
-	    cfg->nameindex = -(choose_number++);
-	    tokenize_choices( cfg, choice_list );
-	    free( choice_list );
-	}
-	break;
-
-    case token_comment:
-	pnt = get_qstring(pnt, &cfg->label);
-	if ( last_menuoption != NULL )
-	{
-	    pnt = get_qstring(pnt, &cfg->label);
-	    if (cfg->label == NULL)
-		syntax_error( "missing comment text" );
-	    last_menuoption->label = cfg->label;
-	    last_menuoption = NULL;
-	}
-	break;
-
-    case token_define_bool:
-    case token_define_tristate:
-	pnt = get_string( pnt, &buffer );
-	cfg->nameindex = get_varnum( buffer );
-	while ( *pnt == ' ' || *pnt == '\t' )
-	    pnt++;
-	if ( ( pnt[0] == 'Y'  || pnt[0] == 'M' || pnt[0] == 'N'
-	||     pnt[0] == 'y'  || pnt[0] == 'm' || pnt[0] == 'n' )
-	&&   ( pnt[1] == '\0' || pnt[1] == ' ' || pnt[1] == '\t' ) )
-	{
-	    if      ( *pnt == 'n' || *pnt == 'N' ) cfg->value = strdup( "CONSTANT_N" );
-	    else if ( *pnt == 'y' || *pnt == 'Y' ) cfg->value = strdup( "CONSTANT_Y" );
-	    else if ( *pnt == 'm' || *pnt == 'M' ) cfg->value = strdup( "CONSTANT_M" );
-	}
-	else if ( *pnt == '$' )
-	{
-	    pnt++;
-	    pnt = get_string( pnt, &cfg->value );
-	}
-	else
-	{
-	    syntax_error( "unknown define_bool value" );
-	}
-	get_varnum( cfg->value );
-	break;
-
-    case token_define_hex:
-    case token_define_int:
-	pnt = get_string( pnt, &buffer );
-	cfg->nameindex = get_varnum( buffer );
-	pnt = get_string( pnt, &cfg->value );
-	break;
-
-    case token_define_string:
-	pnt = get_string( pnt, &buffer );
-	cfg->nameindex = get_varnum( buffer );
-	pnt = get_qnqstring( pnt, &cfg->value );
-	if (cfg->value == NULL)
-	    syntax_error( "missing value" );
-	break;
-
-    case token_dep_bool:
-    case token_dep_mbool:
-    case token_dep_tristate:
-	pnt = get_qstring ( pnt, &cfg->label );
-	pnt = get_string  ( pnt, &buffer );
-	cfg->nameindex = get_varnum( buffer );
-
-	while ( *pnt == ' ' || *pnt == '\t' )
-	    pnt++;
-
-	dep_ptr = &(cfg->depend);
-
-	do {
-	    *dep_ptr = (struct dependency *) malloc( sizeof( struct dependency ) );
-	    (*dep_ptr)->next = NULL;
-
-	    if ( ( pnt[0] == 'Y'  || pnt[0] == 'M' || pnt[0] == 'N'
-	    ||     pnt[0] == 'y'  || pnt[0] == 'm' || pnt[0] == 'n' )
-	    &&   ( pnt[1] == '\0' || pnt[1] == ' ' || pnt[1] == '\t' ) )
-	    {
-		/* dep_tristate 'foo' CONFIG_FOO m */
-		if      ( pnt[0] == 'Y' || pnt[0] == 'y' )
-		    (*dep_ptr)->name = strdup( "CONSTANT_Y" );
-		else if ( pnt[0] == 'N' || pnt[0] == 'n' )
-		    (*dep_ptr)->name = strdup( "CONSTANT_N" );
-		else
-		    (*dep_ptr)->name = strdup( "CONSTANT_M" );
-		pnt++;
-		get_varnum( (*dep_ptr)->name );
-	    }
-	    else if ( *pnt == '$' )
-	    {
-		pnt++;
-		pnt = get_string( pnt, &(*dep_ptr)->name );
-		get_varnum( (*dep_ptr)->name );
-	    }
-	    else
-	    {
-		syntax_error( "can't handle dep_bool/dep_mbool/dep_tristate condition" );
-	    }
-	    dep_ptr = &(*dep_ptr)->next;
-	    while ( *pnt == ' ' || *pnt == '\t' )
-		pnt++;
-	} while ( *pnt );
-
-	/*
-	 * Create a conditional for this object's dependencies.
-	 */
-	{
-	    char fake_if [1024];
-	    struct dependency * dep;
-	    struct condition ** cond_ptr;
-	    int first = 1;
-
-	    cond_ptr = &(cfg->cond);
-	    for ( dep = cfg->depend; dep; dep = dep->next )
-	    {
-		if ( token == token_dep_tristate
-		&& ! strcmp( dep->name, "CONSTANT_M" ) )
-		{
-		    continue;
-		}
-		if ( first )
-		{
-		    first = 0;
-		}
-		else
-		{
-		    *cond_ptr = malloc( sizeof(struct condition) );
-		    memset( *cond_ptr, 0, sizeof(struct condition) );
-		    (*cond_ptr)->op = op_and;
-		    cond_ptr = &(*cond_ptr)->next;
-		}
-		*cond_ptr = malloc( sizeof(struct condition) );
-		memset( *cond_ptr, 0, sizeof(struct condition) );
-		(*cond_ptr)->op = op_lparen;
-		if ( token == token_dep_bool )
-		    sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"\" ]; then",
-			dep->name, dep->name );
-		else
-		    sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"m\" -o \"$%s\" = \"\" ]; then",
-			dep->name, dep->name, dep->name );
-		(*cond_ptr)->next = tokenize_if( fake_if );
-		while ( *cond_ptr )
-		    cond_ptr = &(*cond_ptr)->next;
-		*cond_ptr = malloc( sizeof(struct condition) );
-		memset( *cond_ptr, 0, sizeof(struct condition) );
-		(*cond_ptr)->op = op_rparen;
-		cond_ptr = &(*cond_ptr)->next;
-	    }
-	}
-	break;
-
-    case token_else:
-    case token_endmenu:
-    case token_fi:
-	break;
-
-    case token_hex:
-    case token_int:
-	pnt = get_qstring ( pnt, &cfg->label );
-	pnt = get_string  ( pnt, &buffer );
-	cfg->nameindex = get_varnum( buffer );
-	pnt = get_string  ( pnt, &cfg->value );
-	break;
-
-    case token_string:
-	pnt = get_qstring ( pnt, &cfg->label );
-	pnt = get_string  ( pnt, &buffer );
-	cfg->nameindex = get_varnum( buffer );
-	pnt = get_qnqstring  ( pnt, &cfg->value );
-	if (cfg->value == NULL)
-	    syntax_error( "missing initial value" );
-	break;
-
-    case token_if:
-	cfg->cond = tokenize_if( pnt );
-	break;
-
-    case token_mainmenu_name:
-	pnt = get_qstring( pnt, &cfg->label );
-	break;
-
-    case token_mainmenu_option:
-	if ( strncmp( pnt, "next_comment", 12 ) == 0 )
-	    last_menuoption = cfg;
-	else
-	    pnt = get_qstring( pnt, &cfg->label );
-	break;
-
-    case token_unset:
-	pnt = get_string( pnt, &buffer );
-	cfg->nameindex = get_varnum( buffer );
-	while ( *pnt == ' ' || *pnt == '\t' )
-	    pnt++;
-	while (*pnt)
-	{
-	    cfg->next = (struct kconfig *) malloc( sizeof(struct kconfig) );
-	    memset( cfg->next, 0, sizeof(struct kconfig) );
-	    cfg = cfg->next;
-	    cfg->token = token_unset;
-	    pnt = get_string( pnt, &buffer );
-	    cfg->nameindex = get_varnum( buffer );
-	    while ( *pnt == ' ' || *pnt == '\t' )
-		pnt++;
-	}
-	break;
-    }
-    return;
-}
-
-
-
-/*
- * Implement the "source" command.
- */
-static void do_source( const char * filename )
-{
-    char buffer [2048];
-    FILE * infile;
-    const char * old_file;
-    int old_lineno;
-    int offset;
-
-    /* open the file */
-    if ( strcmp( filename, "-" ) == 0 )
-	infile = stdin;
-    else
-	infile = fopen( filename, "r" );
-
-    /* if that failed, try ../filename */
-    if ( infile == NULL )
-    {
-	sprintf( buffer, "../%s", filename );
-	infile = fopen( buffer, "r" );
-    }
-
-    if ( infile == NULL )
-    {
-	sprintf( buffer, "unable to open %s", filename );
-	syntax_error( buffer );
-    }
-
-    /* push the new file name and line number */
-    old_file     = current_file;
-    old_lineno   = lineno;
-    current_file = filename;
-    lineno       = 0;
-
-    /* read and process lines */
-    for ( offset = 0; ; )
-    {
-	char * pnt;
-
-	/* read a line */
-	fgets( buffer + offset, sizeof(buffer) - offset, infile );
-	if ( feof( infile ) )
-	    break;
-	lineno++;
-
-	/* strip the trailing return character */
-	pnt = buffer + strlen(buffer) - 1;
-	if ( *pnt == '\n' )
-	    *pnt-- = '\0';
-
-	/* eat \ NL pairs */
-	if ( *pnt == '\\' )
-	{
-	    offset = pnt - buffer;
-	    continue;
-	}
-
-	/* tokenize this line */
-	tokenize_line( buffer );
-	offset = 0;
-    }
-
-    /* that's all, folks */
-    if ( infile != stdin )
-	fclose( infile );
-    current_file = old_file;
-    lineno       = old_lineno;
-    return;
-}
-
-
-
-/*
- * Main program.
- */
-int main( int argc, const char * argv [] )
-{
-    do_source        ( "-"         );
-    fix_conditionals ( config_list );
-    dump_tk_script   ( config_list );
-    free(vartable);
-    return 0;
-}
diff -Nru a/scripts/tkparse.h b/scripts/tkparse.h
--- a/scripts/tkparse.h	Sun Nov 10 19:28:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,127 +0,0 @@
-/*
- * tkparse.h
- */
-
-/*
- * Token types (mostly statement types).
- */
-
-enum e_token
-{
-    token_UNKNOWN,
-    token_bool, 
-    token_choice_header,
-    token_choice_item,
-    token_comment, 
-    token_define_bool,
-    token_define_hex,
-    token_define_int,
-    token_define_string,
-    token_define_tristate,
-    token_dep_bool,
-    token_dep_mbool,
-    token_dep_tristate,
-    token_else, 
-    token_endmenu,
-    token_fi, 
-    token_hex,
-    token_if, 
-    token_int,
-    token_mainmenu_name, 
-    token_mainmenu_option, 
-    token_source,
-    token_string,
-    token_then,
-    token_tristate, 
-    token_unset,
-};
-
-/*
- * Operator types for conditionals.
- */
-
-enum operator
-{
-    op_eq,
-    op_neq,
-    op_and,
-    op_and1,
-    op_or,
-    op_bang,
-    op_lparen,
-    op_rparen,
-    op_constant,
-    op_variable,
-    op_true,
-    op_false,
-    op_nuked
-};
-
-/*
- * Conditions come in linked lists.
- * Some operators take strings:
- *
- *   op_constant   "foo"
- *   op_variable   "$ARCH", "$CONFIG_PMAC", "$CONFIG_EXPERIMENTAL"
- *
- * Most "$..." constructs refer to a variable which is defined somewhere
- * in the script.  Note that it is legal to test variables which are never
- * defined, such as variables that are meaningful only on other architectures.
- */
-
-struct condition
-{
-    struct condition *	next;
-    enum operator	op;
-    const char *	str;		/* op_constant */
-    int			nameindex;	/* op_variable */
-};
-
-/*
- * Dependency list for dep_bool, dep_mbool, dep_tristate
- */
-
-struct dependency
-{
-    char *		name;
-    struct dependency *	next;
-};
-
-/*
- * A statement from a config.in file
- */
-
-struct kconfig
-{
-    struct kconfig *	next;
-    enum e_token	token;
-    int			nameindex;
-    char *		label;
-    char *		value;
-    struct condition *	cond;
-    struct dependency *	depend;		/* token_dep_tristate */
-    struct kconfig *	cfg_parent;	/* token_choice_item */
-
-    /* used only in tkgen.c */
-    int			menu_number;
-    int			menu_line;
-    struct kconfig *	menu_next;
-};
-
-struct variable
-{
-    char *	name;
-    char	defined;
-    char	global_written;
-};
-
-extern struct variable *vartable;
-extern int max_varnum;
-
-/*
- * Prototypes
- */
-
-extern void fix_conditionals ( struct kconfig * scfg );		/* tkcond.c */
-extern void dump_tk_script   ( struct kconfig * scfg );		/* tkgen.c  */
-extern int get_varnum        ( char * name );			/* tkparse.c */
diff -Nru a/sound/core/info.c b/sound/core/info.c
--- a/sound/core/info.c	Sun Nov 10 19:28:41 2002
+++ b/sound/core/info.c	Sun Nov 10 19:28:41 2002
@@ -699,12 +699,10 @@
  */
 
 
-int snd_info_card_register(snd_card_t * card)
+int snd_info_card_create(snd_card_t * card)
 {
 	char str[8];
-	char *s;
 	snd_info_entry_t *entry;
-	struct proc_dir_entry *p;
 
 	snd_assert(card != NULL, return -ENXIO);
 
@@ -717,11 +715,20 @@
 		return -ENOMEM;
 	}
 	card->proc_root = entry;
+	return 0;
+}
+
+int snd_info_card_register(snd_card_t * card)
+{
+	char *s;
+	struct proc_dir_entry *p;
+
+	snd_assert(card != NULL, return -ENXIO);
 
-	if (!strcmp(card->id, str))
+	if (!strcmp(card->id, card->proc_root->name))
 		return 0;
 
-	s = snd_kmalloc_strdup(str, GFP_KERNEL);
+	s = snd_kmalloc_strdup(card->proc_root->name, GFP_KERNEL);
 	if (s == NULL)
 		return -ENOMEM;
 	p = snd_create_proc_entry(card->id, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, snd_proc_root);
@@ -738,7 +745,7 @@
 	return 0;
 }
 
-int snd_info_card_unregister(snd_card_t * card)
+int snd_info_card_free(snd_card_t * card)
 {
 	void *data;
 
diff -Nru a/sound/core/init.c b/sound/core/init.c
--- a/sound/core/init.c	Sun Nov 10 19:28:37 2002
+++ b/sound/core/init.c	Sun Nov 10 19:28:37 2002
@@ -23,6 +23,7 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/time.h>
+#include <linux/ctype.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/info.h>
@@ -45,7 +46,6 @@
 			 struct module *module, int extra_size)
 {
 	snd_card_t *card;
-	snd_info_entry_t *entry;
 	int err;
 
 	if (extra_size < 0)
@@ -79,8 +79,6 @@
 	snd_cards_lock |= 1 << idx;		/* lock it */
 	write_unlock(&snd_card_rwlock);
 	card->number = idx;
-	if (!card->id[0])
-		sprintf(card->id, "card%i", card->number);
 	card->module = module;
 	INIT_LIST_HEAD(&card->devices);
 	rwlock_init(&card->control_rwlock);
@@ -97,28 +95,14 @@
 		snd_printd("unable to register control minors\n");
 		goto __error;
 	}
-	if ((err = snd_info_card_register(card)) < 0) {
-		snd_printd("unable to register card info\n");
+	if ((err = snd_info_card_create(card)) < 0) {
+		snd_printd("unable to create card info\n");
 		goto __error_ctl;
 	}
-	if ((entry = snd_info_create_card_entry(card, "id", card->proc_root)) == NULL) {
-		snd_printd("unable to create card entry\n");
-		goto __error_info;
-	}
-	entry->content = SNDRV_INFO_CONTENT_TEXT;
-	entry->c.text.read_size = PAGE_SIZE;
-	entry->c.text.read = snd_card_id_read;
-	if (snd_info_register(entry) < 0) {
-		snd_info_free_entry(entry);
-		goto __error_info;
-	}
-	card->proc_id = entry;
 	if (extra_size > 0)
 		card->private_data = (char *)card + sizeof(snd_card_t);
 	return card;
 
-      __error_info:
-      	snd_info_card_unregister(card);
       __error_ctl:
 	snd_ctl_unregister(card);
       __error:
@@ -157,8 +141,8 @@
 	if (card->private_free)
 		card->private_free(card);
 	snd_info_free_entry(card->proc_id);
-	if (snd_info_card_unregister(card) < 0) {
-		snd_printk(KERN_WARNING "unable to unregister card info\n");
+	if (snd_info_card_free(card) < 0) {
+		snd_printk(KERN_WARNING "unable to free card info\n");
 		/* Not fatal error */
 	}
 	write_lock(&snd_card_rwlock);
@@ -168,9 +152,66 @@
 	return 0;
 }
 
+static void choose_default_id(snd_card_t *card)
+{
+	int i, len, idx_flag = 0, loops = 8;
+	char *id, *spos;
+	
+	id = spos = card->shortname;	
+	while (*id != '\0') {
+		if (*id == ' ')
+			spos = id + 1;
+		id++;
+	}
+	id = card->id;
+	while (*spos != '\0' && id - card->id < sizeof(card->id) - 1) {
+		if (isalnum(*spos))
+			*id++ = *spos;
+		spos++;
+	}
+	*id = '\0';
+
+	id = card->id;
+
+	while (1) {
+	      	if (loops-- == 0) {
+      			snd_printk(KERN_ERR "unable to choose default card id (%s)", id);
+      			strcpy(card->id, card->proc_root->name);
+      			return;
+      		}
+	      	if (!snd_info_check_reserved_words(id))
+      			goto __change;
+		for (i = 0; i < snd_ecards_limit; i++) {
+			if (snd_cards[i] && !strcmp(snd_cards[i]->id, id))
+				goto __change;
+		}
+		break;
+
+	      __change:
+		len = strlen(id);
+		if (idx_flag)
+			id[len-1]++;
+		else if (len <= sizeof(card->id) - 3) {
+			strcat(id, "_1");
+			idx_flag++;
+		} else {
+			spos = id + len - 2;
+			if (len <= sizeof(card->id) - 2)
+				spos++;
+			*spos++ = '_';
+			*spos++ = '1';
+			*spos++ = '\0';
+			idx_flag++;
+		}
+	}
+		
+	strcpy(card->id, id);
+}
+
 int snd_card_register(snd_card_t * card)
 {
 	int err;
+	snd_info_entry_t *entry;
 
 	snd_runtime_check(card != NULL, return -EINVAL);
 	if ((err = snd_device_register_all(card)) < 0)
@@ -181,9 +222,28 @@
 		write_unlock(&snd_card_rwlock);
 		return 0;
 	}
+	if (!card->id[0])
+		choose_default_id(card);
 	snd_cards[card->number] = card;
 	snd_cards_count++;
 	write_unlock(&snd_card_rwlock);
+	if ((err = snd_info_card_register(card)) < 0) {
+		snd_printd("unable to create card info\n");
+		goto __skip_info;
+	}
+	if ((entry = snd_info_create_card_entry(card, "id", card->proc_root)) == NULL) {
+		snd_printd("unable to create card entry\n");
+		goto __skip_info;
+	}
+	entry->content = SNDRV_INFO_CONTENT_TEXT;
+	entry->c.text.read_size = PAGE_SIZE;
+	entry->c.text.read = snd_card_id_read;
+	if (snd_info_register(entry) < 0) {
+		snd_info_free_entry(entry);
+		entry = NULL;
+	}
+	card->proc_id = entry;
+      __skip_info:
 #if defined(CONFIG_SND_MIXER_OSS) || defined(CONFIG_SND_MIXER_OSS_MODULE)
 	if (snd_mixer_oss_notify_callback)
 		snd_mixer_oss_notify_callback(card, 0);
diff -Nru a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c
--- a/sound/core/oss/pcm_oss.c	Sun Nov 10 19:28:41 2002
+++ b/sound/core/oss/pcm_oss.c	Sun Nov 10 19:28:41 2002
@@ -564,7 +564,15 @@
 		} else {
 			ret = snd_pcm_lib_read(substream, ptr, frames);
 		}
-		if (ret != -EPIPE && ret != -ESTRPIPE)
+		if (ret == -EPIPE) {
+			if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
+				ret = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, 0);
+				if (ret < 0)
+					break;
+			}
+			continue;
+		}
+		if (ret != -ESTRPIPE)
 			break;
 	}
 	return ret;
diff -Nru a/sound/core/pcm_native.c b/sound/core/pcm_native.c
--- a/sound/core/pcm_native.c	Sun Nov 10 19:28:38 2002
+++ b/sound/core/pcm_native.c	Sun Nov 10 19:28:38 2002
@@ -1996,7 +1996,7 @@
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	int err;
-	snd_pcm_sframes_t n;
+	snd_pcm_sframes_t n = 0;
 
 	spin_lock_irq(&runtime->lock);
 	switch (runtime->status->state) {
@@ -2014,8 +2014,6 @@
 			n = snd_pcm_playback_hw_avail(runtime);
 		else
 			n = snd_pcm_capture_avail(runtime);
-		if (put_user(n, res))
-			err = -EFAULT;
 		break;
 	case SNDRV_PCM_STATE_XRUN:
 		err = -EPIPE;
@@ -2026,6 +2024,9 @@
 		break;
 	}
 	spin_unlock_irq(&runtime->lock);
+	if (!err)
+		if (put_user(n, res))
+			err = -EFAULT;
 	return err;
 }
 		
@@ -2668,12 +2669,13 @@
 	if (offset > dma_bytes - PAGE_SIZE)
 		return NOPAGE_SIGBUS;
 	if (substream->ops->page) {
-		vaddr = substream->ops->page(substream, offset);
-		if (! vaddr)
+		page = substream->ops->page(substream, offset);
+		if (! page)
 			return NOPAGE_OOM;
-	} else
+	} else {
 		vaddr = runtime->dma_area + offset;
-	page = virt_to_page(vaddr);
+		page = virt_to_page(vaddr);
+	}
 	get_page(page);
 #ifndef LINUX_2_2
 	return page;
diff -Nru a/sound/core/pcm_sgbuf.c b/sound/core/pcm_sgbuf.c
--- a/sound/core/pcm_sgbuf.c	Sun Nov 10 19:28:41 2002
+++ b/sound/core/pcm_sgbuf.c	Sun Nov 10 19:28:41 2002
@@ -66,7 +66,7 @@
 	sgbuf->tblsize = tblsize;
 	sgbuf->table = kmalloc(sizeof(struct snd_sg_page) * tblsize, GFP_KERNEL);
 	if (! sgbuf->table) {
-		snd_pcm_sgbuf_free(substream);
+		snd_pcm_sgbuf_delete(substream);
 		return -ENOMEM;
 	}
 	memset(sgbuf->table, 0, sizeof(struct snd_sg_page) * tblsize);
@@ -158,9 +158,8 @@
 
 /*
  * get the page pointer on the given offset
- * used as the page callback of pcm ops
  */
-void *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
+static void *sgbuf_get_addr(snd_pcm_substream_t *substream, unsigned long offset)
 {
 	struct snd_sg_buf *sgbuf;
 	unsigned int idx;
@@ -173,6 +172,19 @@
 }
 
 /*
+ * get the page struct at the given offset
+ * used as the page callback of pcm ops
+ */
+struct page *snd_pcm_sgbuf_ops_page(snd_pcm_substream_t *substream, unsigned long offset)
+{
+	void *addr = sgbuf_get_addr(substream, offset);
+	if (addr)
+		return virt_to_page(addr);
+	else
+		return 0;
+}
+
+/*
  * do copy_from_user to the sg buffer
  */
 static int copy_from_user_sg_buf(snd_pcm_substream_t *substream,
@@ -184,7 +196,7 @@
 	hwoff -= p;
 	len = PAGE_SIZE - hwoff;
 	for (;;) {
-		addr = snd_pcm_sgbuf_ops_page(substream, p);
+		addr = sgbuf_get_addr(substream, p);
 		if (! addr)
 			return -EFAULT;
 		if (len > bytes)
@@ -214,7 +226,7 @@
 	hwoff -= p;
 	len = PAGE_SIZE - hwoff;
 	for (;;) {
-		addr = snd_pcm_sgbuf_ops_page(substream, p);
+		addr = sgbuf_get_addr(substream, p);
 		if (! addr)
 			return -EFAULT;
 		if (len > bytes)
@@ -246,7 +258,7 @@
 	len = bytes_to_samples(substream->runtime, PAGE_SIZE - hwoff);
 	page_len = bytes_to_samples(substream->runtime, PAGE_SIZE);
 	for (;;) {
-		addr = snd_pcm_sgbuf_ops_page(substream, p);
+		addr = sgbuf_get_addr(substream, p);
 		if (! addr)
 			return -EFAULT;
 		if (len > samples)
diff -Nru a/sound/core/rawmidi.c b/sound/core/rawmidi.c
--- a/sound/core/rawmidi.c	Sun Nov 10 19:28:37 2002
+++ b/sound/core/rawmidi.c	Sun Nov 10 19:28:37 2002
@@ -699,7 +699,6 @@
 	case SNDRV_RAWMIDI_IOCTL_PARAMS:
 	{
 		snd_rawmidi_params_t params;
-		int err;
 		if (copy_from_user(&params, (snd_rawmidi_params_t *) arg, sizeof(snd_rawmidi_params_t)))
 			return -EFAULT;
 		switch (params.stream) {
@@ -714,9 +713,6 @@
 		default:
 			return -EINVAL;
 		}
-		if (copy_to_user((snd_rawmidi_params_t *) arg, &params, sizeof(snd_rawmidi_params_t)))
-			return -EFAULT;
-		return err;
 	}
 	case SNDRV_RAWMIDI_IOCTL_STATUS:
 	{
diff -Nru a/sound/core/seq/seq_prioq.c b/sound/core/seq/seq_prioq.c
--- a/sound/core/seq/seq_prioq.c	Sun Nov 10 19:28:36 2002
+++ b/sound/core/seq/seq_prioq.c	Sun Nov 10 19:28:36 2002
@@ -25,7 +25,6 @@
 #include <sound/core.h>
 #include "seq_timer.h"
 #include "seq_prioq.h"
-#include "seq_timer.h"
 
 
 /* Implementation is a simple linked list for now...
diff -Nru a/sound/core/timer.c b/sound/core/timer.c
--- a/sound/core/timer.c	Sun Nov 10 19:28:40 2002
+++ b/sound/core/timer.c	Sun Nov 10 19:28:40 2002
@@ -849,6 +849,7 @@
 		snd_timer_free(timer);
 		return -ENOMEM;
 	}
+	init_timer(tlist);
 	tlist->function = snd_timer_s_function;
 	tlist->data = (unsigned long) timer;
 	timer->private_data = tlist;
diff -Nru a/sound/drivers/dummy.c b/sound/drivers/dummy.c
--- a/sound/drivers/dummy.c	Sun Nov 10 19:28:41 2002
+++ b/sound/drivers/dummy.c	Sun Nov 10 19:28:41 2002
@@ -343,6 +343,7 @@
 		return -ENOMEM;
 	}
 	memset(runtime->dma_area, 0, runtime->dma_bytes);
+	init_timer(&dpcm->timer);
 	dpcm->timer.data = (unsigned long) dpcm;
 	dpcm->timer.function = snd_card_dummy_pcm_timer_function;
 	spin_lock_init(&dpcm->lock);
diff -Nru a/sound/drivers/mtpav.c b/sound/drivers/mtpav.c
--- a/sound/drivers/mtpav.c	Sun Nov 10 19:28:40 2002
+++ b/sound/drivers/mtpav.c	Sun Nov 10 19:28:40 2002
@@ -683,6 +683,7 @@
 	if (ncrd != NULL) {
 		spin_lock_init(&ncrd->spinlock);
 
+		init_timer(&ncrd->timer);
 		ncrd->card = NULL;
 		ncrd->irq = -1;
 		ncrd->share_irq = 0;
diff -Nru a/sound/drivers/serial-u16550.c b/sound/drivers/serial-u16550.c
--- a/sound/drivers/serial-u16550.c	Sun Nov 10 19:28:37 2002
+++ b/sound/drivers/serial-u16550.c	Sun Nov 10 19:28:37 2002
@@ -785,6 +785,7 @@
 	uart->prev_in = 0;
 	uart->rstatus = 0;
 	memset(uart->prev_status, 0x80, sizeof(unsigned char) * SNDRV_SERIAL_MAX_OUTS);
+	init_timer(&uart->buffer_timer);
 	uart->buffer_timer.function = snd_uart16550_buffer_timer;
 	uart->buffer_timer.data = (unsigned long)uart;
 	uart->timer_running = 0;
diff -Nru a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c
--- a/sound/i2c/l3/uda1341.c	Sun Nov 10 19:28:39 2002
+++ b/sound/i2c/l3/uda1341.c	Sun Nov 10 19:28:39 2002
@@ -16,7 +16,7 @@
  * 2002-04-12	Tomas Kasparek	Proc interface update, code cleanup
  */
 
-/* $Id: uda1341.c,v 1.4 2002/08/15 12:13:06 perex Exp $ */
+/* $Id: uda1341.c,v 1.5 2002/11/09 13:12:19 perex Exp $ */
 
 #include <sound/driver.h>
 #include <linux/module.h>
@@ -341,7 +341,7 @@
 	
 	snd_iprintf(buffer, "Automatic Gain Ctrl : %s\n", uda->cfg[CMD_AGC] ? "on" : "off");
 	snd_iprintf(buffer, "AGC attack time     : %d ms\n", AGC_atime[uda->cfg[CMD_AGC_TIME]]);
-	snd_iprintf(buffer, "AGC decay time      : %d ns\n", AGC_dtime[uda->cfg[CMD_AGC_TIME]]);
+	snd_iprintf(buffer, "AGC decay time      : %d ms\n", AGC_dtime[uda->cfg[CMD_AGC_TIME]]);
 	snd_iprintf(buffer, "AGC output level    : %s dB\n\n", AGC_level[uda->cfg[CMD_AGC_LEVEL]]);
 
 	snd_iprintf(buffer, "Mute                : %s\n", uda->cfg[CMD_MUTE] ? "on" : "off");
diff -Nru a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c
--- a/sound/isa/cs423x/cs4231_lib.c	Sun Nov 10 19:28:37 2002
+++ b/sound/isa/cs423x/cs4231_lib.c	Sun Nov 10 19:28:37 2002
@@ -124,6 +124,48 @@
  *  Basic I/O functions
  */
 
+#if !defined(EBUS_SUPPORT) && !defined(SBUS_SUPPORT)
+#define __CS4231_INLINE__ inline
+#else
+#define __CS4231_INLINE__ /* nothing */
+#endif
+
+static __CS4231_INLINE__ void cs4231_outb(cs4231_t *chip, u8 offset, u8 val)
+{
+#ifdef EBUS_SUPPORT
+	if (chip->ebus->flag) {
+		writeb(val, chip->port + (offset << 2));
+	} else {
+#endif
+#ifdef SBUS_SUPPORT
+		sbus_writeb(val, chip->port + (offset << 2));
+#endif
+#ifdef EBUS_SUPPORT
+	}
+#endif
+#ifdef LEGACY_SUPPORT
+	outb(val, chip->port + offset);
+#endif
+}
+
+static __CS4231_INLINE__ u8 cs4231_inb(cs4231_t *chip, u8 offset)
+{
+#ifdef EBUS_SUPPORT
+	if (chip->ebus_flag) {
+		return readb(chip->port + (offset << 2));
+	} else {
+#endif
+#ifdef SBUS_SUPPORT
+		return sbus_writeb(chip->port + (offset << 2));
+#endif
+#ifdef EBUS_SUPPORT
+	}
+#endif
+#ifdef LEGACY_SUPPORT
+	return inb(chip->port + offset);
+#endif
+}
+
 void snd_cs4231_outm(cs4231_t *chip, unsigned char reg,
 		     unsigned char mask, unsigned char value)
 {
@@ -131,21 +173,21 @@
 	unsigned char tmp;
 
 	for (timeout = 250;
-	     timeout > 0 && (inb(CS4231P(chip, REGSEL)) & CS4231_INIT);
+	     timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
 	     timeout--)
 	     	udelay(100);
 #ifdef CONFIG_SND_DEBUG
-	if (inb(CS4231P(chip, REGSEL)) & CS4231_INIT)
+	if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
 		snd_printk("outm: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
 #endif
 	if (chip->calibrate_mute) {
 		chip->image[reg] &= mask;
 		chip->image[reg] |= value;
 	} else {
-		outb(chip->mce_bit | reg, CS4231P(chip, REGSEL));
+		cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
 		mb();
 		tmp = (chip->image[reg] & mask) | value;
-		outb(tmp, CS4231P(chip, REG));
+		cs4231_outb(chip, CS4231P(REG), tmp);
 		chip->image[reg] = tmp;
 		mb();
 	}
@@ -156,11 +198,11 @@
 	int timeout;
 
 	for (timeout = 250;
-	     timeout > 0 && (inb(CS4231P(chip, REGSEL)) & CS4231_INIT);
+	     timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
 	     timeout--)
 	     	udelay(10);
-	outb(chip->mce_bit | reg, CS4231P(chip, REGSEL));
-	outb(value, CS4231P(chip, REG));
+	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
+	cs4231_outb(chip, CS4231P(REG), value);
 	mb();
 }
 
@@ -169,15 +211,15 @@
 	int timeout;
 
 	for (timeout = 250;
-	     timeout > 0 && (inb(CS4231P(chip, REGSEL)) & CS4231_INIT);
+	     timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
 	     timeout--)
 	     	udelay(100);
 #ifdef CONFIG_SND_DEBUG
-	if (inb(CS4231P(chip, REGSEL)) & CS4231_INIT)
+	if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
 		snd_printk("out: auto calibration time out - reg = 0x%x, value = 0x%x\n", reg, value);
 #endif
-	outb(chip->mce_bit | reg, CS4231P(chip, REGSEL));
-	outb(value, CS4231P(chip, REG));
+	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
+	cs4231_outb(chip, CS4231P(REG), value);
 	chip->image[reg] = value;
 	mb();
 #if 0
@@ -190,23 +232,23 @@
 	int timeout;
 
 	for (timeout = 250;
-	     timeout > 0 && (inb(CS4231P(chip, REGSEL)) & CS4231_INIT);
+	     timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
 	     timeout--)
 	     	udelay(100);
 #ifdef CONFIG_SND_DEBUG
-	if (inb(CS4231P(chip, REGSEL)) & CS4231_INIT)
+	if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
 		snd_printk("in: auto calibration time out - reg = 0x%x\n", reg);
 #endif
-	outb(chip->mce_bit | reg, CS4231P(chip, REGSEL));
+	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | reg);
 	mb();
-	return inb(CS4231P(chip, REG));
+	return cs4231_inb(chip, CS4231P(REG));
 }
 
 void snd_cs4236_ext_out(cs4231_t *chip, unsigned char reg, unsigned char val)
 {
-	outb(chip->mce_bit | 0x17, CS4231P(chip, REGSEL));
-	outb(reg | (chip->image[CS4236_EXT_REG] & 0x01), CS4231P(chip, REG));
-	outb(val, CS4231P(chip, REG));
+	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
+	cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01));
+	cs4231_outb(chip, CS4231P(REG), val);
 	chip->eimage[CS4236_REG(reg)] = val;
 #if 0
 	printk("ext out : reg = 0x%x, val = 0x%x\n", reg, val);
@@ -215,14 +257,14 @@
 
 unsigned char snd_cs4236_ext_in(cs4231_t *chip, unsigned char reg)
 {
-	outb(chip->mce_bit | 0x17, CS4231P(chip, REGSEL));
-	outb(reg | (chip->image[CS4236_EXT_REG] & 0x01), CS4231P(chip, REG));
+	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | 0x17);
+	cs4231_outb(chip, CS4231P(REG), reg | (chip->image[CS4236_EXT_REG] & 0x01));
 #if 1
-	return inb(CS4231P(chip, REG));
+	return cs4231_inb(chip, CS4231P(REG));
 #else
 	{
 		unsigned char res;
-		res = inb(CS4231P(chip, REG));
+		res = cs4231_inb(chip, CS4231P(REG));
 		printk("ext in : reg = 0x%x, val = 0x%x\n", reg, res);
 		return res;
 	}
@@ -233,8 +275,8 @@
 
 void snd_cs4231_debug(cs4231_t *chip)
 {
-	printk("CS4231 REGS:      INDEX = 0x%02x  ", inb(CS4231P(chip, REGSEL)));
-	printk("                 STATUS = 0x%02x\n", inb(CS4231P(chip, STATUS)));
+	printk("CS4231 REGS:      INDEX = 0x%02x  ", cs4231_inb(chip, CS4231P(REGSEL)));
+	printk("                 STATUS = 0x%02x\n", cs4231_inb(chip, CS4231P(STATUS)));
 	printk("  0x00: left input      = 0x%02x  ", snd_cs4231_in(chip, 0x00));
 	printk("  0x10: alt 1 (CFIG 2)  = 0x%02x\n", snd_cs4231_in(chip, 0x10));
 	printk("  0x01: right input     = 0x%02x  ", snd_cs4231_in(chip, 0x01));
@@ -281,10 +323,10 @@
 
 	/* huh.. looks like this sequence is proper for CS4231A chip (GUS MAX) */
 	for (timeout = 5; timeout > 0; timeout--)
-		inb(CS4231P(chip, REGSEL));
+		cs4231_inb(chip, CS4231P(REGSEL));
 	/* end of cleanup sequence */
 	for (timeout = 250;
-	     timeout > 0 && (inb(CS4231P(chip, REGSEL)) & CS4231_INIT);
+	     timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT);
 	     timeout--)
 	     	udelay(10);
 }
@@ -295,18 +337,18 @@
 	int timeout;
 
 	spin_lock_irqsave(&chip->reg_lock, flags);
-	for (timeout = 250; timeout > 0 && (inb(CS4231P(chip, REGSEL)) & CS4231_INIT); timeout--)
+	for (timeout = 250; timeout > 0 && (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); timeout--)
 		udelay(100);
 #ifdef CONFIG_SND_DEBUG
-	if (inb(CS4231P(chip, REGSEL)) & CS4231_INIT)
+	if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
 		snd_printk("mce_up - auto calibration time out (0)\n");
 #endif
 	chip->mce_bit |= CS4231_MCE;
-	timeout = inb(CS4231P(chip, REGSEL));
+	timeout = cs4231_inb(chip, CS4231P(REGSEL));
 	if (timeout == 0x80)
 		snd_printk("mce_up [0x%lx]: serious init problem - codec still busy\n", chip->port);
 	if (!(timeout & CS4231_MCE))
-		outb(chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));
+		cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
@@ -322,12 +364,12 @@
 	printk("(1) timeout = %i\n", timeout);
 #endif
 #ifdef CONFIG_SND_DEBUG
-	if (inb(CS4231P(chip, REGSEL)) & CS4231_INIT)
-		snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", CS4231P(chip, REGSEL));
+	if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
+		snd_printk("mce_down [0x%lx] - auto calibration time out (0)\n", (long)CS4231P(REGSEL));
 #endif
 	chip->mce_bit &= ~CS4231_MCE;
-	timeout = inb(CS4231P(chip, REGSEL));
-	outb(chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));
+	timeout = cs4231_inb(chip, CS4231P(REGSEL));
+	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
 	if (timeout == 0x80)
 		snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port);
 	if ((timeout & CS4231_MCE) == 0 ||
@@ -364,7 +406,7 @@
 	printk("(3) jiffies = %li\n", jiffies);
 #endif
 	time = HZ / 10;
-	while (inb(CS4231P(chip, REGSEL)) & CS4231_INIT) {
+	while (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) {
 		spin_unlock_irqrestore(&chip->reg_lock, flags);
 		if (time <= 0) {
 			snd_printk("mce_down - auto calibration time out (3)\n");
@@ -377,7 +419,7 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 #if 0
 	printk("(4) jiffies = %li\n", jiffies);
-	snd_printk("mce_down - exit = 0x%x\n", inb(CS4231P(chip, REGSEL)));
+	snd_printk("mce_down - exit = 0x%x\n", cs4231_inb(chip, CS4231P(REGSEL)));
 #endif
 }
 
@@ -403,7 +445,7 @@
 	int result = 0;
 
 #if 0
-	printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, inb(CS4231P(card, STATUS)));
+	printk("codec trigger!!! - what = %i, enable = %i, status = 0x%x\n", what, enable, cs4231_inb(chip, CS4231P(STATUS)));
 #endif
 
 	switch (cmd) {
@@ -423,10 +465,15 @@
 			s = s->link_next;
 		} while (s != substream);
 		spin_lock(&chip->reg_lock);
-		if (cmd == SNDRV_PCM_TRIGGER_START)
+		if (cmd == SNDRV_PCM_TRIGGER_START) {
 			chip->image[CS4231_IFACE_CTRL] |= what;
-		else
+			if (chip->trigger)
+				chip->trigger(chip, what, 1);
+		} else {
 			chip->image[CS4231_IFACE_CTRL] &= ~what;
+			if (chip->trigger)
+				chip->trigger(chip, what, 0);
+		}
 		snd_cs4231_out(chip, CS4231_IFACE_CTRL, chip->image[CS4231_IFACE_CTRL]);
 		spin_unlock(&chip->reg_lock);
 		break;
@@ -640,7 +687,7 @@
 
 	snd_cs4231_mce_down(chip);
 
-#ifdef SNDRV_DEBUG_MCE
+#ifdef SNDRV_DEBUGq_MCE
 	snd_printk("init: (1)\n");
 #endif
 	snd_cs4231_mce_up(chip);
@@ -713,8 +760,8 @@
 		       CS4231_RECORD_IRQ |
 		       CS4231_TIMER_IRQ);
 	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
-	outb(0, CS4231P(chip, STATUS));	/* clear IRQ */
-	outb(0, CS4231P(chip, STATUS));	/* clear IRQ */
+	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
+	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
 	chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE;
 	snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
 	snd_cs4231_out(chip, CS4231_IRQ_STATUS, CS4231_PLAYBACK_IRQ |
@@ -743,8 +790,8 @@
 	/* disable IRQ */
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
-	outb(0, CS4231P(chip, STATUS));	/* clear IRQ */
-	outb(0, CS4231P(chip, STATUS));	/* clear IRQ */
+	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
+	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
 	chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE;
 	snd_cs4231_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]);
 
@@ -765,8 +812,8 @@
 
 	/* clear IRQ again */
 	snd_cs4231_out(chip, CS4231_IRQ_STATUS, 0);
-	outb(0, CS4231P(chip, STATUS));	/* clear IRQ */
-	outb(0, CS4231P(chip, STATUS));	/* clear IRQ */
+	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
+	cs4231_outb(chip, CS4231P(STATUS), 0);	/* clear IRQ */
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	snd_cs4231_calibrate_mute(chip, 0);
@@ -829,6 +876,7 @@
 	return snd_pcm_lib_free_pages(substream);
 }
 
+#ifdef LEGACY_SUPPORT
 static int snd_cs4231_playback_prepare(snd_pcm_substream_t * substream)
 {
 	cs4231_t *chip = snd_pcm_substream_chip(substream);
@@ -850,6 +898,7 @@
 #endif
 	return 0;
 }
+#endif /* LEGACY_SUPPORT */
 
 static int snd_cs4231_capture_hw_params(snd_pcm_substream_t * substream,
 					snd_pcm_hw_params_t * hw_params)
@@ -871,6 +920,7 @@
 	return snd_pcm_lib_free_pages(substream);
 }
 
+#ifdef LEGACY_SUPPORT
 static int snd_cs4231_capture_prepare(snd_pcm_substream_t * substream)
 {
 	cs4231_t *chip = snd_pcm_substream_chip(substream);
@@ -894,6 +944,7 @@
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 	return 0;
 }
+#endif
 
 static void snd_cs4231_overrange(cs4231_t *chip)
 {
@@ -940,6 +991,7 @@
 	spin_unlock(&chip->reg_lock);
 }
 
+#ifdef LEGACY_SUPPORT
 static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t * substream)
 {
 	cs4231_t *chip = snd_pcm_substream_chip(substream);
@@ -961,12 +1013,13 @@
 	ptr = chip->c_dma_size - snd_dma_residue(chip->dma2);
 	return bytes_to_frames(substream->runtime, ptr);
 }
+#endif /* LEGACY_SUPPORT */
 
 /*
 
  */
 
-static int snd_cs4231_probe(cs4231_t *chip)
+int snd_cs4231_probe(cs4231_t *chip)
 {
 	unsigned long flags;
 	int i, id, rev;
@@ -979,7 +1032,7 @@
 	id = 0;
 	for (i = 0; i < 50; i++) {
 		mb();
-		if (inb(CS4231P(chip, REGSEL)) & CS4231_INIT)
+		if (cs4231_inb(chip, CS4231P(REGSEL)) & CS4231_INIT)
 			udelay(2000);
 		else {
 			spin_lock_irqsave(&chip->reg_lock, flags);
@@ -1020,8 +1073,8 @@
 		}
 	}
 	spin_lock_irqsave(&chip->reg_lock, flags);
-	inb(CS4231P(chip, STATUS));	/* clear any pendings IRQ */
-	outb(0, CS4231P(chip, STATUS));
+	cs4231_inb(chip, CS4231P(STATUS));	/* clear any pendings IRQ */
+	cs4231_outb(chip, CS4231P(STATUS), 0);
 	mb();
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
@@ -1189,6 +1242,7 @@
 	    chip->hardware == CS4231_HW_CS4239)
 		runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
 
+#ifdef LEGACY_SUPPORT
 	snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.buffer_bytes_max);
 	snd_pcm_limit_isa_dma_size(chip->dma1, &runtime->hw.period_bytes_max);
 
@@ -1196,14 +1250,20 @@
 		if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma1)) < 0)
 			return err;
 	}
+#endif
 
 	if ((err = snd_cs4231_open(chip, CS4231_MODE_PLAY)) < 0) {
+#ifdef LEGACY_SUPPORT
 		if (chip->release_dma)
 			chip->release_dma(chip, chip->dma_private_data, chip->dma1);
+#endif
 		snd_free_pages(runtime->dma_area, runtime->dma_bytes);
 		return err;
 	}
 	chip->playback_substream = substream;
+#if defined(SBUS_SUPPORT) || defined(EBUS_SUPPORT)
+	chip->p_periods_sent = 0;
+#endif
 	snd_pcm_set_sync(substream);
 	chip->rate_constraint(runtime);
 	return 0;
@@ -1222,21 +1282,28 @@
 	    chip->hardware == CS4231_HW_CS4239)
 		runtime->hw.formats = SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE;
 
+#ifdef LEGACY_SUPPORT
+	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
+	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);
+
 	if (chip->claim_dma) {
 		if ((err = chip->claim_dma(chip, chip->dma_private_data, chip->dma2)) < 0)
 			return err;
 	}
-
-	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.buffer_bytes_max);
-	snd_pcm_limit_isa_dma_size(chip->dma2, &runtime->hw.period_bytes_max);
+#endif
 
 	if ((err = snd_cs4231_open(chip, CS4231_MODE_RECORD)) < 0) {
+#ifdef LEGACY_SUPPORT
 		if (chip->release_dma)
 			chip->release_dma(chip, chip->dma_private_data, chip->dma2);
+#endif
 		snd_free_pages(runtime->dma_area, runtime->dma_bytes);
 		return err;
 	}
 	chip->capture_substream = substream;
+#if defined(SBUS_SUPPORT) || defined(EBUS_SUPPORT)
+	chip->c_periods_sent = 0;
+#endif
 	snd_pcm_set_sync(substream);
 	chip->rate_constraint(runtime);
 	return 0;
@@ -1301,8 +1368,8 @@
 	spin_lock_irqsave(&chip->reg_lock, flags);
 	snd_cs4231_busy_wait(chip);
 	chip->mce_bit &= ~CS4231_MCE;
-	timeout = inb(CS4231P(chip, REGSEL));
-	outb(chip->mce_bit | (timeout & 0x1f), CS4231P(chip, REGSEL));
+	timeout = cs4231_inb(chip, CS4231P(REGSEL));
+	cs4231_outb(chip, CS4231P(REGSEL), chip->mce_bit | (timeout & 0x1f));
 	if (timeout == 0x80)
 		snd_printk("down [0x%lx]: serious init problem - codec still busy\n", chip->port);
 	if ((timeout & CS4231_MCE) == 0 ||
@@ -1334,6 +1401,8 @@
 
 #endif /* CONFIG_PM */
 
+#ifdef LEGACY_SUPPORT
+
 static int snd_cs4231_free(cs4231_t *chip)
 {
 	if (chip->res_port) {
@@ -1373,6 +1442,8 @@
 	return snd_cs4231_free(chip);	
 }
 
+#endif /* LEGACY_SUPPORT */
+
 const char *snd_cs4231_chip_id(cs4231_t *chip)
 {
 	switch (chip->hardware) {
@@ -1392,6 +1463,35 @@
 	}
 }
 
+static int snd_cs4231_new(snd_card_t * card,
+			  unsigned short hardware,
+			  unsigned short hwshare,
+			  cs4231_t ** rchip)
+{
+	cs4231_t *chip;
+
+	*rchip = NULL;
+	chip = snd_magic_kcalloc(cs4231_t, 0, GFP_KERNEL);
+	if (chip == NULL)
+		return -ENOMEM;
+	chip->hardware = hardware;
+	chip->hwshare = hwshare;
+
+	spin_lock_init(&chip->reg_lock);
+	init_MUTEX(&chip->mce_mutex);
+	init_MUTEX(&chip->open_mutex);
+	chip->card = card;
+	chip->rate_constraint = snd_cs4231_xrate;
+	chip->set_playback_format = snd_cs4231_playback_format;
+	chip->set_capture_format = snd_cs4231_capture_format;
+        memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image));
+        
+        *rchip = chip;
+        return 0;
+}
+
+#ifdef LEGACY_SUPPORT
+
 int snd_cs4231_create(snd_card_t * card,
 	              unsigned long port,
 	              unsigned long cport,
@@ -1406,15 +1506,13 @@
 	cs4231_t *chip;
 	int err;
 
-	*rchip = NULL;
-	chip = snd_magic_kcalloc(cs4231_t, 0, GFP_KERNEL);
-	if (chip == NULL)
-		return -ENOMEM;
+	err = snd_cs4231_new(card, hardware, hwshare, &chip);
+	if (err < 0)
+		return err;
+	
 	chip->irq = -1;
 	chip->dma1 = -1;
 	chip->dma2 = -1;
-	chip->hardware = hardware;
-	chip->hwshare = hwshare;
 
 	if ((chip->res_port = request_region(port, 4, "CS4231")) == NULL) {
 		snd_cs4231_free(chip);
@@ -1446,15 +1544,6 @@
 	} else
 		chip->dma2 = dma2;
 
-	spin_lock_init(&chip->reg_lock);
-	init_MUTEX(&chip->mce_mutex);
-	init_MUTEX(&chip->open_mutex);
-	chip->card = card;
-	chip->rate_constraint = snd_cs4231_xrate;
-	chip->set_playback_format = snd_cs4231_playback_format;
-	chip->set_capture_format = snd_cs4231_capture_format;
-        memcpy(&chip->image, &snd_cs4231_original_image, sizeof(snd_cs4231_original_image));
-
 	/* global setup */
 	if (snd_cs4231_probe(chip) < 0) {
 		snd_cs4231_free(chip);
@@ -1486,6 +1575,8 @@
 	return 0;
 }
 
+#endif /* LEGACY_SUPPORT */
+
 static snd_pcm_ops_t snd_cs4231_playback_ops = {
 	.open =		snd_cs4231_playback_open,
 	.close =	snd_cs4231_playback_close,
@@ -1540,7 +1631,23 @@
 		pcm->info_flags |= SNDRV_PCM_INFO_JOINT_DUPLEX;
 	strcpy(pcm->name, snd_cs4231_chip_id(chip));
 
+#ifdef LEGACY_SUPPORT
 	snd_pcm_lib_preallocate_isa_pages_for_all(pcm, 64*1024, chip->dma1 > 3 || chip->dma2 > 3 ? 128*1024 : 64*1024);
+#else
+#  ifdef EBUS_SUPPORT
+        if (chip->ebus_flag) {
+                snd_pcm_lib_preallocate_pci_pages_for_all(chip->dev_u.pdev, pcm,
+                                                          64*1024, 128*1024);
+        } else {
+#  endif
+#  ifdef SBUS_SUPPORT
+                snd_pcm_lib_preallocate_sbus_pages_for_all(chip->dev_u.sdev, pcm,
+                                                           64*1024, 128*1024);
+#  endif
+#  ifdef EBUS_SUPPORT
+        }
+#  endif
+#endif
 
 	chip->pcm = pcm;
 	if (rpcm)
diff -Nru a/sound/isa/es18xx.c b/sound/isa/es18xx.c
--- a/sound/isa/es18xx.c	Sun Nov 10 19:28:39 2002
+++ b/sound/isa/es18xx.c	Sun Nov 10 19:28:39 2002
@@ -154,10 +154,10 @@
 #define ES18XX_PM	0x07
 #define ES18XX_PM_GPO0	0x01
 #define ES18XX_PM_GPO1	0x02
-#define ES18XX_PM_PDR	0x03
-#define ES18XX_PM_ANA	0x04
-#define ES18XX_PM_FM	0x06
-#define ES18XX_PM_SUS	0x08
+#define ES18XX_PM_PDR	0x04
+#define ES18XX_PM_ANA	0x08
+#define ES18XX_PM_FM	0x020
+#define ES18XX_PM_SUS	0x080
 
 typedef struct _snd_es18xx es18xx_t;
 
diff -Nru a/sound/isa/sb/emu8000_pcm.c b/sound/isa/sb/emu8000_pcm.c
--- a/sound/isa/sb/emu8000_pcm.c	Sun Nov 10 19:28:41 2002
+++ b/sound/isa/sb/emu8000_pcm.c	Sun Nov 10 19:28:41 2002
@@ -115,13 +115,15 @@
 /*
  */
 static void
-snd_emu8000_write_wait(emu8000_t *emu)
+snd_emu8000_write_wait(emu8000_t *emu, int can_schedule)
 {
 	while ((EMU8000_SMALW_READ(emu) & 0x80000000) != 0) {
-		set_current_state(TASK_INTERRUPTIBLE);
-		schedule_timeout(1);
-		if (signal_pending(current))
-			break;
+		if (can_schedule) {
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(1);
+			if (signal_pending(current))
+				break;
+		}
 	}
 }
 
@@ -457,7 +459,7 @@
 	emu8k_pcm_t *rec = subs->runtime->private_data;
 	emu8000_t *emu = rec->emu;
 
-	snd_emu8000_write_wait(emu);
+	snd_emu8000_write_wait(emu, 1);
 	if (voice == -1) {
 		unsigned short *buf = src;
 		int i, err;
@@ -494,7 +496,7 @@
 	emu8k_pcm_t *rec = subs->runtime->private_data;
 	emu8000_t *emu = rec->emu;
 
-	snd_emu8000_write_wait(emu);
+	snd_emu8000_write_wait(emu, 1);
 	if (voice == -1 && rec->voices == 1)
 		voice = 0;
 	if (voice == -1) {
@@ -524,7 +526,7 @@
 	emu8000_t *emu = rec->emu;
 	unsigned short *buf = src;
 
-	snd_emu8000_write_wait(emu);
+	snd_emu8000_write_wait(emu, 1);
 	EMU8000_SMALW_WRITE(emu, pos + rec->loop_start[0]);
 	if (rec->voices > 1)
 		EMU8000_SMARW_WRITE(emu, pos + rec->loop_start[1]);
@@ -553,7 +555,7 @@
 	emu8k_pcm_t *rec = subs->runtime->private_data;
 	emu8000_t *emu = rec->emu;
 
-	snd_emu8000_write_wait(emu);
+	snd_emu8000_write_wait(emu, 1);
 	EMU8000_SMALW_WRITE(emu, rec->loop_start[0] + pos);
 	if (rec->voices > 1)
 		EMU8000_SMARW_WRITE(emu, rec->loop_start[1] + pos);
@@ -645,7 +647,7 @@
 		rec->dram_opened = 1;
 
 		/* clear loop blanks */
-		snd_emu8000_write_wait(rec->emu);
+		snd_emu8000_write_wait(rec->emu, 0);
 		EMU8000_SMALW_WRITE(rec->emu, rec->offset);
 		for (i = 0; i < LOOP_BLANK_SIZE; i++)
 			EMU8000_SMLD_WRITE(rec->emu, 0);
diff -Nru a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
--- a/sound/oss/dmasound/dmasound_awacs.c	Sun Nov 10 19:28:38 2002
+++ b/sound/oss/dmasound/dmasound_awacs.c	Sun Nov 10 19:28:38 2002
@@ -1155,8 +1155,7 @@
 	spin_unlock_irqrestore(&dmasound.lock, flags);
 }
 
-static struct timer_list beep_timer = {
-	function: awacs_nosound
+static struct timer_list beep_timer = TIMER_INITIALIZER(awacs_nosound, 0, 0);
 };
 
 /* we generate the beep with a single dbdma command that loops a buffer
diff -Nru a/sound/oss/midibuf.c b/sound/oss/midibuf.c
--- a/sound/oss/midibuf.c	Sun Nov 10 19:28:39 2002
+++ b/sound/oss/midibuf.c	Sun Nov 10 19:28:39 2002
@@ -50,9 +50,7 @@
 static void midi_poll(unsigned long dummy);
 
 
-static struct timer_list poll_timer = {
-	function: midi_poll
-};
+static struct timer_list poll_timer = TIMER_INITIALIZER(midi_poll, 0, 0);
 
 static volatile int open_devs = 0;
 static spinlock_t lock=SPIN_LOCK_UNLOCKED;
diff -Nru a/sound/oss/soundcard.c b/sound/oss/soundcard.c
--- a/sound/oss/soundcard.c	Sun Nov 10 19:28:39 2002
+++ b/sound/oss/soundcard.c	Sun Nov 10 19:28:39 2002
@@ -697,7 +697,7 @@
 
 
 static struct timer_list seq_timer =
-{function: do_sequencer_timer};
+		TIMER_INITIALIZER(do_sequencer_timer, 0, 0);
 
 void request_sound_timer(int count)
 {
diff -Nru a/sound/oss/sys_timer.c b/sound/oss/sys_timer.c
--- a/sound/oss/sys_timer.c	Sun Nov 10 19:28:39 2002
+++ b/sound/oss/sys_timer.c	Sun Nov 10 19:28:39 2002
@@ -29,8 +29,7 @@
 static void     poll_def_tmr(unsigned long dummy);
 static spinlock_t lock=SPIN_LOCK_UNLOCKED;
 
-static struct timer_list def_tmr =
-{function: poll_def_tmr};
+static struct timer_list def_tmr = TIMER_INITIALIZER(poll_def_tmr, 0, 0);
 
 static unsigned long
 tmr2ticks(int tmr_value)
diff -Nru a/sound/oss/uart6850.c b/sound/oss/uart6850.c
--- a/sound/oss/uart6850.c	Sun Nov 10 19:28:40 2002
+++ b/sound/oss/uart6850.c	Sun Nov 10 19:28:40 2002
@@ -77,9 +77,8 @@
 static void poll_uart6850(unsigned long dummy);
 
 
-static struct timer_list uart6850_timer = {
-	function: poll_uart6850
-};
+static struct timer_list uart6850_timer =
+		TIMER_INITIALIZER(poll_uart6850, 0, 0);
 
 static void uart6850_input_loop(void)
 {
diff -Nru a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
--- a/sound/pci/ac97/ac97_codec.c	Sun Nov 10 19:28:39 2002
+++ b/sound/pci/ac97/ac97_codec.c	Sun Nov 10 19:28:39 2002
@@ -105,7 +105,7 @@
 { 0x414c4310, 0xfffffff0, "RL5382", 		NULL },
 { 0x414c4320, 0xfffffff0, "RL5383", 		NULL },
 { 0x414c4710, 0xfffffff0, "ALC200/200P",	NULL },
-{ 0x414c4720, 0xfffffff0, "ALC650",		NULL },
+{ 0x414c4720, 0xfffffff0, "ALC650",		patch_alc650 },
 { 0x414c4730, 0xffffffff, "ALC101",		NULL },
 { 0x414c4740, 0xfffffff0, "ALC202",		NULL },
 { 0x414c4750, 0xfffffff0, "ALC250",		NULL },
@@ -915,6 +915,25 @@
 };
 
 /*
+ * ALC650
+ */
+static const snd_kcontrol_new_t snd_ac97_controls_alc650[] = {
+	AC97_SINGLE("Duplicate Front", AC97_ALC650_MULTICH, 0, 1, 0),
+	AC97_SINGLE("Surround Down Mix", AC97_ALC650_MULTICH, 1, 1, 0),
+	AC97_SINGLE("Center/LFE Down Mix", AC97_ALC650_MULTICH, 2, 1, 0),
+	AC97_SINGLE("Exchange Center/LFE", AC97_ALC650_MULTICH, 3, 1, 0),
+	AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0),
+	AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0),
+	AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0),
+	AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0),
+	AC97_SINGLE("IEC958 Input Monitor", AC97_ALC650_MULTICH, 13, 1, 0),
+#if 0 /* always set in patch_alc650 */
+	AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0),
+	AC97_SINGLE("IEC958 Input Pin Enable", AC97_ALC650_CLOCK, 1, 1, 0),
+#endif
+};
+
+/*
  *
  */
 
@@ -1340,7 +1359,7 @@
 	}
 	
 	/* build S/PDIF controls */
-	if (ac97->ext_id & AC97_EA_SPDIF) {
+	if (ac97->ext_id & AC97_EI_SPDIF) {
 		if (ac97->flags & AC97_CS_SPDIF) {
 			for (idx = 0; idx < 3; idx++)
 				if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_spdif[idx], ac97))) < 0)
@@ -1379,7 +1398,7 @@
 		ac97->spdif_status = SNDRV_PCM_DEFAULT_CON_SPDIF;
 	}
 	
-	/* build Sigmatel specific controls */
+	/* build chip specific controls */
 	switch (ac97->id) {
 	case AC97_ID_STAC9700:
 	case AC97_ID_STAC9708:
@@ -1393,6 +1412,12 @@
 		if (snd_ac97_try_bit(ac97, AC97_SIGMATEL_ANALOG, 0))
 			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_sigmatel_controls[1], ac97))) < 0)
 				return err;
+		break;
+	case AC97_ID_ALC650:
+		for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_alc650); idx++)
+			if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_alc650[idx], ac97))) < 0)
+				return err;
+		break;
 	default:
 		/* nothing */
 		break;
diff -Nru a/sound/pci/ac97/ac97_id.h b/sound/pci/ac97/ac97_id.h
--- a/sound/pci/ac97/ac97_id.h	Sun Nov 10 19:28:41 2002
+++ b/sound/pci/ac97/ac97_id.h	Sun Nov 10 19:28:41 2002
@@ -43,3 +43,4 @@
 #define AC97_ID_CS4299		0x43525930
 #define AC97_ID_CS4201		0x43525948
 #define AC97_ID_CS4205		0x43525958
+#define AC97_ID_ALC650		0x414c4720
diff -Nru a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
--- a/sound/pci/ac97/ac97_patch.c	Sun Nov 10 19:28:41 2002
+++ b/sound/pci/ac97/ac97_patch.c	Sun Nov 10 19:28:41 2002
@@ -168,7 +168,7 @@
 
 	ac97->flags |= AC97_CS_SPDIF; 
 	ac97->rates[AC97_RATES_SPDIF] &= ~SNDRV_PCM_RATE_32000;
-        ac97->ext_id |= AC97_EA_SPDIF;	/* force the detection of spdif */
+        ac97->ext_id |= AC97_EI_SPDIF;	/* force the detection of spdif */
 	snd_ac97_write_cache(ac97, AC97_CSR_ACMODE, 0x0080);
 	return 0;
 }
@@ -184,7 +184,7 @@
 int patch_conexant(ac97_t * ac97)
 {
 	ac97->flags |= AC97_CX_SPDIF;
-        ac97->ext_id |= AC97_EA_SPDIF;	/* force the detection of spdif */
+        ac97->ext_id |= AC97_EI_SPDIF;	/* force the detection of spdif */
 	return 0;
 }
 
@@ -334,5 +334,13 @@
 	/* it seems that most vendors connect line-out connector to headphone out of AC'97 */
 	misc = snd_ac97_read(ac97, AC97_AD_MISC);
 	snd_ac97_write_cache(ac97, AC97_AD_MISC, misc | 0x0420);
+	return 0;
+}
+
+int patch_alc650(ac97_t * ac97)
+{
+	/* enable spdif in */
+	snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK,
+			     snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x03);
 	return 0;
 }
diff -Nru a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
--- a/sound/pci/ac97/ac97_patch.h	Sun Nov 10 19:28:36 2002
+++ b/sound/pci/ac97/ac97_patch.h	Sun Nov 10 19:28:36 2002
@@ -38,3 +38,4 @@
 int patch_ad1885(ac97_t * ac97);
 int patch_ad1886(ac97_t * ac97);
 int patch_ad1980(ac97_t * ac97);
+int patch_alc650(ac97_t * ac97);
diff -Nru a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c
--- a/sound/pci/ali5451/ali5451.c	Sun Nov 10 19:28:41 2002
+++ b/sound/pci/ali5451/ali5451.c	Sun Nov 10 19:28:41 2002
@@ -233,6 +233,7 @@
 	unsigned long	port;
 	unsigned char	revision;
 
+	unsigned int hw_initialized: 1;
 	struct resource *res_port;
 
 	struct pci_dev	*pci;
@@ -1965,7 +1966,8 @@
 
 static int snd_ali_free(ali_t * codec)
 {
-	snd_ali_disable_address_interrupt(codec);
+	if (codec->hw_initialized)
+		snd_ali_disable_address_interrupt(codec);
 	if (codec->irq >= 0) {
 		synchronize_irq(codec->irq);
 		free_irq(codec->irq, (void *)codec);
@@ -2036,13 +2038,11 @@
 {
 	snd_ali_printk("resouces allocation ...\n");
 	if ((codec->res_port = request_region(codec->port, 0x100, "ALI 5451")) == NULL) {
-		snd_ali_free(codec);
 		snd_printk("Unalbe to request io ports.\n");
 		return -EBUSY;
 	}
 
 	if (request_irq(codec->pci->irq, snd_ali_card_interrupt, SA_INTERRUPT|SA_SHIRQ, "ALI 5451", (void *)codec)) {
-		snd_ali_free(codec);
 		snd_printk("Unable to request irq.\n");
 		return -EBUSY;
 	}
@@ -2112,6 +2112,7 @@
 	pci_set_master(pci);
 	
 	if (snd_ali_resources(codec)) {
+		snd_ali_free(codec);
 		return -EBUSY;
 	}
 
@@ -2156,7 +2157,6 @@
 
 	if ((err = snd_ali_chip_init(codec)) < 0) {
 		snd_printk("ali create: chip init error.\n");
-		snd_ali_free(codec);
 		return err;
 	}
 
@@ -2167,6 +2167,7 @@
 #endif
 
 	snd_ali_enable_address_interrupt(codec);
+	codec->hw_initialized = 1;
 
 	*r_ali = codec;
 	snd_ali_printk("created.\n");
diff -Nru a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c
--- a/sound/pci/cs46xx/cs46xx.c	Sun Nov 10 19:28:41 2002
+++ b/sound/pci/cs46xx/cs46xx.c	Sun Nov 10 19:28:41 2002
@@ -110,6 +110,16 @@
 		snd_card_free(card);
 		return err;
 	}
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	if ((err = snd_cs46xx_pcm_rear(chip,1, NULL)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+	if ((err = snd_cs46xx_pcm_iec958(chip,2,NULL)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+#endif
 	if ((err = snd_cs46xx_mixer(chip)) < 0) {
 		snd_card_free(card);
 		return err;
@@ -118,6 +128,12 @@
 		snd_card_free(card);
 		return err;
 	}
+	if ((err = snd_cs46xx_start_dsp(chip)) < 0) {
+		snd_card_free(card);
+		return err;
+	}
+
+
 	snd_cs46xx_gameport(chip);
 
 	strcpy(card->driver, "CS46xx");
@@ -132,6 +148,7 @@
 		snd_card_free(card);
 		return err;
 	}
+
 	pci_set_drvdata(pci, chip);
 	dev++;
 	return 0;
diff -Nru a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c
--- a/sound/pci/cs46xx/cs46xx_lib.c	Sun Nov 10 19:28:37 2002
+++ b/sound/pci/cs46xx/cs46xx_lib.c	Sun Nov 10 19:28:37 2002
@@ -15,8 +15,8 @@
  *  TODO:
  *    - Secondary CODEC on some soundcards
  *    - SPDIF input support for other sample rates then 48khz
- *    - Independent PCM channels for rear output
  *    - Posibility to mix the SPDIF output with analog sources.
+ *    - PCM channels for Center and LFE on secondary codec
  *
  *  NOTE: with CONFIG_SND_CS46XX_NEW_DSP unset uses old DSP image (which
  *        is default configuration), no SPDIF, no secondary codec, no
@@ -269,23 +269,35 @@
 				   unsigned short val)
 {
 	cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return);
+#ifndef CONFIG_SND_CS46XX_NEW_DSP
 	int val2 = 0;
+#endif
 	int codec_index = -1;
 
 	/* UGGLY: nr_ac97_codecs == 0 primery codec detection is in progress */
 	if (ac97 == chip->ac97[CS46XX_PRIMARY_CODEC_INDEX] || chip->nr_ac97_codecs == 0)
 		codec_index = CS46XX_PRIMARY_CODEC_INDEX;
-	/* UGGLY: nr_ac97_codecs == 0 secondary codec detection is in progress */
+	/* UGGLY: nr_ac97_codecs == 1 secondary codec detection is in progress */
 	else  if (ac97 == chip->ac97[CS46XX_SECONDARY_CODEC_INDEX] || chip->nr_ac97_codecs == 1)
 		codec_index = CS46XX_SECONDARY_CODEC_INDEX;
 	else
 		snd_assert(0,return);
-	chip->active_ctrl(chip, 1);
+
+#ifndef CONFIG_SND_CS46XX_NEW_DSP
 	if (reg == AC97_CD)
 		val2 = snd_cs46xx_codec_read(chip, AC97_CD, codec_index);
+#endif
 
 	snd_cs46xx_codec_write(chip, reg, val, codec_index);
 
+#ifndef CONFIG_SND_CS46XX_NEW_DSP
+    /* Benny: I've not found *one* soundcard where
+       this code below could do any sense, and
+       with the HW mixering it's anyway broken, with
+       more then 1 PCM stream the amplifier will not
+       be turned off by unmuting CD channel. So just
+       lets skip it.
+    */
 	
 	/*
 	 *	Adjust power if the mixer is selected/deselected according
@@ -323,6 +335,7 @@
 	}
 
 	chip->active_ctrl(chip, -1);
+#endif
 }
 
 
@@ -432,9 +445,33 @@
 	snd_cs46xx_poke(chip, BA1_FRMT, 0xadf);
 }
 
+static int cs46xx_wait_for_fifo(cs46xx_t * chip,int retry_timeout) 
+{
+	u32 i, status;
+	/*
+	 * Make sure the previous FIFO write operation has completed.
+	 */
+	for(i = 0; i < 50; i++){
+		status = snd_cs46xx_peekBA0(chip, BA0_SERBST);
+    
+		if( !(status & SERBST_WBSY) )
+			break;
+
+		mdelay(retry_timeout);
+	}
+  
+	if(status & SERBST_WBSY) {
+		snd_printk( KERN_ERR "cs46xx: failure waiting for FIFO command to complete\n");
+
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static void snd_cs46xx_clear_serial_FIFOs(cs46xx_t *chip)
 {
-	int idx, loop, powerdown = 0;
+	int idx, powerdown = 0;
 	unsigned int tmp;
 
 	/*
@@ -451,24 +488,23 @@
 	 *  We want to clear out the serial port FIFOs so we don't end up playing
 	 *  whatever random garbage happens to be in them.  We fill the sample FIFOS
 	 *  with zero (silence).
-         */
+	 */
 	snd_cs46xx_pokeBA0(chip, BA0_SERBWP, 0);
 
 	/*
 	 *  Fill all 256 sample FIFO locations.
 	 */
-	for (idx = 0; idx < 256; idx++) {
+	for (idx = 0; idx < 0xFF; idx++) {
 		/*
 		 *  Make sure the previous FIFO write operation has completed.
 		 */
-		for (loop = 0; loop < 5; loop++) {
-			udelay(50);
-			if (!(snd_cs46xx_peekBA0(chip, BA0_SERBST) & SERBST_WBSY))
-				break;
-		}
-		if (snd_cs46xx_peekBA0(chip, BA0_SERBST) & SERBST_WBSY) {
+		if (cs46xx_wait_for_fifo(chip,1)) {
+			snd_printdd ("failed waiting for FIFO at addr (%02X)\n",idx);
+
 			if (powerdown)
 				snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp);
+          
+			break;
 		}
 		/*
 		 *  Write the serial port FIFO index.
@@ -692,6 +728,8 @@
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	snd_pcm_sframes_t diff;
 	cs46xx_pcm_t * cpcm;
+	int buffer_size = runtime->period_size * CS46XX_FRAGS * 4;
+
 	cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
 
 	diff = runtime->control->appl_ptr - cpcm->appl_ptr;
@@ -702,11 +740,11 @@
 	}
 	cpcm->sw_ready += frames << cpcm->shift;
 	cpcm->appl_ptr = runtime->control->appl_ptr + frames;
-	while (cpcm->hw_ready < CS46XX_BUFFER_SIZE && 
+	while (cpcm->hw_ready < buffer_size && 
 	       cpcm->sw_ready > 0) {
-		size_t hw_to_end = CS46XX_BUFFER_SIZE - cpcm->hw_data;
+		size_t hw_to_end = buffer_size - cpcm->hw_data;
 		size_t sw_to_end = cpcm->sw_bufsize - cpcm->sw_data;
-		size_t bytes = CS46XX_BUFFER_SIZE - cpcm->hw_ready;
+		size_t bytes = buffer_size - cpcm->hw_ready;
 		if (cpcm->sw_ready < bytes)
 			bytes = cpcm->sw_ready;
 		if (hw_to_end < bytes)
@@ -717,7 +755,7 @@
 		       runtime->dma_area + cpcm->sw_data,
 		       bytes);
 		cpcm->hw_data += bytes;
-		if (cpcm->hw_data == CS46XX_BUFFER_SIZE)
+		if (cpcm->hw_data == buffer_size)
 			cpcm->hw_data = 0;
 		cpcm->sw_data += bytes;
 		if (cpcm->sw_data == cpcm->sw_bufsize)
@@ -734,6 +772,7 @@
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	snd_pcm_sframes_t diff = runtime->control->appl_ptr - chip->capt.appl_ptr;
+	int buffer_size = runtime->period_size * CS46XX_FRAGS * 4;
 	if (diff) {
 		if (diff < -(snd_pcm_sframes_t) (runtime->boundary / 2))
 			diff += runtime->boundary;
@@ -743,7 +782,7 @@
 	chip->capt.appl_ptr = runtime->control->appl_ptr + frames;
 	while (chip->capt.hw_ready > 0 && 
 	       chip->capt.sw_ready < chip->capt.sw_bufsize) {
-		size_t hw_to_end = CS46XX_BUFFER_SIZE - chip->capt.hw_data;
+		size_t hw_to_end = buffer_size - chip->capt.hw_data;
 		size_t sw_to_end = chip->capt.sw_bufsize - chip->capt.sw_data;
 		size_t bytes = chip->capt.sw_bufsize - chip->capt.sw_ready;
 		if (chip->capt.hw_ready < bytes)
@@ -756,7 +795,7 @@
 		       chip->capt.hw_area + chip->capt.hw_data,
 		       bytes);
 		chip->capt.hw_data += bytes;
-		if (chip->capt.hw_data == CS46XX_BUFFER_SIZE)
+		if (chip->capt.hw_data == buffer_size)
 			chip->capt.hw_data = 0;
 		chip->capt.sw_data += bytes;
 		if (chip->capt.sw_data == chip->capt.sw_bufsize)
@@ -789,6 +828,7 @@
 	size_t ptr;
 	cs46xx_pcm_t *cpcm = snd_magic_cast(cs46xx_pcm_t, substream->runtime->private_data, return -ENXIO);
 	ssize_t bytes;
+	int buffer_size = substream->runtime->period_size * CS46XX_FRAGS * 4;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 	snd_assert (cpcm->pcm_channel,return -ENXIO);
@@ -801,7 +841,7 @@
 	bytes = ptr - cpcm->hw_io;
 
 	if (bytes < 0)
-		bytes += CS46XX_BUFFER_SIZE;
+		bytes += buffer_size;
 	cpcm->hw_io = ptr;
 	cpcm->hw_ready -= bytes;
 	cpcm->sw_io += bytes;
@@ -823,8 +863,10 @@
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
 	size_t ptr = snd_cs46xx_peek(chip, BA1_CBA) - chip->capt.hw_addr;
 	ssize_t bytes = ptr - chip->capt.hw_io;
+	int buffer_size = substream->runtime->period_size * CS46XX_FRAGS * 4;
+
 	if (bytes < 0)
-		bytes += CS46XX_BUFFER_SIZE;
+		bytes += buffer_size;
 	chip->capt.hw_io = ptr;
 	chip->capt.hw_ready += bytes;
 	chip->capt.sw_io += bytes;
@@ -910,7 +952,9 @@
 			snd_cs46xx_playback_transfer(substream, 0);
 
 		/* raise playback volume */
-		snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 0xE) << 2, 0x80008000);
+		cs46xx_dsp_scb_set_volume (chip,cpcm->pcm_channel->pcm_reader_scb,
+					   chip->dsp_spos_instance->dac_volume_right,
+					   chip->dsp_spos_instance->dac_volume_left);
 #else
 		if (substream->runtime->periods != CS46XX_FRAGS)
 			snd_cs46xx_playback_transfer(substream, 0);
@@ -924,8 +968,9 @@
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-        /* mute channel */
-		snd_cs46xx_poke(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 0xE) << 2, 0xffffffff);
+		/* mute channel */
+		cs46xx_dsp_scb_set_volume (chip,cpcm->pcm_channel->pcm_reader_scb,0,0);
+
 		if (!cpcm->pcm_channel->unlinked)
 			cs46xx_dsp_pcm_unlink(chip,cpcm->pcm_channel);
 #else
@@ -978,6 +1023,44 @@
 	return result;
 }
 
+static int _cs46xx_adjust_sample_rate (cs46xx_t *chip, cs46xx_pcm_t *cpcm,
+				       int sample_rate) 
+{
+	/* if this is the only PCMReaderSCB child under current
+	   SrcTask then there no need to re-create pcm-channel */
+	if ( cpcm->pcm_channel->src_scb->ref_count == 1 &&
+	     cpcm->pcm_channel->sample_rate != sample_rate &&
+	     /* never set a 0 khz sample rate */
+	     sample_rate) {
+		/* sample rate not set or we can reuse
+		   the same SRC*/
+		cs46xx_dsp_set_src_sample_rate (chip,cpcm->pcm_channel->src_scb,sample_rate);
+		cpcm->pcm_channel->sample_rate = sample_rate;
+	} 
+
+	/* if there is more then 1 PCMReaderSCB child's under current
+	   SrcTask then we must recreate channel */
+	if (cpcm->pcm_channel->sample_rate != sample_rate &&
+	    cpcm->pcm_channel->src_scb->ref_count != 1 &&
+	    /* never set a 0 khz sample rate */
+	    sample_rate) {
+		int unlinked = cpcm->pcm_channel->unlinked;
+		cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel);
+
+		if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm, 
+									 cpcm->hw_addr,
+									 cpcm->pcm_channel->pcm_channel_id)) == NULL) {
+			snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n");
+			up (&chip->spos_mutex);
+			return -ENXIO;
+		}
+
+		if (!unlinked) cs46xx_dsp_pcm_link (chip,cpcm->pcm_channel);
+		cpcm->pcm_channel->sample_rate = sample_rate;
+	}
+
+	return 0;
+}
 static int snd_cs46xx_playback_hw_params(snd_pcm_substream_t * substream,
 					 snd_pcm_hw_params_t * hw_params)
 {
@@ -985,27 +1068,88 @@
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	cs46xx_pcm_t *cpcm;
 	int err;
-
+	cs46xx_t *chip = snd_pcm_substream_chip(substream);
+	int sample_rate = params_rate(hw_params);
+	int period_size = params_period_size(hw_params);
 	cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
 
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	down (&chip->spos_mutex);
+
+	snd_assert (cpcm->pcm_channel != NULL);
+
+	/* if IEC958 is opened in AC3 mode dont adjust SRCTask is not
+	   used so dont adjust sample rate */
+	if (cpcm->pcm_channel->pcm_channel_id != DSP_IEC958_CHANNEL ||
+	    !(chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE)) {
+		if (_cs46xx_adjust_sample_rate (chip,cpcm,sample_rate)) {
+			return -ENXIO;
+		}
+	}
+
+	if (cs46xx_dsp_pcm_channel_set_period (chip,cpcm->pcm_channel,period_size * 4)) {
+		 up (&chip->spos_mutex);
+		 return -EINVAL;
+	 }
+	snd_printdd ("period_size (%d), periods (%d)\n",
+		     period_size, params_periods(hw_params));
+#endif
+
 	if (params_periods(hw_params) == CS46XX_FRAGS) {
 		if (runtime->dma_area != cpcm->hw_area)
 			snd_pcm_lib_free_pages(substream);
 		runtime->dma_area = cpcm->hw_area;
 		runtime->dma_addr = cpcm->hw_addr;
 		runtime->dma_bytes = cpcm->hw_size;
+
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+		if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) {
+			substream->ops = &snd_cs46xx_playback_ops;
+		} else if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_REAR_CHANNEL) {
+			substream->ops = &snd_cs46xx_playback_rear_ops;
+		} else if (cpcm->pcm_channel->pcm_channel_id == DSP_IEC958_CHANNEL) {
+			substream->ops = &snd_cs46xx_playback_iec958_ops;
+		} else {
+			snd_assert(0);
+		}
+#else
 		substream->ops = &snd_cs46xx_playback_ops;
+#endif
+
 	} else {
 		if (runtime->dma_area == cpcm->hw_area) {
 			runtime->dma_area = NULL;
 			runtime->dma_addr = 0;
 			runtime->dma_bytes = 0;
 		}
-		if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0)
+		if ((err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params))) < 0) {
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+			up (&chip->spos_mutex);
+#endif
 			return err;
+		}
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+		if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_MAIN_CHANNEL) {
+			substream->ops = &snd_cs46xx_playback_indirect_ops;
+		} else if (cpcm->pcm_channel->pcm_channel_id == DSP_PCM_REAR_CHANNEL) {
+			substream->ops = &snd_cs46xx_playback_indirect_rear_ops;
+		} else if (cpcm->pcm_channel->pcm_channel_id == DSP_IEC958_CHANNEL) {
+			substream->ops = &snd_cs46xx_playback_indirect_iec958_ops;
+		} else {
+			snd_assert(0);
+		}
+#else
 		substream->ops = &snd_cs46xx_playback_indirect_ops;
+#endif
+
 	}
 
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	up (&chip->spos_mutex);
+#endif
+
 	return 0;
 }
 
@@ -1038,35 +1182,10 @@
 	cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return -ENXIO);
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
-    down (&chip->spos_mutex);
-
-	if ( cpcm->pcm_channel->src_scb->ref_count == 1 &&
-	     cpcm->pcm_channel->sample_rate != runtime->rate) {
-		/* sample rate not set or we can reuse
-		   the same SRC*/
-
-		cs46xx_dsp_set_src_sample_rate (chip,cpcm->pcm_channel->src_scb,runtime->rate);
-		cpcm->pcm_channel->sample_rate = runtime->rate;
-	} 
-
-	if (cpcm->pcm_channel->sample_rate != runtime->rate &&
-	    cpcm->pcm_channel->src_scb->ref_count != 1) {
-		int unlinked = cpcm->pcm_channel->unlinked;
-		cs46xx_dsp_destroy_pcm_channel (chip,cpcm->pcm_channel);
-
-		if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, runtime->rate, cpcm, cpcm->hw_addr)) == NULL) {
-			snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n");
-			up (&chip->spos_mutex);
-			return -ENXIO;
-		}
-
-		if (!unlinked) cs46xx_dsp_pcm_link (chip,cpcm->pcm_channel);
-		cpcm->pcm_channel->sample_rate = runtime->rate;
-	}
+    snd_assert (cpcm->pcm_channel != NULL, return -ENXIO);
 
 	pfie = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address + 1) << 2 );
 	pfie &= ~0x0000f03f;
-	up (&chip->spos_mutex);
 #else
 	/* old dsp */
 	pfie = snd_cs46xx_peek(chip, BA1_PFIE);
@@ -1101,6 +1220,7 @@
 	cpcm->appl_ptr = 0;
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
+
 	tmp = snd_cs46xx_peek(chip, (cpcm->pcm_channel->pcm_reader_scb->address) << 2);
 	tmp &= ~0x000003ff;
 	tmp |= (4 << cpcm->shift) - 1;
@@ -1128,7 +1248,13 @@
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	int err;
+	int period_size = params_period_size(hw_params);
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	snd_printdd ("capture period size (%d)\n",period_size);
 
+	cs46xx_dsp_pcm_ostream_set_period (chip,period_size * 4);
+#endif
 	if (runtime->periods == CS46XX_FRAGS) {
 		if (runtime->dma_area != chip->capt.hw_area)
 			snd_pcm_lib_free_pages(substream);
@@ -1285,8 +1411,8 @@
 	.channels_min =		1,
 	.channels_max =		2,
 	.buffer_bytes_max =	(256 * 1024),
-	.period_bytes_min =	CS46XX_PERIOD_SIZE,
-	.period_bytes_max =	CS46XX_PERIOD_SIZE,
+	.period_bytes_min =	CS46XX_MIN_PERIOD_SIZE,
+	.period_bytes_max =	CS46XX_MAX_PERIOD_SIZE,
 	.periods_min =		CS46XX_FRAGS,
 	.periods_max =		1024,
 	.fifo_size =		0,
@@ -1305,13 +1431,23 @@
 	.channels_min =		2,
 	.channels_max =		2,
 	.buffer_bytes_max =	(256 * 1024),
-	.period_bytes_min =	CS46XX_PERIOD_SIZE,
-	.period_bytes_max =	CS46XX_PERIOD_SIZE,
+	.period_bytes_min =	CS46XX_MIN_PERIOD_SIZE,
+	.period_bytes_max =	CS46XX_MAX_PERIOD_SIZE,
 	.periods_min =		CS46XX_FRAGS,
 	.periods_max =		1024,
 	.fifo_size =		0,
 };
 
+static unsigned int period_sizes[] = { 8, 16, 32, 64, 128, 256, 512 };
+
+#define PERIOD_SIZES sizeof(period_sizes) / sizeof(period_sizes[0])
+
+static snd_pcm_hw_constraint_list_t hw_constraints_period_sizes = {
+	.count = PERIOD_SIZES,
+	.list = period_sizes,
+	.mask = 0
+};
+
 static void snd_cs46xx_pcm_free_substream(snd_pcm_runtime_t *runtime)
 {
 	cs46xx_pcm_t * cpcm = snd_magic_cast(cs46xx_pcm_t, runtime->private_data, return);
@@ -1320,7 +1456,7 @@
 		snd_magic_kfree(cpcm);
 }
 
-static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream)
+static int _cs46xx_playback_open_channel (snd_pcm_substream_t * substream,int pcm_channel_id)
 {
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
 	cs46xx_pcm_t * cpcm;
@@ -1342,7 +1478,7 @@
 	cpcm->substream = substream;
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 	down (&chip->spos_mutex);
-	cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, runtime->rate, cpcm, cpcm->hw_addr);
+	cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, runtime->rate, cpcm, cpcm->hw_addr,pcm_channel_id);
 
 	if (cpcm->pcm_channel == NULL) {
 		snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n");
@@ -1352,6 +1488,8 @@
 		return -ENOMEM;
 	}
 
+	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 
+				   &hw_constraints_period_sizes);
 	up (&chip->spos_mutex);
 #else
 	chip->playback_pcm = cpcm; /* HACK */
@@ -1365,6 +1503,52 @@
 	return 0;
 }
 
+static int snd_cs46xx_playback_open(snd_pcm_substream_t * substream)
+{
+	snd_printdd("open front channel\n");
+	return _cs46xx_playback_open_channel(substream,DSP_PCM_MAIN_CHANNEL);
+}
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+static int snd_cs46xx_playback_open_rear(snd_pcm_substream_t * substream)
+{
+	snd_printdd("open rear channel\n");
+
+	return _cs46xx_playback_open_channel(substream,DSP_PCM_REAR_CHANNEL);
+}
+
+static int snd_cs46xx_playback_open_iec958(snd_pcm_substream_t * substream)
+{
+	cs46xx_t *chip = snd_pcm_substream_chip(substream);
+
+	snd_printdd("open raw iec958 channel\n");
+
+	down (&chip->spos_mutex);
+	cs46xx_iec958_pre_open (chip);
+	up (&chip->spos_mutex);
+
+	return _cs46xx_playback_open_channel(substream,DSP_IEC958_CHANNEL);
+}
+
+static int snd_cs46xx_playback_close(snd_pcm_substream_t * substream);
+
+static int snd_cs46xx_playback_close_iec958(snd_pcm_substream_t * substream)
+{
+	int err;
+	cs46xx_t *chip = snd_pcm_substream_chip(substream);
+  
+	snd_printdd("close raw iec958 channel\n");
+
+	err = snd_cs46xx_playback_close(substream);
+
+	down (&chip->spos_mutex);
+	cs46xx_iec958_post_close (chip);
+	up (&chip->spos_mutex);
+
+	return err;
+}
+#endif
+
 static int snd_cs46xx_capture_open(snd_pcm_substream_t * substream)
 {
 	cs46xx_t *chip = snd_pcm_substream_chip(substream);
@@ -1375,11 +1559,15 @@
 	substream->runtime->hw = snd_cs46xx_capture;
 
 	if (chip->accept_valid)
-      substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID;
+		substream->runtime->hw.info |= SNDRV_PCM_INFO_MMAP_VALID;
 
 	chip->active_ctrl(chip, 1);
 	chip->amplifier_ctrl(chip, 1);
 
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+	snd_pcm_hw_constraint_list(substream->runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 
+				   &hw_constraints_period_sizes);
+#endif
 	return 0;
 }
 
@@ -1422,6 +1610,55 @@
 	return 0;
 }
 
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+snd_pcm_ops_t snd_cs46xx_playback_rear_ops = {
+	.open =			snd_cs46xx_playback_open_rear,
+	.close =		snd_cs46xx_playback_close,
+	.ioctl =		snd_pcm_lib_ioctl,
+	.hw_params =		snd_cs46xx_playback_hw_params,
+	.hw_free =		snd_cs46xx_playback_hw_free,
+	.prepare =		snd_cs46xx_playback_prepare,
+	.trigger =		snd_cs46xx_playback_trigger,
+	.pointer =		snd_cs46xx_playback_direct_pointer,
+};
+
+snd_pcm_ops_t snd_cs46xx_playback_indirect_rear_ops = {
+	.open =			snd_cs46xx_playback_open_rear,
+	.close =		snd_cs46xx_playback_close,
+	.ioctl =		snd_pcm_lib_ioctl,
+	.hw_params =		snd_cs46xx_playback_hw_params,
+	.hw_free =		snd_cs46xx_playback_hw_free,
+	.prepare =		snd_cs46xx_playback_prepare,
+	.trigger =		snd_cs46xx_playback_trigger,
+	.copy =			snd_cs46xx_playback_copy,
+	.pointer =		snd_cs46xx_playback_indirect_pointer,
+};
+
+snd_pcm_ops_t snd_cs46xx_playback_iec958_ops = {
+	.open =			snd_cs46xx_playback_open_iec958,
+	.close =		snd_cs46xx_playback_close_iec958,
+	.ioctl =		snd_pcm_lib_ioctl,
+	.hw_params =		snd_cs46xx_playback_hw_params,
+	.hw_free =		snd_cs46xx_playback_hw_free,
+	.prepare =		snd_cs46xx_playback_prepare,
+	.trigger =		snd_cs46xx_playback_trigger,
+	.pointer =		snd_cs46xx_playback_direct_pointer,
+};
+
+snd_pcm_ops_t snd_cs46xx_playback_indirect_iec958_ops = {
+	.open =			snd_cs46xx_playback_open_iec958,
+	.close =		snd_cs46xx_playback_close_iec958,
+	.ioctl =		snd_pcm_lib_ioctl,
+	.hw_params =		snd_cs46xx_playback_hw_params,
+	.hw_free =		snd_cs46xx_playback_hw_free,
+	.prepare =		snd_cs46xx_playback_prepare,
+	.trigger =		snd_cs46xx_playback_trigger,
+	.copy =			snd_cs46xx_playback_copy,
+	.pointer =		snd_cs46xx_playback_indirect_pointer,
+};
+
+#endif
+
 snd_pcm_ops_t snd_cs46xx_playback_ops = {
 	.open =			snd_cs46xx_playback_open,
 	.close =		snd_cs46xx_playback_close,
@@ -1476,6 +1713,20 @@
 }
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
+static void snd_cs46xx_pcm_rear_free(snd_pcm_t *pcm)
+{
+	cs46xx_t *chip = snd_magic_cast(cs46xx_t, pcm->private_data, return);
+	chip->pcm_rear = NULL;
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
+static void snd_cs46xx_pcm_iec958_free(snd_pcm_t *pcm)
+{
+	cs46xx_t *chip = snd_magic_cast(cs46xx_t, pcm->private_data, return);
+	chip->pcm_iec958 = NULL;
+	snd_pcm_lib_preallocate_free_for_all(pcm);
+}
+
 #define MAX_PLAYBACK_CHANNELS	(DSP_MAX_PCM_CHANNELS - 1)
 #else
 #define MAX_PLAYBACK_CHANNELS	1
@@ -1490,6 +1741,7 @@
 		*rpcm = NULL;
 	if ((err = snd_pcm_new(chip->card, "CS46xx", device, MAX_PLAYBACK_CHANNELS, 1, &pcm)) < 0)
 		return err;
+
 	pcm->private_data = chip;
 	pcm->private_free = snd_cs46xx_pcm_free;
 
@@ -1505,13 +1757,74 @@
 
 	if (rpcm)
 		*rpcm = pcm;
+
+	return 0;
+}
+
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+int __devinit snd_cs46xx_pcm_rear(cs46xx_t *chip, int device, snd_pcm_t ** rpcm)
+{
+	snd_pcm_t *pcm;
+	int err;
+
+	if (rpcm)
+		*rpcm = NULL;
+
+	if ((err = snd_pcm_new(chip->card, "CS46xx - Rear", device, MAX_PLAYBACK_CHANNELS, 0, &pcm)) < 0)
+		return err;
+
+	pcm->private_data = chip;
+	pcm->private_free = snd_cs46xx_pcm_rear_free;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs46xx_playback_rear_ops);
+
+	/* global setup */
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "CS46xx - Rear");
+	chip->pcm_rear = pcm;
+
+	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
+
+	if (rpcm)
+		*rpcm = pcm;
+
 	return 0;
 }
 
+int __devinit snd_cs46xx_pcm_iec958(cs46xx_t *chip, int device, snd_pcm_t ** rpcm)
+{
+	snd_pcm_t *pcm;
+	int err;
+
+	if (rpcm)
+		*rpcm = NULL;
+
+	if ((err = snd_pcm_new(chip->card, "CS46xx - IEC958", device, 1, 0, &pcm)) < 0)
+		return err;
+
+	pcm->private_data = chip;
+	pcm->private_free = snd_cs46xx_pcm_iec958_free;
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_cs46xx_playback_iec958_ops);
+
+	/* global setup */
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "CS46xx - IEC958");
+	chip->pcm_rear = pcm;
+
+	snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 256*1024);
+
+	if (rpcm)
+		*rpcm = pcm;
+
+	return 0;
+}
+#endif
+
 /*
  *  Mixer routines
  */
-
 static void snd_cs46xx_mixer_free_ac97(ac97_t *ac97)
 {
 	cs46xx_t *chip = snd_magic_cast(cs46xx_t, ac97->private_data, return);
@@ -1534,7 +1847,7 @@
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 	uinfo->count = 2;
 	uinfo->value.integer.min = 0;
-	uinfo->value.integer.max = 32767;
+	uinfo->value.integer.max = 0x7fff;
 	return 0;
 }
 
@@ -1556,26 +1869,9 @@
 			    (0xffff - ucontrol->value.integer.value[1]));
 	unsigned int old = snd_cs46xx_peek(chip, reg);
 	int change = (old != val);
+
 	if (change) {
 		snd_cs46xx_poke(chip, reg, val);
-#ifdef CONFIG_SND_CS46XX_NEW_DSP
-		/* NOTE: this updates the current left and right volume
-		   that should be automatically updated by the DSP and
-		   not touched by the host. But for some strange reason
-		   the DSP only updates the right channel volume, so with
-		   this dirty hack we force updating the right and left
-		   channel volume. 
-		*/
-		snd_cs46xx_poke(chip, reg + 4, val);
-
-		/* shadow the SPDIF input volume */
-		if (reg == (ASYNCRX_SCB_ADDR + 0xE) << 2) {
-			/* FIXME: I known this is uggly ...
-			   any other suggestion ? 
-			*/
-			chip->dsp_spos_instance->spdif_input_volume = val;
-		}
-#endif
 	}
 
 	return change;
@@ -1583,6 +1879,57 @@
 
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 
+static int snd_cs46xx_vol_dac_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] = chip->dsp_spos_instance->dac_volume_right;
+	ucontrol->value.integer.value[1] = chip->dsp_spos_instance->dac_volume_left;
+
+	return 0;
+}
+
+static int snd_cs46xx_vol_dac_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+	int change = 0;
+
+	if (chip->dsp_spos_instance->dac_volume_right != ucontrol->value.integer.value[0] ||
+	    chip->dsp_spos_instance->dac_volume_left != ucontrol->value.integer.value[1]) {
+		cs46xx_dsp_set_dac_volume(chip,
+					  ucontrol->value.integer.value[0],
+					  ucontrol->value.integer.value[1]);
+		change = 1;
+	}
+
+	return change;
+}
+
+static int snd_cs46xx_vol_iec958_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_input_volume_right;
+	ucontrol->value.integer.value[1] = chip->dsp_spos_instance->spdif_input_volume_left;
+	return 0;
+}
+
+static int snd_cs46xx_vol_iec958_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+	int change = 0;
+
+	if (chip->dsp_spos_instance->spdif_input_volume_right != ucontrol->value.integer.value[0] ||
+	    chip->dsp_spos_instance->spdif_input_volume_left != ucontrol->value.integer.value[1]) {
+		cs46xx_dsp_set_iec958_volume (chip,
+					      ucontrol->value.integer.value[0],
+					      ucontrol->value.integer.value[1]);
+		change = 1;
+	}
+
+	return change;
+}
+
 static int snd_mixer_boolean_info(snd_kcontrol_t *kcontrol, 
 				  snd_ctl_elem_info_t *uinfo)
 {
@@ -1600,7 +1947,7 @@
 	int reg = kcontrol->private_value;
 
 	if (reg == CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT)
-		ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_status_out;
+		ucontrol->value.integer.value[0] = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED);
 	else
 		ucontrol->value.integer.value[0] = chip->dsp_spos_instance->spdif_status_in;
 
@@ -1615,13 +1962,15 @@
 
 	switch (kcontrol->private_value) {
 	case CS46XX_MIXER_SPDIF_OUTPUT_ELEMENT:
-		change = chip->dsp_spos_instance->spdif_status_out;
+		down (&chip->spos_mutex);
+		change = (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED);
 		if (ucontrol->value.integer.value[0] && !change) 
 			cs46xx_dsp_enable_spdif_out(chip);
 		else if (change && !ucontrol->value.integer.value[0])
 			cs46xx_dsp_disable_spdif_out(chip);
 
-		res = (change != chip->dsp_spos_instance->spdif_status_out);
+		res = (change != (chip->dsp_spos_instance->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED));
+		up (&chip->spos_mutex);
 		break;
 	case CS46XX_MIXER_SPDIF_INPUT_ELEMENT:
 		change = chip->dsp_spos_instance->spdif_status_in;
@@ -1686,6 +2035,35 @@
 	return 0;
 }
 
+static int snd_cs46xx_iec958_ac3_mode_get(snd_kcontrol_t *kcontrol, 
+					  snd_ctl_elem_value_t *ucontrol) 
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	if (!ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) 
+		ucontrol->value.integer.value[0] = 1;
+	else
+		ucontrol->value.integer.value[0] = 0;
+
+	return 0;
+}
+
+static int snd_cs46xx_iec958_ac3_mode_put(snd_kcontrol_t *kcontrol, 
+                                      snd_ctl_elem_value_t *ucontrol) 
+{
+	cs46xx_t *chip = snd_kcontrol_chip(kcontrol);
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+	int old = ins->spdif_status_out;
+
+	if (ucontrol->value.integer.value[0]) 
+		ins->spdif_status_out |= DSP_SPDIF_STATUS_AC3_MODE;
+	else
+		ins->spdif_status_out &= ~DSP_SPDIF_STATUS_AC3_MODE;
+
+	return (old != ins->spdif_status_out);
+}
+
 static int snd_cs46xx_pcm_capture_put(snd_kcontrol_t *kcontrol, 
                                       snd_ctl_elem_value_t *ucontrol)
 {
@@ -1720,7 +2098,7 @@
 }
 
 /*
- *	Game Theatre XP card - EGPIO[0] is used to select SDPIF input optical or coaxial.
+ *	Game Theatre XP card - EGPIO[0] is used to select SPDIF input optical or coaxial.
  */ 
 static int snd_herc_spdif_select_put(snd_kcontrol_t *kcontrol, 
                                        snd_ctl_elem_value_t *ucontrol)
@@ -1818,13 +2196,13 @@
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "DAC Volume",
 	.info = snd_cs46xx_vol_info,
+#ifndef CONFIG_SND_CS46XX_NEW_DSP
 	.get = snd_cs46xx_vol_get,
 	.put = snd_cs46xx_vol_put,
-
-#ifndef CONFIG_SND_CS46XX_NEW_DSP
 	.private_value = BA1_PVOL,
 #else
-	.private_value = (MASTERMIX_SCB_ADDR + 0xE) << 2,
+	.get = snd_cs46xx_vol_dac_get,
+	.put = snd_cs46xx_vol_dac_put,
 #endif
 },
 
@@ -1865,6 +2243,13 @@
 },
 {
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name = "IEC 958 AC3 Mode Switch",
+	.info = snd_mixer_boolean_info,
+	.get = snd_cs46xx_iec958_ac3_mode_get,
+	.put = snd_cs46xx_iec958_ac3_mode_put,
+},
+{
+	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "IEC 958 Input Switch",
 	.info = snd_mixer_boolean_info,
 	.get = snd_cs46xx_iec958_get,
@@ -1875,8 +2260,8 @@
 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 	.name = "IEC 958 Input Volume",
 	.info = snd_cs46xx_vol_info,
-	.get = snd_cs46xx_vol_get,
-	.put = snd_cs46xx_vol_put,
+	.get = snd_cs46xx_vol_iec958_get,
+	.put = snd_cs46xx_vol_iec958_put,
 	.private_value = (ASYNCRX_SCB_ADDR + 0xE) << 2,
 },
 #endif
@@ -1927,6 +2312,48 @@
 	.put = snd_herc_spdif_select_put,
 },
 };
+
+
+static void snd_cs46xx_sec_codec_reset (ac97_t * ac97)
+{
+	signed long end_time;
+	int err;
+
+	/* reset to defaults */
+	snd_ac97_write(ac97, AC97_RESET, 0);	
+
+	/* set codec in extended mode */
+	snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x3);
+
+	udelay(50);
+
+	/* it's necessary to wait awhile until registers are accessible after RESET */
+	/* because the PCM or MASTER volume registers can be modified, */
+	/* the REC_GAIN register is used for tests */
+	end_time = jiffies + HZ;
+	do {
+		unsigned short ext_mid;
+    
+		/* use preliminary reads to settle the communication */
+		snd_ac97_read(ac97, AC97_RESET);
+		snd_ac97_read(ac97, AC97_VENDOR_ID1);
+		snd_ac97_read(ac97, AC97_VENDOR_ID2);
+		/* modem? */
+		ext_mid = snd_ac97_read(ac97, AC97_EXTENDED_MID);
+		if (ext_mid != 0xffff && (ext_mid & 1) != 0)
+			return;
+
+		/* test if we can write to the record gain volume register */
+		snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a05);
+		if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05)
+			return;
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(HZ/100);
+	} while (time_after_eq(end_time, jiffies));
+
+	snd_printk("CS46xx secondary codec dont respond!\n");  
+}
 #endif
 
 int __devinit snd_cs46xx_mixer(cs46xx_t *chip)
@@ -2001,11 +2428,16 @@
 	/* well, one codec only ... */
 	goto _end;
  _ok2:
+	/* set secondary codec in extended mode */
+
+	/* use custom reset to set secondary codec in
+	   extended mode */
+	ac97.reset = snd_cs46xx_sec_codec_reset;
+
 	if ((err = snd_ac97_mixer(card, &ac97, &chip->ac97[CS46XX_SECONDARY_CODEC_INDEX])) < 0)
 		return err;
 	chip->nr_ac97_codecs = 2;
-    
-	/* add cs4630 mixer controls */
+
  _end:
 
 	/* dosoundcard specific mixer setup */
@@ -2016,6 +2448,7 @@
     
 #endif /* CONFIG_SND_CS46XX_NEW_DSP */
 
+	/* add cs4630 mixer controls */
 	for (idx = 0; idx < sizeof(snd_cs46xx_controls) / 
 		     sizeof(snd_cs46xx_controls[0]); idx++) {
 		snd_kcontrol_t *kctl;
@@ -2491,10 +2924,8 @@
 /*
  *  initialize chip
  */
-
 static int snd_cs46xx_chip_init(cs46xx_t *chip, int busywait)
 {
-	unsigned int tmp;
 	int timeout;
 
 	/* 
@@ -2581,6 +3012,11 @@
 	snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, CLKCR1_PLLP | CLKCR1_SWCE);
 
 	/*
+	 * Enable FIFO  Host Bypass
+	 */
+	snd_cs46xx_pokeBA0(chip, BA0_SERBCF, SERBCF_HBP);
+
+	/*
 	 *  Fill the serial port FIFOs with silence.
 	 */
 	snd_cs46xx_clear_serial_FIFOs(chip);
@@ -2598,6 +3034,7 @@
 	snd_cs46xx_pokeBA0(chip, BA0_SERC2, SERC2_SI1F_AC97 | SERC1_SO1EN);
 	snd_cs46xx_pokeBA0(chip, BA0_SERMC1, SERMC1_PTC_AC97 | SERMC1_MSPE);
 
+
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 	snd_cs46xx_pokeBA0(chip, BA0_SERC7, SERC7_ASDI2EN);
 	snd_cs46xx_pokeBA0(chip, BA0_SERC3, 0);
@@ -2608,6 +3045,7 @@
 
 	mdelay(5);
 
+
 	/*
 	 * Wait for the codec ready signal from the AC97 codec.
 	 */
@@ -2660,6 +3098,7 @@
 	snd_cs46xx_pokeBA0(chip, BA0_ACCTL2, ACCTL_VFRM | ACCTL_ESYN | ACCTL_RSTN);
 #endif
 
+
 	/*
 	 *  Wait until we've sampled input slots 3 and 4 as valid, meaning that
 	 *  the codec is pumping ADC data across the AC-link.
@@ -2688,7 +3127,10 @@
 	 *  Now, assert valid frame and the slot 3 and 4 valid bits.  This will
 	 *  commense the transfer of digital audio data to the AC97 codec.
 	 */
-	snd_cs46xx_pokeBA0(chip, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4 | ACOSV_SLV7 | ACOSV_SLV8);
+
+	snd_cs46xx_pokeBA0(chip, BA0_ACOSV, ACOSV_SLV3 | ACOSV_SLV4 | 
+			   ACOSV_SLV7 | ACOSV_SLV8);
+
 
 	/*
 	 *  Power down the DAC and ADC.  We will power them up (if) when we need
@@ -2703,13 +3145,21 @@
 	/* tmp = snd_cs46xx_peekBA0(chip, BA0_CLKCR1) & ~CLKCR1_SWCE; */
 	/* snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp); */
 
+	return 0;
+}
+
+/*
+ *  start and load DSP 
+ */
+int __devinit snd_cs46xx_start_dsp(cs46xx_t *chip)
+{	
+	unsigned int tmp;
 	/*
-         *  Reset the processor.
-         */
+	 *  Reset the processor.
+	 */
 	snd_cs46xx_reset(chip);
-
 	/*
-         *  Download the image to the processor.
+	 *  Download the image to the processor.
 	 */
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 #if 0
@@ -2741,7 +3191,6 @@
 
 	if (cs46xx_dsp_scb_and_task_init(chip) < 0)
 		return -EIO;
-	snd_printdd("[get here]\n");
 #else
 	/* old image */
 	if (snd_cs46xx_download_image(chip) < 0) {
@@ -2775,7 +3224,7 @@
 	 *  Enable interrupts on the part.
 	 */
 	snd_cs46xx_pokeBA0(chip, BA0_HICR, HICR_IEV | HICR_CHGM);
-
+        
 	tmp = snd_cs46xx_peek(chip, BA1_PFIE);
 	tmp &= ~0x0000f03f;
 	snd_cs46xx_poke(chip, BA1_PFIE, tmp);	/* playback interrupt enable */
@@ -2785,19 +3234,24 @@
 	tmp |=  0x00000001;
 	snd_cs46xx_poke(chip, BA1_CIE, tmp);	/* capture interrupt enable */
 	
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
 	/* set the attenuation to 0dB */ 
-	snd_cs46xx_poke(chip, BA1_PVOL, 0x80008000);
-	snd_cs46xx_poke(chip, BA1_CVOL, 0x80008000);
+	snd_cs46xx_poke(chip, (MASTERMIX_SCB_ADDR + 0xE) << 2, 0x80008000); 
+	snd_cs46xx_poke(chip, (VARIDECIMATE_SCB_ADDR + 0xE) << 2, 0x80008000);
+
+	/*
+	 * Initialize cs46xx SPDIF controller
+	 */
 
-#ifdef CONFIG_SND_CS46XX_NEW_DSP
 	/* time countdown enable */
 	cs46xx_poke_via_dsp (chip,SP_ASER_COUNTDOWN, 0x80000000);
-        
+
 	/* SPDIF input MASTER ENABLE */
 	cs46xx_poke_via_dsp (chip,SP_SPDIN_CONTROL, 0x800003ff);
-
-	/* mute spdif out */
-	cs46xx_dsp_disable_spdif_out(chip);
+#else
+	/* set the attenuation to 0dB */ 
+	snd_cs46xx_poke(chip, BA1_PVOL, 0x80008000);
+	snd_cs46xx_poke(chip, BA1_CVOL, 0x80008000);
 #endif
 
 	return 0;
@@ -2812,15 +3266,26 @@
 {	
 }
 
-
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
 static int voyetra_setup_eapd_slot(cs46xx_t *chip)
 {
-	int i;
-	u32 idx;
-	u16 modem_power,pin_config,logic_type,valid_slots,status;
+	
+	u32 idx, valid_slots,tmp,powerdown = 0;
+	u16 modem_power,pin_config,logic_type;
+
+	snd_printdd ("cs46xx: cs46xx_setup_eapd_slot()+\n");
+
+	/*
+	 *  See if the devices are powered down.  If so, we must power them up first
+	 *  or they will not respond.
+	 */
+	tmp = snd_cs46xx_peekBA0(chip, BA0_CLKCR1);
+
+	if (!(tmp & CLKCR1_SWCE)) {
+		snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp | CLKCR1_SWCE);
+		powerdown = 1;
+	}
 
-	snd_printd ("cs46xx: cs46xx_setup_eapd_slot()+\n");
 	/*
 	 * Clear PRA.  The Bonzo chip will be used for GPIO not for modem
 	 * stuff.
@@ -2831,45 +3296,50 @@
 	}
 
 	modem_power = snd_cs46xx_codec_read (chip, 
-					     BA0_AC97_EXT_MODEM_POWER,
+					     AC97_EXTENDED_MSTATUS,
 					     CS46XX_SECONDARY_CODEC_INDEX);
 	modem_power &=0xFEFF;
 
 	snd_cs46xx_codec_write(chip, 
-			       BA0_AC97_EXT_MODEM_POWER, modem_power,
+			       AC97_EXTENDED_MSTATUS, modem_power,
 			       CS46XX_SECONDARY_CODEC_INDEX);
 
 	/*
 	 * Set GPIO pin's 7 and 8 so that they are configured for output.
 	 */
 	pin_config = snd_cs46xx_codec_read (chip, 
-					    BA0_AC97_GPIO_PIN_CONFIG,
+					    AC97_GPIO_CFG,
 					    CS46XX_SECONDARY_CODEC_INDEX);
 	pin_config &=0x27F;
 
 	snd_cs46xx_codec_write(chip, 
-			       BA0_AC97_GPIO_PIN_CONFIG, pin_config,
+			       AC97_GPIO_CFG, pin_config,
 			       CS46XX_SECONDARY_CODEC_INDEX);
     
 	/*
 	 * Set GPIO pin's 7 and 8 so that they are compatible with CMOS logic.
 	 */
 
-	logic_type = snd_cs46xx_codec_read(chip, BA0_AC97_GPIO_PIN_TYPE,
+	logic_type = snd_cs46xx_codec_read(chip, AC97_GPIO_POLARITY,
 					   CS46XX_SECONDARY_CODEC_INDEX);
 	logic_type &=0x27F;
-	snd_cs46xx_codec_write (chip, BA0_AC97_GPIO_PIN_TYPE, logic_type,
+	snd_cs46xx_codec_write (chip, AC97_GPIO_POLARITY, logic_type,
 				CS46XX_SECONDARY_CODEC_INDEX);
 
 	valid_slots = snd_cs46xx_peekBA0(chip, BA0_ACOSV);
 	valid_slots |= 0x200;
 	snd_cs46xx_pokeBA0(chip, BA0_ACOSV, valid_slots);
 
+	if ( cs46xx_wait_for_fifo(chip,1) ) {
+	  snd_printdd("FIFO is busy\n");
+	  
+	  return -EINVAL;
+	}
+
 	/*
 	 * Fill slots 12 with the correct value for the GPIO pins. 
 	 */
 	for(idx = 0x90; idx <= 0x9F; idx++) {
-
 		/*
 		 * Initialize the fifo so that bits 7 and 8 are on.
 		 *
@@ -2877,25 +3347,16 @@
 		 * the left.  0x1800 corresponds to bits 7 and 8.
 		 */
 		snd_cs46xx_pokeBA0(chip, BA0_SERBWP, 0x1800);
-      
+
 		/*
-		 * Make sure the previous FIFO write operation has completed.
+		 * Wait for command to complete
 		 */
-		for(i = 0; i < 5; i++){
-			status = snd_cs46xx_peekBA0(chip, BA0_SERBST);
+		if ( cs46xx_wait_for_fifo(chip,200) ) {
+			snd_printdd("failed waiting for FIFO at addr (%02X)\n",idx);
 
-			if( !(status & SERBST_WBSY) ) {
-				break;
-			}
-			mdelay(100);
-		}
-
-		if(status & SERBST_WBSY) {
-			snd_printk( KERN_ERR "cs46xx: cs46xx_setup_eapd_slot() " \
-				    "Failure to write the GPIO pins for slot 12.\n");
 			return -EINVAL;
 		}
-      
+            
 		/*
 		 * Write the serial port FIFO index.
 		 */
@@ -2907,6 +3368,16 @@
 		snd_cs46xx_pokeBA0(chip, BA0_SERBCM, SERBCM_WRC);
 	}
 
+	/* wait for last command to complete */
+	cs46xx_wait_for_fifo(chip,200);
+
+	/*
+	 *  Now, if we powered up the devices, then power them back down again.
+	 *  This is kinda ugly, but should never happen.
+	 */
+	if (powerdown)
+		snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp);
+
 	return 0;
 }
 #endif
@@ -2981,6 +3452,18 @@
 	}
 }
 
+static void voyetra_mixer_init (cs46xx_t *chip)
+{
+	snd_printdd ("initializing Voyetra mixer\n");
+
+	/* turnon Amplifier and leave it on */
+	chip->amplifier_ctrl(chip, 1);
+  
+	/* Enable SPDIF out */
+	snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, EGPIODR_GPOE0);
+	snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, EGPIODR_GPOE0);
+}
+
 static void hercules_mixer_init (cs46xx_t *chip)
 {
 #ifdef CONFIG_SND_CS46XX_NEW_DSP
@@ -3113,7 +3596,7 @@
 
 static struct cs_card_type __initdata cards[] = {
 	{0x1489, 0x7001, "Genius Soundmaker 128 value", NULL, amp_none, NULL, NULL},
-	{0x5053, 0x3357, "Voyetra", NULL, amp_voyetra, NULL, NULL},
+	{0x5053, 0x3357, "Voyetra", NULL, amp_voyetra, NULL, voyetra_mixer_init},
 	{0x1071, 0x6003, "Mitac MI6020/21", NULL, amp_voyetra, NULL, NULL},
 	{0x14AF, 0x0050, "Hercules Game Theatre XP", NULL, amp_hercules, NULL, hercules_mixer_init},
 	{0x1681, 0x0050, "Hercules Game Theatre XP", NULL, amp_hercules, NULL, hercules_mixer_init},
@@ -3286,7 +3769,7 @@
 
 	for (cp = &cards[0]; cp->name; cp++) {
 		if (cp->vendor == ss_vendor && cp->id == ss_card) {
-			snd_printd("hack for %s enabled\n", cp->name);
+			snd_printd ("hack for %s enabled\n", cp->name);
 			if (cp->init)
 				cp->init(chip);
 			chip->amplifier_ctrl = cp->amp;
@@ -3362,7 +3845,7 @@
 		snd_cs46xx_free(chip);
 		return err;
 	}
-
+	
 	chip->active_ctrl(chip, -1);
 
 	*rchip = chip;
diff -Nru a/sound/pci/cs46xx/cs46xx_lib.h b/sound/pci/cs46xx/cs46xx_lib.h
--- a/sound/pci/cs46xx/cs46xx_lib.h	Sun Nov 10 19:28:37 2002
+++ b/sound/pci/cs46xx/cs46xx_lib.h	Sun Nov 10 19:28:37 2002
@@ -35,9 +35,17 @@
 #define CS46XX_BA1_REG_SIZE	  0x0100
 
 
-#define CS46XX_PERIOD_SIZE 2048
+
+#ifdef CONFIG_SND_CS46XX_NEW_DSP
+#define CS46XX_MIN_PERIOD_SIZE 1
+#define CS46XX_MAX_PERIOD_SIZE 1024*1024
+#else
+#define CS46XX_MIN_PERIOD_SIZE 2048
+#define CS46XX_MAX_PERIOD_SIZE 2048
+#endif
+
 #define CS46XX_FRAGS 2
-#define CS46XX_BUFFER_SIZE CS46XX_PERIOD_SIZE * CS46XX_FRAGS
+/* #define CS46XX_BUFFER_SIZE CS46XX_MAX_PERIOD_SIZE * CS46XX_FRAGS */
 
 #define SCB_NO_PARENT             0
 #define SCB_ON_PARENT_NEXT_SCB    1
@@ -51,6 +59,10 @@
 extern snd_pcm_ops_t snd_cs46xx_playback_indirect_ops;
 extern snd_pcm_ops_t snd_cs46xx_capture_ops;
 extern snd_pcm_ops_t snd_cs46xx_capture_indirect_ops;
+extern snd_pcm_ops_t snd_cs46xx_playback_rear_ops;
+extern snd_pcm_ops_t snd_cs46xx_playback_indirect_rear_ops;
+extern snd_pcm_ops_t snd_cs46xx_playback_iec958_ops;
+extern snd_pcm_ops_t snd_cs46xx_playback_indirect_iec958_ops;
 
 
 /*
@@ -96,6 +108,7 @@
                                             unsigned long len);
 int                    snd_cs46xx_clear_BA1(cs46xx_t *chip,unsigned long offset,unsigned long len);
 int                    cs46xx_dsp_enable_spdif_out (cs46xx_t *chip);
+int                    cs46xx_dsp_enable_spdif_hw (cs46xx_t *chip);
 int                    cs46xx_dsp_disable_spdif_out (cs46xx_t *chip);
 int                    cs46xx_dsp_enable_spdif_in (cs46xx_t *chip);
 int                    cs46xx_dsp_disable_spdif_in (cs46xx_t *chip);
@@ -185,7 +198,8 @@
                                                           dsp_scb_descriptor_t * snoop_scb,
                                                           dsp_scb_descriptor_t * parent_scb,
                                                           int scb_child_type);
-pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sample_rate, void * private_data, u32 hw_dma_addr);
+pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sample_rate, void * private_data, u32 hw_dma_addr,
+                                                          int pcm_channel_id);
 void                       cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,
                                                            pcm_channel_descriptor_t * pcm_channel);
 void                       cs46xx_dsp_set_src_sample_rate(cs46xx_t * chip,dsp_scb_descriptor_t * src, 
@@ -194,6 +208,15 @@
 int                        cs46xx_dsp_pcm_link (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel);
 dsp_scb_descriptor_t *     cs46xx_add_record_source (cs46xx_t *chip,dsp_scb_descriptor_t * source,
                                                      u16 addr,char * scb_name);
-int                         cs46xx_src_unlink(cs46xx_t *chip,dsp_scb_descriptor_t * src);
-int                         cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src);
+int                        cs46xx_src_unlink(cs46xx_t *chip,dsp_scb_descriptor_t * src);
+int                        cs46xx_src_link(cs46xx_t *chip,dsp_scb_descriptor_t * src);
+int                        cs46xx_iec958_pre_open (cs46xx_t *chip);
+int                        cs46xx_iec958_post_close (cs46xx_t *chip);
+int                        cs46xx_dsp_pcm_channel_set_period (cs46xx_t * chip,
+							       pcm_channel_descriptor_t * pcm_channel,
+							       int period_size);
+int                        cs46xx_dsp_pcm_ostream_set_period (cs46xx_t * chip,
+							      int period_size);
+int                        cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 right,u16 left);
+int                        cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 right,u16 left);
 #endif /* __CS46XX_LIB_H__ */
diff -Nru a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c
--- a/sound/pci/cs46xx/dsp_spos.c	Sun Nov 10 19:28:41 2002
+++ b/sound/pci/cs46xx/dsp_spos.c	Sun Nov 10 19:28:41 2002
@@ -257,7 +257,10 @@
 	ins->spdif_in_sample_rate = 48000;
 
 	/* maximize volume */
-	ins->spdif_input_volume = 0x80008000;
+	ins->dac_volume_right = 0x8000;
+	ins->dac_volume_left = 0x8000;
+	ins->spdif_input_volume_right = 0x8000;
+	ins->spdif_input_volume_left = 0x8000;
 
 	return ins;
 }
@@ -1017,11 +1020,10 @@
 	dsp_scb_descriptor_t * codec_in_scb;
 	dsp_scb_descriptor_t * src_task_scb;
 	dsp_scb_descriptor_t * master_mix_scb;
+	dsp_scb_descriptor_t * rear_mix_scb;
 	dsp_scb_descriptor_t * record_mix_scb;
 	dsp_scb_descriptor_t * write_back_scb;
 	dsp_scb_descriptor_t * vari_decimate_scb;
-	dsp_scb_descriptor_t * pcm_serial_input_task;
-	dsp_scb_descriptor_t * asynch_tx_scb;
 	dsp_scb_descriptor_t * sec_codec_out_scb;
 	dsp_scb_descriptor_t * magic_snoop_scb;
 
@@ -1095,6 +1097,7 @@
 		ins->the_null_scb->sub_list_ptr = ins->the_null_scb;
 		ins->the_null_scb->next_scb_ptr = ins->the_null_scb;
 		ins->the_null_scb->parent_scb_ptr = NULL;
+		cs46xx_dsp_proc_register_scb_desc (chip,ins->the_null_scb);
 	}
 
 	{
@@ -1264,9 +1267,9 @@
 
 	/* create codec in */
 	codec_in_scb = cs46xx_dsp_create_codec_in_scb(chip,"CodecInSCB",0x0010,0x00A0,
-                                                  CODEC_INPUT_BUF1,
-                                                  CODECIN_SCB_ADDR,codec_out_scb,
-                                                  SCB_ON_PARENT_NEXT_SCB);
+						      CODEC_INPUT_BUF1,
+						      CODECIN_SCB_ADDR,codec_out_scb,
+						      SCB_ON_PARENT_NEXT_SCB);
 	if (!codec_in_scb) goto _fail_end;
 	ins->codec_in_scb = codec_in_scb;
 
@@ -1309,46 +1312,38 @@
 
 	/* create secondary CODEC output */
 	sec_codec_out_scb = cs46xx_dsp_create_codec_out_scb(chip,"CodecOutSCB_II",0x0010,0x0040,
-							    OUTPUTSNOOP_SCB_ADDR,
+							    REAR_MIXER_SCB_ADDR,
 							    SEC_CODECOUT_SCB_ADDR,codec_in_scb,
 							    SCB_ON_PARENT_NEXT_SCB);
 	if (!sec_codec_out_scb) goto _fail_end;
 
+
+	/* create the rear PCM channel  mixer SCB */
+	rear_mix_scb = cs46xx_dsp_create_mix_only_scb(chip,"RearMixerSCB",
+						      MIX_SAMPLE_BUF3,
+						      REAR_MIXER_SCB_ADDR,
+						      sec_codec_out_scb,
+						      SCB_ON_PARENT_SUBLIST_SCB);
+	ins->rear_mix_scb = rear_mix_scb;
+	if (!rear_mix_scb) goto _fail_end;
+
 	/* the magic snooper */
 	magic_snoop_scb = cs46xx_dsp_create_magic_snoop_scb (chip,"MagicSnoopSCB_I",OUTPUTSNOOP_SCB_ADDR,
 							     OUTPUT_SNOOP_BUFFER,
 							     codec_out_scb,
 							     sec_codec_out_scb,
-							     SCB_ON_PARENT_SUBLIST_SCB);
+							     SCB_ON_PARENT_NEXT_SCB);
 
+    
 	if (!magic_snoop_scb) goto _fail_end;
 	ins->ref_snoop_scb = magic_snoop_scb;
 
-
-	/* The asynch. transfer task */
-	asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
-							   SPDIFO_SCB_INST,
-							   SPDIFO_IP_OUTPUT_BUFFER1,
-							   magic_snoop_scb,
-							   SCB_ON_PARENT_NEXT_SCB);
-
-	if (!asynch_tx_scb) goto _fail_end;
-
-	/* pcm input */
-	pcm_serial_input_task = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
-								       PCMSERIALINII_SCB_ADDR,
-								       magic_snoop_scb,asynch_tx_scb,
-								       SCB_ON_PARENT_SUBLIST_SCB);
-  
-	if (!pcm_serial_input_task) goto _fail_end;
-
 	/* SP IO access */
 	if (!cs46xx_dsp_create_spio_write_scb(chip,"SPIOWriteSCB",SPIOWRITE_SCB_ADDR,
-					      asynch_tx_scb,
+					      magic_snoop_scb,
 					      SCB_ON_PARENT_NEXT_SCB))
 		goto _fail_end;
 
-
 	/* SPDIF input sampel rate converter */
 	src_task_scb = cs46xx_dsp_create_src_task_scb(chip,"SrcTaskSCB_SPDIFI",
 						      SRC_OUTPUT_BUF1,
@@ -1505,6 +1500,7 @@
 		};
 
 		spdifo_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFOSCB",(u32 *)&spdifo_scb,SPDIFO_SCB_INST);
+
 		snd_assert(spdifo_scb_desc, return -EIO);
 		spdifi_scb_desc = cs46xx_dsp_create_scb(chip,"SPDIFISCB",(u32 *)&spdifi_scb,SPDIFI_SCB_INST);
 		snd_assert(spdifi_scb_desc, return -EIO);
@@ -1530,6 +1526,11 @@
 		   is the FG task tree */
 		fg_entry->parent_scb_ptr = spdifo_scb_desc;
 
+		/* for proc fs */
+		cs46xx_dsp_proc_register_scb_desc (chip,spdifo_scb_desc);
+		cs46xx_dsp_proc_register_scb_desc (chip,spdifi_scb_desc);
+		cs46xx_dsp_proc_register_scb_desc (chip,async_codec_scb_desc);
+
 		/* Async MASTER ENABLE, affects both SPDIF input and output */
 		snd_cs46xx_pokeBA0(chip, BA0_ASER_MASTER, 0x1 );
 	}
@@ -1537,7 +1538,7 @@
 	return 0;
 }
 
-int cs46xx_dsp_enable_spdif_out (cs46xx_t *chip)
+int cs46xx_dsp_enable_spdif_hw (cs46xx_t *chip)
 {
 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
 
@@ -1547,29 +1548,11 @@
 	/* SPDIF output MASTER ENABLE */
 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x80000000);
 
-	/* right and left validate bit 
-	   NOTE: 0x80000000 and enables the SCMC protection on stream 
-	*/
+	/* right and left validate bit */
 	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12));
 
 	/* monitor state */
-	ins->spdif_status_out = 1;
-
-	return 0;
-}
-
-int  cs46xx_dsp_disable_spdif_out (cs46xx_t *chip)
-{
-	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
-
-	/* disable  SPDIF output FIFO slot */
-	snd_cs46xx_pokeBA0(chip, BA0_ASER_FADDR, 0);
-
-	/* SPDIF output MASTER DISABLE */
-	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CONTROL, 0x0);
-
-	/* monitor state */
-	ins->spdif_status_out = 0;
+	ins->spdif_status_out |= DSP_SPDIF_STATUS_HW_ENABLED;
 
 	return 0;
 }
@@ -1605,8 +1588,10 @@
 	cs46xx_src_link(chip,ins->spdif_in_src);
 
 	/* restore SPDIF input volume */
-	snd_cs46xx_poke(chip, (ASYNCRX_SCB_ADDR + 0xE) << 2, ins->spdif_input_volume);
-	snd_cs46xx_poke(chip, (ASYNCRX_SCB_ADDR + 0xF) << 2, ins->spdif_input_volume);
+	cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,
+				   ins->spdif_input_volume_right,
+				   ins->spdif_input_volume_left);
+
 	spin_unlock_irq(&chip->reg_lock);
 
 	/* set SPDIF input sample rate and unmute
@@ -1736,6 +1721,44 @@
 		snd_printk(KERN_ERR "dsp_spos: SPIOWriteTask not responding\n");
 		return -EBUSY;
 	}
+
+	return 0;
+}
+
+int cs46xx_dsp_set_dac_volume (cs46xx_t * chip,u16 right,u16 left)
+{
+	int i;
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	down(&chip->spos_mutex);
+
+	ins->dac_volume_right = right;
+	ins->dac_volume_left = left;
+
+	for (i = 0; i < DSP_MAX_PCM_CHANNELS; ++i) {
+		if (ins->pcm_channels[i].active &&
+		    !ins->pcm_channels[i].unlinked) {
+			cs46xx_dsp_scb_set_volume (chip,ins->pcm_channels[i].pcm_reader_scb,
+						   right,left);
+			
+		}
+	}
+
+	up(&chip->spos_mutex);
+
+	return 0;
+}
+
+int cs46xx_dsp_set_iec958_volume (cs46xx_t * chip,u16 right,u16 left) {
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	down(&chip->spos_mutex);
+	cs46xx_dsp_scb_set_volume (chip,ins->spdif_in_src,
+				   right,left);
+
+	ins->spdif_input_volume_right = right;
+	ins->spdif_input_volume_left = left;
+	up(&chip->spos_mutex);
 
 	return 0;
 }
diff -Nru a/sound/pci/cs46xx/dsp_spos.h b/sound/pci/cs46xx/dsp_spos.h
--- a/sound/pci/cs46xx/dsp_spos.h	Sun Nov 10 19:28:36 2002
+++ b/sound/pci/cs46xx/dsp_spos.h	Sun Nov 10 19:28:36 2002
@@ -73,7 +73,10 @@
 #define SPDIFI_IP_OUTPUT_BUFFER1 0x0E00
 #define SPDIFO_IP_OUTPUT_BUFFER1 0x1000
 #define MIX_SAMPLE_BUF1          0x1400
-#define MIX_SAMPLE_BUF2          0x3000
+#define MIX_SAMPLE_BUF2          0x2D00
+#define MIX_SAMPLE_BUF3          0x2E00
+#define MIX_SAMPLE_BUF4          0x2F00
+#define MIX_SAMPLE_BUF5          0x3000
 
 /* Task stack address */
 #define HFG_STACK                0x066A
@@ -104,6 +107,8 @@
 #define OUTPUTSNOOPII_SCB_ADDR   0x150
 #define PCMSERIALIN_PCM_SCB_ADDR 0x160
 #define RECORD_MIXER_SCB_ADDR    0x170
+#define REAR_MIXER_SCB_ADDR      0x180
+#define SPDIF_MIXER_SCB_ADDR     0x190
 
 /* hyperforground SCB's*/
 #define HFG_TREE_SCB             0xBA0
@@ -123,6 +128,7 @@
 #define SCBfuncEntryPtr      0xA
 #define SRCCorPerGof         0x2
 #define SRCPhiIncr6Int26Frac 0xd
+#define SCBVolumeCtrl        0xe
 
 /* conf */
 #define UseASER1Input 1
@@ -178,6 +184,23 @@
 #define SP_SPDOUT_STATUS  0x804C
 #define SP_SPDOUT_CONTROL 0x804D
 #define SP_SPDOUT_CSUV    0x808E
+
+static inline void cs46xx_dsp_spos_update_scb (cs46xx_t * chip,dsp_scb_descriptor_t * scb) 
+{
+	/* update nextSCB and subListPtr in SCB */
+	snd_cs46xx_poke(chip,
+			(scb->address + SCBsubListPtr) << 2,
+			(scb->sub_list_ptr->address << 0x10) |
+			(scb->next_scb_ptr->address));	
+}
+
+static inline void cs46xx_dsp_scb_set_volume (cs46xx_t * chip,dsp_scb_descriptor_t * scb,
+					      u16 right,u16 left) {
+	unsigned int val = ((0xffff - right) << 16 | (0xffff - left));	
+
+	snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val);
+	snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val);
+}
 
 #endif /* __DSP_SPOS_H__ */
 #endif /* CONFIG_SND_CS46XX_NEW_DSP  */
diff -Nru a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c
--- a/sound/pci/cs46xx/dsp_spos_scb_lib.c	Sun Nov 10 19:28:41 2002
+++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c	Sun Nov 10 19:28:41 2002
@@ -150,17 +150,11 @@
 		spin_lock_irqsave(&chip->reg_lock, flags);    
 
 		/* update parent first entry in DSP RAM */
-		snd_cs46xx_poke(chip,
-				(scb->parent_scb_ptr->address + SCBsubListPtr) << 2,
-				(scb->parent_scb_ptr->sub_list_ptr->address << 0x10) |
-				(scb->parent_scb_ptr->next_scb_ptr->address));
+		cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
 
 		/* then update entry in DSP RAM */
-		snd_cs46xx_poke(chip,
-				(scb->address + SCBsubListPtr) << 2,
-				(scb->sub_list_ptr->address << 0x10) |
-				(scb->next_scb_ptr->address));
-    
+		cs46xx_dsp_spos_update_scb(chip,scb);
+
 		scb->parent_scb_ptr = NULL;
 		spin_unlock_irqrestore(&chip->reg_lock, flags);
 	}
@@ -173,6 +167,7 @@
   
 	for (i = 0; i < dword_count ; ++i ) {
 		writel(0, dst);
+		dst += 4;
 	}  
 }
 
@@ -328,11 +323,9 @@
 		}
 
 		spin_lock_irqsave(&chip->reg_lock, flags);
+
 		/* update entry in DSP RAM */
-		snd_cs46xx_poke(chip,
-				(scb->parent_scb_ptr->address + SCBsubListPtr) << 2,
-				(scb->parent_scb_ptr->sub_list_ptr->address << 0x10) |
-				(scb->parent_scb_ptr->next_scb_ptr->address));
+		cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr);
 
 		spin_unlock_irqrestore(&chip->reg_lock, flags);
 	}
@@ -610,7 +603,7 @@
 		src_buffer_addr << 0x10,
 		0x04000000,
 		{ 
-			0xffff,0xffff,
+			0x8000,0x8000,
 			0xffff,0xffff
 		}
 	};
@@ -665,7 +658,7 @@
 		/* D */ 0,
 		{
 			/* E */ 0x8000,0x8000,
-			/* F */ 0x8000,0x8000
+			/* F */ 0xffff,0xffff
 		}
 	};
 
@@ -832,7 +825,7 @@
 		0x0058,0x0028,      /* Min Delta 7 dwords == 28 bytes */
 		/* : Max delta 25 dwords == 100 bytes */
 		0,hfg_scb_address,  /* Point to HFG task SCB */
-		0,0,				/* Initialize current Delta and Consumer ptr adjustment count */
+		0,0,		    /* Initialize current Delta and Consumer ptr adjustment count */
 		0,                  /* Initialize accumulated Phi to 0 */
 		0,0x2aab,           /* Const 1/3 */
     
@@ -847,13 +840,13 @@
     
 		RSCONFIG_SAMPLE_16STEREO + RSCONFIG_MODULO_256, /* Stereo, 256 dword */
 		(asynch_buffer_address) << 0x10,  /* This should be automagically synchronized
-                                             to the producer pointer */
+                                                     to the producer pointer */
     
 		/* There is no correct initial value, it will depend upon the detected
 		   rate etc  */
 		0x18000000,                     /* Phi increment for approx 32k operation */
 		0x8000,0x8000,                  /* Volume controls are unused at this time */
-		0x8000,0x8000
+		0xffff,0xffff
 	};
   
 	scb = cs46xx_dsp_create_generic_scb(chip,scb_name,(u32 *)&asynch_fg_tx_scb,
@@ -1093,15 +1086,46 @@
 };
 
 
-pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,u32 sample_rate, void * private_data, u32 hw_dma_addr)
+pcm_channel_descriptor_t * cs46xx_dsp_create_pcm_channel (cs46xx_t * chip,
+                                                          u32 sample_rate, void * private_data, 
+                                                          u32 hw_dma_addr,
+                                                          int pcm_channel_id)
 {
 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
-	dsp_scb_descriptor_t * src_scb = NULL,* pcm_scb;
+	dsp_scb_descriptor_t * src_scb = NULL,* pcm_scb, * mixer_scb = NULL;
 	/*dsp_scb_descriptor_t * pcm_parent_scb;*/
 	char scb_name[DSP_MAX_SCB_NAME];
 	int i,pcm_index = -1, insert_point, src_index = -1;
 	unsigned long flags;
 
+	switch (pcm_channel_id) {
+	case DSP_PCM_MAIN_CHANNEL:
+		mixer_scb = ins->master_mix_scb;
+		break;
+	case DSP_PCM_REAR_CHANNEL:
+		mixer_scb = ins->rear_mix_scb;
+		break;
+	case DSP_PCM_CENTER_CHANNEL:
+		/* TODO */
+		snd_assert(0);
+		break;
+	case DSP_PCM_LFE_CHANNEL:
+		/* TODO */
+		snd_assert(0);
+		break;
+	case DSP_IEC958_CHANNEL:
+		snd_assert (ins->asynch_tx_scb != NULL, return NULL);
+		mixer_scb = ins->asynch_tx_scb;
+		if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) {
+			snd_printdd ("IEC958 opened in AC3 mode\n");
+			/*src_scb = ins->asynch_tx_scb;
+			  ins->asynch_tx_scb->ref_count ++;*/
+		}
+		break;
+	default:
+		snd_assert (0);
+		return NULL;
+	}
 	/* default sample rate is 44100 */
 	if (!sample_rate) sample_rate = 44100;
 
@@ -1114,7 +1138,9 @@
 		if (i == CS46XX_DSP_CAPTURE_CHANNEL) continue;
 
 		if (ins->pcm_channels[i].active) {
-			if (!src_scb && ins->pcm_channels[i].sample_rate == sample_rate) {
+			if (!src_scb && 
+			    ins->pcm_channels[i].sample_rate == sample_rate &&
+			    ins->pcm_channels[i].mixer_scb == mixer_scb) {
 				src_scb = ins->pcm_channels[i].src_scb;
 				ins->pcm_channels[i].src_scb->ref_count ++;
 				src_index = ins->pcm_channels[i].src_slot;
@@ -1148,11 +1174,11 @@
 		snd_assert (src_index != -1,return NULL);
 
 		/* we need to create a new SRC SCB */
-		if (ins->master_mix_scb->sub_list_ptr == ins->the_null_scb) {
-			src_parent_scb = ins->master_mix_scb;
+		if (mixer_scb->sub_list_ptr == ins->the_null_scb) {
+			src_parent_scb = mixer_scb;
 			insert_point = SCB_ON_PARENT_SUBLIST_SCB;
 		} else {
-			src_parent_scb = find_next_free_scb(chip,ins->master_mix_scb->sub_list_ptr);
+			src_parent_scb = find_next_free_scb(chip,mixer_scb->sub_list_ptr);
 			insert_point = SCB_ON_PARENT_NEXT_SCB;
 		}
 
@@ -1172,7 +1198,9 @@
 			return NULL;
 		}
 
-		cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate);
+		if (pcm_channel_id != DSP_IEC958_CHANNEL ||
+		    !(ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE))
+			cs46xx_dsp_set_src_sample_rate(chip,src_scb,sample_rate);
 
 		ins->nsrc_scb ++;
 	} 
@@ -1180,7 +1208,8 @@
   
 	snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index);
 
-	snd_printdd( "dsp_spos: creating PCM \"%s\"\n",scb_name);
+	snd_printdd( "dsp_spos: creating PCM \"%s\" (%d)\n",scb_name,
+                 pcm_channel_id);
 
 	pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name,
 						   pcm_reader_buffer_addr[pcm_index],
@@ -1206,12 +1235,91 @@
 	ins->pcm_channels[pcm_index].src_slot = src_index;
 	ins->pcm_channels[pcm_index].active = 1;
 	ins->pcm_channels[pcm_index].pcm_slot = pcm_index;
+	ins->pcm_channels[pcm_index].mixer_scb = mixer_scb;
+	ins->pcm_channels[pcm_index].pcm_channel_id = pcm_channel_id;
 	ins->npcm_channels ++;
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 
 	return (ins->pcm_channels + pcm_index);
 }
 
+int cs46xx_dsp_pcm_channel_set_period (cs46xx_t * chip,
+				       pcm_channel_descriptor_t * pcm_channel,
+				       int period_size)
+{
+	u32 temp = snd_cs46xx_peek (chip,pcm_channel->pcm_reader_scb->address << 2);
+	temp &= ~DMA_RQ_C1_SOURCE_SIZE_MASK;
+
+	switch (period_size) {
+	case 2048:
+		temp |= DMA_RQ_C1_SOURCE_MOD1024;
+		break;
+	case 1024:
+		temp |= DMA_RQ_C1_SOURCE_MOD512;
+		break;
+	case 512:
+		temp |= DMA_RQ_C1_SOURCE_MOD256;
+		break;
+	case 256:
+		temp |= DMA_RQ_C1_SOURCE_MOD128;
+		break;
+	case 128:
+		temp |= DMA_RQ_C1_SOURCE_MOD64;
+		break;
+	case 64:
+		temp |= DMA_RQ_C1_SOURCE_MOD32;
+		break;		      
+	case 32:
+		temp |= DMA_RQ_C1_SOURCE_MOD16;
+		break; 
+	default:
+		snd_printdd ("period size (%d) not supported by HW\n");
+		return -EINVAL;
+	}
+
+	snd_cs46xx_poke (chip,pcm_channel->pcm_reader_scb->address << 2,temp);
+
+	return 0;
+}
+
+int cs46xx_dsp_pcm_ostream_set_period (cs46xx_t * chip,
+				       int period_size)
+{
+	u32 temp = snd_cs46xx_peek (chip,WRITEBACK_SCB_ADDR << 2);
+	temp &= ~DMA_RQ_C1_DEST_SIZE_MASK;
+
+	switch (period_size) {
+	case 2048:
+		temp |= DMA_RQ_C1_DEST_MOD1024;
+		break;
+	case 1024:
+		temp |= DMA_RQ_C1_DEST_MOD512;
+		break;
+	case 512:
+		temp |= DMA_RQ_C1_DEST_MOD256;
+		break;
+	case 256:
+		temp |= DMA_RQ_C1_DEST_MOD128;
+		break;
+	case 128:
+		temp |= DMA_RQ_C1_DEST_MOD64;
+		break;
+	case 64:
+		temp |= DMA_RQ_C1_DEST_MOD32;
+		break;		      
+	case 32:
+		temp |= DMA_RQ_C1_DEST_MOD16;
+		break; 
+	default:
+		snd_printdd ("period size (%d) not supported by HW\n");
+		return -EINVAL;
+	}
+
+	snd_cs46xx_poke (chip,WRITEBACK_SCB_ADDR << 2,temp);
+
+	return 0;
+}
+
 void cs46xx_dsp_destroy_pcm_channel (cs46xx_t * chip,pcm_channel_descriptor_t * pcm_channel)
 {
 	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
@@ -1293,17 +1401,13 @@
 	snd_assert (pcm_channel->pcm_reader_scb->parent_scb_ptr == NULL, ; );
 	pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb;
 
-	/* update entry in DSP RAM */
 	spin_lock_irqsave(&chip->reg_lock, flags);
-	snd_cs46xx_poke(chip,
-			(pcm_channel->pcm_reader_scb->address + SCBsubListPtr) << 2,
-			(pcm_channel->pcm_reader_scb->sub_list_ptr->address << 0x10) |
-			(pcm_channel->pcm_reader_scb->next_scb_ptr->address));
-    
-	snd_cs46xx_poke(chip,
-			(parent_scb->address + SCBsubListPtr) << 2,
-			(parent_scb->sub_list_ptr->address << 0x10) |
-			(parent_scb->next_scb_ptr->address));
+
+	/* update SCB entry in DSP RAM */
+	cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb);
+
+	/* update parent SCB entry */
+	cs46xx_dsp_spos_update_scb(chip,parent_scb);
 
 	pcm_channel->unlinked = 0;
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
@@ -1358,14 +1462,16 @@
 	spin_lock_irqsave(&chip->reg_lock, flags);
 
 	/* mute SCB */
-	snd_cs46xx_poke(chip, (src->address + 0xE) << 2, 0xffffffff);
+	/* cs46xx_dsp_scb_set_volume (chip,src,0,0); */
+
 	snd_cs46xx_poke(chip, (src->address + SRCCorPerGof) << 2,
 	  ((correctionPerSec << 16) & 0xFFFF0000) | (correctionPerGOF & 0xFFFF));
 
 	snd_cs46xx_poke(chip, (src->address + SRCPhiIncr6Int26Frac) << 2, phiIncr);
 
 	/* raise volume */
-	snd_cs46xx_poke(chip, (src->address + 0xE) << 2, 0x80008000);
+	/* cs46xx_dsp_scb_set_volume (chip,src,0x7fff,0x7fff); */
+	
 	spin_unlock_irqrestore(&chip->reg_lock, flags);
 }
 
@@ -1399,7 +1505,7 @@
 	snd_assert (src->parent_scb_ptr != NULL,  return -EINVAL );
 
 	/* mute SCB */
-	snd_cs46xx_poke(chip, (src->address + 0xE) << 2, 0xffffffff);
+	cs46xx_dsp_scb_set_volume (chip,src,0,0);
 
 	_dsp_unlink_scb (chip,src);
 
@@ -1425,10 +1531,144 @@
 	src->parent_scb_ptr = parent_scb;
 
 	/* update entry in DSP RAM */
-	snd_cs46xx_poke(chip,
-			(parent_scb->address + SCBsubListPtr) << 2,
-			(parent_scb->sub_list_ptr->address << 0x10) |
-			(parent_scb->next_scb_ptr->address));
+	cs46xx_dsp_spos_update_scb(chip,parent_scb);
+  
+	return 0;
+}
+
+int cs46xx_dsp_enable_spdif_out (cs46xx_t *chip)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	if ( ! (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) ) {
+		cs46xx_dsp_enable_spdif_hw (chip);
+	}
+
+	/* dont touch anything if SPDIF is open */
+	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
+		/* when cs46xx_iec958_post_close(...) is called it
+		   will call this function if necesary depending on
+		   this bit */
+		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
+
+		return -EBUSY;
+	}
+
+	snd_assert (ins->asynch_tx_scb == NULL, return -EINVAL);
+	snd_assert (ins->master_mix_scb->next_scb_ptr == ins->the_null_scb, return -EINVAL);
+
+	/* reset output snooper sample buffer pointer */
+	snd_cs46xx_poke (chip, (ins->ref_snoop_scb->address + 2) << 2,
+			 (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10 );
+	
+	/* The asynch. transfer task */
+	ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
+								SPDIFO_SCB_INST,
+								SPDIFO_IP_OUTPUT_BUFFER1,
+								ins->master_mix_scb,
+								SCB_ON_PARENT_NEXT_SCB);
+	if (!ins->asynch_tx_scb) return -ENOMEM;
+
+	ins->spdif_pcm_input_scb = cs46xx_dsp_create_pcm_serial_input_scb(chip,"PCMSerialInput_II",
+									  PCMSERIALINII_SCB_ADDR,
+									  ins->ref_snoop_scb,
+									  ins->asynch_tx_scb,
+									  SCB_ON_PARENT_SUBLIST_SCB);
   
+	
+	if (!ins->spdif_pcm_input_scb) return -ENOMEM;
+
+	/* monitor state */
+	ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
+
+	return 0;
+}
+
+int  cs46xx_dsp_disable_spdif_out (cs46xx_t *chip)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	/* dont touch anything if SPDIF is open */
+	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) {
+		ins->spdif_status_out &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
+		return -EBUSY;
+	}
+
+	/* check integrety */
+	snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
+	snd_assert (ins->spdif_pcm_input_scb != NULL,return -EINVAL);
+	snd_assert (ins->master_mix_scb->next_scb_ptr == ins->asynch_tx_scb, return -EINVAL);
+	snd_assert (ins->asynch_tx_scb->parent_scb_ptr == ins->master_mix_scb, return -EINVAL);
+
+	cs46xx_dsp_remove_scb (chip,ins->spdif_pcm_input_scb);
+	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
+
+	ins->spdif_pcm_input_scb = NULL;
+	ins->asynch_tx_scb = NULL;
+
+	/* clear buffer to prevent any undesired noise */
+	_dsp_clear_sample_buffer(chip,SPDIFO_IP_OUTPUT_BUFFER1,256);
+
+	/* monitor state */
+	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_OUTPUT_ENABLED;
+
+
+	return 0;
+}
+
+int cs46xx_iec958_pre_open (cs46xx_t *chip)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
+		/* remove AsynchFGTxSCB and and PCMSerialInput_II */
+		cs46xx_dsp_disable_spdif_out (chip);
+
+		/* save state */
+		ins->spdif_status_out |= DSP_SPDIF_STATUS_OUTPUT_ENABLED;
+	}
+	
+	/* if not enabled already */
+	if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) {
+		cs46xx_dsp_enable_spdif_hw (chip);
+	}
+
+	/* Create the asynch. transfer task  for playback */
+	ins->asynch_tx_scb = cs46xx_dsp_create_asynch_fg_tx_scb(chip,"AsynchFGTxSCB",ASYNCTX_SCB_ADDR,
+								SPDIFO_SCB_INST,
+								SPDIFO_IP_OUTPUT_BUFFER1,
+								ins->master_mix_scb,
+								SCB_ON_PARENT_NEXT_SCB);
+
+
+	if (ins->spdif_status_out & DSP_SPDIF_STATUS_AC3_MODE) 
+		/* set left (13), right validity bit (12) , and non-audio(1) and profsional bit (0) */
+		cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12) | (1 << 1) | 1);
+
+	ins->spdif_status_out  |= DSP_SPDIF_STATUS_PLAYBACK_OPEN;
+
+	return 0;
+}
+
+int cs46xx_iec958_post_close (cs46xx_t *chip)
+{
+	dsp_spos_instance_t * ins = chip->dsp_spos_instance;
+
+	snd_assert (ins->asynch_tx_scb != NULL, return -EINVAL);
+
+	ins->spdif_status_out  &= ~DSP_SPDIF_STATUS_PLAYBACK_OPEN;
+
+	/* restore settings */
+	cs46xx_poke_via_dsp (chip,SP_SPDOUT_CSUV, 0x00000000 | (1 << 13) | (1 << 12));
+	
+	/* deallocate stuff */
+	cs46xx_dsp_remove_scb (chip,ins->asynch_tx_scb);
+	ins->asynch_tx_scb = NULL;
+
+	/* restore state */
+	if ( ins->spdif_status_out & DSP_SPDIF_STATUS_OUTPUT_ENABLED ) {
+		cs46xx_dsp_enable_spdif_out (chip);
+	}
+	
 	return 0;
 }
diff -Nru a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
--- a/sound/pci/emu10k1/emufx.c	Sun Nov 10 19:28:40 2002
+++ b/sound/pci/emu10k1/emufx.c	Sun Nov 10 19:28:40 2002
@@ -196,6 +196,7 @@
 	{ 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
 	{ 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
 	{ 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
+	{ 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
 	{ 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
 	{ 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
 	{ 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
diff -Nru a/sound/pci/ens1370.c b/sound/pci/ens1370.c
--- a/sound/pci/ens1370.c	Sun Nov 10 19:28:41 2002
+++ b/sound/pci/ens1370.c	Sun Nov 10 19:28:41 2002
@@ -37,6 +37,7 @@
 #endif
 #define SNDRV_GET_ID
 #include <sound/initval.h>
+#include <sound/asoundef.h>
 
 #define chip_t ensoniq_t
 
@@ -109,66 +110,70 @@
 #define ES_REG_CONTROL	0x00	/* R/W: Interrupt/Chip select control register */
 #define   ES_1370_ADC_STOP	(1<<31)		/* disable capture buffer transfers */
 #define   ES_1370_XCTL1 	(1<<30)		/* general purpose output bit */
-#define   ES_1371_SPDIF_EN	(1<<26)		/* SPDIF enable */
-#define   ES_1371_JOY_ASEL(o)	(((o)&0x03)<<24)	/* joystick port mapping */
+#define   ES_1373_TEST_BIT	(1<<29)		/* should be set to 0 for normal operation */
+#define   ES_1373_RECEN_B	(1<<28)		/* mix record with playback for I2S/SPDIF out */
+#define   ES_1373_SPDIF_THRU	(1<<26)		/* 0 = SPDIF thru mode, 1 = SPDIF == dig out */
+#define   ES_1371_JOY_ASEL(o)	(((o)&0x03)<<24)/* joystick port mapping */
 #define   ES_1371_JOY_ASELM	(0x03<<24)	/* mask for above */
 #define   ES_1371_JOY_ASELI(i)  (((i)>>24)&0x03)
-#define   ES_1371_GPIO_IN(i)	(((i)>>20)&0x0f)	/* GPIO in [3:0] pins - R/O */
-#define   ES_1370_PCLKDIVO(o)	(((o)&0x1fff)<<16)	/* clock divide ratio for DAC2 */
+#define   ES_1371_GPIO_IN(i)	(((i)>>20)&0x0f)/* GPIO in [3:0] pins - R/O */
+#define   ES_1370_PCLKDIVO(o)	(((o)&0x1fff)<<16)/* clock divide ratio for DAC2 */
 #define   ES_1370_PCLKDIVM	((0x1fff)<<16)	/* mask for above */
-#define   ES_1370_PCLKDIVI(i)	(((i)>>16)&0x1fff)	/* clock divide ratio for DAC2 */
-#define   ES_1371_GPIO_OUT(o)	(((o)&0x0f)<<16)	/* GPIO out [3:0] pins - W/R */
+#define   ES_1370_PCLKDIVI(i)	(((i)>>16)&0x1fff)/* clock divide ratio for DAC2 */
+#define   ES_1371_GPIO_OUT(o)	(((o)&0x0f)<<16)/* GPIO out [3:0] pins - W/R */
 #define   ES_1371_GPIO_OUTM     (0x0f<<16)	/* mask for above */
 #define   ES_MSFMTSEL		(1<<15)		/* MPEG serial data format; 0 = SONY, 1 = I2S */
 #define   ES_1370_M_SBB		(1<<14)		/* clock source for DAC - 0 = clock generator; 1 = MPEG clocks */
 #define   ES_1371_SYNC_RES	(1<<14)		/* Warm AC97 reset */
-#define   ES_1370_WTSRSEL(o)	(((o)&0x03)<<12)	/* fixed frequency clock for DAC1 */
+#define   ES_1370_WTSRSEL(o)	(((o)&0x03)<<12)/* fixed frequency clock for DAC1 */
 #define   ES_1370_WTSRSELM	(0x03<<12)	/* mask for above */
 #define   ES_1371_ADC_STOP	(1<<13)		/* disable CCB transfer capture information */
 #define   ES_1371_PWR_INTRM	(1<<12)		/* power level change interrupts enable */
 #define   ES_1370_DAC_SYNC	(1<<11)		/* DAC's are synchronous */
-#define   ES_1371_M_CB		(1<<11)		/* capture clock source; 0 = ADC; 1 = I2S */
+#define   ES_1371_M_CB		(1<<11)		/* capture clock source; 0 = AC'97 ADC; 1 = I2S */
 #define   ES_CCB_INTRM		(1<<10)		/* CCB voice interrupts enable */
-#define   ES_1370_M_CB		(1<<9)	/* capture clock source; 0 = ADC; 1 = MPEG */
-#define   ES_1370_XCTL0		(1<<8)	/* generap purpose output bit */
-#define   ES_1371_PDLEV(o)	(((o)&0x03)<<8)		/* current power down level */
+#define   ES_1370_M_CB		(1<<9)		/* capture clock source; 0 = ADC; 1 = MPEG */
+#define   ES_1370_XCTL0		(1<<8)		/* generap purpose output bit */
+#define   ES_1371_PDLEV(o)	(((o)&0x03)<<8)	/* current power down level */
 #define   ES_1371_PDLEVM	(0x03<<8)	/* mask for above */
-#define   ES_BREQ		(1<<7)	/* memory bus request enable */
-#define   ES_DAC1_EN		(1<<6)	/* DAC1 playback channel enable */
-#define   ES_DAC2_EN		(1<<5)	/* DAC2 playback channel enable */
-#define   ES_ADC_EN		(1<<4)	/* ADC capture channel enable */
-#define   ES_UART_EN		(1<<3)	/* UART enable */
-#define   ES_JYSTK_EN		(1<<2)	/* Joystick module enable */
-#define   ES_1370_CDC_EN	(1<<1)	/* Codec interface enable */
-#define   ES_1371_XTALCKDIS	(1<<1)	/* Xtal clock disable */
-#define   ES_1370_SERR_DISABLE	(1<<0)	/* PCI serr signal disable */
-#define   ES_1371_PCICLKDIS     (1<<0)	/* PCI clock disable */
+#define   ES_BREQ		(1<<7)		/* memory bus request enable */
+#define   ES_DAC1_EN		(1<<6)		/* DAC1 playback channel enable */
+#define   ES_DAC2_EN		(1<<5)		/* DAC2 playback channel enable */
+#define   ES_ADC_EN		(1<<4)		/* ADC capture channel enable */
+#define   ES_UART_EN		(1<<3)		/* UART enable */
+#define   ES_JYSTK_EN		(1<<2)		/* Joystick module enable */
+#define   ES_1370_CDC_EN	(1<<1)		/* Codec interface enable */
+#define   ES_1371_XTALCKDIS	(1<<1)		/* Xtal clock disable */
+#define   ES_1370_SERR_DISABLE	(1<<0)		/* PCI serr signal disable */
+#define   ES_1371_PCICLKDIS     (1<<0)		/* PCI clock disable */
 #define ES_REG_STATUS	0x04	/* R/O: Interrupt/Chip select status register */
-#define   ES_INTR               (1<<31)	/* Interrupt is pending */
-#define   ES_1371_ST_AC97_RST	(1<<29) /* CT5880 AC'97 Reset bit */
-#define   ES_1371_ST_SPDIF_EN	(1<<18) /* SPDIF enable */
-#define   ES_1371_ST_SPDIF_TEST (1<<17) /* SPDIF test */
-#define   ES_1371_TEST          (1<<16) /* test ASIC */
-#define   ES_1370_CSTAT		(1<<10)	/* CODEC is busy or register write in progress */
-#define   ES_1370_CBUSY         (1<<9)	/* CODEC is busy */
-#define   ES_1370_CWRIP		(1<<8)	/* CODEC register write in progress */
-#define   ES_1371_SYNC_ERR	(1<<8)	/* CODEC synchronization error occured */
-#define   ES_1371_VC(i)         (((i)>>6)&0x03)		/* voice code from CCB module */
-#define   ES_1370_VC(i)		(((i)>>5)&0x03)		/* voice code from CCB module */
-#define   ES_1371_MPWR          (1<<5)	/* power level interrupt pending */
-#define   ES_MCCB		(1<<4)	/* CCB interrupt pending */
-#define   ES_UART		(1<<3)	/* UART interrupt pending */
-#define   ES_DAC1		(1<<2)	/* DAC1 channel interrupt pending */
-#define   ES_DAC2		(1<<1)	/* DAC2 channel interrupt pending */
-#define   ES_ADC		(1<<0)	/* ADC channel interrupt pending */
+#define   ES_INTR               (1<<31)		/* Interrupt is pending */
+#define   ES_1371_ST_AC97_RST	(1<<29)		/* CT5880 AC'97 Reset bit */
+#define   ES_1373_GPIO_INT_EN(o)(((o)&0x0f)<<20)/* GPIO [3:0] pins - interrupt enable */
+#define   ES_1373_SPDIF_EN	(1<<18)		/* SPDIF enable */
+#define   ES_1373_SPDIF_TEST	(1<<17)		/* SPDIF test */
+#define   ES_1371_TEST          (1<<16)		/* test ASIC */
+#define   ES_1373_GPIO_INT(i)	(((i)&0x0f)>>12)/* GPIO [3:0] pins - interrupt pending */
+#define   ES_1370_CSTAT		(1<<10)		/* CODEC is busy or register write in progress */
+#define   ES_1370_CBUSY         (1<<9)		/* CODEC is busy */
+#define   ES_1370_CWRIP		(1<<8)		/* CODEC register write in progress */
+#define   ES_1371_SYNC_ERR	(1<<8)		/* CODEC synchronization error occured */
+#define   ES_1371_VC(i)         (((i)>>6)&0x03)	/* voice code from CCB module */
+#define   ES_1370_VC(i)		(((i)>>5)&0x03)	/* voice code from CCB module */
+#define   ES_1371_MPWR          (1<<5)		/* power level interrupt pending */
+#define   ES_MCCB		(1<<4)		/* CCB interrupt pending */
+#define   ES_UART		(1<<3)		/* UART interrupt pending */
+#define   ES_DAC1		(1<<2)		/* DAC1 channel interrupt pending */
+#define   ES_DAC2		(1<<1)		/* DAC2 channel interrupt pending */
+#define   ES_ADC		(1<<0)		/* ADC channel interrupt pending */
 #define ES_REG_UART_DATA 0x08	/* R/W: UART data register */
 #define ES_REG_UART_STATUS 0x09	/* R/O: UART status register */
-#define   ES_RXINT		(1<<7)	/* RX interrupt occured */
-#define   ES_TXINT		(1<<2)	/* TX interrupt occured */
-#define   ES_TXRDY		(1<<1)	/* transmitter ready */
-#define   ES_RXRDY		(1<<0)	/* receiver ready */
+#define   ES_RXINT		(1<<7)		/* RX interrupt occured */
+#define   ES_TXINT		(1<<2)		/* TX interrupt occured */
+#define   ES_TXRDY		(1<<1)		/* transmitter ready */
+#define   ES_RXRDY		(1<<0)		/* receiver ready */
 #define ES_REG_UART_CONTROL 0x09	/* W/O: UART control register */
-#define   ES_RXINTEN		(1<<7)	/* RX interrupt enable */
+#define   ES_RXINTEN		(1<<7)		/* RX interrupt enable */
 #define   ES_TXINTENO(o)	(((o)&0x03)<<5)	/* TX interrupt enable */
 #define   ES_TXINTENM		(0x03<<5)	/* mask for above */
 #define   ES_TXINTENI(i)	(((i)>>5)&0x03)
@@ -191,29 +196,29 @@
 #define   ES_1371_CODEC_READ(i)    (((i)>>0)&0xffff)
 
 #define ES_REG_1371_SMPRATE 0x10	/* W/R: Codec rate converter interface register */
-#define   ES_1371_SRC_RAM_ADDRO(o) (((o)&0x7f)<<25)	/* address of the sample rate converter */
+#define   ES_1371_SRC_RAM_ADDRO(o) (((o)&0x7f)<<25)/* address of the sample rate converter */
 #define   ES_1371_SRC_RAM_ADDRM	   (0x7f<<25)	/* mask for above */
-#define   ES_1371_SRC_RAM_ADDRI(i) (((i)>>25)&0x7f)	/* address of the sample rate converter */
+#define   ES_1371_SRC_RAM_ADDRI(i) (((i)>>25)&0x7f)/* address of the sample rate converter */
 #define   ES_1371_SRC_RAM_WE	   (1<<24)	/* R/W: read/write control for sample rate converter */
 #define   ES_1371_SRC_RAM_BUSY     (1<<23)	/* R/O: sample rate memory is busy */
 #define   ES_1371_SRC_DISABLE      (1<<22)	/* sample rate converter disable */
 #define   ES_1371_DIS_P1	   (1<<21)	/* playback channel 1 accumulator update disable */
 #define   ES_1371_DIS_P2	   (1<<20)	/* playback channel 1 accumulator update disable */
 #define   ES_1371_DIS_R1	   (1<<19)	/* capture channel accumulator update disable */
-#define   ES_1371_SRC_RAM_DATAO(o) (((o)&0xffff)<<0)	/* current value of the sample rate converter */
+#define   ES_1371_SRC_RAM_DATAO(o) (((o)&0xffff)<<0)/* current value of the sample rate converter */
 #define   ES_1371_SRC_RAM_DATAM	   (0xffff<<0)	/* mask for above */
-#define   ES_1371_SRC_RAM_DATAI(i) (((i)>>0)&0xffff)	/* current value of the sample rate converter */
+#define   ES_1371_SRC_RAM_DATAI(i) (((i)>>0)&0xffff)/* current value of the sample rate converter */
 
 #define ES_REG_1371_LEGACY 0x18	/* W/R: Legacy control/status register */
 #define   ES_1371_JFAST		(1<<31)		/* fast joystick timing */
 #define   ES_1371_HIB		(1<<30)		/* host interrupt blocking enable */
 #define   ES_1371_VSB		(1<<29)		/* SB; 0 = addr 0x220xH, 1 = 0x22FxH */
-#define   ES_1371_VMPUO(o)	(((o)&0x03)<<27)	/* base register address; 0 = 0x320xH; 1 = 0x330xH; 2 = 0x340xH; 3 = 0x350xH */
+#define   ES_1371_VMPUO(o)	(((o)&0x03)<<27)/* base register address; 0 = 0x320xH; 1 = 0x330xH; 2 = 0x340xH; 3 = 0x350xH */
 #define   ES_1371_VMPUM		(0x03<<27)	/* mask for above */
-#define   ES_1371_VMPUI(i)	(((i)>>27)&0x03)	/* base register address */
-#define   ES_1371_VCDCO(o)	(((o)&0x03)<<25)	/* CODEC; 0 = 0x530xH; 1 = undefined; 2 = 0xe80xH; 3 = 0xF40xH */
+#define   ES_1371_VMPUI(i)	(((i)>>27)&0x03)/* base register address */
+#define   ES_1371_VCDCO(o)	(((o)&0x03)<<25)/* CODEC; 0 = 0x530xH; 1 = undefined; 2 = 0xe80xH; 3 = 0xF40xH */
 #define   ES_1371_VCDCM		(0x03<<25)	/* mask for above */
-#define   ES_1371_VCDCI(i)	(((i)>>25)&0x03)	/* CODEC address */
+#define   ES_1371_VCDCI(i)	(((i)>>25)&0x03)/* CODEC address */
 #define   ES_1371_FIRQ		(1<<24)		/* force an interrupt */
 #define   ES_1371_SDMACAP	(1<<23)		/* enable event capture for slave DMA controller */
 #define   ES_1371_SPICAP	(1<<22)		/* enable event capture for slave IRQ controller */
@@ -223,36 +228,38 @@
 #define   ES_1371_SVCAP		(1<<18)		/* enable event capture for SB registers */
 #define   ES_1371_CDCCAP	(1<<17)		/* enable event capture for CODEC registers */
 #define   ES_1371_BACAP		(1<<16)		/* enable event capture for SoundScape base address */
-#define   ES_1371_EXI(i)	(((i)>>8)&0x07)		/* event number */
-#define   ES_1371_AI(i)		(((i)>>3)&0x1f)		/* event significant I/O address */
+#define   ES_1371_EXI(i)	(((i)>>8)&0x07)	/* event number */
+#define   ES_1371_AI(i)		(((i)>>3)&0x1f)	/* event significant I/O address */
 #define   ES_1371_WR		(1<<2)	/* event capture; 0 = read; 1 = write */
 #define   ES_1371_LEGINT	(1<<0)	/* interrupt for legacy events; 0 = interrupt did occur */
 
+#define ES_REG_CHANNEL_STATUS 0x1c /* R/W: first 32-bits from S/PDIF channel status block, es1373 */
+
 #define ES_REG_SERIAL	0x20	/* R/W: Serial interface control register */
 #define   ES_1371_DAC_TEST	(1<<22)		/* DAC test mode enable */
-#define   ES_P2_END_INCO(o)	(((o)&0x07)<<19)	/* binary offset value to increment / loop end */
+#define   ES_P2_END_INCO(o)	(((o)&0x07)<<19)/* binary offset value to increment / loop end */
 #define   ES_P2_END_INCM	(0x07<<19)	/* mask for above */
-#define   ES_P2_END_INCI(i)	(((i)>>16)&0x07)	/* binary offset value to increment / loop end */
-#define   ES_P2_ST_INCO(o)	(((o)&0x07)<<16)	/* binary offset value to increment / start */
+#define   ES_P2_END_INCI(i)	(((i)>>16)&0x07)/* binary offset value to increment / loop end */
+#define   ES_P2_ST_INCO(o)	(((o)&0x07)<<16)/* binary offset value to increment / start */
 #define   ES_P2_ST_INCM		(0x07<<16)	/* mask for above */
-#define   ES_P2_ST_INCI(i)	(((i)<<16)&0x07)	/* binary offset value to increment / start */
+#define   ES_P2_ST_INCI(i)	(((i)<<16)&0x07)/* binary offset value to increment / start */
 #define   ES_R1_LOOP_SEL	(1<<15)		/* ADC; 0 - loop mode; 1 = stop mode */
 #define   ES_P2_LOOP_SEL	(1<<14)		/* DAC2; 0 - loop mode; 1 = stop mode */
 #define   ES_P1_LOOP_SEL	(1<<13)		/* DAC1; 0 - loop mode; 1 = stop mode */
 #define   ES_P2_PAUSE		(1<<12)		/* DAC2; 0 - play mode; 1 = pause mode */
 #define   ES_P1_PAUSE		(1<<11)		/* DAC1; 0 - play mode; 1 = pause mode */
 #define   ES_R1_INT_EN		(1<<10)		/* ADC interrupt enable */
-#define   ES_P2_INT_EN		(1<<9)	/* DAC2 interrupt enable */
-#define   ES_P1_INT_EN		(1<<8)	/* DAC1 interrupt enable */
-#define   ES_P1_SCT_RLD		(1<<7)	/* force sample counter reload for DAC1 */
-#define   ES_P2_DAC_SEN		(1<<6)	/* when stop mode: 0 - DAC2 play back zeros; 1 = DAC2 play back last sample */
-#define   ES_R1_MODEO(o)	(((o)&0x03)<<4)		/* ADC mode; 0 = 8-bit mono; 1 = 8-bit stereo; 2 = 16-bit mono; 3 = 16-bit stereo */
+#define   ES_P2_INT_EN		(1<<9)		/* DAC2 interrupt enable */
+#define   ES_P1_INT_EN		(1<<8)		/* DAC1 interrupt enable */
+#define   ES_P1_SCT_RLD		(1<<7)		/* force sample counter reload for DAC1 */
+#define   ES_P2_DAC_SEN		(1<<6)		/* when stop mode: 0 - DAC2 play back zeros; 1 = DAC2 play back last sample */
+#define   ES_R1_MODEO(o)	(((o)&0x03)<<4)	/* ADC mode; 0 = 8-bit mono; 1 = 8-bit stereo; 2 = 16-bit mono; 3 = 16-bit stereo */
 #define   ES_R1_MODEM		(0x03<<4)	/* mask for above */
 #define   ES_R1_MODEI(i)	(((i)>>4)&0x03)
-#define   ES_P2_MODEO(o)	(((o)&0x03)<<2)		/* DAC2 mode; -- '' -- */
+#define   ES_P2_MODEO(o)	(((o)&0x03)<<2)	/* DAC2 mode; -- '' -- */
 #define   ES_P2_MODEM		(0x03<<2)	/* mask for above */
 #define   ES_P2_MODEI(i)	(((i)>>2)&0x03)
-#define   ES_P1_MODEO(o)	(((o)&0x03)<<0)		/* DAC1 mode; -- '' -- */
+#define   ES_P1_MODEO(o)	(((o)&0x03)<<0)	/* DAC1 mode; -- '' -- */
 #define   ES_P1_MODEM		(0x03<<0)	/* mask for above */
 #define   ES_P1_MODEI(i)	(((i)>>0)&0x03)
 
@@ -386,6 +393,10 @@
 	snd_rawmidi_substream_t *midi_input;
 	snd_rawmidi_substream_t *midi_output;
 
+	unsigned int spdif;
+	unsigned int spdif_default;
+	unsigned int spdif_stream;
+
 	snd_info_entry_t *proc_entry;
 
 #ifdef CHIP1370
@@ -1032,6 +1043,10 @@
 	ensoniq->playback1_substream = substream;
 	runtime->hw = snd_ensoniq_playback1;
 	snd_pcm_set_sync(substream);
+	spin_lock_irq(&ensoniq->reg_lock);
+	if (ensoniq->spdif && ensoniq->playback2_substream == NULL)
+		ensoniq->spdif_stream = ensoniq->spdif_default;
+	spin_unlock_irq(&ensoniq->reg_lock);
 #ifdef CHIP1370
 	snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 				   &snd_es1370_hw_constraints_rates);
@@ -1051,6 +1066,10 @@
 	ensoniq->playback2_substream = substream;
 	runtime->hw = snd_ensoniq_playback2;
 	snd_pcm_set_sync(substream);
+	spin_lock_irq(&ensoniq->reg_lock);
+	if (ensoniq->spdif && ensoniq->playback1_substream == NULL)
+		ensoniq->spdif_stream = ensoniq->spdif_default;
+	spin_unlock_irq(&ensoniq->reg_lock);
 #ifdef CHIP1370
 	snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
 				      &snd_es1370_hw_constraints_clock);
@@ -1241,6 +1260,116 @@
 
 #ifdef CHIP1371
 
+
+static int snd_ens1373_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
+	uinfo->count = 1;
+	return 0;
+}
+
+static int snd_ens1373_spdif_default_get(snd_kcontrol_t * kcontrol,
+                                         snd_ctl_elem_value_t * ucontrol)
+{
+	ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
+	spin_lock_irq(&ensoniq->reg_lock);
+	ucontrol->value.iec958.status[0] = (ensoniq->spdif_default >> 0) & 0xff;
+	ucontrol->value.iec958.status[1] = (ensoniq->spdif_default >> 8) & 0xff;
+	ucontrol->value.iec958.status[2] = (ensoniq->spdif_default >> 16) & 0xff;
+	ucontrol->value.iec958.status[3] = (ensoniq->spdif_default >> 24) & 0xff;
+	spin_unlock_irq(&ensoniq->reg_lock);
+	return 0;
+}
+
+static int snd_ens1373_spdif_default_put(snd_kcontrol_t * kcontrol,
+                                         snd_ctl_elem_value_t * ucontrol)
+{
+	ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
+	unsigned int val;
+	int change;
+
+	val = ((u32)ucontrol->value.iec958.status[0] << 0) |
+	      ((u32)ucontrol->value.iec958.status[1] << 8) |
+	      ((u32)ucontrol->value.iec958.status[2] << 16) |
+	      ((u32)ucontrol->value.iec958.status[3] << 24);
+	spin_lock_irq(&ensoniq->reg_lock);
+	change = ensoniq->spdif_default != val;
+	ensoniq->spdif_default = val;
+	if (change && ensoniq->playback1_substream == NULL && ensoniq->playback2_substream == NULL)
+		outl(val, ES_REG(ensoniq, CHANNEL_STATUS));
+	spin_unlock_irq(&ensoniq->reg_lock);
+	return change;
+}
+
+static int snd_ens1373_spdif_mask_get(snd_kcontrol_t * kcontrol,
+                                         snd_ctl_elem_value_t * ucontrol)
+{
+	ucontrol->value.iec958.status[0] = 0xff;
+	ucontrol->value.iec958.status[1] = 0xff;
+	ucontrol->value.iec958.status[2] = 0xff;
+	ucontrol->value.iec958.status[3] = 0xff;
+	return 0;
+}
+
+static int snd_ens1373_spdif_stream_get(snd_kcontrol_t * kcontrol,
+                                         snd_ctl_elem_value_t * ucontrol)
+{
+	ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
+	spin_lock_irq(&ensoniq->reg_lock);
+	ucontrol->value.iec958.status[0] = (ensoniq->spdif_stream >> 0) & 0xff;
+	ucontrol->value.iec958.status[1] = (ensoniq->spdif_stream >> 8) & 0xff;
+	ucontrol->value.iec958.status[2] = (ensoniq->spdif_stream >> 16) & 0xff;
+	ucontrol->value.iec958.status[3] = (ensoniq->spdif_stream >> 24) & 0xff;
+	spin_unlock_irq(&ensoniq->reg_lock);
+	return 0;
+}
+
+static int snd_ens1373_spdif_stream_put(snd_kcontrol_t * kcontrol,
+                                        snd_ctl_elem_value_t * ucontrol)
+{
+	ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
+	unsigned int val;
+	int change;
+
+	val = ((u32)ucontrol->value.iec958.status[0] << 0) |
+	      ((u32)ucontrol->value.iec958.status[1] << 8) |
+	      ((u32)ucontrol->value.iec958.status[2] << 16) |
+	      ((u32)ucontrol->value.iec958.status[3] << 24);
+	spin_lock_irq(&ensoniq->reg_lock);
+	change = ensoniq->spdif_stream != val;
+	ensoniq->spdif_stream = val;
+	if (change && (ensoniq->playback1_substream != NULL || ensoniq->playback2_substream != NULL))
+		outl(val, ES_REG(ensoniq, CHANNEL_STATUS));
+	spin_unlock_irq(&ensoniq->reg_lock);
+	return change;
+}
+
+static snd_kcontrol_new_t snd_ens1373_spdif_default __devinitdata =
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+	.info =		snd_ens1373_spdif_info,
+	.get =		snd_ens1373_spdif_default_get,
+	.put =		snd_ens1373_spdif_default_put,
+};
+
+static snd_kcontrol_new_t snd_ens1373_spdif_mask __devinitdata =
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK),
+	.info =		snd_ens1373_spdif_info,
+	.get =		snd_ens1373_spdif_mask_get
+};
+
+static snd_kcontrol_new_t snd_ens1373_spdif_stream __devinitdata =
+{
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =		SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
+	.info =		snd_ens1373_spdif_info,
+	.get =		snd_ens1373_spdif_stream_get,
+	.put =		snd_ens1373_spdif_stream_put
+};
+
 #define ES1371_SPDIF(xname) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_es1371_spdif_info, \
   .get = snd_es1371_spdif_get, .put = snd_es1371_spdif_put }
@@ -1257,32 +1386,30 @@
 static int snd_es1371_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
 	
-	spin_lock_irqsave(&ensoniq->reg_lock, flags);
-	ucontrol->value.integer.value[0] = ensoniq->ctrl & ES_1371_SPDIF_EN ? 1 : 0;
-	spin_unlock_irqrestore(&ensoniq->reg_lock, flags);
+	spin_lock_irq(&ensoniq->reg_lock);
+	ucontrol->value.integer.value[0] = ensoniq->ctrl & ES_1373_SPDIF_THRU ? 1 : 0;
+	spin_unlock_irq(&ensoniq->reg_lock);
 	return 0;
 }
 
 static int snd_es1371_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
 {
 	ensoniq_t *ensoniq = snd_kcontrol_chip(kcontrol);
-	unsigned long flags;
 	unsigned int nval1, nval2;
 	int change;
 	
-	nval1 = ucontrol->value.integer.value[0] ? ES_1371_SPDIF_EN : 0;
-	nval2 = ucontrol->value.integer.value[0] ? ES_1371_ST_SPDIF_EN : 0;
-	spin_lock_irqsave(&ensoniq->reg_lock, flags);
-	change = (ensoniq->ctrl & ES_1371_SPDIF_EN) != nval1;
-	ensoniq->ctrl &= ~ES_1371_SPDIF_EN;
+	nval1 = ucontrol->value.integer.value[0] ? ES_1373_SPDIF_THRU : 0;
+	nval2 = ucontrol->value.integer.value[0] ? ES_1373_SPDIF_EN : 0;
+	spin_lock_irq(&ensoniq->reg_lock);
+	change = (ensoniq->ctrl & ES_1373_SPDIF_THRU) != nval1;
+	ensoniq->ctrl &= ~ES_1373_SPDIF_THRU;
 	ensoniq->ctrl |= nval1;
-	ensoniq->cssr &= ~ES_1371_ST_SPDIF_EN;
+	ensoniq->cssr &= ~ES_1373_SPDIF_EN;
 	ensoniq->cssr |= nval2;
 	outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL));
 	outl(ensoniq->cssr, ES_REG(ensoniq, STATUS));
-	spin_unlock_irqrestore(&ensoniq->reg_lock, flags);
+	spin_unlock_irq(&ensoniq->reg_lock);
 	return change;
 }
 
@@ -1299,7 +1426,7 @@
 	unsigned short vid;		/* vendor ID */
 	unsigned short did;		/* device ID */
 	unsigned char rev;		/* revision */
-} es1371_spdif_present[] = {
+} __devinitdata es1371_spdif_present[] = {
 	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C },
 	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D },
 	{ .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E },
@@ -1325,9 +1452,29 @@
 		if (ensoniq->pci->vendor == es1371_spdif_present[idx].vid &&
 		    ensoniq->pci->device == es1371_spdif_present[idx].did &&
 		    ensoniq->rev == es1371_spdif_present[idx].rev) {
-		    	snd_kcontrol_t *kctl = snd_ctl_new1(&snd_es1371_mixer_spdif, ensoniq); 
+		    	snd_kcontrol_t *kctl;
+			int index = 0; 
+
+			ensoniq->spdif_default = ensoniq->spdif_stream = SNDRV_PCM_DEFAULT_CON_SPDIF;
+			outl(ensoniq->spdif_default, ES_REG(ensoniq, CHANNEL_STATUS));
+
 		    	if (ensoniq->u.es1371.ac97->ext_id & AC97_EI_SPDIF)
-			    	kctl->id.index = 1;
+			    	index++;
+
+		    	kctl = snd_ctl_new1(&snd_es1371_mixer_spdif, ensoniq);
+			kctl->id.index = index;
+			snd_ctl_add(card, kctl);
+
+			kctl = snd_ctl_new1(&snd_ens1373_spdif_default, ensoniq);
+			kctl->id.index = index;
+			snd_ctl_add(card, kctl);
+
+			kctl = snd_ctl_new1(&snd_ens1373_spdif_mask, ensoniq);
+			kctl->id.index = index;
+			snd_ctl_add(card, kctl);
+
+			kctl = snd_ctl_new1(&snd_ens1373_spdif_stream, ensoniq);
+			kctl->id.index = index;
 			snd_ctl_add(card, kctl);
 			break;
 		}
diff -Nru a/sound/pci/ice1712/ak4524.c b/sound/pci/ice1712/ak4524.c
--- a/sound/pci/ice1712/ak4524.c	Sun Nov 10 19:28:40 2002
+++ b/sound/pci/ice1712/ak4524.c	Sun Nov 10 19:28:40 2002
@@ -1,7 +1,7 @@
 /*
  *   ALSA driver for ICEnsemble ICE1712 (Envy24)
  *
- *   AK4524 / AK4528 interface
+ *   AK4524 / AK4528 / AK4529 interface
  *
  *	Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz>
  *
@@ -67,6 +67,7 @@
 
 	addr &= 0x07;
 	/* build I2C address + data byte */
+	/* assume C1=1, C0=0 */
 	addrdata = 0xa000 | (addr << 8) | data;
 	for (idx = 15; idx >= 0; idx--) {
 		tmp &= ~(ak->data_mask | ak->clk_mask);
@@ -80,11 +81,13 @@
 		udelay(1);
 	}
 
-	if ((addr != 0x04 && addr != 0x05) || (data & 0x80) == 0)
-		ak->images[chip][addr] = data;
-	else
-		ak->ipga_gain[chip][addr-4] = data;
-
+	if (ak->type == SND_AK4524) {
+		if ((addr != 0x04 && addr != 0x05) || (data & 0x80) == 0)
+			ak->images[chip][addr] = data;
+		else
+			ak->ipga_gain[chip][addr-4] = data;
+	}
+	
 	if (ak->cs_mask == ak->cs_addr) {
 		if (ak->cif) {
 			/* assert a cs pulse to trigger */
@@ -112,16 +115,26 @@
 	unsigned char reg;
 	ak4524_t *ak = &ice->ak4524;
 	
-	for (chip = 0; chip < ak->num_dacs/2; chip++) {
-		snd_ice1712_ak4524_write(ice, chip, 0x01, state ? 0x00 : 0x03);
-		if (state)
-			continue;
-		for (reg = 0x04; reg < (ak->is_ak4528 ? 0x06 : 0x08); reg++)
-			snd_ice1712_ak4524_write(ice, chip, reg, ak->images[chip][reg]);
-		if (ak->is_ak4528)
-			continue;
-		for (reg = 0x04; reg < 0x06; reg++)
-			snd_ice1712_ak4524_write(ice, chip, reg, ak->ipga_gain[chip][reg-4]);
+	switch (ak->type) {
+	case SND_AK4524:
+	case SND_AK4528:
+		for (chip = 0; chip < ak->num_dacs/2; chip++) {
+			snd_ice1712_ak4524_write(ice, chip, 0x01, state ? 0x00 : 0x03);
+			if (state)
+				continue;
+			/* DAC volumes */
+			for (reg = 0x04; reg < (ak->type == SND_AK4528 ? 0x06 : 0x08); reg++)
+				snd_ice1712_ak4524_write(ice, chip, reg, ak->images[chip][reg]);
+			if (ak->type == SND_AK4528)
+				continue;
+			/* IPGA */
+			for (reg = 0x04; reg < 0x06; reg++)
+				snd_ice1712_ak4524_write(ice, chip, reg, ak->ipga_gain[chip][reg-4]);
+		}
+		break;
+	case SND_AK4529:
+		/* FIXME: needed for ak4529? */
+		break;
 	}
 }
 
@@ -130,7 +143,7 @@
  */
 void __devinit snd_ice1712_ak4524_init(ice1712_t *ice)
 {
-	static unsigned char inits[] = {
+	static unsigned char inits_ak4524[] = {
 		0x00, 0x07, /* 0: all power up */
 		0x01, 0x00, /* 1: ADC/DAC reset */
 		0x02, 0x60, /* 2: 24bit I2S */
@@ -144,28 +157,68 @@
 		0x07, 0x00, /* 7: DAC right muted */
 		0xff, 0xff
 	};
-	int chip, idx;
-	unsigned char *ptr, reg, data;
+	static unsigned char inits_ak4528[] = {
+		0x00, 0x07, /* 0: all power up */
+		0x01, 0x00, /* 1: ADC/DAC reset */
+		0x02, 0x60, /* 2: 24bit I2S */
+		0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */
+		0x01, 0x03, /* 1: ADC/DAC enable */
+		0x04, 0x00, /* 4: ADC left muted */
+		0x05, 0x00, /* 5: ADC right muted */
+		0xff, 0xff
+	};
+	static unsigned char inits_ak4529[] = {
+		0x09, 0x01, /* 9: ATS=0, RSTN=1 */
+		0x0a, 0x3f, /* A: all power up, no zero/overflow detection */
+		0x00, 0x08, /* 0: TDM=0, 24bit I2S, SMUTE=0 */
+		0x01, 0x00, /* 1: ACKS=0, ADC, loop off */
+		0x02, 0xff, /* 2: LOUT1 muted */
+		0x03, 0xff, /* 3: ROUT1 muted */
+		0x04, 0xff, /* 4: LOUT2 muted */
+		0x05, 0xff, /* 5: ROUT2 muted */
+		0x06, 0xff, /* 6: LOUT3 muted */
+		0x07, 0xff, /* 7: ROUT3 muted */
+		0x0b, 0xff, /* B: LOUT4 muted */
+		0x0c, 0xff, /* C: ROUT4 muted */
+		0x08, 0x55, /* 8: deemphasis all off */
+		0xff, 0xff
+	};
+	int chip, num_chips;
+	unsigned char *ptr, reg, data, *inits;
 	ak4524_t *ak = &ice->ak4524;
 
-	for (chip = idx = 0; chip < ak->num_dacs/2; chip++) {
+	switch (ak->type) {
+	case SND_AK4524:
+		inits = inits_ak4524;
+		num_chips = ak->num_dacs / 2;
+		break;
+	case SND_AK4528:
+		inits = inits_ak4528;
+		num_chips = ak->num_dacs / 2;
+		break;
+	case SND_AK4529:
+	default:
+		inits = inits_ak4529;
+		num_chips = 1;
+		break;
+	}
+
+	for (chip = 0; chip < num_chips; chip++) {
 		ptr = inits;
 		while (*ptr != 0xff) {
 			reg = *ptr++;
 			data = *ptr++;
-			if (ak->is_ak4528) {
-				if (reg > 5)
-					continue;
-				if (reg >= 4 && (data & 0x80))
-					continue;
-			}
-			if (reg == 0x03 && ak->is_ak4528)
-				data = 0x0d;	/* deemphasis off, turn LR highpass filters on */
 			snd_ice1712_ak4524_write(ice, chip, reg, data);
 		}
 	}
 }
 
+
+#define AK_GET_CHIP(val)		(((val) >> 8) & 0xff)
+#define AK_GET_ADDR(val)		((val) & 0xff)
+#define AK_GET_SHIFT(val)		(((val) >> 16) & 0xff)
+#define AK_COMPOSE(chip,addr,shift)	(((chip) << 8) | (addr) | ((shift) << 16))
+
 static int snd_ice1712_ak4524_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
@@ -178,8 +231,8 @@
 static int snd_ice1712_ak4524_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int chip = kcontrol->private_value / 8;
-	int addr = kcontrol->private_value % 8;
+	int chip = AK_GET_CHIP(kcontrol->private_value);
+	int addr = AK_GET_ADDR(kcontrol->private_value);
 	ucontrol->value.integer.value[0] = ice->ak4524.images[chip][addr];
 	return 0;
 }
@@ -187,8 +240,8 @@
 static int snd_ice1712_ak4524_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int chip = kcontrol->private_value / 8;
-	int addr = kcontrol->private_value % 8;
+	int chip = AK_GET_CHIP(kcontrol->private_value);
+	int addr = AK_GET_ADDR(kcontrol->private_value);
 	unsigned char nval = ucontrol->value.integer.value[0];
 	int change = ice->ak4524.images[chip][addr] != nval;
 	if (change)
@@ -208,8 +261,8 @@
 static int snd_ice1712_ak4524_ipga_gain_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int chip = kcontrol->private_value / 8;
-	int addr = kcontrol->private_value % 8;
+	int chip = AK_GET_CHIP(kcontrol->private_value);
+	int addr = AK_GET_ADDR(kcontrol->private_value);
 	ucontrol->value.integer.value[0] = ice->ak4524.ipga_gain[chip][addr-4] & 0x7f;
 	return 0;
 }
@@ -217,8 +270,8 @@
 static int snd_ice1712_ak4524_ipga_gain_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int chip = kcontrol->private_value / 8;
-	int addr = kcontrol->private_value % 8;
+	int chip = AK_GET_CHIP(kcontrol->private_value);
+	int addr = AK_GET_ADDR(kcontrol->private_value);
 	unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80;
 	int change = ice->ak4524.ipga_gain[chip][addr] != nval;
 	if (change)
@@ -243,21 +296,26 @@
 static int snd_ice1712_ak4524_deemphasis_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int chip = kcontrol->id.index;
-	ucontrol->value.enumerated.item[0] = ice->ak4524.images[chip][3] & 3;
+	int chip = AK_GET_CHIP(kcontrol->private_value);
+	int addr = AK_GET_ADDR(kcontrol->private_value);
+	int shift = AK_GET_SHIFT(kcontrol->private_value);
+	ucontrol->value.enumerated.item[0] = (ice->ak4524.images[chip][addr] >> shift) & 3;
 	return 0;
 }
 
 static int snd_ice1712_ak4524_deemphasis_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol)
 {
 	ice1712_t *ice = snd_kcontrol_chip(kcontrol);
-	int chip = kcontrol->id.index;
-	unsigned char nval = ucontrol->value.enumerated.item[0];
+	int chip = AK_GET_CHIP(kcontrol->private_value);
+	int addr = AK_GET_ADDR(kcontrol->private_value);
+	int shift = AK_GET_SHIFT(kcontrol->private_value);
+	unsigned char nval = ucontrol->value.enumerated.item[0] & 3;
 	int change;
-	nval |= (nval & 3) | (ice->ak4524.images[chip][3] & ~3);
-	change = ice->ak4524.images[chip][3] != nval;
+	
+	nval = (nval << shift) | (ice->ak4524.images[chip][addr] & ~(3 << shift));
+	change = ice->ak4524.images[chip][addr] != nval;
 	if (change)
-		snd_ice1712_ak4524_write(ice, chip, 3, nval);
+		snd_ice1712_ak4524_write(ice, chip, addr, nval);
 	return change;
 }
 
@@ -280,15 +338,24 @@
 		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
 		ctl.get = snd_ice1712_ak4524_volume_get;
 		ctl.put = snd_ice1712_ak4524_volume_put;
-		if (ak->is_ak4528)
-			ctl.private_value = (idx / 2) * 8 + (idx % 2) + 4; /* register 4 & 5 */
-		else
-			ctl.private_value = (idx / 2) * 8 + (idx % 2) + 6; /* register 6 & 7 */
+		switch (ak->type) {
+		case SND_AK4524:
+			ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0); /* register 6 & 7 */
+			break;
+		case SND_AK4528:
+			ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0); /* register 4 & 5 */
+			break;
+		case SND_AK4529: {
+			int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */
+			ctl.private_value = AK_COMPOSE(0, val, 0);
+			break;
+		}
+		}
 		ctl.private_data = ice;
 		if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
 			return err;
 	}
-	for (idx = 0; idx < ak->num_adcs && !ak->is_ak4528; ++idx) {
+	for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) {
 		snd_kcontrol_t ctl;
 		memset(&ctl, 0, sizeof(ctl));
 		strcpy(ctl.id.name, "ADC Volume");
@@ -298,7 +365,7 @@
 		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
 		ctl.get = snd_ice1712_ak4524_volume_get;
 		ctl.put = snd_ice1712_ak4524_volume_put;
-		ctl.private_value = (idx / 2) * 8 + (idx % 2) + 4; /* register 4 & 5 */
+		ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0); /* register 4 & 5 */
 		ctl.private_data = ice;
 		if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
 			return err;
@@ -310,7 +377,7 @@
 		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
 		ctl.get = snd_ice1712_ak4524_ipga_gain_get;
 		ctl.put = snd_ice1712_ak4524_ipga_gain_put;
-		ctl.private_value = (idx / 2) * 8 + (idx % 2) + 4; /* register 4 & 5 */
+		ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0); /* register 4 & 5 */
 		ctl.private_data = ice;
 		if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
 			return err;
@@ -325,6 +392,17 @@
 		ctl.access = SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE;
 		ctl.get = snd_ice1712_ak4524_deemphasis_get;
 		ctl.put = snd_ice1712_ak4524_deemphasis_put;
+		switch (ak->type) {
+		case SND_AK4524:
+		case SND_AK4528:
+			ctl.private_value = AK_COMPOSE(idx, 3, 0); /* register 3 */
+			break;
+		case SND_AK4529: {
+			int shift = idx == 3 ? 6 : (2 - idx) * 2;
+			ctl.private_value = AK_COMPOSE(0, 8, shift); /* register 8 with shift */
+			break;
+		}
+		}
 		ctl.private_data = ice;
 		if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl))) < 0)
 			return err;
diff -Nru a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c
--- a/sound/pci/ice1712/delta.c	Sun Nov 10 19:28:37 2002
+++ b/sound/pci/ice1712/delta.c	Sun Nov 10 19:28:37 2002
@@ -337,6 +337,9 @@
 	case ICE1712_SUBDEVICE_AUDIOPHILE:
 		ice->num_total_dacs = 2;
 		break;
+	case ICE1712_SUBDEVICE_DELTA410:
+		ice->num_total_dacs = 8;
+		break;
 	case ICE1712_SUBDEVICE_DELTA44:
 	case ICE1712_SUBDEVICE_DELTA66:
 		ice->num_total_dacs = ice->omni ? 8 : 4;
@@ -350,6 +353,7 @@
 	/* initialize spdif */
 	switch (ice->eeprom.subvendor) {
 	case ICE1712_SUBDEVICE_AUDIOPHILE:
+	case ICE1712_SUBDEVICE_DELTA410:
 	case ICE1712_SUBDEVICE_DELTA1010LT:
 		if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) {
 			snd_printk("unable to create I2C bus\n");
@@ -378,12 +382,17 @@
 	ak = &ice->ak4524;
 	switch (ice->eeprom.subvendor) {
 	case ICE1712_SUBDEVICE_AUDIOPHILE:
+	case ICE1712_SUBDEVICE_DELTA410:
 		ak->num_adcs = ak->num_dacs = 2;
-		ak->is_ak4528 = 1;
-		ak->cif = 0; /* the default level of the CIF pin from AK4524 */
+		ak->type = SND_AK4528;
+		if (ice->eeprom.subvendor == ICE1712_SUBDEVICE_DELTA410) {
+			ak->num_dacs = 8;
+			ak->type = SND_AK4529;
+		}
+		ak->cif = 0; /* the default level of the CIF pin from AK4528/4529 */
 		ak->data_mask = ICE1712_DELTA_AP_DOUT;
 		ak->clk_mask = ICE1712_DELTA_AP_CCLK;
-		ak->cs_mask = ak->cs_addr = ICE1712_DELTA_AP_CS_CODEC; /* select AK4528 codec */
+		ak->cs_mask = ak->cs_addr = ICE1712_DELTA_AP_CS_CODEC; /* select AK4528/4529 codec */
 		ak->cs_none = 0;
 		ak->add_flags = ICE1712_DELTA_AP_CS_DIGITAL; /* assert digital high */
 		ak->mask_flags = 0;
@@ -392,6 +401,7 @@
 		break;
 	case ICE1712_SUBDEVICE_DELTA1010LT:
 		ak->num_adcs = ak->num_dacs = 8;
+		ak->type = SND_AK4524;
 		ak->cif = 0; /* the default level of the CIF pin from AK4524 */
 		ak->data_mask = ICE1712_DELTA_1010LT_DOUT;
 		ak->clk_mask = ICE1712_DELTA_1010LT_CCLK;
@@ -406,6 +416,7 @@
 	case ICE1712_SUBDEVICE_DELTA66:
 	case ICE1712_SUBDEVICE_DELTA44:
 		ak->num_adcs = ak->num_dacs = 4;
+		ak->type = SND_AK4524;
 		ak->cif = 0; /* the default level of the CIF pin from AK4524 */
 		ak->data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA;
 		ak->clk_mask = ICE1712_DELTA_CODEC_SERIAL_CLOCK;
@@ -471,6 +482,8 @@
 	case ICE1712_SUBDEVICE_DELTADIO2496:
 	case ICE1712_SUBDEVICE_DELTA66:
 	case ICE1712_SUBDEVICE_AUDIOPHILE:
+	case ICE1712_SUBDEVICE_DELTA410:
+	case ICE1712_SUBDEVICE_DELTA1010LT:
 		err = snd_ice1712_spdif_build_controls(ice);
 		if (err < 0)
 			return err;
@@ -492,6 +505,7 @@
 	switch (ice->eeprom.subvendor) {
 	case ICE1712_SUBDEVICE_DELTA1010LT:
 	case ICE1712_SUBDEVICE_AUDIOPHILE:
+	case ICE1712_SUBDEVICE_DELTA410:
 	case ICE1712_SUBDEVICE_DELTA44:
 	case ICE1712_SUBDEVICE_DELTA66:
 		err = snd_ice1712_ak4524_build_controls(ice);
@@ -535,6 +549,12 @@
 	{
 		ICE1712_SUBDEVICE_AUDIOPHILE,
 		"M Audio Audiophile 24/96",
+		snd_ice1712_delta_init,
+		snd_ice1712_delta_add_controls,
+	},
+	{
+		ICE1712_SUBDEVICE_DELTA410,
+		"M Audio Delta 410",
 		snd_ice1712_delta_init,
 		snd_ice1712_delta_add_controls,
 	},
diff -Nru a/sound/pci/ice1712/delta.h b/sound/pci/ice1712/delta.h
--- a/sound/pci/ice1712/delta.h	Sun Nov 10 19:28:40 2002
+++ b/sound/pci/ice1712/delta.h	Sun Nov 10 19:28:40 2002
@@ -37,6 +37,7 @@
 #define ICE1712_SUBDEVICE_DELTA66	0x121432d6
 #define ICE1712_SUBDEVICE_DELTA44	0x121433d6
 #define ICE1712_SUBDEVICE_AUDIOPHILE	0x121434d6
+#define ICE1712_SUBDEVICE_DELTA410	0x121438d6
 #define ICE1712_SUBDEVICE_DELTA1010LT	0x12143bd6
 
 /* entry point */
@@ -106,7 +107,8 @@
 /* 0x40 = CODEC_CHIP_A */
 /* 0x80 = CODEC_CHIP_B */
 
-/* MidiMan M-Audio Audiophile definitions */
+/* MidiMan M-Audio Audiophile/Delta410 definitions */
+/* thanks to Kristof Pelckmans <Kristof.Pelckmans@antwerpen.be> for Delta410 info */
 /* 0x01 = DFS */
 #define ICE1712_DELTA_AP_CCLK	0x02	/* SPI clock */
 					/* (clocking on rising edge - 0->1) */
@@ -114,7 +116,7 @@
 #define ICE1712_DELTA_AP_DOUT	0x08	/* data output */
 #define ICE1712_DELTA_AP_CS_DIGITAL 0x10 /* CS8427 chip select */
 					/* low signal = select */
-#define ICE1712_DELTA_AP_CS_CODEC 0x20	/* AK4528 chip select */
+#define ICE1712_DELTA_AP_CS_CODEC 0x20	/* AK4528 (audiophile), AK4529 (Delta410) chip select */
 					/* low signal = select */
 
 /* MidiMan M-Audio Delta1010LT definitions */
diff -Nru a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
--- a/sound/pci/ice1712/ews.c	Sun Nov 10 19:28:38 2002
+++ b/sound/pci/ice1712/ews.c	Sun Nov 10 19:28:38 2002
@@ -406,6 +406,7 @@
 	switch (ice->eeprom.subvendor) {
 	case ICE1712_SUBDEVICE_EWS88MT:
 		ak->num_adcs = ak->num_dacs = 8;
+		ak->type = SND_AK4524;
 		ak->cif = 1; /* CIF high */
 		ak->data_mask = ICE1712_EWS88_SERIAL_DATA;
 		ak->clk_mask = ICE1712_EWS88_SERIAL_CLOCK;
@@ -418,6 +419,7 @@
 		break;
 	case ICE1712_SUBDEVICE_EWX2496:
 		ak->num_adcs = ak->num_dacs = 2;
+		ak->type = SND_AK4524;
 		ak->cif = 1; /* CIF high */
 		ak->data_mask = ICE1712_EWS88_SERIAL_DATA;
 		ak->clk_mask = ICE1712_EWS88_SERIAL_CLOCK;
@@ -430,6 +432,7 @@
 		break;
 	case ICE1712_SUBDEVICE_DMX6FIRE:
 		ak->num_adcs = ak->num_dacs = 6;
+		ak->type = SND_AK4524;
 		ak->cif = 1; /* CIF high */
 		ak->data_mask = ICE1712_6FIRE_SERIAL_DATA;
 		ak->clk_mask = ICE1712_6FIRE_SERIAL_CLOCK;
diff -Nru a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
--- a/sound/pci/ice1712/ice1712.c	Sun Nov 10 19:28:38 2002
+++ b/sound/pci/ice1712/ice1712.c	Sun Nov 10 19:28:38 2002
@@ -1532,7 +1532,7 @@
 
 /*
  */
-static int snd_ice1712_spdif_default_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+static int snd_ice1712_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
 {
 	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
 	uinfo->count = 1;
@@ -1559,20 +1559,13 @@
 
 static snd_kcontrol_new_t snd_ice1712_spdif_default __devinitdata =
 {
-	.iface =		SNDRV_CTL_ELEM_IFACE_PCM,
-	.name =           SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
-	.info =		snd_ice1712_spdif_default_info,
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT),
+	.info =		snd_ice1712_spdif_info,
 	.get =		snd_ice1712_spdif_default_get,
 	.put =		snd_ice1712_spdif_default_put
 };
 
-static int snd_ice1712_spdif_mask_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
-	uinfo->count = 1;
-	return 0;
-}
-
 static int snd_ice1712_spdif_maskc_get(snd_kcontrol_t * kcontrol,
 				       snd_ctl_elem_value_t * ucontrol)
 {
@@ -1617,29 +1610,22 @@
 
 static snd_kcontrol_new_t snd_ice1712_spdif_maskc __devinitdata =
 {
-	.access =		SNDRV_CTL_ELEM_ACCESS_READ,
-	.iface =		SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name =           SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
-	.info =		snd_ice1712_spdif_mask_info,
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK),
+	.info =		snd_ice1712_spdif_info,
 	.get =		snd_ice1712_spdif_maskc_get,
 };
 
 static snd_kcontrol_new_t snd_ice1712_spdif_maskp __devinitdata =
 {
-	.access =		SNDRV_CTL_ELEM_ACCESS_READ,
-	.iface =		SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name =           SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
-	.info =		snd_ice1712_spdif_mask_info,
+	.access =	SNDRV_CTL_ELEM_ACCESS_READ,
+	.iface =	SNDRV_CTL_ELEM_IFACE_MIXER,
+	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK),
+	.info =		snd_ice1712_spdif_info,
 	.get =		snd_ice1712_spdif_maskp_get,
 };
 
-static int snd_ice1712_spdif_stream_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
-{
-	uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
-	uinfo->count = 1;
-	return 0;
-}
-
 static int snd_ice1712_spdif_stream_get(snd_kcontrol_t * kcontrol,
 					snd_ctl_elem_value_t * ucontrol)
 {
@@ -1660,10 +1646,10 @@
 
 static snd_kcontrol_new_t snd_ice1712_spdif_stream __devinitdata =
 {
-	.access =		SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
-	.iface =		SNDRV_CTL_ELEM_IFACE_PCM,
-	.name =           SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
-	.info =		snd_ice1712_spdif_stream_info,
+	.access =	SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE,
+	.iface =	SNDRV_CTL_ELEM_IFACE_PCM,
+	.name =         SNDRV_CTL_NAME_IEC958("",PLAYBACK,PCM_STREAM),
+	.info =		snd_ice1712_spdif_info,
 	.get =		snd_ice1712_spdif_stream_get,
 	.put =		snd_ice1712_spdif_stream_put
 };
diff -Nru a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h
--- a/sound/pci/ice1712/ice1712.h	Sun Nov 10 19:28:36 2002
+++ b/sound/pci/ice1712/ice1712.h	Sun Nov 10 19:28:36 2002
@@ -239,10 +239,12 @@
 struct snd_ak4524 {
 	int num_adcs;			/* AK4524 or AK4528 ADCs */
 	int num_dacs;			/* AK4524 or AK4528 DACs */
-	unsigned char images[4][8];
+	unsigned char images[4][16];
 	unsigned char ipga_gain[4][2];
 	/* */
-	unsigned int is_ak4528: 1;	/* AK4524 or AK4528 */
+	enum {
+		SND_AK4524, SND_AK4528, SND_AK4529
+	} type;
 	unsigned int cif: 1;
 	unsigned char data_mask;
 	unsigned char clk_mask;
diff -Nru a/sound/pci/rme9652/hammerfall_mem.c b/sound/pci/rme9652/hammerfall_mem.c
--- a/sound/pci/rme9652/hammerfall_mem.c	Sun Nov 10 19:28:37 2002
+++ b/sound/pci/rme9652/hammerfall_mem.c	Sun Nov 10 19:28:37 2002
@@ -25,7 +25,7 @@
     along with this program; if not, write to the Free Software
     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
-    $Id: hammerfall_mem.c,v 1.4 2002/10/21 18:28:25 perex Exp $
+    $Id: hammerfall_mem.c,v 1.5 2002/11/04 09:11:42 perex Exp $
 
 
     Tue Oct 17 2000  Jaroslav Kysela <perex@suse.cz>
@@ -34,7 +34,6 @@
     
 */
 
-#include <linux/config.h>
 #include <linux/version.h>
 #include <linux/module.h>
 #include <linux/pci.h>
diff -Nru a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
--- a/sound/pci/rme9652/hdsp.c	Sun Nov 10 19:28:38 2002
+++ b/sound/pci/rme9652/hdsp.c	Sun Nov 10 19:28:38 2002
@@ -949,6 +949,7 @@
 	spin_lock_irqsave (&hmidi->lock, flags);
 	if (up) {
 		if (!hmidi->istimer) {
+			init_timer(&hmidi->timer);
 			hmidi->timer.function = snd_hdsp_midi_output_timer;
 			hmidi->timer.data = (unsigned long) hmidi;
 			hmidi->timer.expires = 1 + jiffies;
diff -Nru a/sound/pci/via82xx.c b/sound/pci/via82xx.c
--- a/sound/pci/via82xx.c	Sun Nov 10 19:28:38 2002
+++ b/sound/pci/via82xx.c	Sun Nov 10 19:28:38 2002
@@ -201,11 +201,16 @@
 } viadev_t;
 
 
+/*
+ * allocate and initialize the descriptor buffers
+ * periods = number of periods
+ * fragsize = period size in bytes
+ */
 static int build_via_table(viadev_t *dev, snd_pcm_substream_t *substream,
-			   struct pci_dev *pci)
+			   struct pci_dev *pci,
+			   int periods, int fragsize)
 {
-	int i, idx, ofs, rest, fragsize;
-	snd_pcm_runtime_t *runtime = substream->runtime;
+	int i, idx, ofs, rest;
 	struct snd_sg_buf *sgbuf = snd_magic_cast(snd_pcm_sgbuf_t, substream->dma_private, return -EINVAL);
 
 	if (! dev->table) {
@@ -223,10 +228,9 @@
 	}
 
 	/* fill the entries */
-	fragsize = snd_pcm_lib_period_bytes(substream);
 	idx = 0;
 	ofs = 0;
-	for (i = 0; i < runtime->periods; i++) {
+	for (i = 0; i < periods; i++) {
 		rest = fragsize;
 		/* fill descriptors for a period.
 		 * a period can be split to several descriptors if it's
@@ -241,7 +245,7 @@
 				r = rest;
 			rest -= r;
 			if (! rest) {
-				if (i == runtime->periods - 1)
+				if (i == periods - 1)
 					flag = VIA_TBL_BIT_EOL; /* buffer boundary */
 				else
 					flag = VIA_TBL_BIT_FLAG; /* period boundary */
@@ -472,19 +476,14 @@
 }
 
 
-static int snd_via82xx_setup_periods(via82xx_t *chip, viadev_t *viadev,
-				     snd_pcm_substream_t *substream)
+static int snd_via82xx_set_format(via82xx_t *chip, viadev_t *viadev,
+				  snd_pcm_substream_t *substream)
 {
 	snd_pcm_runtime_t *runtime = substream->runtime;
 	unsigned long port = chip->port + viadev->reg_offset;
-	int err;
 
 	snd_via82xx_channel_reset(chip, viadev);
 
-	err = build_via_table(viadev, substream, chip->pci);
-	if (err < 0)
-		return err;
-
 	outl((u32)viadev->table_addr, port + VIA_REG_OFFSET_TABLE_PTR);
 	switch (chip->chip_type) {
 	case TYPE_VIA686:
@@ -583,11 +582,28 @@
 static int snd_via82xx_hw_params(snd_pcm_substream_t * substream,
 				 snd_pcm_hw_params_t * hw_params)
 {
-	return snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
+	viadev_t *viadev = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? &chip->playback : &chip->capture;
+	int err;
+
+	err = snd_pcm_sgbuf_alloc(substream, params_buffer_bytes(hw_params));
+	if (err < 0)
+		return err;
+	err = build_via_table(viadev, substream, chip->pci,
+			      params_periods(hw_params),
+			      params_period_bytes(hw_params));
+	if (err < 0)
+		return err;
+	return err;
 }
 
 static int snd_via82xx_hw_free(snd_pcm_substream_t * substream)
 {
+	via82xx_t *chip = snd_pcm_substream_chip(substream);
+	viadev_t *viadev = substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? &chip->playback : &chip->capture;
+
+	clean_via_table(viadev, substream, chip->pci);
+	snd_pcm_sgbuf_free(substream);
 	return 0;
 }
 
@@ -606,7 +622,7 @@
 		tmp = inl(VIAREG(chip, PLAYBACK_STOP_IDX)) & ~0xfffff;
 		outl(tmp | (0xffff * runtime->rate)/(48000/16), VIAREG(chip, PLAYBACK_STOP_IDX));
 	}
-	return snd_via82xx_setup_periods(chip, &chip->playback, substream);
+	return snd_via82xx_set_format(chip, &chip->playback, substream);
 }
 
 static int snd_via82xx_capture_prepare(snd_pcm_substream_t * substream)
@@ -617,7 +633,7 @@
 	snd_ac97_set_rate(chip->ac97, AC97_PCM_LR_ADC_RATE, runtime->rate);
 	if (chip->chip_type == TYPE_VIA8233)
 		outb(VIA_REG_CAPTURE_FIFO_ENABLE, VIAREG(chip, CAPTURE_FIFO));
-	return snd_via82xx_setup_periods(chip, &chip->capture, substream);
+	return snd_via82xx_set_format(chip, &chip->capture, substream);
 }
 
 static inline unsigned int snd_via82xx_cur_ptr(via82xx_t *chip, viadev_t *viadev)
@@ -761,20 +777,16 @@
 static int snd_via82xx_playback_close(snd_pcm_substream_t * substream)
 {
 	via82xx_t *chip = snd_pcm_substream_chip(substream);
-
-	clean_via_table(&chip->playback, substream, chip->pci);
-	snd_pcm_sgbuf_delete(substream);
 	chip->playback.substream = NULL;
+	snd_pcm_sgbuf_delete(substream);
 	return 0;
 }
 
 static int snd_via82xx_capture_close(snd_pcm_substream_t * substream)
 {
 	via82xx_t *chip = snd_pcm_substream_chip(substream);
-
-	clean_via_table(&chip->capture, substream, chip->pci);
-	snd_pcm_sgbuf_delete(substream);
 	chip->capture.substream = NULL;
+	snd_pcm_sgbuf_delete(substream);
 	return 0;
 }
 
diff -Nru a/sound/sparc/amd7930.c b/sound/sparc/amd7930.c
--- a/sound/sparc/amd7930.c	Sun Nov 10 19:28:37 2002
+++ b/sound/sparc/amd7930.c	Sun Nov 10 19:28:37 2002
@@ -29,7 +29,6 @@
  * --- End of notes from Thoamas's original driver ---
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
diff -Nru a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c
--- a/sound/usb/usbaudio.c	Sun Nov 10 19:28:40 2002
+++ b/sound/usb/usbaudio.c	Sun Nov 10 19:28:40 2002
@@ -935,7 +935,8 @@
 	struct usb_device *dev = subs->dev;
 	struct usb_host_config *config = dev->actconfig;
 	struct usb_host_interface *alts;
-	struct usb_interface *iface;	
+	struct usb_interface_descriptor *altsd;
+	struct usb_interface *iface;
 	struct audioformat *fmt;
 	unsigned int ep, attr;
 	unsigned char data[3];
@@ -951,7 +952,8 @@
 
 	iface = &config->interface[fmt->iface];
 	alts = &iface->altsetting[fmt->altset_idx];
-	snd_assert(alts->desc.bAlternateSetting == fmt->altsetting, return -EINVAL);
+	altsd = get_iface_desc(alts);
+	snd_assert(altsd->bAlternateSetting == fmt->altsetting, return -EINVAL);
 
 	/* close the old interface */
 	if (subs->interface >= 0 && subs->interface != fmt->iface) {
@@ -973,31 +975,31 @@
 	}
 
 	/* create a data pipe */
-	ep = alts->endpoint[0].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	ep = get_endpoint(alts, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 	if (is_playback)
 		subs->datapipe = usb_sndisocpipe(dev, ep);
 	else
 		subs->datapipe = usb_rcvisocpipe(dev, ep);
 	subs->syncpipe = subs->syncinterval = 0;
-	subs->maxpacksize = alts->endpoint[0].desc.wMaxPacketSize;
+	subs->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize;
 	subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize);
 	subs->fill_max = 0;
 
 	/* we need a sync pipe in async OUT or adaptive IN mode */
-	attr = alts->endpoint[0].desc.bmAttributes & EP_ATTR_MASK;
+	attr = get_endpoint(alts, 0)->bmAttributes & EP_ATTR_MASK;
 	if ((is_playback && attr == EP_ATTR_ASYNC) ||
 	    (! is_playback && attr == EP_ATTR_ADAPTIVE)) {
 		/* check endpoint */
-		if (alts->desc.bNumEndpoints < 2 ||
-		    alts->endpoint[1].desc.bmAttributes != 0x01 ||
-		    alts->endpoint[1].desc.bSynchAddress != 0) {
+		if (altsd->bNumEndpoints < 2 ||
+		    get_endpoint(alts, 1)->bmAttributes != 0x01 ||
+		    get_endpoint(alts, 1)->bSynchAddress != 0) {
 			snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
 				   dev->devnum, fmt->iface, fmt->altsetting);
 			return -EINVAL;
 		}
-		ep = alts->endpoint[1].desc.bEndpointAddress;
-		if ((is_playback && ep != (alts->endpoint[0].desc.bSynchAddress | USB_DIR_IN)) ||
-		    (! is_playback && ep != (alts->endpoint[0].desc.bSynchAddress & ~USB_DIR_IN))) {
+		ep = get_endpoint(alts, 1)->bEndpointAddress;
+		if ((is_playback && ep != (get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) ||
+		    (! is_playback && ep != (get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN))) {
 			snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n",
 				   dev->devnum, fmt->iface, fmt->altsetting);
 			return -EINVAL;
@@ -1007,10 +1009,10 @@
 			subs->syncpipe = usb_rcvisocpipe(dev, ep);
 		else
 			subs->syncpipe = usb_sndisocpipe(dev, ep);
-		subs->syncinterval = alts->endpoint[1].desc.bRefresh;
+		subs->syncinterval = get_endpoint(alts, 1)->bRefresh;
 	}
 
-	ep = alts->endpoint[0].desc.bEndpointAddress;
+	ep = get_endpoint(alts, 0)->bEndpointAddress;
 	/* if endpoint has pitch control, enable it */
 	if (fmt->attributes & EP_CS_ATTR_PITCH_CONTROL) {
 		data[0] = 1;
@@ -1676,6 +1678,7 @@
 	struct usb_host_config *config;
 	struct usb_interface *iface;
 	struct usb_host_interface *alts;
+	struct usb_interface_descriptor *altsd;
 	int i, altno, err, stream;
 	int channels, nr_rates, pcm_format, format;
 	struct audioformat *fp;
@@ -1688,19 +1691,20 @@
 	iface = &config->interface[iface_no];
 	for (i = 0; i < iface->num_altsetting; i++) {
 		alts = &iface->altsetting[i];
+		altsd = get_iface_desc(alts);
 		/* skip invalid one */
-		if (alts->desc.bInterfaceClass != USB_CLASS_AUDIO ||
-		    alts->desc.bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING ||
-		    alts->desc.bNumEndpoints < 1)
+		if (altsd->bInterfaceClass != USB_CLASS_AUDIO ||
+		    altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING ||
+		    altsd->bNumEndpoints < 1)
 			continue;
 		/* must be isochronous */
-		if ((alts->endpoint[0].desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
+		if ((get_endpoint(alts, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
 		    USB_ENDPOINT_XFER_ISOC)
 			continue;
 		/* check direction */
-		stream = (alts->endpoint[0].desc.bEndpointAddress & USB_DIR_IN) ?
+		stream = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN) ?
 			SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK;
-		altno = alts->desc.bAlternateSetting;
+		altno = altsd->bAlternateSetting;
 
 		/* get audio formats */
 		fmt = snd_usb_find_csint_desc(buffer, buflen, NULL, AS_GENERAL, iface_no, altno);
@@ -1767,8 +1771,8 @@
 		fp->altsetting = altno;
 		fp->altset_idx = i;
 		fp->format = pcm_format;
-		fp->endpoint = alts->endpoint[0].desc.bEndpointAddress;
-		fp->ep_attr = alts->endpoint[0].desc.bmAttributes;
+		fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
+		fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
 		fp->channels = channels;
 		fp->attributes = csep[3];
 
@@ -1857,8 +1861,10 @@
 	 */
 	config = dev->actconfig;
 	for (i = 0; i < p1[7]; i++) {
+		struct usb_host_interface *alts;
+		struct usb_interface_descriptor *altsd;
 		j = p1[8 + i];
-		if (j >= config->desc.bNumInterfaces) {
+		if (j >= get_cfg_desc(config)->bNumInterfaces) {
 			snd_printk(KERN_ERR "%d:%u:%d : does not exist\n",
 				   dev->devnum, ctrlif, j);
 			continue;
@@ -1868,8 +1874,10 @@
 			snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", dev->devnum, ctrlif, j);
 			continue;
 		}
-		if (iface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO &&
-		    iface->altsetting[0].desc.bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) {
+		alts = &iface->altsetting[0];
+		altsd = get_iface_desc(alts);
+		if (altsd->bInterfaceClass == USB_CLASS_AUDIO &&
+		    altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) {
 			if (snd_usb_create_midi_interface(chip, iface, NULL) < 0) {
 				snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j);
 				continue;
@@ -1877,9 +1885,9 @@
 			usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1);
 			continue;
 		}
-		if (iface->altsetting[0].desc.bInterfaceClass != USB_CLASS_AUDIO ||
-		    iface->altsetting[0].desc.bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING) {
-			snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", dev->devnum, ctrlif, j, iface->altsetting[0].bInterfaceClass);
+		if (altsd->bInterfaceClass != USB_CLASS_AUDIO ||
+		    altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING) {
+			snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", dev->devnum, ctrlif, j, altsd->bInterfaceClass);
 			/* skip non-supported classes */
 			continue;
 		}
@@ -1941,7 +1949,7 @@
 	struct usb_interface *iface;
 	int err;
 
-	if (cfg->desc.bNumInterfaces != 3) {
+	if (get_cfg_desc(cfg)->bNumInterfaces != 3) {
 		snd_printdd(KERN_ERR "invalid UA-100 descriptor\n");
 		return -ENXIO;
 	}
@@ -2134,18 +2142,22 @@
 				 struct usb_interface *intf,
 				 const struct usb_device_id *usb_id)
 {
-	struct usb_host_config *config = dev->actconfig;	
+	struct usb_host_config *config = dev->actconfig;
 	const snd_usb_audio_quirk_t *quirk = (const snd_usb_audio_quirk_t *)usb_id->driver_info;
 	int i;
 	snd_card_t *card;
 	snd_usb_audio_t *chip;
-	int ifnum = intf->altsetting->desc.bInterfaceNumber;
+	struct usb_host_interface *alts;
+	int ifnum;
+
+	alts = &intf->altsetting[0];
+	ifnum = get_iface_desc(alts)->bInterfaceNumber;
 
 	if (quirk && quirk->ifnum != QUIRK_ANY_INTERFACE && ifnum != quirk->ifnum)
 		goto __err_val;
 
-	if (usb_set_configuration(dev, config->desc.bConfigurationValue) < 0) {
-		snd_printk(KERN_ERR "cannot set configuration (value 0x%x)\n", config->desc.bConfigurationValue);
+	if (usb_set_configuration(dev, get_cfg_desc(config)->bConfigurationValue) < 0) {
+		snd_printk(KERN_ERR "cannot set configuration (value 0x%x)\n", get_cfg_desc(config)->bConfigurationValue);
 		goto __err_val;
 	}
 
diff -Nru a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
--- a/sound/usb/usbaudio.h	Sun Nov 10 19:28:40 2002
+++ b/sound/usb/usbaudio.h	Sun Nov 10 19:28:40 2002
@@ -191,4 +191,15 @@
 
 int snd_usb_create_midi_interface(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk);
 
+/*
+ * retrieve usb_interface descriptor from the host interface
+ * (conditional for compatibility with the older API)
+ */
+#ifndef get_iface_desc
+#define get_iface_desc(iface)	(&iface->desc)
+#define get_endpoint(alt,ep)	(&(alt)->endpoint[ep].desc)
+#define get_ep_desc(ep)		(&(ep)->desc)
+#define get_cfg_desc(cfg)	(&(cfg)->desc)
+#endif
+
 #endif /* __USBAUDIO_H */
diff -Nru a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c
--- a/sound/usb/usbmidi.c	Sun Nov 10 19:28:41 2002
+++ b/sound/usb/usbmidi.c	Sun Nov 10 19:28:41 2002
@@ -515,7 +515,8 @@
 static struct usb_endpoint_descriptor* snd_usbmidi_get_int_epd(snd_usb_midi_t* umidi)
 {
 	struct usb_interface* intf;
-	struct usb_host_interface* intfd;
+	struct usb_host_interface *hostif;
+	struct usb_interface_descriptor* intfd;
 
 	if (umidi->chip->dev->descriptor.idVendor != 0x0582)
 		return NULL;
@@ -523,29 +524,37 @@
 	if (!intf || intf->num_altsetting != 2)
 		return NULL;
 
-	intfd = &intf->altsetting[0];
-	if (intfd->desc.bNumEndpoints != 2 ||
-	    (intfd->endpoint[0].desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ||
-	    (intfd->endpoint[1].desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
+	hostif = &intf->altsetting[0];
+	intfd = get_iface_desc(hostif);
+	if (intfd->bNumEndpoints != 2 ||
+	    (get_endpoint(hostif, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ||
+	    (get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
 		return NULL;
 
-	intfd = &intf->altsetting[1];
-	if (intfd->desc.bNumEndpoints != 2 ||
-	    (intfd->endpoint[0].desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ||
-	    (intfd->endpoint[1].desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
+	hostif = &intf->altsetting[1];
+	intfd = get_iface_desc(hostif);
+	if (intfd->bNumEndpoints != 2 ||
+	    (get_endpoint(hostif, 0)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK ||
+	    (get_endpoint(hostif, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT)
 		return NULL;
 
-	usb_set_interface(umidi->chip->dev, intfd->desc.bInterfaceNumber,
-			  intfd->desc.bAlternateSetting);
-	return &intfd->endpoint[1].desc;
+	usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber,
+			  intfd->bAlternateSetting);
+	return get_endpoint(hostif, 1);
 }
 
 static struct usb_endpoint_descriptor* snd_usbmidi_get_midiman_int_epd(snd_usb_midi_t* umidi)
 {
 	struct usb_interface* intf = umidi->iface;
-	if (!intf || intf->altsetting[0].desc.bNumEndpoints < 1)
+	struct usb_host_interface *hostif;
+	struct usb_interface_descriptor *intfd;
+	if (!intf)
+		return NULL;
+	hostif = &intf->altsetting[0];
+	intfd = get_iface_desc(hostif);
+	if (intfd->bNumEndpoints < 1)
 		return NULL;
-	return &intf->altsetting[0].endpoint[0].desc;
+	return get_endpoint(hostif, 0);
 }
 
 /*
@@ -772,18 +781,21 @@
 			   	   snd_usb_midi_endpoint_info_t* endpoints)
 {
 	struct usb_interface* intf;
-	struct usb_host_interface* intfd;
+	struct usb_host_interface *hostif;
+	struct usb_interface_descriptor* intfd;
 	struct usb_ms_header_descriptor* ms_header;
-	struct usb_host_endpoint* ep;
+	struct usb_host_endpoint *hostep;
+	struct usb_endpoint_descriptor* ep;
 	struct usb_ms_endpoint_descriptor* ms_ep;
 	int i, epidx;
 
 	intf = umidi->iface;
 	if (!intf)
 		return -ENXIO;
-	intfd = &intf->altsetting[0];
-	ms_header = (struct usb_ms_header_descriptor*)intfd->extra;
-	if (intfd->extralen >= 7 &&
+	hostif = &intf->altsetting[0];
+	intfd = get_iface_desc(hostif);
+	ms_header = (struct usb_ms_header_descriptor*)hostif->extra;
+	if (hostif->extralen >= 7 &&
 	    ms_header->bLength >= 7 &&
 	    ms_header->bDescriptorType == USB_DT_CS_INTERFACE &&
 	    ms_header->bDescriptorSubtype == HEADER)
@@ -793,33 +805,34 @@
 		printk(KERN_WARNING "snd-usb-midi: MIDIStreaming interface descriptor not found\n");
 
 	epidx = 0;
-	for (i = 0; i < intfd->desc.bNumEndpoints; ++i) {
-		ep = &intfd->endpoint[i];
-		if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
+	for (i = 0; i < intfd->bNumEndpoints; ++i) {
+		hostep = &hostif->endpoint[i];
+		ep = get_ep_desc(hostep);
+		if ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK)
 			continue;
-		ms_ep = (struct usb_ms_endpoint_descriptor*)ep->extra;
-		if (ep->extralen < 4 ||
+		ms_ep = (struct usb_ms_endpoint_descriptor*)hostep->extra;
+		if (hostep->extralen < 4 ||
 		    ms_ep->bLength < 4 ||
 		    ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT ||
 		    ms_ep->bDescriptorSubtype != MS_GENERAL)
 			continue;
 		if (endpoints[epidx].epnum != 0 &&
-		    endpoints[epidx].epnum != (ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) {
+		    endpoints[epidx].epnum != (ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)) {
 			++epidx;
 			if (epidx >= MIDI_MAX_ENDPOINTS) {
 				printk(KERN_WARNING "snd-usb-midi: too many endpoints\n");
 				break;
 			}
 		}
-		endpoints[epidx].epnum = ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-		if (ep->desc.bEndpointAddress & USB_DIR_IN) {
+		endpoints[epidx].epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+		if (ep->bEndpointAddress & USB_DIR_IN) {
 			endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
 		} else {
 			endpoints[epidx].out_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1;
 		}
 		printk(KERN_INFO "snd-usb-midi: detected %d %s jack(s) on endpoint %d\n",
 		       ms_ep->bNumEmbMIDIJack,
-		       ep->desc.bEndpointAddress & USB_DIR_IN ? "input" : "output",
+		       ep->bEndpointAddress & USB_DIR_IN ? "input" : "output",
 		       endpoints[epidx].epnum);
 	}
 	return 0;
@@ -833,17 +846,19 @@
 			       	       snd_usb_midi_endpoint_info_t* endpoint)
 {
 	struct usb_interface* intf;
-	struct usb_host_interface* intfd;
+	struct usb_host_interface *hostif;
+	struct usb_interface_descriptor* intfd;
 	struct usb_endpoint_descriptor* epd;
 
 	if (endpoint->epnum == -1) {
 		intf = umidi->iface;
 		if (!intf || intf->num_altsetting < 1)
 			return -ENOENT;
-		intfd = intf->altsetting;
-		if (intfd->desc.bNumEndpoints < 1)
+		hostif = intf->altsetting;
+		intfd = get_iface_desc(hostif);
+		if (intfd->bNumEndpoints < 1)
 			return -ENOENT;
-		epd = &intfd->endpoint [0].desc;
+		epd = get_endpoint(hostif, 0);
 		endpoint->epnum = epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 	}
 	return 0;
@@ -856,18 +871,20 @@
 				     snd_usb_midi_endpoint_info_t* endpoint)
 {
 	struct usb_interface* intf;
-	struct usb_host_interface* intfd;
+	struct usb_host_interface *hostif;
+	struct usb_interface_descriptor* intfd;
 	uint8_t* cs_desc;
 
 	intf = umidi->iface;
 	if (!intf)
 		return -ENOENT;
-	intfd = intf->altsetting;
-	if (intfd->desc.bNumEndpoints < 1)
+	hostif = intf->altsetting;
+	intfd = get_iface_desc(hostif);
+	if (intfd->bNumEndpoints < 1)
 		return -ENOENT;
 
-	for (cs_desc = intfd->extra;
-	     cs_desc < intfd->extra + intfd->extralen && cs_desc[0] >= 2;
+	for (cs_desc = hostif->extra;
+	     cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2;
 	     cs_desc += cs_desc[0]) {
 		if (cs_desc[1] == CS_AUDIO_INTERFACE) {
 			if (cs_desc[2] == MIDI_IN_JACK)
@@ -890,33 +907,35 @@
 {
 	snd_usb_midi_endpoint_info_t ep_info;
 	struct usb_interface* intf;
-	struct usb_host_interface* intfd;
+	struct usb_host_interface *hostif;
+	struct usb_interface_descriptor* intfd;
 	struct usb_endpoint_descriptor* epd;
 	int cable, err;
 
 	intf = umidi->iface;
 	if (!intf)
 		return -ENOENT;
-	intfd = intf->altsetting;
-	if (intfd->desc.bNumEndpoints < (ports > 1 ? 5 : 3)) {
+	hostif = intf->altsetting;
+	intfd = get_iface_desc(hostif);
+	if (intfd->bNumEndpoints < (ports > 1 ? 5 : 3)) {
 		snd_printdd(KERN_ERR "not enough endpoints\n");
 		return -ENOENT;
 	}
 
-	epd = &intfd->endpoint[0].desc;
+	epd = get_endpoint(hostif, 0);
 	if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_IN ||
 	    (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_INT) {
 		snd_printdd(KERN_ERR "endpoint[0] isn't interrupt\n");
 		return -ENXIO;
 	}
-	epd = &intfd->endpoint[2].desc;
+	epd = get_endpoint(hostif, 2);
 	if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT ||
 	    (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) {
 		snd_printdd(KERN_ERR "endpoint[2] isn't bulk output\n");
 		return -ENXIO;
 	}
 	if (ports > 1) {
-		epd = &intfd->endpoint[4].desc;
+		epd = get_endpoint(hostif, 4);
 		if ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) != USB_DIR_OUT ||
 		    (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_BULK) {
 			snd_printdd(KERN_ERR "endpoint[4] isn't bulk output\n");
@@ -924,13 +943,13 @@
 		}
 	}
 
-	ep_info.epnum = intfd->endpoint[2].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	ep_info.epnum = get_endpoint(hostif, 2)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 	ep_info.out_cables = 0x5555 & ((1 << ports) - 1);
 	err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);
 	if (err < 0)
 		return err;
 
-	ep_info.epnum = intfd->endpoint[0].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	ep_info.epnum = get_endpoint(hostif, 0)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 	ep_info.in_cables = (1 << ports) - 1;
 	err = snd_usbmidi_in_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);
 	if (err < 0)
@@ -938,7 +957,7 @@
 	umidi->endpoints[0].in->urb->complete = snd_usbmidi_in_midiman_complete;
 
 	if (ports > 1) {
-		ep_info.epnum = intfd->endpoint[4].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+		ep_info.epnum = get_endpoint(hostif, 4)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 		ep_info.out_cables = 0xaaaa & ((1 << ports) - 1);
 		err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[1]);
 		if (err < 0)
diff -Nru a/usr/Makefile b/usr/Makefile
--- a/usr/Makefile	Sun Nov 10 19:28:40 2002
+++ b/usr/Makefile	Sun Nov 10 19:28:40 2002
@@ -1,18 +1,16 @@
 
-include arch/$(ARCH)/Makefile
-
 obj-y := initramfs_data.o
 
 host-progs := gen_init_cpio
 
 clean-files := initramfs_data.cpio.gz
 
-$(obj)/initramfs_data.o: $(obj)/initramfs_data.cpio.gz
-	$(OBJCOPY) $(ARCHBLOBLFLAGS) \
-		--rename-section .data=.init.initramfs \
-		$(obj)/initramfs_data.cpio.gz $(obj)/initramfs_data.o
-	$(STRIP) -s $(obj)/initramfs_data.o
+LDFLAGS_initramfs_data.o := $(LDFLAGS_BLOB) -r -T
+
+$(obj)/initramfs_data.o: $(src)/initramfs_data.scr $(obj)/initramfs_data.cpio.gz FORCE
+	$(call if_changed,ld)
 
 $(obj)/initramfs_data.cpio.gz: $(obj)/gen_init_cpio
-	( cd $(obj) ; ./gen_init_cpio | gzip -9c > initramfs_data.cpio.gz )
+	./$< | gzip -9c > $@
+
 
diff -Nru a/usr/initramfs_data.scr b/usr/initramfs_data.scr
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/usr/initramfs_data.scr	Sun Nov 10 19:28:41 2002
@@ -0,0 +1,4 @@
+SECTIONS
+{
+	.init.ramfs : { *(.data) }
+}
