diff -u --recursive --new-file v2.2.1/linux/Documentation/00-INDEX linux/Documentation/00-INDEX
--- v2.2.1/linux/Documentation/00-INDEX	Tue Dec 22 14:16:53 1998
+++ linux/Documentation/00-INDEX	Mon Feb  1 12:03:20 1999
@@ -57,6 +57,8 @@
 	- info on the in-kernel binary support for Java(tm)
 joystick.txt
 	- info on using joystick devices (and driver) with linux.
+kbuild/
+	- directory with info about the kernel build process
 kmod.txt
 	- - info on the kernel module loader/unloader (kerneld replacement)
 locks.txt
diff -u --recursive --new-file v2.2.1/linux/Documentation/kbuild/00-INDEX linux/Documentation/kbuild/00-INDEX
--- v2.2.1/linux/Documentation/kbuild/00-INDEX	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/kbuild/00-INDEX	Mon Feb  1 12:03:20 1999
@@ -0,0 +1,8 @@
+00-INDEX
+    	- this file: info on the kernel build process
+bug-list.txt
+	- known bugs in kbuild programs
+commands.txt
+	- overview of kbuild commands
+config-language.txt
+	- specification of Config Language, the language in Config.in files
diff -u --recursive --new-file v2.2.1/linux/Documentation/kbuild/bug-list.txt linux/Documentation/kbuild/bug-list.txt
--- v2.2.1/linux/Documentation/kbuild/bug-list.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/kbuild/bug-list.txt	Mon Feb  1 12:03:20 1999
@@ -0,0 +1,22 @@
+Bug List
+21 January 1999
+Michael Elizabeth Chastain, <mailto:mec@shout.net>
+
+- If a variable has a value of "m" in the previous .config file,
+  and a type of bool in the Config script, then all the interpreters
+  get confused.  This happens frequently when someone changes a
+  tristate option to a bool option and people in the field have
+  .config files with a value of 'm'.  For example: CONFIG_PSMOUSE.
+
+- CONFIG_MODVERSIONS has incorrect dependencies.  If you have a
+  problem building the kernel, and you have CONFIG_MODVERSIONS turned
+  on, do a 'make dep' followed by 'make clean' before you try anything
+  else.
+
+- 'make dep' uses multistage dependencies, so the .hdepend file contains
+  'touch' commands.  As a result, building a kernel often touches files
+  in include/linux/*.h.  This messes up CVS and other systems which like
+  to rely on file dates.
+
+- 'make dep' fails for C files which include other C files, such as
+  drivers/cdrom/sbpcd2.c.
diff -u --recursive --new-file v2.2.1/linux/Documentation/kbuild/commands.txt linux/Documentation/kbuild/commands.txt
--- v2.2.1/linux/Documentation/kbuild/commands.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/kbuild/commands.txt	Mon Feb  1 12:03:20 1999
@@ -0,0 +1,113 @@
+Overview of Kbuild Commands
+24 January 1999
+Michael Elizabeth Chastain, <mailto:mec@shout.net>
+
+
+
+=== Introduction
+
+Someday we'll get our arms around all this stuff and clean it up
+a little!  Meanwhile, this file describes the system as it is today.
+
+
+
+=== Quick Start
+
+If you are building a kernel for the first time, here are the commands
+you need:
+
+    make config
+    make dep
+    make bzImage
+
+Instead of 'make config', you can run 'make menuconfig' for a full-screen
+text interface, or 'make xconfig' for an X interface using TCL/TK.
+
+'make bzImage' will leave your new kernel image in arch/i386/boot/bzImage.
+You can also use 'make bzdisk' or 'make bzlilo'.
+
+See the lilo documentation for more information on how to use lilo.
+You can also use the 'loadlin' program to boot Linux from MS-DOS.
+
+Some computers won't work with 'make bzImage', either due to hardware
+problems or very old versions of lilo or loadlin.  If your kernel image
+is small, you may use 'make zImage', 'make zdisk', or 'make zlilo'
+on theses systems.
+
+If you find a file name 'vmlinux' in the top directory of the source tree,
+just ignore it.  This is an intermediate file and you can't boot from it.
+
+Other architectures: the information above is oriented towards the
+i386.  On other architectures, there are no 'bzImage' files; simply
+use 'zImage' or 'vmlinux' as appropriate for your architecture.
+
+Note: the difference between 'zImage' files and 'bzImage' files is that
+'bzImage' uses a different layout and a different loading algorithm,
+and thus has a larger capacity.  Both files use gzip compression.
+The 'bz' in 'bzImage' stands for 'big zImage', not for 'bzip'!
+
+
+
+=== Top Level Makefile targets
+
+Here are the targets available at the top level:
+
+    make config, make oldconfig, make menuconfig, make xconfig
+
+	Configure the Linux kernel.  You must do this before almost
+	anything else.
+
+	config		line-oriented interface
+	oldconfig	line-oriented interface, re-uses old values
+	menuconfig	curses-based full-screen interface
+	xconfig		X window system interface
+
+    make checkconfig
+
+	This runs a little perl script that checks the source tree for
+	missing instances of #include <linux/config.h>.  Someone needs to
+	do this occasionally, because the C preprocessor will silently give
+	bad results if these symbols haven't been included (it treats
+	undefined symbols in preprocessor directives as defined to 0).
+	Superfluous uses of #include <linux/config.h> are also reported,
+	but you can ignore these, because smart CONFIG_* dependencies
+	make them harmless.
+
+	You can run 'make checkconfig' without configuring the kernel.
+	Also, 'make checkconfig' does not modify any files.
+
+    make checkhelp
+
+	This runs another little perl script that checks the source tree
+	for options that are in Config.in files but are not documented
+	in scripts/Configure.help.  Again, someone needs to do this
+	occasionally.  If you are adding configuration options, it's
+	nice if you do it before you publish your patch!
+
+	You can run 'make checkhelp' withoug configuring the kernel.
+	Also, 'make checkhelp' does not modify any files.
+
+    make dep, make depend
+
+	'make dep' is a synonym for the long form, 'make depend'.
+
+	This command does two things.  First, it computes dependency
+	information about which .o files depend on which .h files.
+	It records this information in a top-level file named .hdepend
+	and in one file per source directory named .depend.
+
+	Second, if you have CONFIG_MODVERSIONS enabled, 'make dep'
+	computes symbol version information for all of the files that
+	export symbols (note that both resident and modular files may
+	export symbols).
+
+	If you do not enable CONFIG_MODVERSIONS, you only have to run
+	'make dep' once, right after the first time you configure
+	the kernel.  The .hdepend files and the .depend file are
+	independent of your configuration.
+
+	If you do enable CONFIG_MODVERSIONS, you must run 'make dep'
+	every time you change your configuration, because the module
+	symbol version information depends on the configuration.
+
+[to be continued ...]
diff -u --recursive --new-file v2.2.1/linux/Documentation/kbuild/config-language.txt linux/Documentation/kbuild/config-language.txt
--- v2.2.1/linux/Documentation/kbuild/config-language.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/kbuild/config-language.txt	Mon Feb  1 12:03:20 1999
@@ -0,0 +1,630 @@
+Config Language Specification
+21 January 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             (in development)
+
+'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.
+
+This document describes the behaviour of all four interpreters, even though
+mconfig has not been released at the time of writing.
+
+
+
+=== 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 $-substition will be performed on the word.
+
+    A /symbol/ is a single unquoted word.
+
+    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_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:    does not display, but writes to output files
+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 enhancment.
+
+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 '\\'.
+
+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: not implemented
+Xconfig:    not 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: not implemented
+Xconfig:    not implemented
+mconfig:    implemented
+
+Example:
+
+    # Not from the corpus
+    define_int CONFIG_UID_TORVALDS 2026
+
+
+
+=== 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: not implemented
+Xconfig:    not 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:  not implemented
+Menuconfig: not implemented
+Xconfig:    not implemented
+mconfig:    implemented
+
+Example:
+
+    # not from the corpus
+    if [ "$CONFIG_ZFTAPE" != "n" ]; then
+      comment 'The compressor will be built as a module only!'
+      define_tristate CONFIG_ZFT_COMPRESSOR m
+    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 a value of "n", or which has some
+other value, restricts the input range to "n".
+
+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:  not implemented
+Menuconfig: not implemented
+XConfig:    not implemented
+mconfig:    implemented
+
+    # not from the corpus
+    dep_bool 'RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000 $CONFIG_PCI
+
+
+
+=== 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 as 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 a value of "n", or which has some
+other value, restricts the input range to "n".
+
+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 (but silently ignores dependencies after the first)
+Xconfig:    implemented (but silently ignores dependencies after the first)
+mconfig:    implemented
+
+
+
+=== 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:    not implemented
+mconfig:    implemented
+
+
+
+=== 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
+
+
+
+=== 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.
+
+    "..."		a literal
+    "$..."		a variable
+
+    /atom/  = /atom/	true if atoms have identical value
+    /atom/ != /atom/	true if atoms have different value
+
+    /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
+
+Configure:  implemented
+Menuconfig: implemented
+XConfig:    implemented, with bugs
+mconfig:    implemented
+
+Xconfig has several known bugs, and probably some unknown bugs too:
+
+- In a comparison, if the left-hand atom is a variable and that variable
+  is from a choice list, the right-hand atom must be "y".
+
+- In a comparison, if the right-hand atom is a variable and that variable
+  is from a choice list, you lose.  tkparse will throw a segmentation
+  violation, silently generate bizarre TCL code, or something else.
+
+- tkparse gives the wrong precedence to -o, -a, and !.  Don't use both
+  -o and -a in an expression.  Don't use ! at all.
+
+
+
+=== 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 -u --recursive --new-file v2.2.1/linux/Documentation/sound/ESS linux/Documentation/sound/ESS
--- v2.2.1/linux/Documentation/sound/ESS	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/sound/ESS	Mon Feb  1 14:04:39 1999
@@ -0,0 +1,33 @@
+Documentation for the ESS AudioDrive chips
+
+In 2.2 kernels the SoundBlaster driver not only tries to detect an ESS chip, it
+tries to detect the type of ESS chip too. The correct detection of the chip 
+doesn't always succeed however, so the default behaviour is 2.0 behaviour
+which means: only detect ES688 and ES1688.
+
+All ESS chips now have a recording level setting. This is a need-to-have for
+people who want to use their ESS for recording sound.
+
+Every chip that's detected as a later-than-es1688 chip has a 6 bits logarithmic
+master volume control.
+
+Every chip that's detected as a ES1887 now has Full Duplex support. Made a 
+little testprogram that showes that is works, haven't seen a real program that
+needs this however.
+
+For ESS chips an additional parameter "esstype" can be specified. This controls
+the (auto) detection of the ESS chips. It can have 3 kinds of values:
+
+-1   Act like 2.0 kernels: only detect ES688 or ES1688.
+0	 Try to auto-detect the chip (may fail for ES1688)
+688  The chip will be treated as  ES688
+1688  ,,  ,,   ,,  ,,    ,,   ,, ES1688
+1868  ,,  ,,   ,,  ,,    ,,   ,, ES1868
+1869  ,,  ,,   ,,  ,,    ,,   ,, ES1869
+1788  ,,  ,,   ,,  ,,    ,,   ,, ES1788
+1887  ,,  ,,   ,,  ,,    ,,   ,, ES1887
+1888  ,,  ,,   ,,  ,,    ,,   ,, ES1888
+
+Because Full Duplex is supported for ES1887 you can specify a second DMA
+channel by specifying module parameter dma16. It can be one of: 0, 1, 3 or 5.
+
diff -u --recursive --new-file v2.2.1/linux/Documentation/sound/OPL3-SA linux/Documentation/sound/OPL3-SA
--- v2.2.1/linux/Documentation/sound/OPL3-SA	Tue Aug 18 22:02:01 1998
+++ linux/Documentation/sound/OPL3-SA	Mon Feb  1 10:41:47 1999
@@ -2,8 +2,7 @@
 
 ---
 Note: This howto only describes how to setup the OPL3-SA1 chip; this info
-does not apply to the SA2, SA3, or SA4. Contact hannu@opensound.com for
-the support details of these other SAx chips.
+does not apply to the SA2, SA3, or SA4. 
 ---
 
 The Yamaha OPL3-SA1 sound chip is usually found built into motherboards, and
diff -u --recursive --new-file v2.2.1/linux/Makefile linux/Makefile
--- v2.2.1/linux/Makefile	Thu Jan 28 12:58:02 1999
+++ linux/Makefile	Mon Feb  1 12:03:19 1999
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 2
-SUBLEVEL = 1
+SUBLEVEL = 2
 EXTRAVERSION =
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
@@ -221,35 +221,27 @@
 		mkdir include/linux/modules; \
 	fi
 
-oldconfig: symlinks scripts/split-include
+oldconfig: symlinks
 	$(CONFIG_SHELL) scripts/Configure -d arch/$(ARCH)/config.in
-	if [ -r include/linux/autoconf.h ]; then \
-	    scripts/split-include include/linux/autoconf.h include/config; \
-	fi
 
-xconfig: symlinks scripts/split-include
+xconfig: symlinks
 	$(MAKE) -C scripts kconfig.tk
 	wish -f scripts/kconfig.tk
-	if [ -r include/linux/autoconf.h ]; then \
-	    scripts/split-include include/linux/autoconf.h include/config; \
-	fi
 
-menuconfig: include/linux/version.h symlinks scripts/split-include
+menuconfig: include/linux/version.h symlinks
 	$(MAKE) -C scripts/lxdialog all
 	$(CONFIG_SHELL) scripts/Menuconfig arch/$(ARCH)/config.in
-	if [ -r include/linux/autoconf.h ]; then \
-	    scripts/split-include include/linux/autoconf.h include/config; \
-	fi
 
-config: symlinks scripts/split-include
+config: symlinks
 	$(CONFIG_SHELL) scripts/Configure arch/$(ARCH)/config.in
-	if [ -r include/linux/autoconf.h ]; then \
-	    scripts/split-include include/linux/autoconf.h include/config; \
-	fi
+
+include/config/MARKER: scripts/split-include include/linux/autoconf.h
+	scripts/split-include include/linux/autoconf.h include/config
+	@ touch include/config/MARKER
 
 linuxsubdirs: $(patsubst %, _dir_%, $(SUBDIRS))
 
-$(patsubst %, _dir_%, $(SUBDIRS)) : dummy
+$(patsubst %, _dir_%, $(SUBDIRS)) : dummy include/config/MARKER
 	$(MAKE) -C $(patsubst _dir_%, %, $@)
 
 $(TOPDIR)/include/linux/version.h: include/linux/version.h
@@ -286,10 +278,10 @@
 	@echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver
 	@mv -f .ver $@
 
-init/version.o: init/version.c include/linux/compile.h
+init/version.o: init/version.c include/linux/compile.h include/config/MARKER
 	$(CC) $(CFLAGS) -DUTS_MACHINE='"$(ARCH)"' -c -o init/version.o init/version.c
 
-init/main.o: init/main.c
+init/main.o: init/main.c include/config/MARKER
 	$(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $<
 
 fs lib mm ipc kernel drivers net: dummy
diff -u --recursive --new-file v2.2.1/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.2.1/linux/arch/alpha/config.in	Tue Jan 19 11:32:50 1999
+++ linux/arch/alpha/config.in	Mon Feb  1 12:03:20 1999
@@ -243,7 +243,7 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
+comment 'Old CD-ROM drivers (not SCSI, not IDE)'
 
 bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
 if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
diff -u --recursive --new-file v2.2.1/linux/arch/alpha/kernel/entry.S linux/arch/alpha/kernel/entry.S
--- v2.2.1/linux/arch/alpha/kernel/entry.S	Mon Jan 25 17:44:34 1999
+++ linux/arch/alpha/kernel/entry.S	Mon Feb  1 10:41:47 1999
@@ -186,6 +186,18 @@
 	jsr	$31,do_entIF
 .end entIF
 
+.align 3
+.globl	entDbg
+.ent	entDbg
+entDbg:
+	SAVE_ALL
+	lda	$8,0x3fff
+	bic	$30,$8,$8
+	lda	$26,ret_from_sys_call
+	jsr	$31,do_entDbg
+.end entDbg
+
+
 /*
  * Fork() is one of the special system calls: it needs to
  * save the callee-saved regs so that the regs can be found
diff -u --recursive --new-file v2.2.1/linux/arch/alpha/kernel/proto.h linux/arch/alpha/kernel/proto.h
--- v2.2.1/linux/arch/alpha/kernel/proto.h	Wed Jan 13 15:00:41 1999
+++ linux/arch/alpha/kernel/proto.h	Mon Feb  1 10:41:47 1999
@@ -187,6 +187,7 @@
 extern void entMM(void);
 extern void entSys(void);
 extern void entUna(void);
+extern void entDbg(void);
 
 /* process.c */
 extern void generic_kill_arch (int mode, char *reboot_cmd);
diff -u --recursive --new-file v2.2.1/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- v2.2.1/linux/arch/alpha/kernel/traps.c	Fri Oct 23 22:01:19 1998
+++ linux/arch/alpha/kernel/traps.c	Mon Feb  1 10:41:47 1999
@@ -121,9 +121,9 @@
 #endif
 
 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)
+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)
 {
 	if ((summary & 1)) {
 		/*
@@ -145,9 +145,10 @@
 	unlock_kernel();
 }
 
-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)
+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)
 {
 	lock_kernel();
 	die_if_kernel("Instruction fault", &regs, type, 0);
@@ -230,6 +231,25 @@
 	unlock_kernel();
 }
 
+/* There is an ifdef in the PALcode in MILO that enables a 
+   "kernel debugging entry point" as an unprivilaged call_pal.
+
+   We don't want to have anything to do with it, but unfortunately
+   several versions of MILO included in distributions have it enabled,
+   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)
+{
+	lock_kernel();
+	die_if_kernel("Instruction fault", &regs, type, 0);
+	force_sig(SIGILL, current);
+	unlock_kernel();
+}
+
+
 /*
  * entUna has a different register layout to be reasonably simple. It
  * needs access to all the integer registers (the kernel doesn't use
@@ -895,4 +915,5 @@
 	wrent(entIF, 3);
 	wrent(entUna, 4);
 	wrent(entSys, 5);
+	wrent(entDbg, 6);
 }
diff -u --recursive --new-file v2.2.1/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.2.1/linux/arch/i386/config.in	Wed Jan 20 23:14:04 1999
+++ linux/arch/i386/config.in	Mon Feb  1 12:03:20 1999
@@ -158,7 +158,7 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
+comment 'Old CD-ROM drivers (not SCSI, not IDE)'
 
 bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
 if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
diff -u --recursive --new-file v2.2.1/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
--- v2.2.1/linux/arch/i386/kernel/io_apic.c	Mon Dec 28 15:00:52 1998
+++ linux/arch/i386/kernel/io_apic.c	Wed Feb  3 14:56:43 1999
@@ -202,7 +202,7 @@
 DO_ACTION( mask,    0, |= 0x00010000, io_apic_sync())		/* mask = 1 */
 DO_ACTION( unmask,  0, &= 0xfffeffff, )				/* mask = 0 */
 
-static void __init clear_IO_APIC_pin(unsigned int pin)
+static void clear_IO_APIC_pin(unsigned int pin)
 {
 	struct IO_APIC_route_entry entry;
 
@@ -215,6 +215,13 @@
 	io_apic_write(0x11 + 2 * pin, *(((int *)&entry) + 1));
 }
 
+static void clear_IO_APIC (void)
+{
+	int pin;
+
+	for (pin = 0; pin < nr_ioapic_registers; pin++)
+		clear_IO_APIC_pin(pin);
+}
 
 /*
  * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to
@@ -625,7 +632,7 @@
 /*
  * Set up a certain pin as ExtINT delivered interrupt
  */
-void __init setup_ExtINT_pin(unsigned int pin)
+void __init setup_ExtINT_pin(unsigned int pin, int irq)
 {
 	struct IO_APIC_route_entry entry;
 
@@ -635,11 +642,16 @@
 	memset(&entry,0,sizeof(entry));
 
 	entry.delivery_mode = dest_ExtINT;
-	entry.dest_mode = 1;				/* logical delivery */
+	entry.dest_mode = 0;				/* physical delivery */
 	entry.mask = 0;					/* unmask IRQ now */
-	entry.dest.logical.logical_dest = 0x01;		/* logical CPU #0 */
+	/*
+	 * We use physical delivery to get the timer IRQ
+	 * to the boot CPU. 'boot_cpu_id' is the physical
+	 * APIC ID of the boot CPU.
+	 */
+	entry.dest.physical.physical_dest = boot_cpu_id;
 
-	entry.vector = 0;				/* it's ignored */
+	entry.vector = assign_irq_vector(irq);
 
 	entry.polarity = 0;
 	entry.trigger = 0;
@@ -754,7 +766,7 @@
 
 static void __init init_sym_mode(void)
 {
-	int i, pin;
+	int i;
 
 	for (i = 0; i < PIN_MAP_SIZE; i++) {
 		irq_2_pin[i].pin = -1;
@@ -784,8 +796,7 @@
 	/*
 	 * Do not trust the IO-APIC being empty at bootup
 	 */
-	for (pin = 0; pin < nr_ioapic_registers; pin++)
-		clear_IO_APIC_pin(pin);
+	clear_IO_APIC();
 }
 
 /*
@@ -793,6 +804,15 @@
  */
 void init_pic_mode(void)
 {
+	/*
+	 * Clear the IO-APIC before rebooting:
+	 */
+	clear_IO_APIC();
+
+	/*
+	 * Put it back into PIC mode (has an effect only on
+	 * certain boards)
+	 */
 	printk("disabling symmetric IO mode... ");
 		outb_p(0x70, 0x22);
 		outb_p(0x00, 0x23);
@@ -1178,7 +1198,7 @@
 
 		if (pin2 != -1) {
 			printk(".. (found pin %d) ...", pin2);
-			setup_ExtINT_pin(pin2);
+			setup_ExtINT_pin(pin2, 0);
 			make_8259A_irq(0);
 		}
 
diff -u --recursive --new-file v2.2.1/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.2.1/linux/arch/i386/kernel/smp.c	Mon Jan 25 17:44:34 1999
+++ linux/arch/i386/kernel/smp.c	Mon Feb  1 10:59:05 1999
@@ -147,6 +147,17 @@
 #define APIC_DEFAULT_PHYS_BASE 0xfee00000
 
 /*
+ * Reads and clears the Pentium Timestamp-Counter
+ */
+#define READ_TSC(x)	__asm__ __volatile__ (  "rdtsc" \
+				:"=a" (((unsigned long*)&(x))[0]),  \
+				 "=d" (((unsigned long*)&(x))[1]))
+
+#define CLEAR_TSC \
+	__asm__ __volatile__ ("\t.byte 0x0f, 0x30;\n"::\
+		"a"(0x00001000), "d"(0x00001000), "c"(0x10):"memory")
+
+/*
  *	Setup routine for controlling SMP activation
  *
  *	Command-line option of "nosmp" or "maxcpus=0" will disable SMP
@@ -710,24 +721,19 @@
 	value |= 0xff;			/* Set spurious IRQ vector to 0xff */
  	apic_write(APIC_SPIV,value);
 
- 	value = apic_read(APIC_TASKPRI);
- 	value &= ~APIC_TPRI_MASK;	/* Set Task Priority to 'accept all' */
- 	apic_write(APIC_TASKPRI,value);
-
 	/*
-	 * Set arbitrarion priority to 0
+	 * Set Task Priority to 'accept all'
 	 */
- 	value = apic_read(APIC_ARBPRI);
- 	value &= ~APIC_ARBPRI_MASK;
- 	apic_write(APIC_ARBPRI, value);
+ 	value = apic_read(APIC_TASKPRI);
+ 	value &= ~APIC_TPRI_MASK;
+ 	apic_write(APIC_TASKPRI,value);
 
 	/*
-	 * Set the logical destination ID to 'all', just to be safe.
+	 * Clear the logical destination ID, just to be safe.
 	 * also, put the APIC into flat delivery mode.
 	 */
  	value = apic_read(APIC_LDR);
 	value &= ~APIC_LDR_MASK;
-	value |= SET_APIC_LOGICAL_ID(0xff);
  	apic_write(APIC_LDR,value);
 
  	value = apic_read(APIC_DFR);
@@ -735,8 +741,6 @@
  	apic_write(APIC_DFR, value);
 
 	udelay(100);			/* B safe */
-	ack_APIC_irq();
-	udelay(100);
 }
 
 unsigned long __init init_smp_mappings(unsigned long memory_start)
@@ -1815,10 +1819,6 @@
  * closely follows bus clocks.
  */
 
-#define RDTSC(x)	__asm__ __volatile__ (  "rdtsc" \
-				:"=a" (((unsigned long*)&x)[0]),  \
-				 "=d" (((unsigned long*)&x)[1]))
-
 /*
  * The timer chip is already set up at HZ interrupts per second here,
  * but we do not accept timer interrupts yet. We only allow the BP
@@ -1937,7 +1937,7 @@
 	/*
 	 * We wrapped around just now. Let's start:
 	 */
-	RDTSC(t1);
+	READ_TSC(t1);
 	tt1=apic_read(APIC_TMCCT);
 
 #define LOOPS (HZ/10)
@@ -1948,7 +1948,7 @@
 		wait_8254_wraparound ();
 
 	tt2=apic_read(APIC_TMCCT);
-	RDTSC(t2);
+	READ_TSC(t2);
 
 	/*
 	 * The APIC bus clock counter is 32 bits only, it
diff -u --recursive --new-file v2.2.1/linux/arch/m68k/config.in linux/arch/m68k/config.in
--- v2.2.1/linux/arch/m68k/config.in	Wed Jan 20 23:14:04 1999
+++ linux/arch/m68k/config.in	Mon Feb  1 12:03:20 1999
@@ -346,13 +346,13 @@
 source fs/Config.in
 
 if [ "$CONFIG_VME" = "n" ]; then
+  mainmenu_option next_comment
+  comment 'Console drivers'
   if [ "$CONFIG_HP300" = "y" ]; then
     bool 'Frame buffer support' CONFIG_FB
   else
     define_bool CONFIG_FB y
   fi
-  mainmenu_option next_comment
-  comment 'Console drivers'
   source drivers/video/Config.in
   endmenu
 fi
diff -u --recursive --new-file v2.2.1/linux/arch/mips/config.in linux/arch/mips/config.in
--- v2.2.1/linux/arch/mips/config.in	Tue Jan 19 11:32:51 1999
+++ linux/arch/mips/config.in	Mon Feb  1 12:03:20 1999
@@ -179,7 +179,7 @@
 	endmenu
 
 	mainmenu_option next_comment
-	comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
+	comment 'Old CD-ROM drivers (not SCSI, not IDE)'
 
 	bool 'Support non-SCSI/IDE/ATAPI drives' CONFIG_CD_NO_IDESCSI
 	if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
diff -u --recursive --new-file v2.2.1/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.2.1/linux/arch/ppc/config.in	Tue Jan 19 11:32:51 1999
+++ linux/arch/ppc/config.in	Mon Feb  1 12:03:20 1999
@@ -152,7 +152,7 @@
 endmenu
 
 mainmenu_option next_comment
-comment 'CD-ROM drivers (not for SCSI or IDE/ATAPI drives)'
+comment 'Old CD-ROM drivers (not SCSI, not IDE)'
 
 bool 'Support non-SCSI/IDE/ATAPI CDROM drives' CONFIG_CD_NO_IDESCSI
 if [ "$CONFIG_CD_NO_IDESCSI" != "n" ]; then
diff -u --recursive --new-file v2.2.1/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.2.1/linux/drivers/block/genhd.c	Wed Jan 13 15:00:41 1999
+++ linux/drivers/block/genhd.c	Mon Feb  1 17:25:53 1999
@@ -130,6 +130,14 @@
 		SYS_IND(p) == LINUX_EXTENDED_PARTITION);
 }
 
+static int sector_partition_scale(kdev_t dev)
+{
+       if (hardsect_size[MAJOR(dev)] != NULL)
+               return (hardsect_size[MAJOR(dev)][MINOR(dev)]/512);
+       else
+               return (1);
+}
+
 static unsigned int get_ptable_blocksize(kdev_t dev)
 {
   int ret = 1024;
@@ -149,6 +157,7 @@
    * the natural blocksize for the device so that we don't have to try
    * and read partial sectors.  Anything smaller should be just fine.
    */
+
   switch( blksize_size[MAJOR(dev)][MINOR(dev)] )
     {
     case 2048:
@@ -196,6 +205,7 @@
 	struct partition *p;
 	unsigned long first_sector, first_size, this_sector, this_size;
 	int mask = (1 << hd->minor_shift) - 1;
+	int sector_size = sector_partition_scale(dev);
 	int i;
 
 	first_sector = hd->part[MINOR(dev)].start_sect;
@@ -233,22 +243,22 @@
 		 * First process the data partition(s)
 		 */
 		for (i=0; i<4; i++, p++) {
-		    if (!NR_SECTS(p) || is_extended_partition(p))
-		      continue;
+			if (!NR_SECTS(p) || is_extended_partition(p))
+				continue;
 
-		    /* Check the 3rd and 4th entries -
-		       these sometimes contain random garbage */
-		    if (i >= 2
-			&& START_SECT(p) + NR_SECTS(p) > this_size
-			&& (this_sector + START_SECT(p) < first_sector ||
-			    this_sector + START_SECT(p) + NR_SECTS(p) >
-			     first_sector + first_size))
-		      continue;
-
-		    add_partition(hd, current_minor, this_sector+START_SECT(p), NR_SECTS(p));
-		    current_minor++;
-		    if ((current_minor & mask) == 0)
-		      goto done;
+			/* Check the 3rd and 4th entries -
+			   these sometimes contain random garbage */
+			if (i >= 2
+				&& START_SECT(p) + NR_SECTS(p) > this_size
+				&& (this_sector + START_SECT(p) < first_sector ||
+				    this_sector + START_SECT(p) + NR_SECTS(p) >
+				     first_sector + first_size))
+				continue;
+
+			add_partition(hd, current_minor, this_sector+START_SECT(p)*sector_size, NR_SECTS(p)*sector_size);
+			current_minor++;
+			if ((current_minor & mask) == 0)
+				goto done;
 		}
 		/*
 		 * Next, process the (first) extended partition, if present.
@@ -262,20 +272,21 @@
 		 */
 		p -= 4;
 		for (i=0; i<4; i++, p++)
-		  if(NR_SECTS(p) && is_extended_partition(p))
-		    break;
+			if(NR_SECTS(p) && is_extended_partition(p))
+				break;
 		if (i == 4)
-		  goto done;	 /* nothing left to do */
+			goto done;	 /* nothing left to do */
 
-		hd->part[current_minor].nr_sects = NR_SECTS(p);
-		hd->part[current_minor].start_sect = first_sector + START_SECT(p);
-		this_sector = first_sector + START_SECT(p);
+		hd->part[current_minor].nr_sects = NR_SECTS(p) * sector_size; /* JSt */
+		hd->part[current_minor].start_sect = first_sector + START_SECT(p) * sector_size;
+		this_sector = first_sector + START_SECT(p) * sector_size;
 		dev = MKDEV(hd->major, current_minor);
 		brelse(bh);
 	}
 done:
 	brelse(bh);
 }
+
 #ifdef CONFIG_SOLARIS_X86_PARTITION
 static void
 solaris_x86_partition(struct gendisk *hd, kdev_t dev, long offset) {
@@ -317,11 +328,13 @@
 #endif
 
 #ifdef CONFIG_BSD_DISKLABEL
-static void check_and_add_bsd_partition(struct gendisk *hd, struct bsd_partition *bsd_p)
+static void check_and_add_bsd_partition(struct gendisk *hd,
+					struct bsd_partition *bsd_p, kdev_t dev)
 {
 	struct hd_struct *lin_p;
 		/* check relative position of partitions.  */
-	for (lin_p = hd->part + 1; lin_p - hd->part < current_minor; lin_p++) {
+	for (lin_p = hd->part + 1 + MINOR(dev);
+	     lin_p - hd->part - MINOR(dev) < current_minor; lin_p++) {
 			/* no relationship -> try again */
 		if (lin_p->start_sect + lin_p->nr_sects <= bsd_p->p_offset 
 			|| lin_p->start_sect >= bsd_p->p_offset + bsd_p->p_size)
@@ -383,7 +396,7 @@
 			break;
 
 		if (p->p_fstype != BSD_FS_UNUSED) 
-			check_and_add_bsd_partition(hd, p);
+			check_and_add_bsd_partition(hd, p, dev);
 	}
 	brelse(bh);
 
@@ -436,6 +449,7 @@
 	struct partition *p;
 	unsigned char *data;
 	int mask = (1 << hd->minor_shift) - 1;
+	int sector_size = sector_partition_scale(dev);
 #ifdef CONFIG_BSD_DISKLABEL
 	/* no bsd disklabel as a default */
 	kdev_t bsd_kdev = 0;
@@ -538,7 +552,7 @@
 	for (i=1 ; i<=4 ; minor++,i++,p++) {
 		if (!NR_SECTS(p))
 			continue;
-		add_partition(hd, minor, first_sector+START_SECT(p), NR_SECTS(p));
+               add_partition(hd, minor, first_sector+START_SECT(p)*sector_size, NR_SECTS(p)*sector_size);
 		if (is_extended_partition(p)) {
 			printk(" <");
 			/*
@@ -790,7 +804,7 @@
 	struct sgi_partition *p;
 #define SGI_LABEL_MAGIC 0x0be5a941
 
-	if(!(bh = bread(dev, 0, 1024))) {
+	if(!(bh = bread(dev, 0, get_ptable_blocksize(dev)))) {
 		printk("Dev %s: unable to read partition table\n", kdevname(dev));
 		return -1;
 	}
@@ -854,11 +868,18 @@
 	int			 blk;
 	int			 part, res;
 
+	/*
+	 *	Don't bother touching M/O 2K media.
+	 */
+	 
+	if (get_ptable_blocksize(dev) != 1024)
+		return 0;
+		
 	set_blocksize(dev,512);
 	res = 0;
 
 	for (blk = 0; blk < RDB_ALLOCATION_LIMIT; blk++) {
-		if(!(bh = bread(dev,blk,512))) {
+		if(!(bh = bread(dev,blk,get_ptable_blocksize(dev)))) {
 			printk("Dev %s: unable to read RDB block %d\n",
 			       kdevname(dev),blk);
 			goto rdb_done;
@@ -875,7 +896,7 @@
 			blk = htonl(rdb->rdb_PartitionList);
 			brelse(bh);
 			for (part = 1; blk > 0 && part <= 16; part++) {
-				if (!(bh = bread(dev,blk,512))) {
+				if (!(bh = bread(dev,blk, get_ptable_blocksize(dev)))) {
 					printk("Dev %s: unable to read partition block %d\n",
 						       kdevname(dev),blk);
 					goto rdb_done;
@@ -908,6 +929,10 @@
 	}
 
 rdb_done:
+	/*
+	 *	FIXME: should restore the original size. Then we could clean
+	 *	up the M/O skip. Amiga people ?
+	 */
 	set_blocksize(dev,BLOCK_SIZE);
 	return res;
 }
@@ -1089,7 +1114,7 @@
 	      partsect = extensect = pi->st;
 	      while (1)
 		{
-		  xbh = bread (dev, partsect / 2, 1024);
+		  xbh = bread (dev, partsect / 2, get_ptable_blocksize(dev));
 		  if (!xbh)
 		    {
 		      printk (" block %ld read failed\n", partsect);
diff -u --recursive --new-file v2.2.1/linux/drivers/block/ide-disk.c linux/drivers/block/ide-disk.c
--- v2.2.1/linux/drivers/block/ide-disk.c	Tue Jan 19 11:32:51 1999
+++ linux/drivers/block/ide-disk.c	Sat Jan 30 10:06:14 1999
@@ -101,20 +101,6 @@
 		id->cyls = lba_sects / (16 * 63); /* correct cyls */
 		return 1;	/* lba_capacity is our only option */
 	}
-	/*
-	 * This is a split test for drives less than 8 Gig only.
-	 * Drives less than 8GB sometimes declare that they have 15 heads.
-	 * This is an accounting trick (0-15) == (1-16), just an initial
-	 * zero point difference.
-	 */
-	if ((id->lba_capacity < 16514064) && (lba_sects > chs_sects) &&
-	    ((id->heads == 15) || (id->heads == 16)) && (id->sectors == 63)) {
-		if (id->heads == 15)
-			id->cyls = lba_sects / (15 * 63); /* correct cyls */
-		if (id->heads == 16)
-			id->cyls = lba_sects / (16 * 63); /* correct cyls */
-		return 1;	/* lba_capacity is our only option */
-	}
 	/* perform a rough sanity check on lba_sects:  within 10% is "okay" */
 	if ((lba_sects - chs_sects) < _10_percent) {
 		return 1;	/* lba_capacity is good */
diff -u --recursive --new-file v2.2.1/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.2.1/linux/drivers/block/ide-probe.c	Thu Jan  7 15:11:36 1999
+++ linux/drivers/block/ide-probe.c	Mon Feb  1 14:04:42 1999
@@ -720,17 +720,39 @@
 	}
 	if (register_blkdev (hwif->major, hwif->name, ide_fops)) {
 		printk("%s: UNABLE TO GET MAJOR NUMBER %d\n", hwif->name, hwif->major);
-	} else if (init_irq (hwif)) {
-		printk("%s: UNABLE TO GET IRQ %d\n", hwif->name, hwif->irq);
-		(void) unregister_blkdev (hwif->major, hwif->name);
-	} else {
-		init_gendisk(hwif);
-		blk_dev[hwif->major].data = hwif;
-		blk_dev[hwif->major].request_fn = rfn;
-		blk_dev[hwif->major].queue = ide_get_queue;
-		read_ahead[hwif->major] = 8;	/* (4kB) */
-		hwif->present = 1;	/* success */
+		return (hwif->present = 0);
 	}
+	
+	if (init_irq (hwif)) {
+		int i = hwif->irq;
+		/*
+		 *	It failed to initialise. Find the default IRQ for 
+		 *	this port and try that.
+		 */
+		if (!(hwif->irq = ide_default_irq(hwif->io_ports[IDE_DATA_OFFSET]))) 
+		{
+			printk("%s: Disabled unable to get IRQ %d.\n", hwif->name, i);
+			(void) unregister_blkdev (hwif->major, hwif->name);
+			return (hwif->present = 0);
+		}
+		if(init_irq (hwif)) 
+		{
+			printk("%s: probed IRQ %d and default IRQ %d failed.\n",
+				hwif->name, i, hwif->irq);
+			(void) unregister_blkdev (hwif->major, hwif->name);
+			return (hwif->present = 0);
+		}
+		printk("%s: probed IRQ %d failed, using default.\n",
+			hwif->name, hwif->irq);
+	}
+	
+	init_gendisk(hwif);
+	blk_dev[hwif->major].data = hwif;
+	blk_dev[hwif->major].request_fn = rfn;
+	blk_dev[hwif->major].queue = ide_get_queue;
+	read_ahead[hwif->major] = 8;	/* (4kB) */
+	hwif->present = 1;	/* success */
+
 #if (DEBUG_SPINLOCK > 0)
 {
 	static int done = 0;
diff -u --recursive --new-file v2.2.1/linux/drivers/char/bttv.c linux/drivers/char/bttv.c
--- v2.2.1/linux/drivers/char/bttv.c	Mon Jan 25 17:44:34 1999
+++ linux/drivers/char/bttv.c	Mon Feb  1 14:04:42 1999
@@ -2880,9 +2880,6 @@
 
 		} else if (I2CRead(&(btv->i2c), I2C_STBEE)>=0) {
 			btv->type=BTTV_STB;
-		} else 
-		        if (I2CRead(&(btv->i2c), I2C_VHX)>=0) {
-			        btv->type=BTTV_VHX;
 		} else {
 			if (I2CRead(&(btv->i2c), 0x80)>=0) /* check for msp34xx */
 				btv->type = BTTV_MIROPRO;
@@ -2907,8 +2904,8 @@
         }
         if(btv->type==BTTV_AVERMEDIA98)
         {
-          btv->pll.pll_ifreq=28636363;
-          btv->pll.pll_crystal=BT848_IFORM_XT0;
+        	btv->pll.pll_ifreq=28636363;
+        	btv->pll.pll_crystal=BT848_IFORM_XT0;
         }
           
 	if (btv->have_tuner && btv->tuner_type != -1) 
diff -u --recursive --new-file v2.2.1/linux/drivers/char/bttv.h linux/drivers/char/bttv.h
--- v2.2.1/linux/drivers/char/bttv.h	Mon Jan 25 17:44:34 1999
+++ linux/drivers/char/bttv.h	Mon Feb  1 14:04:42 1999
@@ -206,7 +206,8 @@
 #define BTTV_MIROPRO       0x0b
 #define BTTV_ADSTECH_TV    0x0c
 #define BTTV_AVERMEDIA98   0x0d
-#define BTTV_VHX   	   0x0e
+#define BTTV_VHX           0x0e
+#define BTTV_ZOLTRIX       0x0f
 
 #define AUDIO_TUNER        0x00
 #define AUDIO_RADIO        0x01
diff -u --recursive --new-file v2.2.1/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.2.1/linux/drivers/char/vt.c	Wed Jan 13 15:00:41 1999
+++ linux/drivers/char/vt.c	Wed Feb  3 22:57:41 1999
@@ -165,7 +165,7 @@
 			val = K_HOLE;
 		} else
 		    val = (i ? K_HOLE : K_NOSUCHMAP);
-		return __put_user(val, &user_kbe->kb_value);
+		return put_user(val, &user_kbe->kb_value);
 	case KDSKBENT:
 		if (!perm)
 			return -EPERM;
@@ -244,7 +244,7 @@
 	case KDGETKEYCODE:
 		kc = getkeycode(tmp.scancode);
 		if (kc >= 0)
-			kc = __put_user(kc, &user_kbkc->keycode);
+			kc = put_user(kc, &user_kbkc->keycode);
 		break;
 	case KDSETKEYCODE:
 		if (!perm)
@@ -282,8 +282,8 @@
 		p = func_table[i];
 		if(p)
 			for ( ; *p && sz; p++, sz--)
-				__put_user(*p, q++);
-		__put_user('\0', q);
+				put_user(*p, q++);
+		put_user('\0', q);
 		return ((p && *p) ? -EOVERFLOW : 0);
 	case KDSKBSENT:
 		if (!perm)
@@ -603,12 +603,10 @@
 	{
 		struct kbdiacrs *a = (struct kbdiacrs *)arg;
 
-		i = verify_area(VERIFY_WRITE, (void *) a, sizeof(struct kbdiacrs));
-		if (i)
-			return i;
-		__put_user(accent_table_size, &a->kb_cnt);
-		__copy_to_user(a->kbdiacr, accent_table,
-			    accent_table_size*sizeof(struct kbdiacr));
+		if (put_user(accent_table_size, &a->kb_cnt))
+			return -EFAULT;
+		if (copy_to_user(a->kbdiacr, accent_table, accent_table_size*sizeof(struct kbdiacr)))
+			return -EFAULT;
 		return 0;
 	}
 
@@ -619,14 +617,13 @@
 
 		if (!perm)
 			return -EPERM;
-		i = verify_area(VERIFY_READ, (void *) a, sizeof(struct kbdiacrs));
-		if (i)
-			return i;
-		__get_user(ct,&a->kb_cnt);
+		if (get_user(ct,&a->kb_cnt))
+			return -EFAULT;
 		if (ct >= MAX_DIACR)
 			return -EINVAL;
 		accent_table_size = ct;
-		__copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr));
+		if (copy_from_user(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr)))
+			return -EFAULT;
 		return 0;
 	}
 
@@ -717,12 +714,12 @@
 		i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat));
 		if (i)
 			return i;
-		__put_user(fg_console + 1, &vtstat->v_active);
+		put_user(fg_console + 1, &vtstat->v_active);
 		state = 1;	/* /dev/tty0 is always open */
 		for (i = 0, mask = 2; i < MAX_NR_CONSOLES && mask; ++i, mask <<= 1)
 			if (VT_IS_IN_USE(i))
 				state |= mask;
-		return __put_user(state, &vtstat->v_state);
+		return put_user(state, &vtstat->v_state);
 	}
 
 	/*
@@ -856,8 +853,8 @@
 		i = verify_area(VERIFY_READ, (void *)vtsizes, sizeof(struct vt_sizes));
 		if (i)
 			return i;
-		__get_user(ll, &vtsizes->v_rows);
-		__get_user(cc, &vtsizes->v_cols);
+		get_user(ll, &vtsizes->v_rows);
+		get_user(cc, &vtsizes->v_cols);
 		return vc_resize_all(ll, cc);
 	}
 
@@ -870,12 +867,12 @@
 		i = verify_area(VERIFY_READ, (void *)vtconsize, sizeof(struct vt_consize));
 		if (i)
 			return i;
-		__get_user(ll, &vtconsize->v_rows);
-		__get_user(cc, &vtconsize->v_cols);
-		__get_user(vlin, &vtconsize->v_vlin);
-		__get_user(clin, &vtconsize->v_clin);
-		__get_user(vcol, &vtconsize->v_vcol);
-		__get_user(ccol, &vtconsize->v_ccol);
+		get_user(ll, &vtconsize->v_rows);
+		get_user(cc, &vtconsize->v_cols);
+		get_user(vlin, &vtconsize->v_vlin);
+		get_user(clin, &vtconsize->v_clin);
+		get_user(vcol, &vtconsize->v_vcol);
+		get_user(ccol, &vtconsize->v_ccol);
 		vlin = vlin ? vlin : video_scan_lines;
 		if ( clin )
 		  {
diff -u --recursive --new-file v2.2.1/linux/drivers/net/hamradio/baycom_epp.c linux/drivers/net/hamradio/baycom_epp.c
--- v2.2.1/linux/drivers/net/hamradio/baycom_epp.c	Fri Nov 27 13:09:24 1998
+++ linux/drivers/net/hamradio/baycom_epp.c	Mon Feb  1 10:41:47 1999
@@ -1075,6 +1075,7 @@
 	if (!(pp->modes & (PARPORT_MODE_PCECPEPP|PARPORT_MODE_PCEPP))) {
                 printk(KERN_ERR "%s: parport at 0x%lx does not support any EPP mode\n",
 		       bc_drvname, pp->base);
+		parport_release(bc->pdev);
                 parport_unregister_device(bc->pdev);
                 return -EIO;		
 	}
diff -u --recursive --new-file v2.2.1/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c
--- v2.2.1/linux/drivers/scsi/scsi_error.c	Fri Jan  8 22:36:10 1999
+++ linux/drivers/scsi/scsi_error.c	Fri Jan 29 10:30:04 1999
@@ -1972,6 +1972,7 @@
 	     */
             SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler sleeping\n"));
 	    down_interruptible (&sem);
+	    sem.owner = 0;
 
 	    if (signal_pending(current) )
 	      break;
diff -u --recursive --new-file v2.2.1/linux/drivers/sound/midi_synth.c linux/drivers/sound/midi_synth.c
--- v2.2.1/linux/drivers/sound/midi_synth.c	Thu May 14 19:47:42 1998
+++ linux/drivers/sound/midi_synth.c	Mon Feb  1 14:04:42 1999
@@ -12,6 +12,7 @@
  */
 /*
  * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ * Andrew Veliath  : fixed running status in MIDI input state machine
  */
 #include <linux/config.h>
 
@@ -196,13 +197,19 @@
 				      inc->m_left = len_tab[(data >> 4) - 8];
 				      inc->m_buf[0] = inc->m_prev_status = data;
 			      }
-		  } else if (inc->m_prev_status & 0x80)		/* Ignore if no previous status (yet) */
-		    {		/* Data byte (use running status) */
-			    inc->m_state = MST_DATA;
+		    } else if (inc->m_prev_status & 0x80) {
+			    /* Data byte (use running status) */
 			    inc->m_ptr = 2;
-			    inc->m_left = len_tab[(data >> 4) - 8] - 1;
-			    inc->m_buf[0] = inc->m_prev_status;
 			    inc->m_buf[1] = data;
+			    inc->m_buf[0] = inc->m_prev_status;
+			    inc->m_left = len_tab[(inc->m_buf[0] >> 4) - 8] - 1;
+			    if (inc->m_left > 0)
+				    inc->m_state = MST_DATA; /* Not done yet */
+			    else {
+				    inc->m_state = MST_INIT;
+				    do_midi_msg(dev, inc->m_buf, inc->m_ptr);
+				    inc->m_ptr = 0;
+			    }
 		    }
 		  break;	/* MST_INIT */
 
diff -u --recursive --new-file v2.2.1/linux/drivers/sound/sb.h linux/drivers/sound/sb.h
--- v2.2.1/linux/drivers/sound/sb.h	Tue Jan 19 11:32:52 1999
+++ linux/drivers/sound/sb.h	Mon Feb  1 14:04:42 1999
@@ -48,12 +48,6 @@
 #define MDL_ES1868MIDI	14	/* MIDI port of ESS1868 */
 #define MDL_AEDSP	15	/* Audio Excel DSP 16 */
 
-#define SUBMDL_ES1788	0x10	/* Subtype ES1788 for specific handling */
-#define SUBMDL_ES1868	0x11	/* Subtype ES1868 for specific handling */
-#define SUBMDL_ES1869	0x12	/* Subtype ES1869 for specific handling */
-#define SUBMDL_ES1878	0x13	/* Subtype ES1878 for specific handling */
-#define SUBMDL_ES1887	0x14	/* Subtype ES1887 for specific handling */
-#define SUBMDL_ES1888	0x14	/* Subtype ES1888 for specific handling */
 #define SUBMDL_ALS007	42	/* ALS-007 differs from SB16 only in mixer */
 				/* register assignment */
 #define SUBMDL_ALS100	43	/* ALS-100 allows sampling rates of up */
diff -u --recursive --new-file v2.2.1/linux/drivers/sound/sb_card.c linux/drivers/sound/sb_card.c
--- v2.2.1/linux/drivers/sound/sb_card.c	Thu Jan 28 12:58:02 1999
+++ linux/drivers/sound/sb_card.c	Mon Feb  1 14:04:42 1999
@@ -113,7 +113,7 @@
 }
 
 int sb_be_quiet=0;
-int esstype = 0;	/* ESS chip type */
+extern int esstype;	/* ESS chip type */
 
 #ifdef MODULE
 
@@ -130,13 +130,13 @@
 int io = -1;
 int irq = -1;
 int dma = -1;
-int dma16 = -1;	/* Set this for modules that need it */
-int type = 0;	/* Can set this to a specific card type */
-int mad16 = 0;	/* Set mad16=1 to load this as support for mad16 */
-int trix = 0;	/* Set trix=1 to load this as support for trix */
-int pas2 = 0;	/* Set pas2=1 to load this as support for pas2 */
+int dma16 = -1;		/* Set this for modules that need it */
+int type = 0;		/* Can set this to a specific card type */
+int mad16 = 0;		/* Set mad16=1 to load this as support for mad16 */
+int trix = 0;		/* Set trix=1 to load this as support for trix */
+int pas2 = 0;		/* Set pas2=1 to load this as support for pas2 */
 int sm_games = 0;	/* Mixer - see sb_mixer.c */
-int acer = 0;	/* Do acer notebook init */
+int acer = 0;		/* Do acer notebook init */
 
 MODULE_PARM(io, "i");
 MODULE_PARM(irq, "i");
diff -u --recursive --new-file v2.2.1/linux/drivers/sound/sb_ess.c linux/drivers/sound/sb_ess.c
--- v2.2.1/linux/drivers/sound/sb_ess.c	Mon Jan 25 17:44:34 1999
+++ linux/drivers/sound/sb_ess.c	Mon Feb  1 14:06:38 1999
@@ -1,9 +1,38 @@
+#undef FKS_LOGGING
+#undef FKS_TEST
+
 /*
- * Created: 9-Jan-1999
+ * tabs should be 4 spaces, in vi(m): set tabstop=4
  *
  * TODO: 	consistency speed calculations!!
+ *			cleanup!
  * ????:	Did I break MIDI support?
  *
+ * History:
+ *
+ * Rolf Fokkens	(Dec 20 1998):	ES188x recording level support on a per
+ *								input basis.
+ *				(Dec 24 1998):	Recognition of ES1788, ES1887, ES1888,
+ *								ES1868, ES1869 and ES1878. Could be used for
+ *								specific handling in the future. All except
+ *								ES1887 and ES1888 and ES688 are handled like
+ *								ES1688.
+ *				(Dec 27 1998):	RECLEV for all (?) ES1688+ chips. ES188x now
+ *								have the "Dec 20" support + RECLEV
+ *				(Jan  2 1999):	Preparation for Full Duplex. This means
+ *								Audio 2 is now used for playback when dma16
+ *								is specified. The next step would be to use
+ *								Audio 1 and Audio 2 at the same time.
+ *				(Jan  9 1999):	Put all ESS stuff into sb_ess.[ch], this
+ *								includes both the ESS stuff that has been in
+ *								sb_*[ch] before I touched it and the ESS suppor
+ *								I added later
+ *				(Jan 23 1998):	Full Duplex seems to work. I wrote a small
+ *								test proggy which works OK. Haven't found
+ *								any applications to test it though. So why did
+ *								I bother to create it anyway?? :) Just for
+ *								fun.
+ *
  * This files contains ESS chip specifics. It's based on the existing ESS
  * handling as it resided in sb_common.c, sb_mixer.c and sb_audio.c. This
  * file adds features like:
@@ -19,27 +48,13 @@
  *
  * ESS detection isn't full proof (yet). If it fails an additional module
  * parameter esstype can be specified to be one of the following:
- * 688, 1688, 1868, 1869, 1788, 1887, 1888
- *
- * History:
- *
- * Rolf Fokkens	(Dec 20 1998):	ES188x recording level support on a per
- *								input basis.
- *				(Dec 24 1998):	Recognition of ES1788, ES1887, ES1888,
- *								ES1868, ES1869 and ES1878. Could be used for
- *								specific handling in the future. All except
- *								ES1887 and ES1888 and ES688 are handled like
- *								ES1688.
- *				(Dec 27 1998):	RECLEV for all (?) ES1688+ chips. ES188x now
- *								have the "Dec 20" support + RECLEV
- *				(jan  2 1999):	Preparation for Full Duplex. This means
- *								Audio 2 is now used for playback when dma16
- *								is specified. The next step would be to use
- *								Audio 1 and Audio 2 at the same time.
+ * -1, 0, 688, 1688, 1868, 1869, 1788, 1887, 1888
+ * -1 means: mimic 2.0 behaviour, 
+ *  0 means: auto detect.
+ *   others: explicitly specify chip
+ * -1 is default, cause auto detect still doesn't work.
  */
 
-#undef FKS_LOGGING
-
 /*
  * About the documentation
  *
@@ -156,13 +171,26 @@
  * ES1946	yes		This is a PCI chip; not handled by this driver
  */
 
+#include <linux/config.h>
+#include <linux/delay.h>
+
 #include "sound_config.h"
 #include "sb_mixer.h"
 #include "sb.h"
 
 #include "sb_ess.h"
 
-extern int esstype; /* module parameter in sb_card.c */
+#define ESSTYPE_LIKE20	-1		/* Mimic 2.0 behaviour					*/
+#define ESSTYPE_DETECT	0		/* Mimic 2.0 behaviour					*/
+
+int esstype = ESSTYPE_LIKE20; /* module parameter in sb_card.c */
+
+#define SUBMDL_ES1788	0x10	/* Subtype ES1788 for specific handling */
+#define SUBMDL_ES1868	0x11	/* Subtype ES1868 for specific handling */
+#define SUBMDL_ES1869	0x12	/* Subtype ES1869 for specific handling */
+#define SUBMDL_ES1878	0x13	/* Subtype ES1878 for specific handling */
+#define SUBMDL_ES1887	0x14	/* Subtype ES1887 for specific handling */
+#define SUBMDL_ES1888	0x15	/* Subtype ES1888 for specific handling */
 
 #ifdef FKS_LOGGING
 static void ess_show_mixerregs (sb_devc *devc);
@@ -370,45 +398,6 @@
 	}
 }
 
-#if 0
-static void ess_speed(sb_devc * devc)
-{
-	int divider;
-	unsigned char bits = 0;
-	int speed = devc->speed;
-
-	if (speed < 4000)
-		speed = 4000;
-	else if (speed > 48000)
-		speed = 48000;
-
-	if (speed > 22000)
-	{
-		bits = 0x80;
-		divider = 256 - (795500 + speed / 2) / speed;
-	}
-	else
-	{
-		divider = 128 - (397700 + speed / 2) / speed;
-	}
-
-	bits |= (unsigned char) divider;
-
-	ess_write (devc, 0xa1, bits);
-
-	/*
-	* Set filter divider register
-	*/
-
-	speed = (speed * 9) / 20;	/* Set filter roll-off to 90% of speed/2 */
-	divider = 256 - 7160000 / (speed * 82);
-
-	ess_write (devc, 0xa2, divider);
-
-	return;
-}
-#endif
-
 static int ess_audio_prepare_for_input(int dev, int bsize, int bcount)
 {
 	sb_devc *devc = audio_devs[dev]->devc;
@@ -931,6 +920,29 @@
 	return ess_common_set_irq_hw (devc);
 }
 
+#ifdef FKS_TEST
+
+/*
+ * FKS_test:
+ *	for ES1887: 00, 18, non wr bits: 0001 1000
+ *	for ES1868: 00, b8, non wr bits: 1011 1000
+ *	for ES1888: 00, f8, non wr bits: 1111 1000
+ *	for ES1688: 00, f8, non wr bits: 1111 1000
+ *	+   ES968
+ */
+
+static void FKS_test (sb_devc * devc)
+{
+	int val1, val2;
+	val1 = ess_getmixer (devc, 0x64);
+	ess_setmixer (devc, 0x64, ~val1);
+	val2 = ess_getmixer (devc, 0x64) ^ ~val1;
+	ess_setmixer (devc, 0x64, val1);
+	val1 ^= ess_getmixer (devc, 0x64);
+printk (KERN_INFO "FKS: FKS_test %02x, %02x\n", (val1 & 0x0ff), (val2 & 0x0ff));
+};
+#endif
+
 static unsigned int ess_identify (sb_devc * devc)
 {
 	unsigned int val;
@@ -1025,42 +1037,55 @@
 
 	if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80) {
 		char *chip = NULL;
+		int submodel = -1;
 
-		if (esstype) {
-			int submodel = -1;
-
-			switch (esstype) {
-			case 688:
-				submodel = 0x00;
-				break;
-			case 1688:
-				submodel = 0x08;
-				break;
-			case 1868:
-				submodel = SUBMDL_ES1868;
-				break;
-			case 1869:
-				submodel = SUBMDL_ES1869;
-				break;
-			case 1788:
-				submodel = SUBMDL_ES1788;
-				break;
-			case 1887:
-				submodel = SUBMDL_ES1887;
-				break;
-			case 1888:
-				submodel = SUBMDL_ES1888;
-				break;
-			};
-			if (submodel != -1) {
-				devc->submodel = submodel;
-				sprintf (modelname, "ES%d", esstype);
-				chip = modelname;
-			};
+		switch (esstype) {
+		case ESSTYPE_DETECT:
+		case ESSTYPE_LIKE20:
+			break;
+		case 688:
+			submodel = 0x00;
+			break;
+		case 1688:
+			submodel = 0x08;
+			break;
+		case 1868:
+			submodel = SUBMDL_ES1868;
+			break;
+		case 1869:
+			submodel = SUBMDL_ES1869;
+			break;
+		case 1788:
+			submodel = SUBMDL_ES1788;
+			break;
+		case 1887:
+			submodel = SUBMDL_ES1887;
+			break;
+		case 1888:
+			submodel = SUBMDL_ES1888;
+			break;
+		default:
+			printk (KERN_ERR "Invalid esstype=%d specified\n", esstype);
+			return 0;
+		};
+		if (submodel != -1) {
+			devc->submodel = submodel;
+			sprintf (modelname, "ES%d", esstype);
+			chip = modelname;
 		};
 		if (chip == NULL && (ess_minor & 0x0f) < 8) {
 			chip = "ES688";
 		};
+#ifdef FKS_TEST
+FKS_test (devc);
+#endif
+		/*
+		 * If Nothing detected yet, and we want 2.0 behaviour...
+		 * Then let's assume it's ES1688.
+		 */
+		if (chip == NULL && esstype == ESSTYPE_LIKE20) {
+			chip = "ES1688";
+		};
 
 		if (chip == NULL) {
 			int type;
@@ -1080,6 +1105,10 @@
 				chip = "ES1878";
 				devc->submodel = SUBMDL_ES1878;
 				break;
+			default:
+				if ((type & 0x00ff) != ((type >> 8) & 0x00ff)) {
+					printk ("ess_init: Unrecognized %04x\n", type);
+				}
 			};
 		};
 #if 0
diff -u --recursive --new-file v2.2.1/linux/drivers/sound/sys_timer.c linux/drivers/sound/sys_timer.c
--- v2.2.1/linux/drivers/sound/sys_timer.c	Thu May 14 19:47:42 1998
+++ linux/drivers/sound/sys_timer.c	Mon Feb  1 14:04:42 1999
@@ -13,6 +13,7 @@
  */
 /*
  * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ * Andrew Veliath  : adapted tmr2ticks from level 1 sequencer (avoid overflow)
  */
 #include <linux/config.h>
 
@@ -39,11 +40,17 @@
 tmr2ticks(int tmr_value)
 {
 	/*
-	 *    Convert system timer ticks (HZ) to MIDI ticks
-	 *    (divide # of MIDI ticks/minute by # of system ticks/minute).
+	 *    Convert timer ticks to MIDI ticks
 	 */
 
-	return ((tmr_value * curr_tempo * curr_timebase) + (30 * 100)) / (60 * HZ);
+	unsigned long tmp;
+	unsigned long scale;
+
+	/* tmr_value (ticks per sec) *
+	   1000000 (usecs per sec) / HZ (ticks per sec) -=> usecs */
+	tmp = tmr_value * (1000000 / HZ);
+	scale = (60 * 1000000) / (curr_tempo * curr_timebase);	/* usecs per MIDI tick */
+	return (tmp + scale / 2) / scale;
 }
 
 static void
diff -u --recursive --new-file v2.2.1/linux/fs/inode.c linux/fs/inode.c
--- v2.2.1/linux/fs/inode.c	Mon Jan 25 17:44:34 1999
+++ linux/fs/inode.c	Thu Feb  4 22:40:58 1999
@@ -232,13 +232,15 @@
 
 /*
  * Dispose-list gets a local list, so it doesn't need to
- * worry about list corruption.
+ * worry about list corruption. It releases the inode lock
+ * while clearing the inodes.
  */
 static void dispose_list(struct list_head * head)
 {
 	struct list_head *next;
 	int count = 0;
 
+	spin_unlock(&inode_lock);
 	next = head->next;
 	for (;;) {
 		struct list_head * tmp = next;
@@ -256,7 +258,6 @@
 	spin_lock(&inode_lock);
 	list_splice(head, &inode_unused);
 	inodes_stat.nr_free_inodes += count;
-	spin_unlock(&inode_lock);
 }
 
 /*
@@ -305,52 +306,52 @@
 	spin_lock(&inode_lock);
 	busy = invalidate_list(&inode_in_use, sb, &throw_away);
 	busy |= invalidate_list(&sb->s_dirty, sb, &throw_away);
-	spin_unlock(&inode_lock);
-
 	dispose_list(&throw_away);
+	spin_unlock(&inode_lock);
 
 	return busy;
 }
 
 /*
  * This is called with the inode lock held. It searches
- * the in-use for the specified number of freeable inodes.
- * Freeable inodes are moved to a temporary list and then
- * placed on the unused list by dispose_list.
+ * the in-use for freeable inodes, which are moved to a
+ * temporary list and then placed on the unused list by
+ * dispose_list. 
+ *
+ * We don't expect to have to call this very often.
  *
- * Note that we do not expect to have to search very hard:
- * the freeable inodes will be at the old end of the list.
- * 
- * N.B. The spinlock is released to call dispose_list.
+ * N.B. The spinlock is released during the call to
+ *      dispose_list.
  */
 #define CAN_UNUSE(inode) \
-	(((inode)->i_count == 0) && \
-	 (!(inode)->i_state))
+	(((inode)->i_count | (inode)->i_state) == 0)
+#define INODE(entry)	(list_entry(entry, struct inode, i_list))
 
-static int free_inodes(int goal)
+static int free_inodes(void)
 {
-	struct list_head *tmp, *head = &inode_in_use;
-	LIST_HEAD(freeable);
-	int found = 0, depth = goal << 1;
+	struct list_head list, *entry, *freeable = &list;
+	int found = 0;
 
-	while ((tmp = head->prev) != head && depth--) {
-		struct inode * inode = list_entry(tmp, struct inode, i_list);
+	INIT_LIST_HEAD(freeable);
+	entry = inode_in_use.next;
+	while (entry != &inode_in_use) {
+		struct list_head *tmp = entry;
+
+		entry = entry->next;
+		if (!CAN_UNUSE(INODE(tmp)))
+			continue;
 		list_del(tmp);
-		if (CAN_UNUSE(inode)) {
-			list_del(&inode->i_hash);
-			INIT_LIST_HEAD(&inode->i_hash);
-			list_add(tmp, &freeable);
-			if (++found < goal)
-				continue;
-			break;
-		}
-		list_add(tmp, head);
+		list_del(&INODE(tmp)->i_hash);
+		INIT_LIST_HEAD(&INODE(tmp)->i_hash);
+		list_add(tmp, freeable);
+		found = 1;
 	}
+
 	if (found) {
-		spin_unlock(&inode_lock);
-		dispose_list(&freeable);
-		spin_lock(&inode_lock);
+		dispose_list(freeable);
+		found = 1;	/* silly compiler */
 	}
+
 	return found;
 }
 
@@ -374,7 +375,7 @@
 static void try_to_free_inodes(int goal)
 {
 	shrink_dentry_inodes(goal);
-	if (!free_inodes(goal))
+	if (!free_inodes())
 		shrink_dentry_inodes(goal);
 }
 
@@ -385,7 +386,7 @@
 void free_inode_memory(int goal)
 {
 	spin_lock(&inode_lock);
-	free_inodes(goal);
+	free_inodes();
 	spin_unlock(&inode_lock);
 }
 
@@ -450,7 +451,7 @@
 	inodes_stat.preshrink = 1;
 
 	spin_lock(&inode_lock);
-	free_inodes(inodes_stat.nr_inodes >> 2);
+	free_inodes();
 	{
 		struct list_head *tmp = inode_unused.next;
 		if (tmp != &inode_unused) {
diff -u --recursive --new-file v2.2.1/linux/fs/nfsd/nfsproc.c linux/fs/nfsd/nfsproc.c
--- v2.2.1/linux/fs/nfsd/nfsproc.c	Sun Jul 26 11:57:18 1998
+++ linux/fs/nfsd/nfsproc.c	Fri Jan 29 11:09:56 1999
@@ -515,7 +515,7 @@
   PROC(symlink,	 symlinkargs,	void,		none,		RC_REPLSTAT),
   PROC(mkdir,	 createargs,	diropres,	fhandle,	RC_REPLBUFF),
   PROC(rmdir,	 diropargs,	void,		none,		RC_REPLSTAT),
-  PROC(readdir,	 readdirargs,	readdirres,	none,		RC_REPLSTAT),
+  PROC(readdir,	 readdirargs,	readdirres,	none,		RC_REPLBUFF),
   PROC(statfs,	 fhandle,	statfsres,	none,		RC_NOCACHE),
 };
 
diff -u --recursive --new-file v2.2.1/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.2.1/linux/include/linux/sched.h	Tue Jan 19 11:32:53 1999
+++ linux/include/linux/sched.h	Fri Feb  5 09:57:07 1999
@@ -174,6 +174,8 @@
 	unsigned long rss, total_vm, locked_vm;
 	unsigned long def_flags;
 	unsigned long cpu_vm_mask;
+	unsigned long swap_cnt;	/* number of pages to swap on next pass */
+	unsigned long swap_address;
 	/*
 	 * This is an architecture-specific pointer: the portable
 	 * part of Linux does not know about any segments.
@@ -191,7 +193,7 @@
 		0, 0, 0, 				\
 		0, 0, 0, 0,				\
 		0, 0, 0,				\
-		0, 0, NULL }
+		0, 0, 0, 0, NULL }
 
 struct signal_struct {
 	atomic_t		count;
@@ -276,8 +278,6 @@
 /* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */
 	unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
 	int swappable:1;
-	unsigned long swap_address;
-	unsigned long swap_cnt;		/* number of pages to swap on next pass */
 /* process credentials */
 	uid_t uid,euid,suid,fsuid;
 	gid_t gid,egid,sgid,fsgid;
@@ -361,7 +361,7 @@
 /* utime */	{0,0,0,0},0, \
 /* per CPU times */ {0, }, {0, }, \
 /* flt */	0,0,0,0,0,0, \
-/* swp */	0,0,0, \
+/* swp */	0, \
 /* process credentials */					\
 /* uid etc */	0,0,0,0,0,0,0,0,				\
 /* suppl grps*/ 0, {0,},					\
diff -u --recursive --new-file v2.2.1/linux/init/main.c linux/init/main.c
--- v2.2.1/linux/init/main.c	Wed Jan 20 23:14:07 1999
+++ linux/init/main.c	Fri Feb  5 09:29:35 1999
@@ -64,6 +64,7 @@
 static int init(void *);
 extern int bdflush(void *);
 extern int kswapd(void *);
+extern int kpiod(void *);
 extern void kswapd_setup(void);
 
 extern void init_IRQ(void);
@@ -1271,6 +1272,7 @@
 	kernel_thread(bdflush, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	/* Start the background pageout daemon. */
 	kswapd_setup();
+	kernel_thread(kpiod, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 	kernel_thread(kswapd, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 
 #if CONFIG_AP1000
diff -u --recursive --new-file v2.2.1/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.2.1/linux/kernel/ksyms.c	Wed Jan 20 23:14:07 1999
+++ linux/kernel/ksyms.c	Thu Feb  4 13:00:32 1999
@@ -37,6 +37,7 @@
 #include <linux/file.h>
 #include <linux/console.h>
 #include <linux/poll.h>
+#include <linux/mm.h>
 
 #if defined(CONFIG_PROC_FS)
 #include <linux/proc_fs.h>
@@ -105,6 +106,8 @@
 EXPORT_SYMBOL(high_memory);
 EXPORT_SYMBOL(update_vm_cache);
 EXPORT_SYMBOL(vmtruncate);
+EXPORT_SYMBOL(find_vma);
+EXPORT_SYMBOL(get_unmapped_area);
 
 /* filesystem internal functions */
 EXPORT_SYMBOL(in_group_p);
diff -u --recursive --new-file v2.2.1/linux/kernel/sched.c linux/kernel/sched.c
--- v2.2.1/linux/kernel/sched.c	Wed Jan 20 23:14:07 1999
+++ linux/kernel/sched.c	Fri Feb  5 09:38:15 1999
@@ -680,8 +680,18 @@
 
 	sched_data->prevstate = prev->state;
 
+/* this is the scheduler proper: */
 	{
 		struct task_struct * p = init_task.next_run;
+		int c = -1000;
+
+		/* Default process to select.. */
+		next = idle_task;
+		if (prev->state == TASK_RUNNING) {
+			c = goodness(prev, prev, this_cpu);
+			next = prev;
+		}
+
 		/*
 		 * This is subtle.
 		 * Note how we can enable interrupts here, even
@@ -693,36 +703,27 @@
 		 * the scheduler lock
 		 */
 		spin_unlock_irq(&runqueue_lock);
-#ifdef __SMP__
-		prev->has_cpu = 0;
-#endif
-	
 /*
  * Note! there may appear new tasks on the run-queue during this, as
  * interrupts are enabled. However, they will be put on front of the
  * list, so our list starting at "p" is essentially fixed.
  */
-/* this is the scheduler proper: */
-		{
-			int c = -1000;
-			next = idle_task;
-			while (p != &init_task) {
-				if (can_schedule(p)) {
-					int weight = goodness(p, prev, this_cpu);
-					if (weight > c)
-						c = weight, next = p;
-				}
-				p = p->next_run;
+		while (p != &init_task) {
+			if (can_schedule(p)) {
+				int weight = goodness(p, prev, this_cpu);
+				if (weight > c)
+					c = weight, next = p;
 			}
+			p = p->next_run;
+		}
 
-			/* Do we need to re-calculate counters? */
-			if (!c) {
-				struct task_struct *p;
-				read_lock(&tasklist_lock);
-				for_each_task(p)
-					p->counter = (p->counter >> 1) + p->priority;
-				read_unlock(&tasklist_lock);
-			}
+		/* Do we need to re-calculate counters? */
+		if (!c) {
+			struct task_struct *p;
+			read_lock(&tasklist_lock);
+			for_each_task(p)
+				p->counter = (p->counter >> 1) + p->priority;
+			read_unlock(&tasklist_lock);
 		}
 	}
 
@@ -751,10 +752,8 @@
 	 * thus we have to lock the previous process from getting
 	 * rescheduled during switch_to().
 	 */
-	prev->has_cpu = 1;
-
- 	next->has_cpu = 1;
  	next->processor = this_cpu;
+ 	next->has_cpu = 1;
 	spin_unlock(&scheduler_lock);
 #endif /* __SMP__ */
  	if (prev != next) {
diff -u --recursive --new-file v2.2.1/linux/mm/filemap.c linux/mm/filemap.c
--- v2.2.1/linux/mm/filemap.c	Mon Jan 25 17:44:34 1999
+++ linux/mm/filemap.c	Fri Feb  5 09:29:35 1999
@@ -19,6 +19,7 @@
 #include <linux/blkdev.h>
 #include <linux/file.h>
 #include <linux/swapctl.h>
+#include <linux/slab.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -39,6 +40,26 @@
 
 #define release_page(page) __free_page((page))
 
+/* 
+ * Define a request structure for outstanding page write requests
+ * to the background page io daemon
+ */
+
+struct pio_request 
+{
+	struct pio_request *	next;
+	struct file *		file;
+	unsigned long		offset;
+	unsigned long		page;
+};
+static struct pio_request *pio_first = NULL, **pio_last = &pio_first;
+static kmem_cache_t *pio_request_cache;
+static struct wait_queue *pio_wait = NULL;
+
+static inline void 
+make_pio_request(struct file *, unsigned long, unsigned long);
+
+
 /*
  * Invalidate the pages of an inode, removing all pages that aren't
  * locked down (those are sure to be up-to-date anyway, so we shouldn't
@@ -1079,8 +1100,9 @@
 }
 
 static int filemap_write_page(struct vm_area_struct * vma,
-	unsigned long offset,
-	unsigned long page)
+			      unsigned long offset,
+			      unsigned long page,
+			      int wait)
 {
 	int result;
 	struct file * file;
@@ -1098,6 +1120,17 @@
 	 * and file could be released ... increment the count to be safe.
 	 */
 	file->f_count++;
+
+	/* 
+	 * If this is a swapping operation rather than msync(), then
+	 * leave the actual IO, and the restoration of the file count,
+	 * to the kpiod thread.  Just queue the request for now.
+	 */
+	if (!wait) {
+		make_pio_request(file, offset, page);
+		return 0;
+	}
+	
 	down(&inode->i_sem);
 	result = do_write_page(inode, file, (const char *) page, offset);
 	up(&inode->i_sem);
@@ -1113,7 +1146,7 @@
  */
 int filemap_swapout(struct vm_area_struct * vma, struct page * page)
 {
-	return filemap_write_page(vma, page->offset, page_address(page));
+	return filemap_write_page(vma, page->offset, page_address(page), 0);
 }
 
 static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma,
@@ -1150,7 +1183,7 @@
 			return 0;
 		}
 	}
-	error = filemap_write_page(vma, address - vma->vm_start + vma->vm_offset, page);
+	error = filemap_write_page(vma, address - vma->vm_start + vma->vm_offset, page, 1);
 	free_page(page);
 	return error;
 }
@@ -1568,4 +1601,121 @@
 	clear_bit(PG_locked, &page->flags);
 	wake_up(&page->wait);
 	__free_page(page);
+}
+
+
+/* Add request for page IO to the queue */
+
+static inline void put_pio_request(struct pio_request *p)
+{
+	*pio_last = p;
+	p->next = NULL;
+	pio_last = &p->next;
+}
+
+/* Take the first page IO request off the queue */
+
+static inline struct pio_request * get_pio_request(void)
+{
+	struct pio_request * p = pio_first;
+	pio_first = p->next;
+	if (!pio_first)
+		pio_last = &pio_first;
+	return p;
+}
+
+/* Make a new page IO request and queue it to the kpiod thread */
+
+static inline void make_pio_request(struct file *file,
+				    unsigned long offset,
+				    unsigned long page)
+{
+	struct pio_request *p;
+
+	atomic_inc(&mem_map[MAP_NR(page)].count);
+
+	/* 
+	 * We need to allocate without causing any recursive IO in the
+	 * current thread's context.  We might currently be swapping out
+	 * as a result of an allocation made while holding a critical
+	 * filesystem lock.  To avoid deadlock, we *MUST* not reenter
+	 * the filesystem in this thread.
+	 *
+	 * We can wait for kswapd to free memory, or we can try to free
+	 * pages without actually performing further IO, without fear of
+	 * deadlock.  --sct
+	 */
+
+	while ((p = kmem_cache_alloc(pio_request_cache, GFP_BUFFER)) == NULL) {
+		if (try_to_free_pages(__GFP_WAIT))
+			continue;
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(HZ/10);
+	}
+	
+	p->file   = file;
+	p->offset = offset;
+	p->page   = page;
+
+	put_pio_request(p);
+	wake_up(&pio_wait);
+}
+
+
+/*
+ * This is the only thread which is allowed to write out filemap pages
+ * while swapping.
+ * 
+ * To avoid deadlock, it is important that we never reenter this thread.
+ * Although recursive memory allocations within this thread may result
+ * in more page swapping, that swapping will always be done by queuing
+ * another IO request to the same thread: we will never actually start
+ * that IO request until we have finished with the current one, and so
+ * we will not deadlock.  
+ */
+
+int kpiod(void * unused)
+{
+	struct wait_queue wait = {current};
+	struct inode * inode;
+	struct dentry * dentry;
+	struct pio_request * p;
+	
+	current->session = 1;
+	current->pgrp = 1;
+	strcpy(current->comm, "kpiod");
+	sigfillset(&current->blocked);
+	init_waitqueue(&pio_wait);
+
+	lock_kernel();
+	
+	pio_request_cache = kmem_cache_create("pio_request", 
+					      sizeof(struct pio_request),
+					      0, SLAB_HWCACHE_ALIGN, 
+					      NULL, NULL);
+	if (!pio_request_cache)
+		panic ("Could not create pio_request slab cache");
+	
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		add_wait_queue(&pio_wait, &wait);
+		while (!pio_first)
+			schedule();
+		remove_wait_queue(&pio_wait, &wait);
+		current->state = TASK_RUNNING;
+
+		while (pio_first) {
+			p = get_pio_request();
+			dentry = p->file->f_dentry;
+			inode = dentry->d_inode;
+			
+			down(&inode->i_sem);
+			do_write_page(inode, p->file,
+				      (const char *) p->page, p->offset);
+			up(&inode->i_sem);
+			fput(p->file);
+			free_page(p->page);
+			kmem_cache_free(pio_request_cache, p);
+		}
+	}
 }
diff -u --recursive --new-file v2.2.1/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.2.1/linux/mm/vmscan.c	Mon Jan 25 17:44:34 1999
+++ linux/mm/vmscan.c	Fri Feb  5 09:29:36 1999
@@ -202,7 +202,7 @@
 
 	do {
 		int result;
-		tsk->swap_address = address + PAGE_SIZE;
+		tsk->mm->swap_address = address + PAGE_SIZE;
 		result = try_to_swap_out(tsk, vma, address, pte, gfp_mask);
 		if (result)
 			return result;
@@ -274,7 +274,7 @@
 	/*
 	 * Go through process' page directory.
 	 */
-	address = p->swap_address;
+	address = p->mm->swap_address;
 
 	/*
 	 * Find the proper vm-area
@@ -296,8 +296,8 @@
 	}
 
 	/* We didn't find anything for the process */
-	p->swap_cnt = 0;
-	p->swap_address = 0;
+	p->mm->swap_cnt = 0;
+	p->mm->swap_address = 0;
 	return 0;
 }
 
@@ -345,9 +345,9 @@
 				continue;
 			/* Refresh swap_cnt? */
 			if (assign)
-				p->swap_cnt = p->mm->rss;
-			if (p->swap_cnt > max_cnt) {
-				max_cnt = p->swap_cnt;
+				p->mm->swap_cnt = p->mm->rss;
+			if (p->mm->swap_cnt > max_cnt) {
+				max_cnt = p->mm->swap_cnt;
 				pbest = p;
 			}
 		}
diff -u --recursive --new-file v2.2.1/linux/net/ipv4/proc.c linux/net/ipv4/proc.c
--- v2.2.1/linux/net/ipv4/proc.c	Sun Nov  8 14:03:14 1998
+++ linux/net/ipv4/proc.c	Tue Feb  2 11:05:33 1999
@@ -184,6 +184,8 @@
 
 			for (req = sp->tp_pinfo.af_tcp.syn_wait_queue; req;
 			     i++, req = req->dl_next) {
+				if (req->sk)
+					continue;
 				pos += 128;
 				if (pos < offset) 
 					continue;
diff -u --recursive --new-file v2.2.1/linux/net/ipv4/tcp_ipv4.c linux/net/ipv4/tcp_ipv4.c
--- v2.2.1/linux/net/ipv4/tcp_ipv4.c	Thu Jan  7 15:11:42 1999
+++ linux/net/ipv4/tcp_ipv4.c	Fri Feb  5 10:00:04 1999
@@ -1563,12 +1563,6 @@
 	}
 #endif /* CONFIG_FILTER */
 
-	/*
-	 *	socket locking is here for SMP purposes as backlog rcv
-	 *	is currently called with bh processing disabled.
-	 */
-	lock_sock(sk); 
-
 	/* 
 	 * This doesn't check if the socket has enough room for the packet.
 	 * Either process the packet _without_ queueing it and then free it,
@@ -1579,7 +1573,6 @@
 	if (sk->state == TCP_ESTABLISHED) { /* Fast path */
 		if (tcp_rcv_established(sk, skb, skb->h.th, skb->len))
 			goto reset;
-		release_sock(sk);
 		return 0; 
 	} 
 
@@ -1590,14 +1583,21 @@
 		nsk = tcp_v4_hnd_req(sk, skb);
 		if (!nsk) 
 			goto discard;
-		lock_sock(nsk);
-		release_sock(sk);
+
+		/*
+		 * Queue it on the new socket if the new socket is active,
+		 * otherwise we just shortcircuit this and continue with
+		 * the new socket..
+		 */
+		if (atomic_read(&nsk->sock_readers)) {
+			__skb_queue_tail(&nsk->back_log, skb);
+			return 0;
+		}
 		sk = nsk;
 	}
 	
 	if (tcp_rcv_state_process(sk, skb, skb->h.th, skb->len))
 		goto reset;
-	release_sock(sk); 
 	return 0;
 
 reset:
@@ -1609,7 +1609,6 @@
 	 * might be destroyed here. This current version compiles correctly,
 	 * but you have been warned.
 	 */
-	release_sock(sk);  
 	return 0;
 }
 
diff -u --recursive --new-file v2.2.1/linux/net/netsyms.c linux/net/netsyms.c
--- v2.2.1/linux/net/netsyms.c	Fri Jan  8 22:36:27 1999
+++ linux/net/netsyms.c	Mon Feb  1 14:04:39 1999
@@ -382,6 +382,9 @@
 EXPORT_SYMBOL(ipv4_config);
 EXPORT_SYMBOL(dev_open);
 
+/* Used by other modules */
+EXPORT_SYMBOL(in_ntoa);
+
 EXPORT_SYMBOL(ip_rcv);
 EXPORT_SYMBOL(arp_rcv);
 EXPORT_SYMBOL(arp_tbl);
diff -u --recursive --new-file v2.2.1/linux/scripts/Configure linux/scripts/Configure
--- v2.2.1/linux/scripts/Configure	Fri Nov 27 13:09:31 1998
+++ linux/scripts/Configure	Mon Feb  1 12:03:20 1999
@@ -1,4 +1,3 @@
-
 #! /bin/sh
 #
 # This script is used to configure the Linux kernel.
@@ -8,18 +7,8 @@
 # something better'' because the old configure script wasn't flexible
 # enough.
 #
-# Please send comments / questions / bug fixes to raymondc@microsoft.com.
-#
-#              ***** IMPORTANT COMPATIBILITY NOTE ****
-# If configuration changes are made which might adversely effect 
-# Menuconfig or xconfig, please notify the respective maintainers so that 
-# those utilities can be updated in parallel.
-#
-# Menuconfig:  <mec@shout.net>
-# xconfig:     <apenwarr@foxnet.net>  <eric@aib.com>
-#              ****************************************
-#
-# Each line in the config file is a command.
+# 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.
@@ -56,6 +45,9 @@
 #
 # 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).
 
 #
 # Make sure we're really running bash.
@@ -528,10 +520,13 @@
 mv .tmpconfig.h include/linux/autoconf.h
 
 echo
-echo "The Linux kernel should now be configured for your setup."
-echo "Check the top-level Makefile for additional configuration,"
-echo "and do a 'make dep ; make clean' if you want to be sure all"
-echo "the files are correctly re-made"
+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 zImage', 'make zdisk', or 'make zlilo'."
+fi
 echo
 
 exit 0
diff -u --recursive --new-file v2.2.1/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.2.1/linux/scripts/Menuconfig	Wed Jan 13 15:00:45 1999
+++ linux/scripts/Menuconfig	Mon Feb  1 12:03:20 1999
@@ -65,6 +65,9 @@
 # 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).
 
 
 #
@@ -1290,9 +1293,19 @@
 then
 	save_configuration
 	echo
-	echo The linux kernel is now configured for your setup.
+	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 zImage', 'make zdisk', or 'make zlilo.'"
+	fi
+	echo
 else
+	echo
     	echo 
 	echo Your kernel configuration changes were NOT saved.
+	echo
 fi
 exit 0
diff -u --recursive --new-file v2.2.1/linux/scripts/header.tk linux/scripts/header.tk
--- v2.2.1/linux/scripts/header.tk	Tue Jan 19 11:32:53 1999
+++ linux/scripts/header.tk	Mon Feb  1 12:03:20 1999
@@ -4,12 +4,17 @@
 # CHANGES
 # =======
 #
-# 8 January 1998, Michael Elizabeth Chastain, <mec@shout.net>
-# Remove unused do_cmd function (part of the 2.0 sound support).
-# Arrange buttons in three columns for better screen fitting.
-# Add CONSTANT_Y, CONSTANT_M, CONSTANT_N for commands like:
-#   dep_tristate 'foo' CONFIG_FOO m
+# 8 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
+# - Remove unused do_cmd function (part of the 2.0 sound support).
+# - Arrange buttons in three columns for better screen fitting.
+# - Add CONSTANT_Y, CONSTANT_M, CONSTANT_N for commands like:
+#     dep_tristate 'foo' CONFIG_FOO m
 #
+# 23 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
+# - Shut vfix the hell up.
+#
+# 24 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
+# - Improve the exit message (Jeff Ronne).
 
 #
 # This is a handy replacement for ".widget cget" that requires neither tk4
@@ -27,7 +32,6 @@
 proc vfix { var } {
 	global $var
 	if [ catch {eval concat $$var} ] {
-		puts stdout "WARNING - broken Config.in!  $var was not declared!"
 		set $var 0
 	}
 }
@@ -428,8 +432,15 @@
 proc wrapup {w }  {
 	catch {destroy $w}
 	toplevel $w -class Dialog
-	message $w.m -width 400 -aspect 300 -text \
-		"The Linux kernel should now be configured for your setup. Check the top-level Makefile for additional configuration, and do a 'make dep ; make clean' if you want to be sure all the files are correctly re-made."  -relief raised 
+
+	global CONFIG_MODVERSIONS; vfix CONFIG_MODVERSIONS
+	if { ([file exists .hdepend] != 1) || ($CONFIG_MODVERSIONS == 1) } then {
+	    message $w.m -width 400 -aspect 300 -relief raised -text \
+		"End of Linux kernel configuration.  Check the top-level Makefile for additional configuration.  Next, you must run 'make dep'."
+	} else {
+	    message $w.m -width 400 -aspect 300 -relief raised -text \
+		"End of Linux kernel configuration.  Check the top-level Makefile for additional configuration.  Next, you may 'make bzImage', 'make bzdisk', or 'make bzlilo.'"
+	}
 	label $w.bm -bitmap info
 	pack $w.bm $w.m -pady 10 -side top -padx 10
 	wm title $w "Kernel build instructions" 
diff -u --recursive --new-file v2.2.1/linux/scripts/lxdialog/checklist.c linux/scripts/lxdialog/checklist.c
--- v2.2.1/linux/scripts/lxdialog/checklist.c	Tue Mar 10 10:03:37 1998
+++ linux/scripts/lxdialog/checklist.c	Mon Feb  1 12:03:20 1999
@@ -157,6 +157,14 @@
     wattrset (dialog, dialog_attr);
     waddch (dialog, ACS_RTEE);
 
+    if (title != NULL && strlen(title) >= width-2 ) {
+	/* truncate long title -- mec */
+	char * title2 = malloc(width-2+1);
+	memcpy( title2, title, width-2 );
+	title2[width-2] = '\0';
+	title = title2;
+    }
+
     if (title != NULL) {
 	wattrset (dialog, title_attr);
 	mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
diff -u --recursive --new-file v2.2.1/linux/scripts/lxdialog/inputbox.c linux/scripts/lxdialog/inputbox.c
--- v2.2.1/linux/scripts/lxdialog/inputbox.c	Sun Mar 24 10:02:36 1996
+++ linux/scripts/lxdialog/inputbox.c	Mon Feb  1 12:03:20 1999
@@ -69,6 +69,14 @@
     wattrset (dialog, dialog_attr);
     waddch (dialog, ACS_RTEE);
 
+    if (title != NULL && strlen(title) >= width-2 ) {
+	/* truncate long title -- mec */
+	char * title2 = malloc(width-2+1);
+	memcpy( title2, title, width-2 );
+	title2[width-2] = '\0';
+	title = title2;
+    }
+
     if (title != NULL) {
 	wattrset (dialog, title_attr);
 	mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
diff -u --recursive --new-file v2.2.1/linux/scripts/lxdialog/menubox.c linux/scripts/lxdialog/menubox.c
--- v2.2.1/linux/scripts/lxdialog/menubox.c	Wed Jan 13 15:00:45 1999
+++ linux/scripts/lxdialog/menubox.c	Mon Feb  1 12:03:20 1999
@@ -189,6 +189,14 @@
     wbkgdset (dialog, dialog_attr & A_COLOR);
     waddch (dialog, ACS_RTEE);
 
+    if (title != NULL && strlen(title) >= width-2 ) {
+	/* truncate long title -- mec */
+	char * title2 = malloc(width-2+1);
+	memcpy( title2, title, width-2 );
+	title2[width-2] = '\0';
+	title = title2;
+    }
+
     if (title != NULL) {
 	wattrset (dialog, title_attr);
 	mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
diff -u --recursive --new-file v2.2.1/linux/scripts/lxdialog/msgbox.c linux/scripts/lxdialog/msgbox.c
--- v2.2.1/linux/scripts/lxdialog/msgbox.c	Tue Feb  6 23:47:28 1996
+++ linux/scripts/lxdialog/msgbox.c	Mon Feb  1 12:03:20 1999
@@ -43,6 +43,14 @@
 
     draw_box (dialog, 0, 0, height, width, dialog_attr, border_attr);
 
+    if (title != NULL && strlen(title) >= width-2 ) {
+	/* truncate long title -- mec */
+	char * title2 = malloc(width-2+1);
+	memcpy( title2, title, width-2 );
+	title2[width-2] = '\0';
+	title = title2;
+    }
+
     if (title != NULL) {
 	wattrset (dialog, title_attr);
 	mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
diff -u --recursive --new-file v2.2.1/linux/scripts/lxdialog/textbox.c linux/scripts/lxdialog/textbox.c
--- v2.2.1/linux/scripts/lxdialog/textbox.c	Thu Nov 12 16:21:25 1998
+++ linux/scripts/lxdialog/textbox.c	Mon Feb  1 12:03:20 1999
@@ -106,6 +106,14 @@
     wbkgdset (dialog, dialog_attr & A_COLOR);
     waddch (dialog, ACS_RTEE);
 
+    if (title != NULL && strlen(title) >= width-2 ) {
+	/* truncate long title -- mec */
+	char * title2 = malloc(width-2+1);
+	memcpy( title2, title, width-2 );
+	title2[width-2] = '\0';
+	title = title2;
+    }
+
     if (title != NULL) {
 	wattrset (dialog, title_attr);
 	mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
diff -u --recursive --new-file v2.2.1/linux/scripts/lxdialog/yesno.c linux/scripts/lxdialog/yesno.c
--- v2.2.1/linux/scripts/lxdialog/yesno.c	Sat Mar  2 23:22:25 1996
+++ linux/scripts/lxdialog/yesno.c	Mon Feb  1 12:03:20 1999
@@ -63,6 +63,14 @@
     wattrset (dialog, dialog_attr);
     waddch (dialog, ACS_RTEE);
 
+    if (title != NULL && strlen(title) >= width-2 ) {
+	/* truncate long title -- mec */
+	char * title2 = malloc(width-2+1);
+	memcpy( title2, title, width-2 );
+	title2[width-2] = '\0';
+	title = title2;
+    }
+
     if (title != NULL) {
 	wattrset (dialog, title_attr);
 	mvwaddch (dialog, 0, (width - strlen(title))/2 - 1, ' ');
diff -u --recursive --new-file v2.2.1/linux/scripts/tkgen.c linux/scripts/tkgen.c
--- v2.2.1/linux/scripts/tkgen.c	Wed Jan 20 23:14:07 1999
+++ linux/scripts/tkgen.c	Mon Feb  1 12:03:19 1999
@@ -89,6 +89,9 @@
  *   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.
  */
 
 #include <stdio.h>
@@ -749,11 +752,9 @@
 	    break;
 
 	case token_endmenu:
-#if ! defined(BUG_COMPATIBLE)
 	    /* flatten menus with proper scoping */
 	    if ( --menu_depth < 0 )
 		{ fprintf( stderr, "unmatched endmenu\n" ); exit( 1 ); }
-#endif
 	    break;
 
 	case token_bool:
diff -u --recursive --new-file v2.2.1/linux/scripts/tkparse.c linux/scripts/tkparse.c
--- v2.2.1/linux/scripts/tkparse.c	Wed Jan 20 23:14:07 1999
+++ linux/scripts/tkparse.c	Mon Feb  1 12:03:19 1999
@@ -26,6 +26,9 @@
  *   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.
+ *
  * TO DO:
  * - xconfig is at the end of its life cycle.  Contact <mec@shout.net> if
  *   you are interested in working on the replacement.
@@ -434,25 +437,14 @@
 
     case token_define_bool:
 	pnt = get_string( pnt, &cfg->optionname );
-#if ! defined(BUG_COMPATIBLE)
 	while ( *pnt == ' ' || *pnt == '\t' )
 	    pnt++;
-#endif
 	if      ( *pnt == 'n' || *pnt == 'N' ) cfg->value = "0";
 	else if ( *pnt == 'y' || *pnt == 'Y' ) cfg->value = "1";
 	else if ( *pnt == 'm' || *pnt == 'M' ) cfg->value = "2";
 	else
 	{
-#if ! defined(BUG_COMPATIBLE)
 	    syntax_error( "unknown define_bool value" );
-#else
-	    /*
-	     * This ought to give the same output as printf'ing
-	     * through the null pointer ... I don't want to be
-	     * SIGSEGV compatible!
-	     */
-	    cfg->value = "(null)";
-#endif
 	}
 	break;
 
@@ -558,12 +550,7 @@
     if ( infile == NULL )
     {
 	sprintf( buffer, "unable to open %s", filename );
-#if defined(BUG_COMPATIBLE)
-	fprintf( stderr, "%s\n", buffer );
-	return;
-#else
 	syntax_error( buffer );
-#endif
     }
 
     /* push the new file name and line number */
diff -u --recursive --new-file v2.2.1/linux/scripts/tkparse.h linux/scripts/tkparse.h
--- v2.2.1/linux/scripts/tkparse.h	Wed Jan 20 23:14:07 1999
+++ linux/scripts/tkparse.h	Mon Feb  1 12:03:19 1999
@@ -3,14 +3,6 @@
  */
 
 /*
- * Define this symbol to generate exactly the same output, byte for byte,
- * as the previous version of xconfig.  I need to do this to make sure I
- * I don't break anything in my moby edit. -- mec
- */
-
-#define BUG_COMPATIBLE
-
-/*
  * Token types (mostly statement types).
  */
 
