diff -u --recursive --new-file v2.1.132/linux/CREDITS linux/CREDITS
--- v2.1.132/linux/CREDITS	Tue Dec 22 14:16:53 1998
+++ linux/CREDITS	Wed Dec 23 07:56:01 1998
@@ -84,6 +84,14 @@
 S: Cambridge, Massachusetts 02139
 S: USA
 
+N: Jens Axboe
+E: axboe@image.dk
+D: Linux CD-ROM maintainer
+D: jiffies wrap fixes + schedule timeouts depending on HZ == 100
+S: Peter Bangs Vej 258, 2TH
+S: 2500 Valby
+S: Denmark
+
 N: John Aycock
 E: aycock@cpsc.ucalgary.ca
 D: Adaptec 274x driver
diff -u --recursive --new-file v2.1.132/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.132/linux/Documentation/Configure.help	Tue Dec 22 14:16:53 1998
+++ linux/Documentation/Configure.help	Sun Dec 27 10:25:51 1998
@@ -21,7 +21,7 @@
 #
 # Information about what a kernel is, what it does, how to patch and
 # compile it and much more is contained in the Kernel-HOWTO, available
-# via FTP (user: anonymous) from sunsite.unc.edu in the directory
+# via FTP (user: anonymous) from metalab.unc.edu in the directory
 # /pub/Linux/docs/HOWTO. Before you start compiling, make sure that
 # you have the necessary versions of all programs and libraries
 # required to compile and run this kernel; they are listed in the file
@@ -80,6 +80,29 @@
   you say Y here, you will be offered the choice of using features or
   drivers that are currently considered to be in the alpha-test phase.
 
+Symmetric Multi Processing
+CONFIG_SMP
+  This enables support for systems with more than one CPU.  If you have a
+  system with only one CPU, like most personal computers, say N.  If you
+  have a system with more than one CPU, say Y.
+
+  A non-SMP kernel will run on any machine, but will use only one CPU of
+  a multi-CPU machine.  An SMP kernel will run on many, but not all,
+  single-CPU machines.  On a single-CPU machine, a non-SMP kernel
+  will run faster than an SMP kernel.
+
+  People using multiprocessor machines should also say Y to "Enhanced
+  Real Time Clock Support", below.  The "Advanced Power Management"
+  code will be disabled in an SMP kernel.
+
+  If you don't know what to do here, say N.
+  
+  See also: Documentation/SMP.txt, Documentation/smp.tex,
+  Documentation/smp.txt, and Documentation/IO-APIC.txt.  Also see the
+  SMP-FAQ on the WWW at http://www.irisa.fr/prive/mentre/smp-faq/ (to
+  browse the WWW, you need to have access to a machine on the Internet
+  that has a program like lynx or netscape).
+  
 Kernel math emulation
 CONFIG_MATH_EMULATION
   Linux can emulate a math coprocessor (used for floating point
@@ -97,7 +120,7 @@
   loader (lilo or loadlin) about how to pass options to the kernel at
   boot time. The lilo procedure is also explained in the SCSI-HOWTO,
   available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.) This means that it is a
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.) This means that it is a
   good idea to say Y here if you intend to use this kernel on
   different machines. More information about the internals of Linux
   math coprocessor emulation can be found in
@@ -238,11 +261,11 @@
   contained in Documentation/ide.txt. For detailed information about
   hard drives, consult the Disk-HOWTO and the Multi-Disk-HOWTO,
   available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   To fine-tune IDE drive/interface parameters for improved
   performance, look for the hdparm package at
-  ftp://sunsite.unc.edu:/pub/Linux/kernel/patches/diskdrives/
+  ftp://metalab.unc.edu:/pub/Linux/kernel/patches/diskdrives/
 
   If you have one or more IDE drives, say Y here. If your system has
   no IDE drives, or if memory requirements are really tight, you could
@@ -264,7 +287,7 @@
   If you are unsure, then just choose the Enhanced IDE/MFM/RLL driver
   instead of this one. For more detailed information, read the
   Disk-HOWTO, available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   People with SCSI-only systems can say N here.
 
@@ -307,7 +330,7 @@
   a newer protocol used by IDE CDROM and TAPE drives, similar to the
   SCSI protocol. Most new CDROM drives use ATAPI, including the
   NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI
-  double(2X), quad(4X), and six(6X) speed drives.
+  double(2X) or better speed drives.
 
   If you say Y here, the CDROM drive will be identified at boot time
   along with other IDE devices, as "hdb" or "hdc", or something
@@ -316,11 +339,11 @@
   to say Y or M to "ISO 9660 CDROM filesystem support".
 
   Read the CDROM-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO and the file
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO and the file
   Documentation/cdrom/ide-cd. Note that older versions of lilo (the
   Linux boot loader) cannot properly deal with IDE/ATAPI CDROMs, so
   install lilo-16 or higher, available from
-  ftp://sunsite.unc.edu/pub/Linux/system/Linux-boot/lilo.
+  ftp://metalab.unc.edu/pub/Linux/system/Linux-boot/lilo.
 
   If you want to compile the driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -402,7 +425,7 @@
   bootparam" or see the documentation of your boot loader about how to
   pass options to the kernel. The lilo procedure is also explained in
   the SCSI-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.)
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.)
 
   The CMD640 chip is also used on add-in cards by Acculogic, and on
   the "CSA-6400E PCI to IDE controller" that some people have. For
@@ -448,7 +471,7 @@
   for these drives, but you can change that by saying Y to the
   following question "Use DMA by default when available". You can get
   the latest version of the hdparm utility via anonymous FTP from
-  ftp://sunsite.unc.edu/pub/Linux/system/hardware/.
+  ftp://metalab.unc.edu/pub/Linux/system/hardware/.
 
   Read the comments at the beginning of drivers/block/idedma.c and the
   file Documentation/ide.txt for more information. 
@@ -872,7 +895,7 @@
 
   More information about Software RAID on Linux is contained in the
   Software-RAID mini-HOWTO, available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini. There you will also
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. There you will also
   learn where to get the supporting user space utilities raidtools.
 
   If unsure, say N.
@@ -900,7 +923,7 @@
 
   Information about Software RAID on Linux is contained in the
   Software-RAID mini-HOWTO, available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini. There you will also
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. There you will also
   learn where to get the supporting user space utilities raidtools.
 
   If you want to compile this as a module ( = code which can be
@@ -922,7 +945,7 @@
 
   Information about Software RAID on Linux is contained in the
   Software-RAID mini-HOWTO, available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini. There you will also
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. There you will also
   learn where to get the supporting user space utilities raidtools.
 
   If you want to use such a RAID-1 set, say Y. This code is also
@@ -945,7 +968,7 @@
 
   Information about Software RAID on Linux is contained in the
   Software-RAID mini-HOWTO, available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini. There you will also
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. There you will also
   learn where to get the supporting user space utilities raidtools.
 
   If you want to use such a RAID-4/RAID-5 set, say Y. This code is
@@ -1044,7 +1067,7 @@
   address they listen on (e.g. "multihosting" or "virtual domains" or
   "virtual hosting services" on the web server apache and the ftp
   server wuftpd -- read the Virtual-Services-HOWTO, available via FTP
-  (user: anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO)
+  (user: anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO)
   or for connecting to different logical networks through the same
   physical interface (most commonly an Ethernet networking card). See
   Documentation/networking/alias.txt for more info.
@@ -1150,7 +1173,7 @@
   http://www.azstarnet.com/~axplinux/ (to browse the WWW, you need to
   have access to a machine on the Internet that has a program like
   lynx or netscape) and also the Alpha-HOWTO, available via FTP (user:
-  anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. For this
+  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. For this
   question, it suffices to give a unique prefix of the option you want
   to choose. The choices:
   ** Avanti: This is for Mustang (AS200), M3 (AS250), Avanti (AS400)
@@ -1232,7 +1255,7 @@
   standard COM 1/2/3/4 ports. This may happen if you have an AST
   FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available
   via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini), or other custom
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini), or other custom
   serial port hardware which acts similar to standard serial port
   hardware. If you only use the standard COM 1/2/3/4 ports, you can
   say N here to save some memory. You can also say Y if you have an
@@ -1285,7 +1308,7 @@
   your box. Other bus systems are ISA, EISA, Microchannel (MCA) or
   VESA. If you have PCI, say Y, otherwise N. The PCI-HOWTO, available
   via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, contains valuable
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, contains valuable
   information about which PCI hardware does work under Linux and which
   doesn't.
 
@@ -1348,8 +1371,7 @@
   MicroChannel Architecture is found in some IBM PS/2 machines and
   laptops. It is a bus system similar to PCI or ISA. See
   Documentation/mca.txt (and especially the web page given there)
-  before attempting to build an MCA bus kernel. Note that this is
-  still experimental code.
+  before attempting to build an MCA bus kernel.
 
 System V IPC
 CONFIG_SYSVIPC
@@ -1359,13 +1381,13 @@
   thing, and some programs won't run unless you say Y here. In
   particular, if you want to run the DOS emulator dosemu under Linux
   (read the DOSEMU-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO), you'll need to say Y
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO), you'll need to say Y
   here.
   
   You can find documentation about IPC with "info ipc" and also in
   section 6.4 of the Linux Programmer's Guide, available via FTP
   (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/LDP/programmers-guide.
+  ftp://metalab.unc.edu/pub/Linux/docs/LDP/programmers-guide.
 
   Saying Y here enlarges your kernel by about 7 KB. Just say Y.
 
@@ -1410,7 +1432,7 @@
   want to say Y here.
 
   Information about ELF is contained in the ELF HOWTO available via
-  FTP (user: anonymous) at ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  FTP (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   If you find that after upgrading from Linux kernel 1.2 and saying Y
   here, you still can't run any ELF binaries (they just crash), then
@@ -1455,7 +1477,7 @@
 
   If you want to execute JAVA binaries, read the Java on Linux HOWTO,
   available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. You will then need to
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You will then need to
   install the run time system contained in the Java Developers Kit
   (JDK) as described in the HOWTO. This is completely independent of
   the Linux kernel and you do NOT need to say Y here for this to work.
@@ -1499,7 +1521,7 @@
   programs that need an interpreter to run like Java, Python or
   Emacs-Lisp. It's also useful if you often run DOS executables under
   the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO). Once you have
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO). Once you have
   registered such a binary class with the kernel, you can start one of
   those programs simply by typing in its name at a shell prompt; Linux
   will automatically feed it to the correct interpreter.
@@ -1553,24 +1575,6 @@
   In rare cases, it can make sense to specify "Pentium" even if
   running on a 486: the kernel will be smaller but slower.
 
-  If you have a single processor machine, make sure that the line
-  "SMP=1" at the top of the toplevel kernel Makefile is commented out;
-  if you have a multi processor machine and want Linux to use all the
-  processors in parallel (Symmetric Multi Processing), make sure that
-  the line "SMP=1" is not commented out and read Documentation/smp and
-  Documentation/IO-APIC.txt and the SMP-FAQ on the WWW at
-  http://www.irisa.fr/prive/mentre/smp-faq/ (to browse the WWW, you
-  need to have access to a machine on the Internet that has a program
-  like lynx or netscape). People using multiprocessor machines should
-  also say Y to "Enhanced Real Time Clock Support", below.
-
-  If you want to compile a kernel that works on both single processor
-  and multi processor machines, it is possible to set SMP=1. The
-  "Advanced Power Management" code (see configuration option below)
-  will not work in that scenario, though. In addition, the kernel will
-  be slower on single processor machines, and other problems may
-  appear, so this is not recommended.
-
   If you don't know what to do, choose "386".
 
 VGA text console
@@ -1581,7 +1585,7 @@
 
   The program SVGATextMode can be used to utilize SVGA video cards to
   their full potential in text mode. Download it via FTP (user:
-  anonymous) from ftp://sunsite.unc.edu/pub/Linux/utils/console.
+  anonymous) from ftp://metalab.unc.edu/pub/Linux/utils/console.
 
   Say Y.
 
@@ -1596,7 +1600,7 @@
   "man bootparam" or see the documentation of your boot loader about
   how to pass options to the kernel. The lilo procedure is also
   explained in the SCSI-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Read
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Read
   Documentation/svga.txt for more information about the Video mode
   selection support. If unsure, say N.
 
@@ -2232,10 +2236,10 @@
   If you want to configure your Linux box as a packet filter firewall
   for a local TCP/IP based network, say Y here. You may want to read
   the FIREWALL-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   Also, you will need the ipchains tool (available on the WWW at
-  http://www.adelaide.net.au/~rustcorp/) to allow selective blocking
+  http://www.rustcorp.com/linux/ipchains/) to allow selective blocking
   of Internet traffic based on type, origin and destination. 
   Note that the Linux firewall code has changed and the old program
   called ipfwadm won't work anymore.
@@ -2336,9 +2340,7 @@
 
   Saying Y to this option will produce two modules ( = code which can
   be inserted in and removed from the running kernel whenever you
-  want), one encapsulator called tunnel.o and one decapsulator called
-  ipip.o. You can read details in drivers/net/README.tunnel. Most
-  people won't need this and can say N.
+  want). Most people won't need this and can say N.
 
 IP: GRE tunnels over IP
 CONFIG_NET_IPGRE
@@ -2387,7 +2389,7 @@
   Linux box to the Internet using SLiRP [SLiRP is a SLIP/PPP emulator
   that works if you have a regular dial up shell account on some UNIX
   computer; get it via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/system/network/serial/ ].) 
+  ftp://metalab.unc.edu/pub/Linux/system/network/serial/ ].) 
 
   The IP masquerading code will only work if IP forwarding is enabled
   in your kernel; you can do this by saying Y to "/proc
@@ -2400,7 +2402,7 @@
 
   Details on how to set things up are contained in the IP Masquerade
   mini-HOWTO, available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini; there's also some
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini; there's also some
   information on the WWW at
   http://www.tor.shaw.wave.ca/~ambrose/kernel21.html. 
 
@@ -2427,7 +2429,7 @@
 IP: masquerading special modules support
 CONFIG_IP_MASQUERADE_MOD
   This provides support for special modules that can modify the
-  rewriting rules used when masquerading. Please not that this feature
+  rewriting rules used when masquerading. Please note that this feature
   adds a little overhead in the input packet processing chain.
 
   Examples of such modules are ipautofw (allowing the masquerading of
@@ -2437,7 +2439,7 @@
 
   You will need the user space program "ipmasqadm" to use these
   additional modules; you can download it from
-  http://juanjox.home.ml.org/
+  http://juanjox.linuxhq.com/
 
   All this additional code is still under development and so is
   currently marked EXPERIMENTAL.
@@ -2452,7 +2454,7 @@
   ftp://ftp.netis.com/pub/members/rlynch/
 
   You will also need the ipmasqadm tool available from
-  http://juanjox.home.ml.org .
+  http://juanjox.linuxhq.com/ .
 
   The ipautofw code is still under development and so is currently
   marked EXPERIMENTAL. If you want to try it, say Y.
@@ -2483,7 +2485,7 @@
   see ftp://ftp.compsoc.net/users/steve/ipportfw/linux21/
 
   You will need the user space program "ipmasqadm" which can be
-  downloaded from http://juanjox.home.ml.org/
+  downloaded from http://juanjox.linuxhq.com/
 
   The portfw code is still under development and so is currently
   marked EXPERIMENTAL. If you want to try it, say Y.
@@ -2494,12 +2496,12 @@
   it as a module, say M here and read Documentation/modules.txt.
 
 IP: ipmarkfw masquerade support
-CONFIG_IP_MASQUERADE_IPMARKFW
-  This provides functionality equivalent to port forwarding, the
-  difference is that Mark Forwarding uses "firewalling mark" to select
-  which packets must forward (see ipchains(8), "-m" argument).
+CONFIG_IP_MASQUERADE_MFW
+  This provides functionality similar to port forwarding, the
+  difference is that Firewall Mark Forwarding uses "firewalling mark" 
+  to select which packets must forward (see ipchains(8), "-m" argument).
 
-  The markfw code is still under development and so is currently
+  The ip_masq_mfw code is still under development and so is currently
   marked EXPERIMENTAL. If you want to try it, say Y.
 
   This code is also available as a module ( = code which can be
@@ -2538,7 +2540,7 @@
   need to have access to a machine on the Internet that has a program
   like lynx or netscape) and also in the Virtual-Hosting-HOWTO,
   available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   Another scenario would be that there are two logical networks living
   on your local Ethernet and you want to access them both with the
@@ -2605,7 +2607,7 @@
 
   If you actually want to use a diskless Sun 3 machine as an X
   terminal to Linux, say Y here and fetch Linux-Xkernel from
-  ftp://sunsite.unc.edu/pub/Linux/system/network/boot.net/.
+  ftp://metalab.unc.edu/pub/Linux/system/network/boot.net/.
 
   Superior solutions to the problem of booting and configuring
   machines over a net connection are given by the protocol BOOTP and
@@ -2756,9 +2758,9 @@
   used for local networks of Windows machines. You need it if you want
   to access Novell NetWare file or print servers using the Linux
   Novell client ncpfs (available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/system/filesystems/) or from within
+  ftp://metalab.unc.edu/pub/Linux/system/filesystems/) or from within
   the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO). In order to do the
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO). In order to do the
   former, you'll also have to say Y to "NCP filesystem support",
   below.
 
@@ -2768,9 +2770,9 @@
 
   To turn your Linux box into a fully featured NetWare file server and
   IPX router, say Y here and fetch either lwared from
-  ftp://sunsite.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe
+  ftp://metalab.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe
   from ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. For more information,
-  read the IPX-HOWTO in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  read the IPX-HOWTO in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   General information about how to connect Linux, Windows machines and
   Macs is on the WWW at http://www.eats.com/linux_mac_win.html (to
@@ -2793,7 +2795,7 @@
   same address). The way this is done is to create a virtual internal
   "network" inside your box and to assign an IPX address to this
   network. Say Y here if you want to do this; read the IPX-HOWTO at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO for details.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO for details.
 
   The full internal IPX network enables you to allocate sockets on
   different virtual nodes of the internal network. This is done by
@@ -2823,7 +2825,7 @@
   space programs lwared or mars_nwe for the server side).
 
   Say Y here if you have use for SPX; read the IPX-HOWTO at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO for details.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO for details.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -2844,7 +2846,7 @@
   slower LocalTalk is AppleTalk over a proprietary apple network using
   serial links. EtherTalk and LocalTalk are fully supported by Linux.
   The NET-2-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO contains valuable
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO contains valuable
   information as well.
 
   General information about how to connect Linux, Windows machines and
@@ -2928,7 +2930,7 @@
   (to browse the WWW, you need to have access to a machine on the
   Internet that has a program like lynx or netscape) and the HAM-HOWTO
   and the AX25-HOWTO, both available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   Note that the answer to this question won't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -2952,7 +2954,7 @@
   Information about where to get supporting software for Linux amateur
   radio as well as information about how to configure an AX.25 port is
   contained in the AX25-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. You might also want to
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You might also want to
   check out the file Documentation/networking/ax25.txt in the kernel
   source. More information about digital amateur radio in general is
   on the WWW at http://www.tapr.org/tapr/html/pkthome.html. (To browse
@@ -2990,7 +2992,7 @@
   A comprehensive listing of all the software for Linux amateur radio
   users as well as information about how to configure an AX.25 port is
   contained in the AX25-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. You also might want to
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You also might want to
   check out the file Documentation/networking/ax25.txt. More
   information about digital amateur radio in general is on the WWW at
   http://www.tapr.org/tapr/html/pkthome.html (to browse the WWW, you
@@ -3011,7 +3013,7 @@
   A comprehensive listing of all the software for Linux amateur radio
   users as well as information about how to configure an AX.25 port is
   contained in the AX25-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. You also might want to
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You also might want to
   check out the file Documentation/networking/ax25.txt. More
   information about digital amateur radio in general is on the WWW at
   http://www.tapr.org/tapr/html/pkthome.html (to browse the WWW, you
@@ -3079,7 +3081,7 @@
   (http://www.paccomm.com/gracilis.html) boards. They are detected
   automatically. If you have one of these cards, say Y here and read
   the AX25-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/.
 
   This driver can operate multiple boards simultaneously. If you
   compile it as a module (by saying M instead of Y), it will be called
@@ -3105,7 +3107,7 @@
   in order to communicate with other computers. If you want to use
   this, read Documentation/networking/z8530drv.txt and the
   AX25-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Also make sure to say Y
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Also make sure to say Y
   to "Amateur Radio AX.25 Level 2" support.
 
   If you want to compile this as a module ( = code which can be
@@ -3364,7 +3366,7 @@
   probably contains several Ethernet devices, but the kernel is not
   able to recognize more than one at boot time without help; for
   details read the Ethernet-HOWTO, available via FTP (user: anonymous)
-  in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. The Bridging code is
+  in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. The Bridging code is
   still in test. If unsure, say N.
 
 Packet socket
@@ -3419,7 +3421,7 @@
   port version of the 100 MB IOMEGA ZIP drive.
 
   Please read the SCSI-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. The
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. The
   SCSI-Programming-HOWTO contains information about how to add or
   remove an SCSI device from a running Linux machine without
   rebooting. 
@@ -3437,7 +3439,7 @@
   If you want to use a SCSI hard disk or the SCSI or parallel port
   version of the IOMEGA ZIP drive under Linux, say Y and read the
   SCSI-HOWTO, the Disk-HOWTO and the Multi-Disk-HOWTO, available via
-  FTP (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  FTP (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
   This is NOT for SCSI CDROMs.
 
   This driver is also available as a module ( = code which can be
@@ -3453,7 +3455,7 @@
 CONFIG_CHR_DEV_ST
   If you want to use a SCSI tape drive under Linux, say Y and read the
   SCSI-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO and
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO and
   drivers/scsi/README.st in the kernel source. This is NOT for SCSI
   CDROMs.
 
@@ -3467,7 +3469,7 @@
 CONFIG_BLK_DEV_SR
   If you want to use a SCSI CDROM under Linux, say Y and read the
   SCSI-HOWTO and the CDROM-HOWTO from
-  ftp://sunsite.unc.edu:/pub/Linux/docs/HOWTO. Also make sure to say Y
+  ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO. Also make sure to say Y
   or M to "ISO 9660 CDROM filesystem support" later.
 
   This driver is also available as a module ( = code which can be
@@ -3491,11 +3493,11 @@
   directly, so you need some additional software which knows how to
   talk to these devices using the SCSI protocol. For CD-writers, you
   would need the program cdwrite, available via FTP (user: anonymous)
-  from ftp://sunsite.unc.edu/pub/Linux/utils/disk-management; for
+  from ftp://metalab.unc.edu/pub/Linux/utils/disk-management; for
   other devices, it's possible that you'll have to write the driver
   software yourself, so have a look at the SCSI-HOWTO and at the
   SCSI-Programming-HOWTO, both available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu:/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -3558,7 +3560,7 @@
   This is support for the AHA-1510, AHA-1520, AHA-1522, and AHA-2825
   SCSI host adapters. It is explained in section 3.3 of the
   SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. You might also want to
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You might also want to
   read the comments at the top of drivers/scsi/aha152x.c.
 
   This driver is also available as a module ( = code which can be
@@ -3570,7 +3572,7 @@
 CONFIG_SCSI_AHA1542
   This is support for a SCSI host adapter. It is explained in section
   3.4 of the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Note that Trantor was
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that Trantor was
   recently purchased by Adaptec, and some former Trantor products are
   being sold under the Adaptec name. If it doesn't work out of the
   box, you may have to change some settings in drivers/scsi/aha1542.h.
@@ -3584,7 +3586,7 @@
 CONFIG_SCSI_AHA1740
   This is support for a SCSI host adapter. It is explained in section
   3.5 of the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
   of the box, you may have to change some settings in
   drivers/scsi/aha1740.h.
 
@@ -3603,7 +3605,7 @@
   found by checking the help file for each of the available
   configuration options. You also want to read
   drivers/scsi/README.aic7xxx and the SCSI-HOWTO, available via FTP
-  (user: anonymous) at ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
   Note that the AHA2920 SCSI host adapter is *not* supported by this
   driver; choose "Future Domain 16xx SCSI support" instead if you have
   one of those.
@@ -3680,7 +3682,7 @@
 CONFIG_SCSI_BUSLOGIC
   This is support for BusLogic MultiMaster and FlashPoint SCSI Host
   Adapters. Consult the SCSI-HOWTO, available via anonymous FTP from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, and the files
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, and the files
   README.BusLogic and README.FlashPoint in drivers/scsi for more
   information. If this driver does not work correctly without
   modification, please contact the author, Leonard N. Zubkoff, by
@@ -3703,7 +3705,7 @@
 CONFIG_SCSI_DTC3280
   This is support for DTC 3180/3280 SCSI Host Adapters. Please read
   the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO and the file
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO and the file
   drivers/scsi/README.dtc3x80. 
 
   This driver is also available as a module ( = code which can be
@@ -3711,15 +3713,18 @@
   The module will be called dtc.o. If you want to compile it as a
   module, say M here and read Documentation/modules.txt.
 
-EATA-DMA (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support
+EATA-DMA [Obsolete] (DPT, NEC, AT&T, SNI, AST, Olivetti, Alphatronix) support
 CONFIG_SCSI_EATA_DMA
+  This driver is obsolete. You should normally be using the generic EATA
+  driver for this hardware.
+
   This is support for the EATA-DMA protocol compliant SCSI Host
   Adapters like the SmartCache III/IV, SmartRAID controller families
   and the DPT PM2011B and PM2012B controllers. Note that there is
   also another driver for the same hardware: "EATA ISA/EISA/PCI
   support". You should only say Y to one of them. Please read the
   SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -3734,7 +3739,7 @@
   doing so, since this driver only supports hard disks and lacks
   numerous features. You might want to have a look at the SCSI-HOWTO,
   available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -3748,7 +3753,7 @@
   this hardware. If the driver doesn't work out of the box, you may
   have to change some settings in drivers/scsi/u14-34f.c. Read the
   SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Note that there is also
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that there is also
   another driver for the same hardware: "UltraStor SCSI support",
   below. You should say Y to both only if you want 24F support as
   well. 
@@ -3778,7 +3783,7 @@
   other adapters based on the Future Domain chipsets (Quantum
   ISA-200S, ISA-250MG; Adaptec AHA-2920; and at least one IBM board).
   It is explained in section 3.7 of the SCSI-HOWTO, available via FTP
-  (user: anonymous) at ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -3797,7 +3802,7 @@
   This is the generic NCR family of SCSI controllers, not to be
   confused with the NCR 53c7 or 8xx controllers. It is explained in
   section 3.8 of the SCSI-HOWTO, available via FTP (user: anonymous)
-  at ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work
+  at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work
   out of the box, you may have to change some settings in
   drivers/scsi/g_NCR5380.h.
 
@@ -3826,7 +3831,7 @@
   This is the 53c7 and 8xx NCR family of SCSI controllers, not to be
   confused with the NCR 5380 controllers. It is explained in section
   3.8 of the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
   of the box, you may have to change some settings in
   drivers/scsi/53c7,8xx.h.
 
@@ -4011,7 +4016,7 @@
   bootparam" or see the documentation of your boot loader about how to
   pass options to the kernel. The lilo procedure is also explained in
   the SCSI-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -4062,6 +4067,17 @@
   you know that one of your older devices needs it; N is the safe
   answer.
 
+NCR 53C9x MCA support
+CONFIG_SCSI_MCA_53C9X
+  Some Microchannel machines, notably the NCR 35xx line, use a SCSI
+  controller based on the NCR 53C94.  This driver will allow use of
+  the controller on the 3550, and very possibly others.   
+
+  If you want to compile this as a module (= code which can be inserted
+  and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt.  The module will be
+  called mca_53c9x.o.
+ 
 Always IN2000 SCSI support
 CONFIG_SCSI_IN2000
   This is support for an ISA bus SCSI host adapter. You'll find more
@@ -4078,7 +4094,7 @@
 CONFIG_SCSI_PAS16
   This is support for a SCSI host adapter. It is explained in section
   3.10 of the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
   of the box, you may have to change some settings in
   drivers/scsi/pas16.h.
   
@@ -4091,7 +4107,7 @@
 CONFIG_SCSI_PCI2000
   This is support for the PCI2000I EIDE interface card which acts as a
   SCSI host adapter. Please read the SCSI-HOWTO, available via FTP
-  (user: anonymous) at ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   This driver is also available as a module called pci2000.o ( = code
   which can be inserted in and removed from the running kernel
@@ -4102,7 +4118,7 @@
 CONFIG_SCSI_PCI2220I
   This is support for the PCI2220i EIDE interface card which acts as a
   SCSI host adapter. Please read the SCSI-HOWTO, available via FTP
-  (user: anonymous) at ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   This driver is also available as a module called pci2220i.o ( = code
   which can be inserted in and removed from the running kernel
@@ -4113,7 +4129,7 @@
 CONFIG_SCSI_PSI240I
   This is support for the PSI240i EIDE interface card which acts as a
   SCSI host adapter. Please read the SCSI-HOWTO, available via FTP
-  (user: anonymous) at ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  (user: anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   This driver is also available as a module called psi240i.o ( = code
   which can be inserted in and removed from the running kernel
@@ -4129,7 +4145,7 @@
   the Qlogic ISP driver though. Information about this driver is
   contained in drivers/scsi/README.qlogicfas. You should also read
   the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -4146,7 +4162,7 @@
 
   Please read the file drivers/scsi/README.qlogicisp. You should also
   read the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -4158,7 +4174,7 @@
   These are 8-bit SCSI controllers; the ST-01 is also supported by
   this driver. It is explained in section 3.9 of the SCSI-HOWTO,
   available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
   of the box, you may have to change some settings in
   drivers/scsi/seagate.h.
 
@@ -4171,7 +4187,7 @@
 CONFIG_SCSI_T128
   This is support for a SCSI host adapter. It is explained in section
   3.11 of the SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
   of the box, you may have to change some settings in
   drivers/scsi/t128.h. Note that Trantor was purchased by Adaptec, and
   some former Trantor products are being sold under the Adaptec name.
@@ -4186,7 +4202,7 @@
   This is support for the UltraStor 14F, 24F and 34F SCSI-2 host
   adapter family. This driver is explained in section 3.12 of the
   SCSI-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If it doesn't work out
   of the box, you may have to change some settings in
   drivers/scsi/ultrastor.h.
   
@@ -4216,7 +4232,7 @@
   to "PCI BIOS support", the addresses of all the PCI SCSI controllers
   reported by BIOS32 are probed as well. You want to read the start of
   drivers/scsi/eata.c and the SCSI-HOWTO, available via FTP (user:
-  anonymous) at ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   Note that there is also another driver for the same hardware
   available: "EATA-DMA support". You should say Y to only one of them.
@@ -4252,7 +4268,7 @@
   This is support for the NCR53c406a SCSI host adapter. For user
   configurable parameters, check out drivers/scsi/NCR53c406.c in the
   kernel source. Also read the SCSI-HOWTO, available via FTP (user:
-  anonymous) at ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  anonymous) at ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -4296,7 +4312,7 @@
   This is support for the AM53/79C974 SCSI host adapters. Please read
   drivers/scsi/README.AM53C974 for details. Also, the SCSI-HOWTO,
   available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, is for you.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, is for you.
 
   Note that there is another driver for AM53C974 based adapters:
   "Tekram DC390(T) and Am53/79C974 (PCscsi) SCSI support", above.
@@ -4324,7 +4340,7 @@
   driver and how to use it you should read the file
   drivers/scsi/README.ppa. You should also read the SCSI-HOWTO, which
   is available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. If you use this driver,
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If you use this driver,
   you will still be able to use the parallel port for other tasks,
   such as a printer; it is safe to compile both drivers into the
   kernel.
@@ -4441,7 +4457,7 @@
   line with a modem either via UUCP (UUCP is a protocol to forward
   mail and news between unix hosts over telephone lines; read the
   UUCP-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO) or dialing up a shell
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO) or dialing up a shell
   account or a BBS, even using term (term is a program which gives you
   almost full Internet connectivity if you have a regular dial up
   shell account on some Internet connected Unix computer. Read
@@ -4453,7 +4469,7 @@
   you want to use under Linux (make sure you know its name because you
   will be asked for it and read the Ethernet-HOWTO (especially if you
   plan to use more than one network card under Linux), available from
-  ftp://sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini) or if you want to
+  ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO/mini) or if you want to
   use SLIP (Serial Line Internet Protocol is the protocol used to send
   Internet traffic over telephone lines or null modem cables) or CSLIP
   (compressed SLIP) or PPP (Point to Point Protocol, a better and
@@ -4464,7 +4480,7 @@
 
   Make sure to read the NET-2-HOWTO. Eventually, you will have to read
   Olaf Kirch's excellent and free book "Network Administrator's
-  Guide", to be found in ftp://sunsite.unc.edu:/pub/Linux/docs/LDP. If
+  Guide", to be found in ftp://metalab.unc.edu:/pub/Linux/docs/LDP. If
   unsure, say Y.
 
 Dummy net driver support
@@ -4475,7 +4491,7 @@
   inactive SLIP address seem like a real address for local programs.
   If you use SLIP or PPP, you might want to say Y here. Read about it
   in the Network Administrator's Guide, available via FTP (user:
-  anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/LDP. Since this
+  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/LDP. Since this
   thing often comes in handy, the default is Y. It won't enlarge your
   kernel either. What a deal.
 
@@ -4500,11 +4516,11 @@
   Normally, your access provider has to support SLIP in order for you
   to be able to use it, but there is now a SLIP emulator called SLiRP
   around (available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/system/network/serial/ ) which
+  ftp://metalab.unc.edu/pub/Linux/system/network/serial/ ) which
   allows you to use SLIP over a regular dial up shell connection. If
   you plan to use SLiRP, make sure to say Y to CSLIP, below. The
   NET-2-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, explains how to
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, explains how to
   configure SLIP. Note that you don't need this option if you just
   want to run term (term is a program which gives you almost full
   Internet connectivity if you have a regular dial up shell account on
@@ -4528,10 +4544,10 @@
   answer Y, just in case. You will still be able to use plain SLIP. If
   you plan to use SLiRP, the SLIP emulator (available via FTP (user:
   anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/system/network/serial/) which allows
+  ftp://metalab.unc.edu/pub/Linux/system/network/serial/) which allows
   you to use SLIP over a regular dial up shell connection, you
   definitely want to say Y here. The NET-2-HOWTO, available via FTP
-  (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO,
+  (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO,
   explains how to configure CSLIP. This won't enlarge your kernel.
 
 Keepalive and linefill
@@ -4559,7 +4575,7 @@
   program SLiRP can emulate a PPP line if you just have a regular dial
   up shell account on some UNIX computer; get it via FTP (user:
   anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/system/network/serial/). Note that
+  ftp://metalab.unc.edu/pub/Linux/system/network/serial/). Note that
   you don't need "PPP support" if you just want to run term (term is a
   program which gives you almost full Internet connectivity if you
   have a regular dial up shell account on some Internet connected UNIX
@@ -4570,7 +4586,7 @@
 
   To use PPP, you need an additional program called pppd as described
   in Documentation/networking/ppp.txt and in the PPP-HOWTO, available
-  from ftp://sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you upgrade
+  from ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO. If you upgrade
   from an older kernel, you might need to upgrade pppd as well. The
   PPP option enlarges your kernel by about 16 KB.
 
@@ -4637,7 +4653,7 @@
 
   If you want to use an ISA WaveLAN card under Linux, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Some more specific
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Some more specific
   information is contained in Documentation/networking/wavelan.txt and
   in the source code drivers/net/wavelan.p.h.
 
@@ -4722,8 +4738,8 @@
 
   If you want to use PLIP, say Y and read the PLIP mini-HOWTO,
   available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini as well as the
-  NET-2-HOWTO in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Note that
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini as well as the
+  NET-2-HOWTO in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that
   the PLIP protocol was changed and this PLIP driver won't work
   together with the PLIP support in Linux versions 1.0.x. This option
   enlarges your kernel by about 8 KB.
@@ -5078,6 +5094,48 @@
   up to 256Kbits. It supports both PPP and Cisco HDLC
   At this point, the driver can only be compiled as a module.
 
+COSA/SRP sync serial boards support
+CONFIG_COSA
+  This is a driver for COSA and SRP synchronous serial boards.
+  These boards enable to connect synchronous serial devices (for
+  example base-band modems, or any other device with the X.21, V.24,
+  V.35 or V.36 interface) to your Linux box. The cards can work
+  as the character device, synchronous PPP network device, or the Cisco
+  HDLC network device.
+
+  To actually use the COSA or SRP board, you will need user-space
+  utilities for downloading the firmware to the cards and to set 
+  them up. Look at the http://www.fi.muni.cz/~kas/cosa/ for more
+  information about the cards (including the pointer to the user-space
+  utilities). You can also read the comment at the top of the
+  drivers/net/cosa.c for details about the cards and the driver itself.
+
+  The driver will be compiled as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cosa.o. For general information about
+  modules read Documentation/modules.txt.
+
+COSA/SRP sync serial boards support
+CONFIG_COSA
+  This is a driver for COSA and SRP synchronous serial boards.
+  These boards enable to connect synchronous serial devices (for
+  example base-band modems, or any other device with the X.21, V.24,
+  V.35 or V.36 interface) to your Linux box. The cards can work
+  as the character device, synchronous PPP network device, or the Cisco
+  HDLC network device.
+
+  To actually use the COSA or SRP board, you will need user-space
+  utilities for downloading the firmware to the cards and to set 
+  them up. Look at the http://www.fi.muni.cz/~kas/cosa/ for more
+  information about the cards (including the pointer to the user-space
+  utilities). You can also read the comment at the top of the
+  drivers/net/cosa.c for details about the cards and the driver itself.
+
+  The driver will be compiled as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want).
+  The module will be called cosa.o. For general information about
+  modules read Documentation/modules.txt.
+
 WAN Drivers
 CONFIG_WAN_DRIVERS
   Say Y to this option if your Linux box contains a WAN card and you
@@ -5160,7 +5218,7 @@
   If your Linux machine will be connected to an Ethernet and you have
   an Ethernet network interface card (NIC) installed in your computer,
   say Y here and read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. You will
+  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. You will
   then also have to say Y to the driver for your particular NIC.
 
   Note that the answer to this question won't directly affect the
@@ -5187,7 +5245,7 @@
 CONFIG_NET_VENDOR_SMC
   If you have a network (Ethernet) card belonging to this class, say Y
   and read the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   Note that the answer to this question doesn't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -5198,7 +5256,7 @@
 CONFIG_WD80x3
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5211,7 +5269,7 @@
   If you have a network (Ethernet) card of this type and are running
   an MCA based system (PS/2), say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5223,7 +5281,7 @@
 CONFIG_ULTRA
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
   
   Important: There have been many reports that, with some motherboards
   mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible,
@@ -5242,7 +5300,7 @@
 CONFIG_ULTRA32
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5258,7 +5316,7 @@
   into the kernel, and read the file
   Documentation/networking/smc9.txt and the Ethernet-HOWTO, available
   via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you
@@ -5272,7 +5330,7 @@
   with ISA NE2000 cards (they have their own driver, "NE2000/NE1000
   support" below). If you have a PCI NE2000 network (Ethernet) card,
   say Y and read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5285,7 +5343,7 @@
   If you have a network (Ethernet) card belonging to this class, such
   as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
   available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   Note that the answer to this question doesn't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -5296,7 +5354,7 @@
 CONFIG_NI5010
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Note that this is still
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that this is still
   experimental code. 
 
   This driver is also available as a module ( = code which can be
@@ -5309,7 +5367,7 @@
 CONFIG_NI52
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5321,7 +5379,7 @@
 CONFIG_NI65
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5334,7 +5392,7 @@
   This is a driver for the Fast Ethernet PCI network cards based on
   the RTL8129 and RTL8139 chips. If you have one of those, say Y and
   read the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -5373,14 +5431,14 @@
 CONFIG_LANCE
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Some LinkSys cards are
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Some LinkSys cards are
   of this type.
 
 3COM cards
 CONFIG_NET_VENDOR_3COM
   If you have a network (Ethernet) card belonging to this class, say Y
   and read the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   Note that the answer to this question doesn't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -5391,7 +5449,7 @@
 CONFIG_EL1
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Also, consider buying a
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Also, consider buying a
   new card, since the 3c501 is slow, broken, and obsolete: you will
   have problems. Some people suggest to ping ("man ping") a nearby
   machine every minute ("man cron") when using this card.
@@ -5406,7 +5464,7 @@
 CONFIG_EL2
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5419,7 +5477,7 @@
   Information about this network (Ethernet) card can be found in
   Documentation/networking/3c505.txt. If you have a card of this type,
   say Y and read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -5431,7 +5489,7 @@
 CONFIG_EL16
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5443,7 +5501,7 @@
 CONFIG_ELMC
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5456,7 +5514,7 @@
   If you have a network (Ethernet) card belonging to the 3Com
   EtherLinkIII series, say Y and read the Ethernet-HOWTO, available
   via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   If your card is not working you may need to use the DOS
   setup disk to disable Plug & Play mode, and to select the default
@@ -5473,7 +5531,7 @@
   If you have a 3Com "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597)
   or "Boomerang" series (EtherLink XL 3c900 or 3c905) network
   (Ethernet) card, say Y and read the Ethernet-HOWTO, available via
-  FTP (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  FTP (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
   More specific information is in Documentation/networking/vortex.txt
   and in the comments at the beginning of drivers/net/3c59x.c.
 
@@ -5489,7 +5547,7 @@
   of your computer) is ISA (as opposed to EISA, VLB or PCI), say Y.
   Make sure you know the name of your card. Read the Ethernet-HOWTO,
   available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. If unsure, say Y.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. If unsure, say Y.
 
   Note that the answer to this question doesn't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -5508,7 +5566,7 @@
 
   You might also want to have a look at the Ethernet-HOWTO, available
   via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO (even though ARCnet is
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO (even though ARCnet is
   not really Ethernet).
 
   This driver is also available as a module ( = code which can be
@@ -5596,7 +5654,7 @@
 CONFIG_E2100
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5609,7 +5667,7 @@
   Support for CS89x0 chipset based Ethernet cards. If you have a
   network (Ethernet) card of this type, say Y and read the
   Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO as well as
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO as well as
   Documentation/networking/cs89x0.txt.
 
   If you want to compile this as a module ( = code which can be
@@ -5622,7 +5680,7 @@
 CONFIG_DEPCA
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO as well as
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO as well as
   drivers/net/depca.c.
 
   If you want to compile this as a module ( = code which can be
@@ -5637,7 +5695,7 @@
   cards. If this is for you, say Y and read
   Documentation/networking/ewrk3.txt in the kernel source as well as
   the Ethernet-HOWTO, available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -5649,13 +5707,13 @@
 CONFIG_SEEQ8005
   This is a driver for the SEEQ 8005 network (Ethernet) card. If this
   is for you, read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
 AT1700/1720 support
 CONFIG_AT1700
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5668,7 +5726,7 @@
 CONFIG_FMV18X
   If you have a Fujitsu FMV-181/182/183/184 network (Ethernet) card,
   say Y and read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   If you use an FMV-183 or FMV-184 and it is not working, you may need
   to disable Plug & Play mode of the card.
@@ -5684,7 +5742,7 @@
   If you have a network (Ethernet) card of this type, say Y. Note
   however that the EtherExpress PRO/100 Ethernet card has its own
   separate driver. Please read the Ethernet-HOWTO, available via FTP
-  (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5696,7 +5754,7 @@
 CONFIG_EEXPRESS
   If you have an EtherExpress16 network (Ethernet) card, say Y and
   read the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Note that the Intel
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that the Intel
   EtherExpress16 card used to be regarded as a very poor choice
   because the driver was very unreliable. We now have a new driver
   that should do better.
@@ -5711,7 +5769,7 @@
 CONFIG_HPLAN_PLUS
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5723,7 +5781,7 @@
 CONFIG_HPLAN
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5735,7 +5793,7 @@
 CONFIG_HP100
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -5747,7 +5805,7 @@
 CONFIG_NE2000
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Many Ethernet cards
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Many Ethernet cards
   without a specific driver are compatible with NE2000. 
 
   If you have a PCI NE2000 card however, say N here and Y to "PCI
@@ -5766,13 +5824,13 @@
 CONFIG_SK_G16
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
 NE/2 (ne2000 MCA version) support
 CONFIG_NE2_MCA
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5785,7 +5843,7 @@
   This is another class of network cards which attach directly to the
   bus. If you have one of those, say Y and read the Ethernet-HOWTO,
   available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   Note that the answer to this question doesn't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -5797,7 +5855,7 @@
 CONFIG_PCNET32
   If you have a PCnet32 or PCnetPCI based network (Ethernet) card,
   answer Y here and read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5809,7 +5867,7 @@
 CONFIG_AC3200
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5821,7 +5879,7 @@
 CONFIG_LNE390
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5833,7 +5891,7 @@
 CONFIG_NE3210
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Note that this driver
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Note that this driver
   will NOT WORK for NE3200 cards as they are completely different.
 
   This driver is also available as a module ( = code which can be
@@ -5846,7 +5904,7 @@
 CONFIG_APRICOT
   If you have a network (Ethernet) controller of this type, say Y and
   read the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -5860,7 +5918,7 @@
   These include the DE425, DE434, DE435, DE450 and DE500 models. If
   you have a network card of this type, say Y and read the
   Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. More specific
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. More specific
   information is contained in Documentation/networking/de4x5.txt.
 
   This driver is also available as a module ( = code which can be
@@ -5878,7 +5936,7 @@
   (smc9332dst), you can also try the driver for "Generic DECchip"
   cards, above. However, most people with a network card of this type
   will say Y here.) Do read the Ethernet-HOWTO, available via FTP
-  (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
   More specific information is contained in
   Documentation/networking/tulip.txt.
 
@@ -5894,7 +5952,7 @@
   PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6
   models. If you have a network card of this type, say Y and read the
   Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. More specific
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. More specific
   information is contained in Documentation/networking/dgrs.txt.
 
   This driver is also available as a module ( = code which can be
@@ -5907,7 +5965,7 @@
 CONFIG_EEXPRESS_PRO100
   If you have an Intel EtherExpress PRO/100 PCI network (Ethernet)
   card, say Y and read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5919,7 +5977,7 @@
 CONFIG_ETH16I
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5932,7 +5990,7 @@
   If you have a PCI Ethernet network card based on the ThunderLAN chip
   which is supported by this driver, say Y and read the
   Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   Devices currently supported by this driver are Compaq Netelligent,
   Compaq NetFlex and Olicom cards. Please read the file
@@ -5961,7 +6019,7 @@
 CONFIG_ES3210
   If you have a network (Ethernet) card of this type, say Y and read
   the Ethernet-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5974,7 +6032,7 @@
   If you have an SMC EtherPower II 9432 PCI Ethernet network card
   which is based on the SMC83c170, say Y and read the Ethernet-HOWTO,
   available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5993,14 +6051,14 @@
   (Ethernet) card, and this is the Linux driver for it. Note that the
   IBM Thinkpad 300 is compatible with the Z-Note and is also supported
   by this driver. Read the Ethernet-HOWTO, available via FTP (user:
-  anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
 Pocket and portable adapters
 CONFIG_NET_POCKET
   Cute little network (Ethernet) devices which attach to the parallel
   port ("pocket adapters"), commonly used with laptops. If you have
   one of those, say Y and read the Ethernet-HOWTO, available via FTP
-  (user: anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  (user: anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   If you want to plug a network card into the PCMCIA slot of your
   laptop instead (PCMCIA is the standard for credit card size
@@ -6023,7 +6081,7 @@
   This is a network (Ethernet) device which attaches to your parallel
   port. Read drivers/net/atp.c as well as the Ethernet-HOWTO,
   available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO if you want to use this.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO if you want to use this.
   If you intend to use this driver, you should have said N to the
   Parallel Printer support, because the two drivers don't like each
   other.
@@ -6033,7 +6091,7 @@
   This is a network (Ethernet) device which attaches to your parallel
   port. Read Documentation/networking/DLINK.txt as well as the
   Ethernet-HOWTO, available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO if you want to use this.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO if you want to use this.
   It is possible to have several devices share a single parallel port
   and it is safe to compile the corresponding drivers into the kernel.
 
@@ -6047,7 +6105,7 @@
   This is a network (Ethernet) device which attaches to your parallel
   port. Read Documentation/networking/DLINK.txt as well as the
   Ethernet-HOWTO, available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO if you want to use this.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO if you want to use this.
   It is possible to have several devices share a single parallel port
   and it is safe to compile the corresponding drivers into the kernel.
 
@@ -6065,7 +6123,7 @@
   Ring card under Linux, say Y here and to the driver for your
   particular card below and read the Token-Ring mini-HOWTO, available
   via FTP (user:anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Most people can say N
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. Most people can say N
   here.
 
 IBM Tropic chipset based adapter support
@@ -6073,7 +6131,7 @@
   This is support for all IBM Token Ring cards that don't use DMA. If
   you have such a beast, say Y and read the Token-Ring mini-HOWTO,
   available via FTP (user:anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   Warning: this driver will almost definitely fail if more than one
   active Token Ring card is present. 
@@ -6091,7 +6149,7 @@
 
   If you have such an adapter and would like to use it, say Y or M and
   read the Token-Ring mini-HOWTO, available via FTP (user: anonymous)
-  from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   Also read the file linux/Documentation/networking/sktr.txt or check
   the Linux-SNA WWW site for the latest information at
@@ -6181,7 +6239,7 @@
   should say Y to this option if you wish to use it with Linux.
 
 EBSA-110 Ethernet interface
-CONFIG_AM79C961A
+CONFIG_ARM_AM79C961A
   If you wish to compile a kernel for the EBSA-110, then you should
   always answer Y to this.
 
@@ -6189,7 +6247,7 @@
 CONFIG_CD_NO_IDESCSI
   If you have a CDROM drive that is neither SCSI nor IDE/ATAPI, say Y
   here, otherwise N. Read the CDROM-HOWTO, available via FTP (user:
-  anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   Note that the answer to this question doesn't directly affect the
   kernel: saying N will just cause this configure script to skip all
@@ -6446,7 +6504,7 @@
   ext2 filesystem. You need additional software in order to use quota
   support; for details, read the Quota mini-HOWTO, available via FTP
   (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini. Probably the quota
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini. Probably the quota
   support is only useful for multi user systems. If unsure, say N.
 
 Minix fs support
@@ -6487,7 +6545,7 @@
   by about 41 kB.
 
   The Ext2fs-Undeletion mini-HOWTO, available via FTP (user:
-  anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini,
+  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini,
   gives information about how to retrieve deleted files on ext2fs
   filesystems.
 
@@ -6497,9 +6555,9 @@
   
   Ext2fs partitions can be read from within DOS using the ext2tool
   command line tool package (available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/system/filesystems/ext2) and from
+  ftp://metalab.unc.edu/pub/Linux/system/filesystems/ext2) and from
   within Windows NT using the ext2nt command line tool package from
-  ftp://sunsite.unc.edu/pub/Linux/utils/dos. Explore2fs is a graphical
+  ftp://metalab.unc.edu/pub/Linux/utils/dos. Explore2fs is a graphical
   explorer for ext2fs partitions which runs on Windows 95 and Windows
   NT and includes experimental write support; it is available from
   http://jnewbigin-pc.it.swin.edu.au/Linux/Explore2fs.htm.
@@ -6522,7 +6580,7 @@
   listen to audio CDs and watch its LEDs, say Y (and read
   Documentation/filesystems/isofs.txt and the CDROM-HOWTO, available
   via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO), thereby enlarging your
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO), thereby enlarging your
   kernel by about 27 kB; otherwise say N.
 
   If you want to compile this as a module ( = code which can be
@@ -6583,8 +6641,8 @@
   they are compressed; to access compressed MSDOS partitions under
   Linux, you can either use the DOS emulator DOSEMU, described in the
   DOSEMU-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO, or try dmsdosfs in
-  ftp://sunsite.unc.edu/pub/Linux/system/filesystems/dosfs. If you
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO, or try dmsdosfs in
+  ftp://metalab.unc.edu/pub/Linux/system/filesystems/dosfs. If you
   intend to use dosemu with a non-compressed MSDOS partition, say Y
   here) and MSDOS floppies. This means that file access becomes
   transparent, i.e. the MSDOS files look and behave just like all
@@ -6683,7 +6741,7 @@
   programs nfsd and mountd (but does not need to have NFS filesystem
   support enabled in its kernel). NFS is explained in the Network
   Administrator's Guide, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/LDP, on its man page: "man
+  ftp://metalab.unc.edu/pub/Linux/docs/LDP, on its man page: "man
   nfs", and in the NFS-HOWTO.
   
   A superior but less widely used alternative to NFS is provided by
@@ -6703,7 +6761,7 @@
   cannot compile this driver as a module in this case. There are two
   packages designed for booting diskless machines over the net:
   netboot and etherboot, both available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/system/boot/ethernet/ .
+  ftp://metalab.unc.edu/pub/Linux/system/boot/ethernet/ .
 
   If you don't know what all this is about, say N.
 
@@ -6731,7 +6789,7 @@
   You will need the support software from the linux-nfs package
   available at ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/.
   Please read the NFS-HOWTO, available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu:/pub/Linux/docs/HOWTO. 
+  ftp://metalab.unc.edu:/pub/Linux/docs/HOWTO. 
 
   The NFS server is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -6994,6 +7052,24 @@
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
+Unixware slices support (EXPERIMENTAL)
+CONFIG_UNIXWARE_DISKLABEL
+  Like some systems, Unixware uses, except DOS-like partition table,
+  its own slice table inside a partition (VTOC - Virtual Table of
+  Contents). Its format is incompatible with all other OSes. Saying Y
+  here allows you to read VTOC and further mount Unixware partitions
+  read-only from within Linux if you have also said Y to "UFS 
+  filesystem support" or "System V and Coherent filesystem support", 
+  above.
+
+  This is mainly used to carry data from a Unixware box to your
+  Linux box via a removable medium like magneto-optical, ZIP or
+  removable IDE drives. Note, however, that a good portable way to
+  transport files and directories between unixes (and even other
+  operating systems) is given by the tar program ("man tar" or
+  preferably "info tar"). If you don't know what all this is about,
+  say N.
+
 Macintosh partition map support
 CONFIG_MAC_PARTITION
   Say Y here if you want your Linux system to be able to read the
@@ -7011,13 +7087,13 @@
   transport protocol, and not NetBEUI. For details, read
   Documentation/filesystems/smbfs.txt and the SMB-HOWTO, available via
   FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   Note: if you just want your box to act as an SMB *server* and make
   files and printing services available to Windows clients (which need
   to have a TCP/IP stack), you don't need to say Y here; you can use
   the program samba (available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/system/network/samba) for that.
+  ftp://metalab.unc.edu/pub/Linux/system/network/samba) for that.
 
   General information about how to connect Linux, Windows machines and
   Macs is on the WWW at http://www.eats.com/linux_mac_win.html (to
@@ -7067,7 +7143,7 @@
   mount NetWare file server volumes and to access them just like any
   other Unix directory. For details, please read the file
   Documentation/filesystems/ncpfs.txt in the kernel source and the
-  IPX-HOWTO on ftp://sunsite.unc.edu:/pub/Linux/docs/howto.
+  IPX-HOWTO on ftp://metalab.unc.edu:/pub/Linux/docs/howto.
 
   You do not have to say Y here if you want your Linux box to act as a
   file *server* for Novell NetWare clients.
@@ -7489,7 +7565,7 @@
   loadlin) about how to pass options to the kernel at boot time. The
   lilo procedure is also explained in the SCSI-HOWTO, available via
   FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.)
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.)
 
   If unsure, say Y.
 
@@ -7553,7 +7629,7 @@
   your boot loader (lilo or loadlin) about how to pass options to the
   kernel at boot time. The lilo procedure is also explained in the
   SCSI-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.) 
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.) 
 
   If you don't have a VGA card installed and you say Y here, the
   kernel will automatically use the first serial line, /dev/ttyS0, as
@@ -7739,7 +7815,7 @@
   box (as opposed to using a serial printer; if the connector at the
   printer has 9 or 25 holes ["female"], then it's serial), say Y. Also
   read the Printing-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   It is possible to share one parallel port among several devices
   (e.g. printer and ZIP drive) and it is safe to compile the
@@ -7754,7 +7830,7 @@
   of your boot loader (lilo or loadlin) about how to pass options to
   the kernel at boot time. The lilo procedure is also explained in the
   SCSI-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.) The standard base
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.) The standard base
   addresses as well as the syntax of the "lp" command line option can
   be found in drivers/char/lp.c.
 
@@ -7774,7 +7850,7 @@
   Microsoft mouse (made by Logitech) that plugs into a COM port
   (rectangular with 9 or 25 pins). These people say N here. If you
   have something else, read the Busmouse-HOWTO, available via FTP
-  (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO and
+  (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO and
   say Y here.
 
   If you have a laptop, you either have to check the documentation or
@@ -7792,7 +7868,7 @@
   made by Logitech don't use the Logitech protocol anymore; for those,
   you don't need this option. You want to read the Busmouse-HOWTO,
   available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -7812,20 +7888,20 @@
 
   Although PS/2 mice are not technically bus mice, they are explained
   in detail in the Busmouse-HOWTO, available via FTP (user: anonymous)
-  in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. 
+  in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. 
 
   When using a PS/2 mouse, you can get problems if you want to use the
   mouse both on the Linux console and under X. Using the "-R" option
   of the Linux mouse managing program gpm (available from
-  ftp://sunsite.unc.edu:/pub/Linux/system/Daemons) solves this
-  problem, or you can get the "mconv" utility also from sunsite.
+  ftp://metalab.unc.edu:/pub/Linux/system/Daemons) solves this
+  problem, or you can get the "mconv" utility also from metalab.
 
 C&T 82C710 mouse port support (as on TI Travelmate)
 CONFIG_82C710_MOUSE
   This is a certain kind of PS/2 mouse used on the TI Travelmate. If
   you are unsure, try first to say N here and come back if the mouse
   doesn't work. Read the Busmouse-HOWTO, available via FTP (user:
-  anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
 PC110 digitizer pad support
 CONFIG_PC110_PAD
@@ -7845,7 +7921,7 @@
   These animals (also called Inport mice) are connected to an
   expansion board using a round connector with 9 pins. If this is what
   you have, say Y and read the Busmouse-HOWTO, available via FTP
-  (user: anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  (user: anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   If you are unsure, say N and read the HOWTO nevertheless: it will
   tell you what you have. Also be aware that several vendors talk
@@ -7862,7 +7938,7 @@
   This is a rare type of busmouse that is connected to the back of an
   ATI video card. Note that most ATI mice are actually Microsoft
   busmice. Read the Busmouse-HOWTO, available via FTP (user:
-  anonymous) in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  anonymous) in ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -8204,11 +8280,8 @@
   set the MTRRs for the boot CPU and not the secondary CPUs. This can
   lead to all sorts of problems.
 
-  In general you should compile this into the kernel, rather than as a
-  loadable module, because the BIOS fix needs to be done early in the
-  boot sequence. If you compile this as a module, the BIOS fix will be
-  delayed until when you load the module. You do this at your own
-  risk.
+  You can safely say Y even if your machine doesn't have MTRRs, you'll
+  just add about 3k to your kernel.
 
   See Documentation/mtrr.txt for more information.
 
@@ -8234,7 +8307,7 @@
 
   Supporting software is available; for more information, read the
   Battery Powered Linux mini-HOWTO, available via FTP (user:
-  anonymous) from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini.
+  anonymous) from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini.
 
   This driver does not spin down disk drives (see the hdparm(8)
   manpage ("man 8 hdparm") for that), and it doesn't turn off
@@ -8328,7 +8401,7 @@
   is halted. You will need software (e.g., a suitable version of the
   halt(8) command ("man 8 halt")) to cause the computer to power down.
   Recent versions of the sysvinit package available from
-  ftp://sunsite.unc.edu/pub/Linux/system/daemons/init/ (user:
+  ftp://metalab.unc.edu/pub/Linux/system/daemons/init/ (user:
   anonymous) contain support for this ("halt -p" shuts down Linux and
   powers off the computer, if executed from runlevel 0). As with the
   other APM options, this option may not work reliably with some APM
@@ -8461,13 +8534,8 @@
   24 hour alarm. It reports status information via the file /proc/rtc
   and its behaviour is set by various ioctls on /dev/rtc.
 
-  People running SMP (multiprocessor) versions of Linux should say Y
-  here to read and set the RTC clock in a SMP compatible
-  fashion. (They should also read Documentation/smp and
-  Documentation/IO-APIC.txt and the SMP-FAQ on the WWW at
-  http://www.irisa.fr/prive/mentre/smp-faq/ (to browse the WWW, you
-  need to have access to a machine on the Internet that has a program
-  like lynx or netscape).)
+  If you enabled CONFIG_SMP, you should say Y here to read and set the
+  RTC clock in an SMP compatible fashion.
 
   If you think you have a use for such a device (such as periodic data
   sampling), then say Y here, and read Documentation/rtc.txt for
@@ -8491,7 +8559,11 @@
   and "NVRAM" on Ataris. /dev/nvram may be used to view settings
   there, or to change them (with some utility). It could also be used
   to frequently save a few bits of very important data that may not be
-  lost over power-off and for which writing to disk is too insecure.
+  lost over power-off and for which writing to disk is too insecure. Note
+  however that most NVRAM space in a PC belongs to the BIOS and you should
+  NEVER idly tamper with it. See Ralf Browns interrupt list for a guide to 
+  the use of CMOS bytes by your BIOS.
+
   On Atari machines, /dev/nvram is always configured and does not need
   to be selected.
 
@@ -8610,7 +8682,7 @@
   about your sound card and its configuration down (I/O port,
   interrupt and DMA channel), because you will be asked for it. You
   want to read the Sound-HOWTO, available via FTP (user: anonymous)
-  from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. There is also some
+  from ftp://metalab.unc.edu/pub/Linux/docs/HOWTO. There is also some
   information in various README files in drivers/sound, esp. in
   Readme.cards which you should read first to find out whether your
   card is supported by Linux, and, if yes, which driver to use.
@@ -8645,6 +8717,14 @@
   cards from Aztech. It supports the Waverider Pro 32 - 3D and the
   Galaxy Washington 16.
 
+Support for AD1816(A) based cards (EXPERIMENTAL)
+CONFIG_SOUND_AD1816
+  Say M here if you have a soundcard based on the Analog Devices 
+  AD1816(A) chip.
+
+  NOTE: This driver is still EXPERIMENTAL. 
+        See Documentation/sound/AD1816 for further information.
+
 Yamaha OPL3-SA1 audio controller
 CONFIG_SOUND_OPL3SA1
   Say Y or M if you have a Yamaha OPL3-SA1 sound chip, which is
@@ -8852,9 +8932,11 @@
   See Documentation/sound/CS4232 for more information on configuring
   this card.
 
-Support for Yamaha OPL3-SA[2,3,x] based (PnP) cards
+Support for Yamaha OPL3-SA2, SA3, and SAx based PnP cards
 CONFIG_SOUND_OPL3SA2
-  Say Y or M here if you have such a sound card.
+  Say Y or M if you have a card based on one of these Yamaha
+  sound chipsets. Read Documentation/sound/OPL3-SA2 for more
+  information on configuring these cards.
 
 Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers
 CONFIG_SOUND_MAUI
@@ -8975,16 +9057,16 @@
   affect the kernel; saying Y will simply cause this configure script
   to present you with more options. If unsure, say Y.
 
-ACI mixer (miroPCM12)
+ACI mixer (miroPCM12/PCM20)
 CONFIG_ACI_MIXER
   Audio Command Interface (ACI) driver. ACI is a protocol used to
   communicate with the microcontroller on some sound cards produced by
   miro, e.g. the miroSOUND PCM12 and PCM20. The main function of the
   ACI is to control the mixer and to get a product identification.
   This Voxware ACI driver currently only supports the ACI functions on
-  the miroSOUND PCM12 card. On the PCM20, ACI also controls the radio
-  tuner on this card, however this is not yet supported in this
-  software.
+  the miroSOUND PCM12 and PCM20 cards. On the PCM20, ACI also controls
+  the radio tuner. This is supported in the video4linux radio-miropcm20
+  driver.
 
 SB32/AWE support
 CONFIG_AWE32_SYNTH
@@ -8992,7 +9074,7 @@
   similar sound card. See drivers/sound/lowlevel/README.awe,
   Documentation/sound/AWE32 and the Soundblaster-AWE mini-HOWTO,
   available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/mini for more info.
+  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO/mini for more info.
 
 Gallant's Audio Excel DSP 16 support (SC-6000 and SC-6600)
 CONFIG_AEDSP16
@@ -9013,17 +9095,11 @@
   Documentation/sound/AudioExcelDSP16 to get more information about
   this driver and its configuration.
 
-SC-6600 based audio cards (new Audio Excel DSP 16)
-CONFIG_SC6600
-  The SC6600 is the new version of DSP mounted on the Audio Excel DSP
-  16 cards. Find in the manual the FCC ID of your audio card and
-  answer Y if you have an SC6600 DSP.
-
-Audio Excel DSP 16 (MSS emulation)
-CONFIG_AEDSP16_MSS
-  Answer Y if you want your audio card to emulate Microsoft Sound
-  System. You should then say Y to "Microsoft Sound System support"
-  and say N to "Audio Excel DSP 16 (SBPro emulation)".
+I/O base for Audio Excel DSP 16
+CONFIG_AEDSP16_BASE
+  This is the base I/O address of the Audio Excel DSP 16 card. It must
+  be 220 or 240. If you compiled aedsp16.o as a module you can specify
+  this parameter as 'io=0xNNN'.
 
 Audio Excel DSP 16 (SBPro emulation)
 CONFIG_AEDSP16_SBPRO
@@ -9032,6 +9108,68 @@
   (SB16/32/64, ESS, Jazz16) support" and N to "Audio Excel DSP 16 (MSS
   emulation)".
 
+Audio Excel DSP 16 IRQ
+CONFIG_AEDSP16_SB_IRQ
+  This is the IRQ of the Audio Excel DSP 16 card. It must be 5, 7, 9,
+  10 or 11. If you compiled aedsp16.o as a module you can specify
+  this parameter as 'irq=NN'.
+
+Audio Excel DSP 16 DMA
+CONFIG_AEDSP16_SB_DMA
+  This is the IRQ of the Audio Excel DSP 16 card. It must be 0, 1 or 3.
+  If you compiled aedsp16.o as a module you can specify this parameter
+  as 'dma=NN'.
+
+Audio Excel DSP 16 (MSS emulation)
+CONFIG_AEDSP16_MSS
+  Answer Y if you want your audio card to emulate Microsoft Sound
+  System. You should then say Y to "Microsoft Sound System support"
+  and say N to "Audio Excel DSP 16 (SBPro emulation)".
+
+Audio Excel DSP 16 IRQ
+CONFIG_AEDSP16_MSS_IRQ
+  This is the IRQ of the Audio Excel DSP 16 card. It must be 5, 7, 9,
+  10 or 11. If you compiled aedsp16.o as a module you can specify
+  this parameter as 'irq=NN'.
+
+Audio Excel DSP 16 DMA
+CONFIG_AEDSP16_MSS_DMA
+  This is the IRQ of the Audio Excel DSP 16 card. It must be 0, 1 or 3.
+  If you compiled aedsp16.o as a module you can specify this parameter
+  as 'dma=NN'.
+
+SC-6600 based audio cards (new Audio Excel DSP 16)
+CONFIG_SC6600
+  The SC6600 is the new version of DSP mounted on the Audio Excel DSP
+  16 cards. Find in the manual the FCC ID of your audio card and
+  answer Y if you have an SC6600 DSP.
+
+SC-6600 Joystick Interface
+CONFIG_SC6600_JOY
+  This option activate the Joystick interface of Audio Excel DSP 16 card.
+
+SC-6600 CDROM Interface
+CONFIG_SC6600_CDROM
+  This option activate the CDROM interface of Audio Excel DSP 16 card.
+  Required parameter can be: 0 for Sony, 1 for Panasonic, 2 for IDE, 4 for
+  no CDROM present.
+
+Audio Excel DSP 16 (MPU401 emulation)
+CONFIG_AEDSP16_MPU401
+  Answer Y if you want your audio card to emulate the MPU-401 midi
+  interface. You should then say Y to "MPU-401 support".
+  You have to hote that the I/O base for MPU-401 support of aedsp16 is
+  the same you have selected for "MPU-401 support". If you are using
+  this driver as a module you have to specify the MPU I/O base address
+  with the parameter 'mpu_base=0xNNN'.
+
+MPU401 IRQ for Audio Excel DSP 16
+CONFIG_AEDSP16_MPU_IRQ
+  This is the IRQ of the MPU-401 emulation of Audio Excel DSP 16 card.
+  It must be 5, 7, 9, 10 or 0 (to disable MPU-401 interface). If you
+  compiled aedsp16.o as a module you can specify this parameter as
+  'mpu_irq=NN'.
+
 Ensoniq ES1370 based PCI sound cards
 CONFIG_SOUND_ES1370
   Say Y or M if you have a PCI sound card utilizing the Ensoniq
@@ -9057,6 +9195,15 @@
   models are either ES1370 or ES1371 based. This driver differs
   slightly from OSS/Free, so PLEASE READ Documentation/sound/es1371.
 
+Gameport I/O-range selection
+CONFIG_SOUND_ES1371_GAMEPORT
+  Select the I/O-range of the gameport on a ES1371 based soundcard.
+  The card uses 8 ioports and the gameport is available at all eight
+  ioports. Legal hexadecimal values are 200, 208, 210 and 218.
+  The joystick driver will by default use 0x201. 
+  Leave the default 200 unless you have a joystick not attached
+  to your soundcard.
+
 S3 SonicVibes based PCI sound cards
 CONFIG_SOUND_SONICVIBES
   Say Y or M if you have a PCI sound card utilizing the S3
@@ -9489,6 +9636,13 @@
   Say N unless you're willing to code the remaining necessary support.
   ;)
 
+HP9000/300 support
+CONFIG_HP300
+  This option enables support for the HP9000/300 series of workstations.
+  Support for these machines is still very experimental.  If you plan to
+  try to use the kernel on such a machine say Y here.  Everybody else
+  says N.
+
 # CONFIG_APOLLO, etc. coming soon (?)
 
 68020 support
@@ -9932,6 +10086,21 @@
   want). If you want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
+HP DCA serial support
+CONFIG_HPDCA
+  If you want to use the internal "DCA" serial ports on an HP300
+  machine, say Y here.
+
+HP on-board LANCE support
+CONFIG_HPLANCE
+  If you want to use the builtin "LANCE" Ethernet controller on an HP300
+  machine, say Y here.
+
+DIO bus support
+CONFIG_DIO
+  Say Y here to enable support for the "DIO" expansion bus used in HP300
+  machines. If you are using such a system you almost certainly want this.
+
 MSDOS partition support
 CONFIG_MSDOS_PARTITION
   This option enables support for using hard disks that were
@@ -10139,8 +10308,9 @@
 
 Miro PCM20 Radio
 CONFIG_RADIO_MIROPCM20
-  Choose Y here if you have one of these FM radio cards, and then fill
-  in the port address below.
+  Choose Y here if you have this FM radio card. You also need the
+  PCM12/PCM20 ACI mixer in additional low level sound drivers for this
+  to work.
 
   In order to control your radio card, you will need to use programs
   that are compatible with the Video for Linux API. Information on 
@@ -10154,6 +10324,28 @@
   say M here and read Documentation/modules.txt. The module will be
   called radio-miropcm20.o
 
+GemTek Radio Card
+CONFIG_RADIO_GEMTEK
+  Choose Y here if you have this FM radio card, and then fill in the 
+  port address below.
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video for Linux API. Information on 
+  this API and pointers to "v4l" programs may be found on the WWW at
+  http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW,
+  you need to have access to a machine on the Internet that has a 
+  program like lynx or netscape.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called radio-gemtek.o.
+
+GemTek i/o port
+CONFIG_RADIO_GEMTEK_PORT
+  Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is
+  0x34c, if you haven't changed the jumper setting on the card.
+
 BT848 Video For Linux
 CONFIG_VIDEO_BT848
   Support for BT848 based frame grabber/overlay boards. This includes
@@ -10216,6 +10408,19 @@
   to set this option to, please consult any information supplied with
   your system.
 
+Include support for CATS boards
+CONFIG_CATS
+  Say Y here if you wish to include support for the extra hardware found
+  in Chalice CATS machines. The resulting kernel will still run on an 
+  EBSA-285 but will be slightly larger. If in doubt say N.
+
+Debug kernel errors
+CONFIG_DEBUG_ERRORS
+  This option controls verbose debugging information which can be printed
+  when the kernel detects an internal error.  Verbose debugging information
+  is useful when tracking down kernel problems, but it will be meaning less
+  for non-kernel hackers.  It's safe for everyone to say Y.
+
 Build Tools Selection
 CONFIG_BINUTILS_NEW
   Say Y here if and only if you're using GCC 2.8.1/EGCS with a
@@ -10228,6 +10433,261 @@
   it will give useful debugging/error results. If you don't debug the
   kernel, you can say N.
 
+Initial kernel command line
+CONFIG_CMDLINE
+  On some architectures (EBSA285, EBSA110 and Corel Netwinder), there is
+  currently no way for the boot loader to pass arguments to the kernel.
+  For these architectures, you should supply some command-line options
+  at build time by entering them here.  As a minimum, you should specify
+  the memory size and the root device (eg, mem=64M root=/dev/nfs)
+
+IrDA Protocols
+CONFIG_IRDA
+  Say Y here if you want to build support for the IrDA (TM)
+  protocols. The Infrared Data Associations (tm) specifies standards
+  for wireless infrared communication and is supported by most laptops
+  and PDA's If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
+
+  To use Linux support for the IrDA (tm) protocols, you will also need
+  some user-space utilities like the irmanager and probably irattach
+  as well. For more information, visit
+  http://www.cs.uit.no/~dagb/irda/
+
+IrDA Cache last LSAP
+CONFIG_IRDA_CACHE_LAST_LSAP
+  Say Y here if you want IrLMP to cache the last LSAP used. This makes
+  sense since most frames will be sent/received on the same connection.
+  Enabling this option will save a hash-lookup per frame.
+
+  If unsure, say Y.
+
+IrDA Fast RR's
+CONFIG_IRDA_FAST_RR
+  Say Y here is you want IrLAP to send fast RR (Receive Ready) frames
+  when acting as a primary station. This will make IrLAP send out a RR
+  frame immediately when receiving a frame if its own transmit queue is
+  currently empty. This will give a lot of speed improvement when
+  receiving much data since the secondary station will not have to
+  wait the max. turn around time before it is allowed to transmit the
+  next time. If the transmit queue of the secondary is also empty the
+  primary will back off waiting longer for sending out the RR frame
+  until the timeout reaches the normal value. Enabling this option
+  will make the IR-diode burn more power and thus reduce your battery
+  life.
+
+  If unsure, say N.
+
+IrDA Recycle RR's
+CONFIG_IRDA_RECYCLE_RR
+  In the normal life of the IrLAP protocol, it sends a lot of small RR
+  (Receive Ready) frames over the link (at least when it has nothing
+  else to do). Saying Y to this option will make IrLAP recycle these
+  frames thus avoiding many alloc_skb's and kfree_skb's. To do this it
+  will only buffer one of these frame which is enough for the normal
+  case.
+
+  If unsure, say Y.
+
+IrLAP Compression support
+CONFIG_IRDA_COMPRESSION
+  Compression is _not_ part of the IrDA(tm) protocol specification,
+  but its working great! Linux is the first to try out compresson
+  support at the IrLAP layer. This means that you will only benefit
+  from compression if you are running a Linux <-> Linux configuration
+
+IrLAP Deflate Compression Protocol
+CONFIG_IRDA_DEFLATE
+  Say Y here if you want to build support for the Deflate compression
+  protocol. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. The deflate compression (GZIP) is exactly
+  the same as used by the PPP protocol. Enabling this option will
+  build a module called irda_deflate.o
+
+IrLAN Protocol 
+CONFIG_IRLAN
+  Say Y here if you want to build support for the IrLAN protocol. If
+  you want to compile it as a module, say M here and read
+  Documentation/modules.txt. IrLAN emulates an Ethernet and makes it
+  possible to put up an wireless LAN using infrared beams.
+
+IrLAN Client Protocol 
+CONFIG_IRLAN_CLIENT
+  Say Y here if you want to build support for the IrLAN client
+  protocol. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt. The IrLAN client protocol can be used to
+  talk with infrared access points like the HP NetbeamIR, or the ESI
+  JetEye NET. You can also connect to another Linux machine running
+  the IrLAN server protocol for ac-hoc networking!
+
+IrLAN Server Protocol 
+CONFIG_IRLAN_SERVER
+  Say Y here if you want to build support for infrared LAN access. If
+  you want to compile it as a module, say M here and read
+  Documentation/modules.txt. The IrLAN server protocol makes it
+  possible to set up a wireless LAN with a machine running the IrLAN
+  client protocol. Notice that the IrLAN server protocol currently
+  only emulates an access point and does not implement the ad-hoc
+  specification of IrLAN, but this will not be noticeable for the
+  user.
+
+IrOBEX Protocol
+CONFIG_IROBEX
+  Say Y here if you want to build support for the IrOBEX protocol. If
+  you want to compile it as a module, say M here and read
+  Documentation/modules.txt. The module does not actually implement
+  the IrOBEX protocol since that protocol lives in userspace, but it 
+  contains the necessary functions to interface the user-space stuff
+  with the kernel. So you will need to have the user-space library and
+  programs that can use this library installed as well to be able to
+  use the IrOBEX protocol. This module will hopefully be replaced by
+  IrDA sockets in the future.
+
+IrCOMM Protocol
+CONFIG_IRCOMM
+  Say Y here if you want to build support for the IrCOMM protocol. If
+  you want to compile it as a module, say M here and read
+  Documentation/modules.txt. IrCOMM implements serial port emulation,
+  and makes it possible to use all existing applications that
+  understands TTY's with an infrared link. Thus you should be able to
+  use application like PPP, minicom and others. Enabling this option
+  will create two modules called ircomm and ircomm_tty. For more
+  information go to http://www.pluto.dti.ne.jp/~thiguchi/irda/
+
+IrTTY IrDA Device Driver
+CONFIG_IRTTY_SIR
+  Say Y here if you want to build support for the IrTTY line
+  discipline. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt. IrTTY makes it possible to use
+  Linux's own serial driver for all IrDA ports that are 16550
+  compatible. Most IrDA chips are 16550 compatible so you should
+  probably say Y to this option. Using IrTTY will however limit the
+  speed of the connection to 115200 bps (IrDA SIR mode)
+
+  If unsure, say Y.
+
+Winbond W83977AF IrDA Device Driver
+CONFIG_WINBOND_FIR
+  Say Y here if you want to build IrDA support for the Winbond W83977AF
+  super-io chipset. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt. This driver should be used for
+  the IrDA chipset in the Corel NetWinder. The driver supports SIR,
+  MIR and FIR (4Mbps) speeds.
+
+NSC PC87108 IrDA Device Driver
+CONFIG_NSC_FIR
+  Say Y here if you want to build support for the NSC PC87108 IrDA
+  chipset. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt. This drivers currently only supports
+  the ACTiSYS IR2000B ISA card and supports SIR, MIR and FIR (4Mbps)
+  speeds.
+
+ESI JetEye PC Dongle
+CONFIG_ESI_DONGLE
+  Say Y here if you want to build support for the Extended Systems
+  JetEye PC dongle. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt. The ESI dongle attaches to the
+  normal 9-pin serial port connector, and can currently only be used
+  by IrTTY. To activate support for ESI dongles you will have to
+  insert "irattach -d esi" in the /etc/irda/drivers script.
+
+ACTiSYS IR-220L and IR220L+ dongle
+CONFIG_ACTISYS_DONGLE
+  Say Y here if you want to build support for the ACTiSYS
+  IR-220L and IR220L+ dongles. If you want to compile it as a module,
+  say M here and read Documentation/modules.txt. The ACTiSYS dongles
+  attaches to the normal 9-pin serial port connector, and can
+  currently only be used by IrTTY. To activate support for ACTiSYS
+  dongles you will have to insert "irattach -d actisys" or
+  "irattach -d actisys_plus" in the/etc/irda/drivers script.
+
+Tekram IrMate 210B dongle
+CONFIG_TEKRAM_DONGLE
+  Say Y here if you want to build support for the Tekram IrMate 210B 
+  dongle. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt. The Tekram dongle attaches to
+  the normal 9-pin serial port connector, and can currently only be
+  used by IrTTY. To activate support for Tekram dongles you will have
+  to insert "irattach -d tekram" in the /etc/irda/drivers script.
+
+VME (Motorola and BVM) support
+CONFIG_VME
+  Say Y here if you want to build a kernel for a 680x0 based VME
+  board.  Boards currently supported include Motorola boards MVME162,
+  MVME166, MVME167, MVME172, and MVME177.  BVME4000 and BVME6000
+  boards from BVM Ltd are also supported.
+
+MVME162, 166 and 167 support
+CONFIG_MVME16x
+  Say Y to include support for Motorola VME boards.  This will build a
+  kernel which can run on MVME162, MVME166, MVME167, MVME172, and
+  MVME177 boards.  If you select this option you will have to select
+  the appropriate drivers for SCSI, Ethernet and serial ports later
+  on.
+
+BVME4000 and BVME6000 support
+CONFIG_BVME6000
+  Say Y to include support for VME boards from BVM Ltd.  This will
+  build a kernel which can run on BVME4000 and BVME6000 boards.  If
+  you select this option you will have to select the appropriate
+  drivers for SCSI, Ethernet and serial ports later on.
+
+Use write-through caching for 68060 supervisor accesses
+CONFIG_060_WRITETHROUGH
+  The 68060 generally uses copyback caching of recently accessed data.
+  Copyback caching means that memory writes will be held in an on-chip
+  cache and only written back to memory some time later.  Saying Y
+  here will force supervisor (kernel) accesses to use writethrough
+  caching.  Writethrough caching means that data is written to memory
+  straight away, so that cache and memory data always agree.
+  Writethrough caching is less efficient, but is needed for some
+  drivers on 68060 based systems where the 68060 bus snooping signal
+  is hardwired on.  The 53c710 SCSI driver is known to suffer from
+  this problem.
+
+NCR53C710 SCSI driver for MVME16x
+CONFIG_MVME16x_SCSI
+  The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710
+  SCSI controller chip.  Almost everyone using one of these boards
+  will want to say Y to this question.
+
+NCR53C710 SCSI driver for BVME6000
+CONFIG_BVME6000_SCSI
+  The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710
+  SCSI controller chip.  Almost everyone using one of these boards
+  will want to say Y to this question.
+
+MVME16x Ethernet support
+CONFIG_MVME16x_NET
+  This is the driver for the Ethernet interface on the Motorola
+  MVME162, 166, 167, 172 and 177 boards.  Say Y here to include the
+  driver for this chip in your kernel.   If you want to compile it as
+  a module, say M here and read Documentation/modules.txt.
+
+BVME6000 Ethernet support
+CONFIG_BVME6000_NET
+  This is the driver for the Ethernet interface on BVME4000 and
+  BVME6000 VME boards.  Say Y here to include the driver for this chip
+  in your kernel.   If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.
+
+CD2401 support for MVME166/7 serial ports
+CONFIG_SERIAL167
+  This is the driver for the serial ports on the Motorola MVME166,
+  167, and 172 boards.  Everyone using one of these boards should say
+  Y here.
+
+SCC support for MVME162 serial ports
+CONFIG_MVME162_SCC
+  This is the driver for the serial ports on the Motorola MVME162 and
+  172 boards.  Everyone using one of these boards should say Y here.
+
+SCC support for BVME6000 serial ports
+CONFIG_BVME6000_SCC
+  This is the driver for the serial ports on the BVME4000 and BVME6000
+  boards from BVM Ltd.  Everyone using one of these boards should say
+  Y here.
+
 #
 # A couple of things I keep forgetting:
 #   capitalize: AppleTalk, Ethernet, DMA, FTP, Internet, Intel, IRQ, 
@@ -10237,7 +10697,7 @@
 #
 # This is used by Emacs' spell checker ispell.el:
 #
-# LocalWords:  CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp sunsite
+# LocalWords:  CONFIG coprocessor DX Pentium SX lilo loadlin HOWTO ftp metalab
 # LocalWords:  unc edu docs emu README kB BLK DEV FD Thinkpad fd MFM RLL IDE gz
 # LocalWords:  cdrom diskless netboot nfs xzvf ATAPI MB ide pavia rubini pl pd
 # LocalWords:  HD CDROMs IDECD NEC MITSUMI filesystem XT XD PCI BIOS cezar ATEN
diff -u --recursive --new-file v2.1.132/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.132/linux/MAINTAINERS	Thu Nov 19 09:56:27 1998
+++ linux/MAINTAINERS	Sun Dec 27 10:26:11 1998
@@ -94,9 +94,12 @@
 S:	Maintained
 W:	http://rsphy1.anu.edu.au/~gpg109/ne2000.html
 
-AEDSP16 DRIVER
-P:	Riccardo Facchetti
-M:	fizban@tin.it
+AD1816 SOUND DRIVER
+P:	Thorsten Knabe
+M:	Thorsten Knabe <tek@rbg.informatik.tu-darmstadt.de>
+M:	Thorsten Knabe <tek01@hrzpub.tu-darmstadt.de>
+W:	http://www.student.informatik.tu-darmstadt.de/~tek/projects/linux.html
+W:	http://www.tu-darmstadt.de/~tek01/projects/linux.html
 S:	Maintained
 
 ADVANSYS SCSI DRIVER
@@ -105,6 +108,11 @@
 W:	http://www.advansys.com/linux
 S:	Maintained
 
+AEDSP16 DRIVER
+P:	Riccardo Facchetti
+M:	fizban@tin.it
+S:	Maintained
+
 AHA152X SCSI DRIVER
 P:	Juergen E. Fischer
 M:	Juergen Fischer <fischer@et-inf.fho-emden.de>
@@ -167,14 +175,26 @@
 M:	boldt@math.ucsb.edu
 S:	Maintained
 
+COSA/SRP SYNC SERIAL DRIVER
+P:	Jan "Yenya" Kasprzak
+M:	kas@fi.muni.cz
+W:	http://www.fi.muni.cz/~kas/cosa/
+S:	Maintained
+
+COSA/SRP SYNC SERIAL DRIVER
+P:	Jan "Yenya" Kasprzak
+M:	kas@fi.muni.cz
+W:	http://www.fi.muni.cz/~kas/cosa/
+S:	Maintained
+
 CREDITS FILE
 P:	John A. Martin
 M:	jam@acm.org
 S:	Maintained
 
 CYCLADES ASYNC MUX DRIVER
-P:	Marcio Saito
-M:	Marcio Saito <marcio@cyclades.com>
+P:	Ivan Passos
+M:	Ivan Passos <ivan@cyclades.com>
 W:	http://www.cyclades.com/
 S:	Supported
 
@@ -188,13 +208,15 @@
 
 DC390/AM53C974 SCSI driver
 P:	Kurt Garloff
-M:	K.Garloff@ping.de
-W:	ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/
+M:	kurt@garloff.de
+W:	http://www.garloff.de/kurt/linux/dc390/
 S:	Maintained
 
 DECnet NETWORK LAYER
 P:	Steven Whitehouse
 M:	SteveW@ACM.org
+W:	http://www.sucs.swan.ac.uk/~rohan/
+W:	http://www-sigproc.eng.cam.ac.uk/~sjw44/
 L:	netdev@roxanne.nuclecu.unam.mx
 S:	Maintained
 
@@ -350,7 +372,7 @@
 IP FIREWALL
 P:	Paul Russell
 M:	Paul.Russell@rustcorp.com.au
-W:	http://www.adelaide.net.au/~rustcorp/ipfwchains/ipfwchains.html
+W:	http://www.rustcorp.com/linux/ipchains
 S:	Supported
 
 IPX/SPX NETWORK LAYER
@@ -359,6 +381,13 @@
 L:	linux-net@vger.rutgers.edu
 S:	Maintained
 
+IRDA SUBSYSTEM
+P:      Dag Brattli
+M:      Dag Brattli <dagb@cs.uit.no>
+L:      linux-irda@list.uit.no
+W:      http://www.cs.uit.no/~dagb/irda/
+S:      Maintained
+
 ISDN SUBSYSTEM
 P:	Fritz Elfert
 M:	fritz@wuemaus.franken.de
@@ -448,6 +477,13 @@
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
+MTRR AND SIMILAR SUPPORT [i386]
+P:	Richard Gooch
+M:	rgooch@atnf.csiro.au
+L:	linux-kernel@vger.rutgers.edu
+W:	http://www.atnf.csiro.au/~rgooch/linux/kernel-patches.html
+S:	Maintained
+
 MULTISOUND SOUND DRIVER
 P:	Andrew Veliath
 M:	andrewtv@usa.net
@@ -457,7 +493,7 @@
 P:	Petr Vandrovec
 M:	vandrove@vc.cvut.cz
 P:	Volker Lendecke
-M:	lendecke@Math.Uni-Goettingen.de
+M:	vl@kki.org
 L:	linware@sh.cvut.cz
 S:	Maintained
 
@@ -502,6 +538,12 @@
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
+OPL3-SA2, SA3, and SAx DRIVER
+P:	Scott Murray
+M:	scottm@interlog.com
+L:	linux-sound@vger.rutgers.edu
+S:	Maintained
+
 PARALLEL PORT SUPPORT
 P:	Phil Blundell
 M:	Philip.Blundell@pobox.com
@@ -596,7 +638,7 @@
 
 SMB FILESYSTEM
 P:	Volker Lendecke
-M:	lendecke@Math.Uni-Goettingen.de
+M:	vl@kki.org
 L:	samba@listproc.anu.edu.au
 S:	Maintained
 
diff -u --recursive --new-file v2.1.132/linux/Makefile linux/Makefile
--- v2.1.132/linux/Makefile	Tue Dec 22 14:16:53 1998
+++ linux/Makefile	Mon Dec 28 14:09:00 1998
@@ -1,6 +1,7 @@
 VERSION = 2
-PATCHLEVEL = 1
-SUBLEVEL = 132
+PATCHLEVEL = 2
+SUBLEVEL = 0
+EXTRAVERSION =-pre1
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
@@ -58,6 +59,8 @@
 
 ROOT_DEV = CURRENT
 
+KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+
 #
 # INSTALL_PATH specifies where to place the updated kernel and system map
 # images.  Uncomment if you want to place them anywhere other than root.
@@ -278,7 +281,7 @@
 	@mv -f .ver $@
 
 include/linux/version.h: ./Makefile
-	@echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)\" > .ver
+	@echo \#define UTS_RELEASE \"$(KERNELRELEASE)\" > .ver
 	@echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)` >> .ver
 	@echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))' >>.ver
 	@mv -f .ver $@
@@ -305,7 +308,7 @@
 
 modules_install:
 	@( \
-	MODLIB=$(INSTALL_MOD_PATH)/lib/modules/$(VERSION).$(PATCHLEVEL).$(SUBLEVEL); \
+	MODLIB=$(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE); \
 	cd modules; \
 	MODULES=""; \
 	inst_mod() { These="`cat $$1`"; MODULES="$$MODULES $$These"; \
diff -u --recursive --new-file v2.1.132/linux/arch/alpha/defconfig linux/arch/alpha/defconfig
--- v2.1.132/linux/arch/alpha/defconfig	Sun Nov  8 14:02:41 1998
+++ linux/arch/alpha/defconfig	Wed Dec 23 07:34:11 1998
@@ -42,6 +42,7 @@
 # CONFIG_ALPHA_SX164 is not set
 # CONFIG_ALPHA_SABLE is not set
 # CONFIG_ALPHA_TAKARA is not set
+# CONFIG_SMP is not set
 CONFIG_PCI=y
 CONFIG_ALPHA_NEED_ROUNDING_EMULATION=y
 # CONFIG_PCI_QUIRKS is not set
diff -u --recursive --new-file v2.1.132/linux/arch/alpha/kernel/irq.c linux/arch/alpha/kernel/irq.c
--- v2.1.132/linux/arch/alpha/kernel/irq.c	Tue Dec 22 14:16:53 1998
+++ linux/arch/alpha/kernel/irq.c	Sun Dec 27 15:21:50 1998
@@ -38,13 +38,6 @@
 unsigned int local_bh_count[NR_CPUS];
 unsigned long hardirq_no[NR_CPUS];
 
-#define RTC_IRQ    8
-#ifdef CONFIG_RTC
-#define TIMER_IRQ  0        /* timer is the pit */
-#else
-#define TIMER_IRQ  RTC_IRQ  /* the timer is, in fact, the rtc */
-#endif
-
 #if NR_IRQS > 64
 #  error Unable to handle more than 64 irq levels.
 #endif
@@ -824,7 +817,7 @@
 	 * Wait about 100ms for spurious interrupts to mask themselves
 	 * out again...
 	 */
-	for (delay = jiffies + HZ/10; delay > jiffies; )
+	for (delay = jiffies + HZ/10; time_before(jiffies, delay); )
 		barrier();
 
 	/* Now filter out any obviously spurious interrupts.  */
diff -u --recursive --new-file v2.1.132/linux/arch/alpha/kernel/irq.h linux/arch/alpha/kernel/irq.h
--- v2.1.132/linux/arch/alpha/kernel/irq.h	Fri Oct 23 22:01:19 1998
+++ linux/arch/alpha/kernel/irq.h	Sun Dec 27 15:21:50 1998
@@ -21,3 +21,11 @@
 extern void srm_device_interrupt(unsigned long vector, struct pt_regs * regs);
 
 extern void handle_irq(int irq, int ack, struct pt_regs * regs);
+
+#define RTC_IRQ    8
+#ifdef CONFIG_RTC
+#define TIMER_IRQ  0			 /* timer is the pit */
+#else
+#define TIMER_IRQ  RTC_IRQ		 /* timer is the rtc */
+#endif
+
diff -u --recursive --new-file v2.1.132/linux/arch/alpha/kernel/sys_ruffian.c linux/arch/alpha/kernel/sys_ruffian.c
--- v2.1.132/linux/arch/alpha/kernel/sys_ruffian.c	Fri Nov 27 13:09:22 1998
+++ linux/arch/alpha/kernel/sys_ruffian.c	Sun Dec 27 15:21:50 1998
@@ -92,6 +92,12 @@
 		i = ffz(~pld);
 		pld &= pld - 1; /* clear least bit set */
 		if (i == 7) { /* if ISA int */
+			/* Ruffian does not have the RTC connected to 
+			   the CPU timer interrupt.  Instead, it uses the
+			   PIT connected to IRQ 0.  So we must detect that
+			   and route that specifically to where we expected
+			   to find the timer interrupt come in.  */
+
 			/* Copy this code from isa_device_interrupt because
 			   we need to hook into int 0 for the timer.  I
 			   refuse to soil device_interrupt with ifdefs.  */
@@ -107,7 +113,7 @@
 			if (j == 7 && !(inb(0x20) & 0x80)) {
 				/* It's only a passive release... */
 			} else if (j == 0) {
-			  	handle_irq(8, -1, regs); /* fake it */
+			  	handle_irq(TIMER_IRQ, -1, regs);
 				ruffian_ack_irq(0);
 			} else {
 				handle_irq(j, j, regs);
diff -u --recursive --new-file v2.1.132/linux/arch/alpha/kernel/time.c linux/arch/alpha/kernel/time.c
--- v2.1.132/linux/arch/alpha/kernel/time.c	Wed Dec 16 10:32:54 1998
+++ linux/arch/alpha/kernel/time.c	Sun Dec 27 15:21:50 1998
@@ -35,12 +35,7 @@
 #include <linux/timex.h>
 
 #include "proto.h"
-
-#ifdef CONFIG_RTC 
-#define TIMER_IRQ 0  /* using pit for timer */
-#else 
-#define TIMER_IRQ 8  /* using rtc for timer */
-#endif
+#include "irq.h"
 
 static int set_rtc_mmss(unsigned long);
 
diff -u --recursive --new-file v2.1.132/linux/arch/arm/kernel/ecard.c linux/arch/arm/kernel/ecard.c
--- v2.1.132/linux/arch/arm/kernel/ecard.c	Tue Dec 22 14:16:53 1998
+++ linux/arch/arm/kernel/ecard.c	Mon Dec 28 11:04:21 1998
@@ -215,7 +215,7 @@
 		} else
 			lockup = 0;
 
-		if (!last || last + 500 < jiffies) {
+		if (!last || time_after(jiffies, last + 5*HZ)) {
 			last = jiffies;
 			printk(KERN_ERR "\nUnrecognised interrupt from backplane\n");
 		}
diff -u --recursive --new-file v2.1.132/linux/arch/arm/kernel/hw-ebsa285.c linux/arch/arm/kernel/hw-ebsa285.c
--- v2.1.132/linux/arch/arm/kernel/hw-ebsa285.c	Tue Dec 22 14:16:53 1998
+++ linux/arch/arm/kernel/hw-ebsa285.c	Wed Dec 23 09:44:40 1998
@@ -123,7 +123,7 @@
 		err = "system";
 		break;
 	}
-	if (next_warn[idx] <= jiffies) {
+	if (time_after_eq(jiffies, next_warn[idx])) {
 		next_warn[idx] = jiffies + 3 * HZ / 100;
 		printk(KERN_ERR "PCI %s error detected\n", err);
 	}
diff -u --recursive --new-file v2.1.132/linux/arch/arm/kernel/irq.c linux/arch/arm/kernel/irq.c
--- v2.1.132/linux/arch/arm/kernel/irq.c	Tue Dec 22 14:16:53 1998
+++ linux/arch/arm/kernel/irq.c	Wed Dec 23 09:44:40 1998
@@ -356,7 +356,7 @@
 	/*
 	 * wait for spurious interrupts to mask themselves out again
 	 */
-	for (delay = jiffies + HZ/10; delay > jiffies; )
+	for (delay = jiffies + HZ/10; time_before(jiffies, delay); )
 		/* min 100ms delay */;
 
 	/*
diff -u --recursive --new-file v2.1.132/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.1.132/linux/arch/i386/config.in	Tue Dec 22 14:16:53 1998
+++ linux/arch/i386/config.in	Sun Dec 27 10:48:46 1998
@@ -17,9 +17,7 @@
 	 Pentium/K5/5x86/6x86	CONFIG_M586	\
 	 PPro/K6/6x86MX		CONFIG_M686" Pentium
 bool 'Math emulation' CONFIG_MATH_EMULATION
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
-fi
+bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
 bool 'Symmetric multi-processing support' CONFIG_SMP
 endmenu
 
@@ -38,10 +36,16 @@
 bool 'Networking support' CONFIG_NET
 bool 'PCI support' CONFIG_PCI
 if [ "$CONFIG_PCI" = "y" ]; then
-  bool '   PCI BIOS support' CONFIG_PCI_BIOS
-  bool '   PCI direct access support' CONFIG_PCI_DIRECT
-  if [ "$CONFIG_PCI_BIOS" = "n" -a "$CONFIG_PCI_DIRECT" = "n" ]; then
-    define_bool CONFIG_PCI_BIOS "y"
+  unset CONFIG_PCI_BIOS CONFIG_PCI_DIRECT
+  choice 'PCI access mode' \
+	"BIOS		CONFIG_PCI_GOBIOS	\
+	 Direct		CONFIG_PCI_GODIRECT	\
+	 Any		CONFIG_PCI_GOANY"	Any
+  if [ -n "$CONFIG_PCI_GOBIOS" -o -n "$CONFIG_PCI_GOANY" ]; then
+    define_bool CONFIG_PCI_BIOS y
+  fi
+  if [ -n "$CONFIG_PCI_GODIRECT" -o -n "$CONFIG_PCI_GOANY" ]; then
+    define_bool CONFIG_PCI_DIRECT y
   fi
   bool '   PCI quirks' CONFIG_PCI_QUIRKS
   if [ "$CONFIG_PCI_QUIRKS" = "y" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -u --recursive --new-file v2.1.132/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.132/linux/arch/i386/defconfig	Tue Dec 22 14:16:53 1998
+++ linux/arch/i386/defconfig	Sun Dec 27 11:56:34 1998
@@ -15,6 +15,7 @@
 CONFIG_M586=y
 # CONFIG_M686 is not set
 # CONFIG_MATH_EMULATION is not set
+# CONFIG_MTRR is not set
 CONFIG_SMP=y
 
 #
@@ -29,6 +30,9 @@
 #
 CONFIG_NET=y
 CONFIG_PCI=y
+# CONFIG_PCI_GOBIOS is not set
+# CONFIG_PCI_GODIRECT is not set
+CONFIG_PCI_GOANY=y
 CONFIG_PCI_BIOS=y
 CONFIG_PCI_DIRECT=y
 CONFIG_PCI_QUIRKS=y
@@ -211,6 +215,7 @@
 # CONFIG_NET_RADIO is not set
 # CONFIG_TR is not set
 # CONFIG_HOSTESS_SV11 is not set
+# CONFIG_COSA is not set
 # CONFIG_WAN_DRIVERS is not set
 # CONFIG_LAPBETHER is not set
 # CONFIG_X25_ASY is not set
@@ -242,6 +247,10 @@
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
 CONFIG_MOUSE=y
+
+#
+# Mice
+#
 # CONFIG_ATIXL_BUSMOUSE is not set
 # CONFIG_BUSMOUSE is not set
 # CONFIG_MS_BUSMOUSE is not set
@@ -250,9 +259,17 @@
 # CONFIG_PC110_PAD is not set
 # CONFIG_QIC02_TAPE is not set
 # CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
+
+#
+# Video For Linux
+#
 # CONFIG_VIDEO_DEV is not set
-# CONFIG_NVRAM is not set
+
+#
+# Joystick support
+#
 # CONFIG_JOYSTICK is not set
 
 #
@@ -264,36 +281,44 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
-# CONFIG_MINIX_FS is not set
-CONFIG_EXT2_FS=y
-CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
+CONFIG_AUTOFS_FS=y
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
 # CONFIG_FAT_FS is not set
 # CONFIG_MSDOS_FS is not set
 # CONFIG_UMSDOS_FS is not set
 # CONFIG_VFAT_FS is not set
+CONFIG_ISO9660_FS=y
+# CONFIG_JOLIET is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_NTFS_FS is not set
+# CONFIG_HPFS_FS is not set
 CONFIG_PROC_FS=y
+CONFIG_DEVPTS_FS=y
+# CONFIG_ROMFS_FS is not set
+CONFIG_EXT2_FS=y
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Network File Systems
+#
+# CONFIG_CODA_FS is not set
 CONFIG_NFS_FS=y
 CONFIG_NFSD=y
 # CONFIG_NFSD_SUN is not set
 CONFIG_SUNRPC=y
 CONFIG_LOCKD=y
-# CONFIG_CODA_FS is not set
 # CONFIG_SMB_FS is not set
 # CONFIG_NCP_FS is not set
-# CONFIG_HPFS_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_SYSV_FS is not set
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_ROMFS_FS is not set
-CONFIG_AUTOFS_FS=y
-# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
 # CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MAC_PARTITION is not set
 # CONFIG_SMD_DISKLABEL is not set
 # CONFIG_SOLARIS_X86_PARTITION is not set
-CONFIG_DEVPTS_FS=y
-# CONFIG_MAC_PARTITION is not set
 # CONFIG_NLS is not set
 
 #
diff -u --recursive --new-file v2.1.132/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S
--- v2.1.132/linux/arch/i386/kernel/entry.S	Tue Dec 22 14:16:53 1998
+++ linux/arch/i386/kernel/entry.S	Sun Dec 27 22:45:13 1998
@@ -153,10 +153,10 @@
 	ALIGN
 	.globl	ret_from_fork
 ret_from_fork:
-	GET_CURRENT(%ebx)
 #ifdef __SMP__
-	lock ; btrl $0, SYMBOL_NAME(scheduler_lock)
+	call SYMBOL_NAME(schedule_tail)
 #endif /* __SMP__ */
+	GET_CURRENT(%ebx)
 	jmp	ret_from_sys_call
 
 /*
diff -u --recursive --new-file v2.1.132/linux/arch/i386/kernel/i386_ksyms.c linux/arch/i386/kernel/i386_ksyms.c
--- v2.1.132/linux/arch/i386/kernel/i386_ksyms.c	Fri Nov 27 13:09:22 1998
+++ linux/arch/i386/kernel/i386_ksyms.c	Sun Dec 27 22:45:13 1998
@@ -83,7 +83,6 @@
 EXPORT_SYMBOL(__global_sti);
 EXPORT_SYMBOL(__global_save_flags);
 EXPORT_SYMBOL(__global_restore_flags);
-EXPORT_SYMBOL(smp_message_pass);
 EXPORT_SYMBOL(mtrr_hook);
 #endif
 
diff -u --recursive --new-file v2.1.132/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
--- v2.1.132/linux/arch/i386/kernel/io_apic.c	Tue Dec 22 14:16:53 1998
+++ linux/arch/i386/kernel/io_apic.c	Mon Dec 28 10:52:01 1998
@@ -682,7 +682,8 @@
 	printk(".... register #01: %08X\n", *(int *)&reg_01);
 	printk(".......     : max redirection entries: %04X\n", reg_01.entries);
 	if (	(reg_01.entries != 0x0f) && /* ISA-only Neptune boards */
-		(reg_01.entries != 0x17)    /* ISA+PCI boards */
+		(reg_01.entries != 0x17) && /* ISA+PCI boards */
+		(reg_01.entries != 0x3F)    /* Xeon boards */
 	)
 		UNEXPECTED_IO_APIC();
 	if (reg_01.entries == 0x0f)
@@ -690,7 +691,8 @@
 
 	printk(".......     : IO APIC version: %04X\n", reg_01.version);
 	if (	(reg_01.version != 0x10) && /* oldest IO-APICs */
-		(reg_01.version != 0x11)  /* my IO-APIC */
+		(reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */
+		(reg_01.version != 0x13)    /* Xeon IO-APICs */
 	)
 		UNEXPECTED_IO_APIC();
 	if (reg_01.__reserved_1 || reg_01.__reserved_2)
@@ -953,7 +955,7 @@
 
 	if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) {
 		desc->status = status | IRQ_REPLAY;
-		send_IPI(APIC_DEST_SELF, IO_APIC_VECTOR(irq));
+		send_IPI_self(IO_APIC_VECTOR(irq));
 	}
 }
 
diff -u --recursive --new-file v2.1.132/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.1.132/linux/arch/i386/kernel/irq.c	Tue Dec 22 14:16:53 1998
+++ linux/arch/i386/kernel/irq.c	Sun Dec 27 22:45:13 1998
@@ -189,7 +189,7 @@
 /*
  * The following vectors are part of the Linux architecture, there
  * is no hardware IRQ pin equivalent for them, they are triggered
- * through the ICC by us (IPIs), via smp_message_pass():
+ * through the ICC by us (IPIs)
  */
 BUILD_SMP_INTERRUPT(reschedule_interrupt)
 BUILD_SMP_INTERRUPT(invalidate_interrupt)
@@ -297,7 +297,7 @@
 	}
 	p += sprintf(p, "NMI: %10u\n", atomic_read(&nmi_counter));
 #ifdef __SMP__
-	p += sprintf(p, "IPI: %10lu\n", ipi_count);
+	p += sprintf(p, "ERR: %10lu\n", ipi_count);
 #endif		
 	return p - buf;
 }
@@ -709,7 +709,7 @@
 	spin_lock_irqsave(&irq_controller_lock, flags);
 	switch (irq_desc[irq].depth) {
 	case 1:
-		irq_desc[irq].status &= ~IRQ_DISABLED;
+		irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS);
 		irq_desc[irq].handler->enable(irq);
 		/* fall throught */
 	default:
@@ -989,22 +989,22 @@
 	 */
 
 	/* IPI for rescheduling */
-	set_intr_gate(0x30, reschedule_interrupt);
+	set_intr_gate(RESCHEDULE_VECTOR, reschedule_interrupt);
 
 	/* IPI for invalidation */
-	set_intr_gate(0x31, invalidate_interrupt);
+	set_intr_gate(INVALIDATE_TLB_VECTOR, invalidate_interrupt);
 
 	/* IPI for CPU halt */
-	set_intr_gate(0x40, stop_cpu_interrupt);
+	set_intr_gate(STOP_CPU_VECTOR, stop_cpu_interrupt);
 
 	/* self generated IPI for local APIC timer */
-	set_intr_gate(0x41, apic_timer_interrupt);
+	set_intr_gate(LOCAL_TIMER_VECTOR, apic_timer_interrupt);
 
 	/* IPI for MTRR control */
-	set_intr_gate(0x50, mtrr_interrupt);
+	set_intr_gate(MTRR_CHANGE_VECTOR, mtrr_interrupt);
 
 	/* IPI vector for APIC spurious interrupts */
-	set_intr_gate(0xff, spurious_interrupt);
+	set_intr_gate(SPURIOUS_APIC_VECTOR, spurious_interrupt);
 #endif	
 	request_region(0x20,0x20,"pic1");
 	request_region(0xa0,0x20,"pic2");
diff -u --recursive --new-file v2.1.132/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h
--- v2.1.132/linux/arch/i386/kernel/irq.h	Tue Dec 22 14:16:54 1998
+++ linux/arch/i386/kernel/irq.h	Mon Dec 28 14:10:43 1998
@@ -40,7 +40,28 @@
 	unsigned int depth;			/* Disable depth for nested irq disables */
 } irq_desc_t;
 
-#define IRQ0_TRAP_VECTOR 0x51
+/*
+ * Special IRQ vectors used by the SMP architecture:
+ *
+ * (some of the following vectors are 'rare', they might be merged
+ *  into a single vector to save vector space. TLB, reschedule and
+ *  local APIC vectors are performance-critical.)
+ */
+#define RESCHEDULE_VECTOR	0x30
+#define INVALIDATE_TLB_VECTOR	0x31
+#define STOP_CPU_VECTOR		0x40
+#define LOCAL_TIMER_VECTOR	0x41
+#define MTRR_CHANGE_VECTOR	0x50
+
+/*
+ * First vector available to drivers: (vectors 0x51-0xfe)
+ */
+#define IRQ0_TRAP_VECTOR	0x51
+
+/*
+ * This IRQ should never happen, but we print a message nevertheless.
+ */
+#define SPURIOUS_APIC_VECTOR	0xff
 
 extern irq_desc_t irq_desc[NR_IRQS];
 extern int irq_vector[NR_IRQS];
@@ -56,17 +77,18 @@
  * Interrupt entry/exit code at both C and assembly level
  */
 
-void mask_irq(unsigned int irq);
-void unmask_irq(unsigned int irq);
-void disable_8259A_irq(unsigned int irq);
-int i8259A_irq_pending(unsigned int irq);
-void ack_APIC_irq(void);
-void setup_IO_APIC(void);
-int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
-void make_8259A_irq(unsigned int irq);
-void send_IPI(int dest, int vector);
-void init_pic_mode(void);
-void print_IO_APIC(void);
+extern void mask_irq(unsigned int irq);
+extern void unmask_irq(unsigned int irq);
+extern void disable_8259A_irq(unsigned int irq);
+extern int i8259A_irq_pending(unsigned int irq);
+extern void ack_APIC_irq(void);
+extern void setup_IO_APIC(void);
+extern int IO_APIC_get_PCI_irq_vector(int bus, int slot, int fn);
+extern void make_8259A_irq(unsigned int irq);
+extern void FASTCALL(send_IPI_self(int vector));
+extern void smp_send_mtrr(void);
+extern void init_pic_mode(void);
+extern void print_IO_APIC(void);
 
 extern unsigned long long io_apic_irqs;
 
diff -u --recursive --new-file v2.1.132/linux/arch/i386/kernel/mtrr.c linux/arch/i386/kernel/mtrr.c
--- v2.1.132/linux/arch/i386/kernel/mtrr.c	Mon Oct  5 13:13:35 1998
+++ linux/arch/i386/kernel/mtrr.c	Sun Dec 27 22:45:13 1998
@@ -164,6 +164,9 @@
 #include <asm/bitops.h>
 #include <asm/atomic.h>
 
+#include <asm/hardirq.h>
+#include "irq.h"
+
 #define MTRR_VERSION            "1.26 (19981001)"
 
 #define TRUE  1
@@ -612,10 +615,11 @@
     /*  Send a message to all other CPUs and wait for them to enter the
 	barrier  */
     atomic_set (&undone_count, smp_num_cpus - 1);
-    smp_message_pass (MSG_ALL_BUT_SELF, MSG_MTRR_CHANGE, 0, 0);
+    smp_send_mtrr();
     /*  Wait for it to be done  */
     timeout = jiffies + JIFFIE_TIMEOUT;
-    while ( (atomic_read (&undone_count) > 0) && (jiffies < timeout) )
+    while ( (atomic_read (&undone_count) > 0) &&
+	    time_before(jiffies, timeout) )
 	barrier ();
     if (atomic_read (&undone_count) > 0)
     {
diff -u --recursive --new-file v2.1.132/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c
--- v2.1.132/linux/arch/i386/kernel/process.c	Tue Dec 22 14:16:54 1998
+++ linux/arch/i386/kernel/process.c	Sun Dec 27 22:45:13 1998
@@ -140,10 +140,17 @@
 	current->priority = 0;
 	current->counter = -100;
 	while(1) {
-		if (current_cpu_data.hlt_works_ok && !hlt_counter && !current->need_resched)
+		if (current_cpu_data.hlt_works_ok && !hlt_counter &&
+				 !current->need_resched)
 			__asm__("hlt");
-		schedule();
-		check_pgt_cache();
+		/*
+		 * although we are an idle CPU, we do not want to
+		 * get into the scheduler unnecessarily.
+		 */
+		if (current->need_resched) {
+			schedule();
+			check_pgt_cache();
+		}
 	}
 }
 
diff -u --recursive --new-file v2.1.132/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.1.132/linux/arch/i386/kernel/smp.c	Tue Dec 22 14:16:54 1998
+++ linux/arch/i386/kernel/smp.c	Mon Dec 28 10:52:01 1998
@@ -3,12 +3,14 @@
  *	hosts.
  *
  *	(c) 1995 Alan Cox, CymruNET Ltd  <alan@cymru.net>
+ *	(c) 1998 Ingo Molnar
+ *
  *	Supported by Caldera http://www.caldera.com.
  *	Much of the core SMP work is based on previous work by Thomas Radke, to
  *	whom a great many thanks are extended.
  *
- *	Thanks to Intel for making available several different Pentium and
- *	Pentium Pro MP machines.
+ *	Thanks to Intel for making available several different Pentium,
+ *	Pentium Pro and Pentium-II/Xeon MP machines.
  *
  *	This code is released under the GNU public license version 2 or
  *	later.
@@ -26,6 +28,7 @@
  *		Ingo Molnar	:	Added APIC timers, based on code
  *					from Jose Renau
  *		Alan Cox	:	Added EBDA scanning
+ *		Ingo Molnar	:	various cleanups and rewrites
  */
 
 #include <linux/config.h>
@@ -112,6 +115,12 @@
 	return b;
 }
 
+/*
+ * function prototypes:
+ */
+static void cache_APIC_registers (void);
+
+
 static int smp_b_stepping = 0;				/* Set if we find a B stepping CPU			*/
 
 static int max_cpus = -1;				/* Setup configured maximum number of CPUs to activate	*/
@@ -131,19 +140,13 @@
 unsigned char boot_cpu_id = 0;				/* Processor that is doing the boot up 			*/
 static int smp_activated = 0;				/* Tripped once we need to start cross invalidating 	*/
 int apic_version[NR_CPUS];				/* APIC version number					*/
-static volatile int smp_commenced=0;			/* Tripped when we start scheduling 		    	*/
 unsigned long apic_retval;				/* Just debugging the assembler.. 			*/
 
-static volatile unsigned char smp_cpu_in_msg[NR_CPUS];	/* True if this processor is sending an IPI		*/
-
 volatile unsigned long kernel_counter=0;		/* Number of times the processor holds the lock		*/
 volatile unsigned long syscall_count=0;			/* Number of times the processor holds the syscall lock	*/
 
 volatile unsigned long ipi_count;			/* Number of IPIs delivered				*/
 
-volatile unsigned long  smp_proc_in_lock[NR_CPUS] = {0,};/* for computing process time */
-volatile int smp_process_available=0;
-
 const char lk_lockmsg[] = "lock from interrupt context at %p\n"; 
 
 int mp_bus_id_to_type [MAX_MP_BUSSES] = { -1, };
@@ -245,7 +248,7 @@
 
 	if (memcmp(mpc->mpc_signature,MPC_SIGNATURE,4))
 	{
-		printk("Bad signature [%c%c%c%c].\n",
+		panic("SMP mptable: bad signature [%c%c%c%c]!\n",
 			mpc->mpc_signature[0],
 			mpc->mpc_signature[1],
 			mpc->mpc_signature[2],
@@ -254,7 +257,7 @@
 	}
 	if (mpf_checksum((unsigned char *)mpc,mpc->mpc_length))
 	{
-		printk("Checksum error.\n");
+		panic("SMP mptable: checksum error!\n");
 		return 1;
 	}
 	if (mpc->mpc_spec!=0x01 && mpc->mpc_spec!=0x04)
@@ -629,13 +632,17 @@
  *	we use to track CPUs as they power up.
  */
 
+static atomic_t smp_commenced = ATOMIC_INIT(0);
+
 void __init smp_commence(void)
 {
 	/*
 	 *	Lets the callins below out of their loop.
 	 */
 	SMP_PRINTK(("Setting commenced=1, go go go\n"));
-	smp_commenced=1;
+
+	wmb();
+	atomic_set(&smp_commenced,1);
 }
 
 void __init enable_local_APIC(void)
@@ -736,8 +743,8 @@
 	mtrr_init_secondary_cpu ();
 #endif
 	smp_callin();
-	while (!smp_commenced)
-		barrier();
+	while (!atomic_read(&smp_commenced))
+		/* nothing */ ;
 	return cpu_idle(NULL);
 }
 
@@ -760,11 +767,7 @@
 	/*
 	 * We don't actually need to load the full TSS,
 	 * basically just the stack pointer and the eip.
-	 *
-	 * Get the scheduler lock, because we're going
-	 * to release it as part of the "reschedule" return.
 	 */
-	spin_lock(&scheduler_lock);
 
 	asm volatile(
 		"movl %0,%%esp\n\t"
@@ -972,6 +975,27 @@
 	*((volatile unsigned long *)phys_to_virt(8192)) = 0;
 }
 
+cycles_t cacheflush_time;
+extern unsigned long cpu_hz;
+
+static void smp_tune_scheduling (void)
+{
+	/*
+	 * Rough estimation for SMP scheduling, this is the number of
+	 * cycles it takes for a fully memory-limited process to flush
+	 * the SMP-local cache.
+	 *
+	 * (For a P5 this pretty much means we will choose another idle
+	 *  CPU almost always at wakeup time (this is due to the small
+	 *  L1 cache), on PIIs it's around 50-100 usecs, depending on
+	 *  the cache size)
+	 */
+	cacheflush_time = cpu_hz/1024*boot_cpu_data.x86_cache_size/5000;
+	printk("per-CPU timeslice cutoff: %ld.%ld usecs.\n",
+		(long)cacheflush_time/(cpu_hz/1000000),
+		((long)cacheflush_time*100/(cpu_hz/1000000)) % 100);
+}
+
 unsigned int prof_multiplier[NR_CPUS];
 unsigned int prof_counter[NR_CPUS];
 
@@ -1004,6 +1028,7 @@
 	 */
 
 	smp_store_cpu_info(boot_cpu_id);			/* Final full version of the data */
+	smp_tune_scheduling();
 	printk("CPU%d: ", boot_cpu_id);
 	print_cpu_info(&cpu_data[boot_cpu_id]);
 
@@ -1165,6 +1190,7 @@
 		printk(KERN_WARNING "WARNING: SMP operation may be unreliable with B stepping processors.\n");
 	SMP_PRINTK(("Boot done.\n"));
 
+	cache_APIC_registers();
 	/*
 	 * Here we can be sure that there is an IO-APIC in the system. Let's
 	 * go and set it up:
@@ -1175,257 +1201,270 @@
 smp_done:
 }
 
-void send_IPI(int dest, int vector)
-{
-	unsigned long cfg;
-	unsigned long flags;
 
-	__save_flags(flags);
-	__cli();
+/*
+ * the following functions deal with sending IPIs between CPUs.
+ *
+ * We use 'broadcast', CPU->CPU IPIs and self-IPIs too.
+ */
 
-	/*
-	 * prepare target chip field
-	 */
 
-	cfg = apic_read(APIC_ICR2) & 0x00FFFFFF;
-	apic_write(APIC_ICR2, cfg|SET_APIC_DEST_FIELD(dest));
+/*
+ * Silly serialization to work around CPU bug in P5s.
+ * We can safely turn it off on a 686.
+ */
+#if defined(CONFIG_M686) & !defined(SMP_DEBUG)
+# define FORCE_APIC_SERIALIZATION 0
+#else
+# define FORCE_APIC_SERIALIZATION 1
+#endif
 
-	cfg = apic_read(APIC_ICR);
-	cfg &= ~0xFDFFF;
-	cfg |= APIC_DEST_FIELD|APIC_DEST_DM_FIXED|vector;
-	cfg |= dest;
-	
-	/*
-	 * Send the IPI. The write to APIC_ICR fires this off.
-	 */
-	
-	apic_write(APIC_ICR, cfg);
-	__restore_flags(flags);
-}
+static unsigned int cached_APIC_ICR;
+static unsigned int cached_APIC_ICR2;
 
 /*
- * A non wait message cannot pass data or CPU source info. This current setup
- * is only safe because the kernel lock owner is the only person who can send
- * a message.
+ * Caches reserved bits, APIC reads are (mildly) expensive
+ * and force otherwise unnecessary CPU synchronization.
  *
- * Wrapping this whole block in a spinlock is not the safe answer either. A
- * processor may get stuck with IRQs off waiting to send a message and thus
- * not replying to the person spinning for a reply.
- *
- * In the end flush tlb ought to be the NMI and a very short function
- * (to avoid the old IDE disk problems), and other messages sent with IRQs
- * enabled in a civilised fashion. That will also boost performance.
+ * (We could cache other APIC registers too, but these are the
+ * main ones used in RL.)
  */
+#define slow_ICR (apic_read(APIC_ICR) & ~0xFDFFF)
+#define slow_ICR2 (apic_read(APIC_ICR2) & 0x00FFFFFF)
 
-void smp_message_pass(int target, int msg, unsigned long data, int wait)
+void cache_APIC_registers (void)
 {
-	unsigned long cfg;
-	unsigned long dest = 0;
-	unsigned long target_map;
-	int p=smp_processor_id();
-	int irq;
-	int ct=0;
+	cached_APIC_ICR = slow_ICR;
+	cached_APIC_ICR2 = slow_ICR2;
+	mb();
+}
 
+static inline unsigned int __get_ICR (void)
+{
+#if FORCE_APIC_SERIALIZATION
 	/*
-	 *	During boot up send no messages
+	 * Wait for the APIC to become ready - this should never occur. It's
+	 * a debugging check really.
 	 */
-	
-	if (!smp_activated || !smp_commenced)
-		return;
+	int count = 0;
+	unsigned int cfg;
 
+	while (count < 1000)
+	{
+		cfg = slow_ICR;
+		if (!(cfg&(1<<12))) {
+			if (count)
+				atomic_add(count, (atomic_t*)&ipi_count);
+			return cfg;
+		}
+		count++;
+		udelay(10);
+	}
+	printk("CPU #%d: previous IPI still not cleared after 10mS\n",
+			smp_processor_id());
+	return cfg;
+#else
+	return cached_APIC_ICR;
+#endif
+}
 
-	/*
-	 *	Skip the reschedule if we are waiting to clear a
-	 *	message at this time. The reschedule cannot wait
-	 *	but is not critical.
-	 */
+static inline unsigned int __get_ICR2 (void)
+{
+#if FORCE_APIC_SERIALIZATION
+	return slow_ICR2;
+#else
+	return cached_APIC_ICR2;
+#endif
+}
 
-	switch (msg) {
-		case MSG_RESCHEDULE:
-			irq = 0x30;
-			if (smp_cpu_in_msg[p])
-				return;
-			break;
+static inline int __prepare_ICR (unsigned int shortcut, int vector)
+{
+	unsigned int cfg;
 
-		case MSG_INVALIDATE_TLB:
-			/* make this a NMI some day */
-			irq = 0x31;
-			break;
+	cfg = __get_ICR();
+	cfg |= APIC_DEST_FIELD|APIC_DEST_DM_FIXED|shortcut|vector;
 
-		case MSG_STOP_CPU:
-			irq = 0x40;
-			break;
+	return cfg;
+}
 
-		case MSG_MTRR_CHANGE:
-			irq = 0x50;
-			break;
+static inline int __prepare_ICR2 (unsigned int dest)
+{
+	unsigned int cfg;
 
-		default:
-			printk("Unknown SMP message %d\n", msg);
-			return;
-	}
+	cfg = __get_ICR2();
+	cfg |= SET_APIC_DEST_FIELD(dest);
 
-	/*
-	 * Sanity check we don't re-enter this across CPUs.  Only the kernel
-	 * lock holder may send messages.  For a STOP_CPU we are bringing the
-	 * entire box to the fastest halt we can.  A reschedule carries
-	 * no data and can occur during a flush.  Guess what panic
-	 * I got to notice this bug.
-	 */
-	
-	/*
-	 *	We are busy.
-	 */
-	
-	smp_cpu_in_msg[p]++;
+	return cfg;
+}
 
-/*	printk("SMP message pass #%d to %d of %d\n",
-		p, msg, target);*/
+static inline void __send_IPI_shortcut(unsigned int shortcut, int vector)
+{
+	unsigned int cfg;
+/*
+ * Subtle. In the case of the 'never do double writes' workaround we
+ * have to lock out interrupts to be safe. Otherwise it's just one
+ * single atomic write to the APIC, no need for cli/sti.
+ */
+#if FORCE_APIC_SERIALIZATION
+	unsigned long flags;
 
-	/*
-	 * Wait for the APIC to become ready - this should never occur. It's
-	 * a debugging check really.
-	 */
-	
-	while (ct<1000)
-	{
-		cfg=apic_read(APIC_ICR);
-		if (!(cfg&(1<<12)))
-			break;
-		ct++;
-		udelay(10);
-	}
+	__save_flags(flags);
+	__cli();
+#endif
 
 	/*
-	 *	Just pray... there is nothing more we can do
+	 * No need to touch the target chip field
 	 */
-	
-	if (ct==1000)
-		printk("CPU #%d: previous IPI still not cleared after 10mS\n", p);
+
+	cfg = __prepare_ICR(shortcut, vector);
 
 	/*
-	 *	Set the target requirement
+	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
-	
-	if (target==MSG_ALL_BUT_SELF)
-	{
-		dest=APIC_DEST_ALLBUT;
-		target_map=cpu_present_map;
-		cpu_callin_map[0]=(1<<p);
-	}
-	else if (target==MSG_ALL)
-	{
-		dest=APIC_DEST_ALLINC;
-		target_map=cpu_present_map;
-		cpu_callin_map[0]=0;
-	}
-	else
-	{
-		dest=0;
-		target_map=(1<<target);
-		cpu_callin_map[0]=0;
-	}
+	apic_write(APIC_ICR, cfg);
+#if FORCE_APIC_SERIALIZATION
+	__restore_flags(flags);
+#endif
+}
+
+static inline void send_IPI_allbutself(int vector)
+{
+	__send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
+}
+
+static inline void send_IPI_all(int vector)
+{
+	__send_IPI_shortcut(APIC_DEST_ALLINC, vector);
+}
+
+void send_IPI_self(int vector)
+{
+	__send_IPI_shortcut(APIC_DEST_SELF, vector);
+}
+
+static inline void send_IPI_single(int dest, int vector)
+{
+	unsigned long cfg;
+#if FORCE_APIC_SERIALIZATION
+	unsigned long flags;
+
+	__save_flags(flags);
+	__cli();
+#endif
 
 	/*
-	 * Program the APIC to deliver the IPI
+	 * prepare target chip field
 	 */
 
-	send_IPI(dest,irq);
+	cfg = __prepare_ICR2(dest);
+	apic_write(APIC_ICR2, cfg);
 
 	/*
-	 * Spin waiting for completion
+	 * program the ICR 
 	 */
+	cfg = __prepare_ICR(0, vector);
 	
-	switch(wait)
-	{
-		int stuck;
-		case 1:
-			stuck = 50000000;
-			while(cpu_callin_map[0]!=target_map) {
-				--stuck;
-				if (!stuck) {
-					printk("stuck on target_map IPI wait\n");
-					break;
-				}
-			}
-			break;
-		case 2:
-			stuck = 50000000;
-			/* Wait for invalidate map to clear */
-			while (smp_invalidate_needed) {
-				/* Take care of "crossing" invalidates */
-				if (test_bit(p, &smp_invalidate_needed))
-					clear_bit(p, &smp_invalidate_needed);
-				--stuck;
-				if (!stuck) {
-					printk("stuck on smp_invalidate_needed IPI wait (CPU#%d)\n",p);
-					break;
-				}
-			}
-			break;
-	}
-
 	/*
-	 *	Record our completion
+	 * Send the IPI. The write to APIC_ICR fires this off.
 	 */
-	
-	smp_cpu_in_msg[p]--;
+	apic_write(APIC_ICR, cfg);
+#if FORCE_APIC_SERIALIZATION
+	__restore_flags(flags);
+#endif
 }
 
 /*
- *	This is fraught with deadlocks. Linus does a flush tlb at a whim
- *	even with IRQs off. We have to avoid a pair of crossing flushes
- *	or we are doomed.  See the notes about smp_message_pass.
+ * This is fraught with deadlocks. Probably the situation is not that
+ * bad as in the early days of SMP, so we might ease some of the
+ * paranoia here.
  */
 
 void smp_flush_tlb(void)
 {
+	int cpu = smp_processor_id();
+	int stuck;
 	unsigned long flags;
 
-/*	printk("SMI-");*/
-
 	/*
-	 *	The assignment is safe because it's volatile so the compiler cannot reorder it,
-	 *	because the i586 has strict memory ordering and because only the kernel lock holder
-	 *	may issue a tlb flush. If you break any one of those three change this to an atomic
-	 *	bus locked or.
+	 * The assignment is safe because it's volatile so the
+	 * compiler cannot reorder it, because the i586 has
+	 * strict memory ordering and because only the kernel
+	 * lock holder may issue a tlb flush. If you break any
+	 * one of those three change this to an atomic bus
+	 * locked or.
 	 */
 
-	smp_invalidate_needed=cpu_present_map;
+	smp_invalidate_needed = cpu_present_map;
 
 	/*
-	 *	Processors spinning on the lock will see this IRQ late. The smp_invalidate_needed map will
-	 *	ensure they don't do a spurious flush tlb or miss one.
+	 * Processors spinning on some lock with IRQs disabled
+	 * will see this IRQ late. The smp_invalidate_needed
+	 * map will ensure they don't do a spurious flush tlb
+	 * or miss one.
 	 */
 	
 	__save_flags(flags);
 	__cli();
-	smp_message_pass(MSG_ALL_BUT_SELF, MSG_INVALIDATE_TLB, 0L, 2);
+
+	send_IPI_allbutself(INVALIDATE_TLB_VECTOR);
 
 	/*
-	 *	Flush the local TLB
+	 * Spin waiting for completion
 	 */
-	
-	local_flush_tlb();
 
-	__restore_flags(flags);
+	stuck = 50000000;
+	while (smp_invalidate_needed) {
+		/*
+		 * Take care of "crossing" invalidates
+		 */
+		if (test_bit(cpu, &smp_invalidate_needed))
+			clear_bit(cpu, &smp_invalidate_needed);
+		--stuck;
+		if (!stuck) {
+			printk("stuck on TLB IPI wait (CPU#%d)\n",cpu);
+			break;
+		}
+	}
 
 	/*
-	 *	Completed.
+	 *	Flush the local TLB
 	 */
-	
-/*	printk("SMID\n");*/
+	local_flush_tlb();
+
+	__restore_flags(flags);
 }
 
 
+/*
+ * this function sends a 'reschedule' IPI to another CPU.
+ * it goes straight through and wastes no time serializing
+ * anything. Worst case is that we lose a reschedule ...
+ */
+
 void smp_send_reschedule(int cpu)
 {
-	unsigned long flags;
+	send_IPI_single(cpu, RESCHEDULE_VECTOR);
+}
 
-	__save_flags(flags);
-	__cli();
-	smp_message_pass(cpu, MSG_RESCHEDULE, 0L, 0);
-	__restore_flags(flags);
+/*
+ * this function sends a 'stop' IPI to all other CPUs in the system.
+ * it goes straight through.
+ */
+
+void smp_send_stop(void)
+{
+	send_IPI_allbutself(STOP_CPU_VECTOR);
+}
+
+/*
+ * this function sends an 'reload MTRR state' IPI to all other CPUs
+ * in the system. it goes straight through, completion processing
+ * is done on the mttr.c level.
+ */
+
+void smp_send_mtrr(void)
+{
+	send_IPI_allbutself(MTRR_CHANGE_VECTOR);
 }
 
 /*
@@ -1626,12 +1665,9 @@
 	 * Unfortunately the local APIC timer cannot be set up into NMI
 	 * mode. With the IO APIC we can re-route the external timer
 	 * interrupt and broadcast it as an NMI to all CPUs, so no pain.
-	 *
-	 * NOTE: this trap vector (0x41) and the gate in
-	 * BUILD_SMP_TIMER_INTERRUPT should be the same ;)
 	 */
 	tmp_value = apic_read(APIC_LVTT);
-	lvtt1_value = APIC_LVT_TIMER_PERIODIC | 0x41;
+	lvtt1_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
 	apic_write(APIC_LVTT , lvtt1_value);
 
 	/*
diff -u --recursive --new-file v2.1.132/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v2.1.132/linux/arch/i386/kernel/time.c	Tue Dec 22 14:16:54 1998
+++ linux/arch/i386/kernel/time.c	Mon Dec 28 10:52:01 1998
@@ -22,8 +22,10 @@
  *	ported from 2.0.35 Jumbo-9 by Michael Krause <m.krause@tu-harburg.de>).
  * 1998-12-16    Andrea Arcangeli
  *	Fixed Jumbo-9 code in 2.1.131: do_gettimeofday was missing 1 jiffy
- *	because was not accounting lost_ticks. I also removed some ugly
- *	not needed global cli() and where needed I used a disable_irq(0).
+ *	because was not accounting lost_ticks.
+ * 1998-12-24 Copyright (C) 1998  Andrea Arcangeli
+ *	Fixed a xtime SMP race (we need the xtime_lock rw spinlock to
+ *	serialize accesses to xtime/lost_ticks).
  */
 
 /* What about the "updated NTP code" stuff in 2.0 time.c? It's not in
@@ -82,7 +84,9 @@
  */
 static unsigned long fast_gettimeoffset_quotient=0;
 
-static unsigned long do_fast_gettimeoffset(void)
+extern rwlock_t xtime_lock;
+
+static inline unsigned long do_fast_gettimeoffset(void)
 {
 	register unsigned long eax asm("ax");
 	register unsigned long edx asm("dx");
@@ -92,7 +96,6 @@
 		:"=a" (eax), "=d" (edx));
 
 	/* .. relative to previous jiffy (32 bits is enough) */
-	edx = 0;
 	eax -= last_tsc_low;	/* tsc_low delta */
 
 	/*
@@ -106,13 +109,20 @@
 
 	__asm__("mull %2"
 		:"=a" (eax), "=d" (edx)
-		:"r" (fast_gettimeoffset_quotient),
-		 "0" (eax), "1" (edx));
+		:"g" (fast_gettimeoffset_quotient),
+		 "0" (eax));
 
 	/* our adjusted time offset in microseconds */
-	return edx + delay_at_last_interrupt;
+	return delay_at_last_interrupt + edx;
 }
 
+#define TICK_SIZE tick
+
+/*
+ * Older CPU's don't have the rdtsc instruction..
+ */
+#if CPU < 586
+
 /* This function must be called with interrupts disabled 
  * It was inspired by Steve McCanne's microtime-i386 for BSD.  -- jrs
  * 
@@ -145,8 +155,6 @@
  * comp.protocols.time.ntp!
  */
 
-#define TICK_SIZE tick
-
 static unsigned long do_slow_gettimeoffset(void)
 {
 	int count;
@@ -228,6 +236,12 @@
 
 static unsigned long (*do_gettimeoffset)(void) = do_slow_gettimeoffset;
 
+#else
+
+#define do_gettimeoffset()	do_fast_gettimeoffset()
+
+#endif
+
 /*
  * This version of gettimeofday has microsecond resolution
  * and better than microsecond precision on fast x86 machines with TSC.
@@ -236,22 +250,31 @@
 {
 	extern volatile unsigned long lost_ticks;
 	unsigned long flags;
+	unsigned long usec, sec;
 
-	save_flags(flags); cli();
-	*tv = xtime;
-	tv->tv_usec += do_gettimeoffset();
-	if (lost_ticks)
-		tv->tv_usec += lost_ticks * (1000000/HZ);
-	restore_flags(flags);
-	while (tv->tv_usec >= 1000000) {
-		tv->tv_usec -= 1000000;
-		tv->tv_sec++;
+	read_lock_irqsave(&xtime_lock, flags);
+	usec = do_gettimeoffset();
+	{
+		unsigned long lost = lost_ticks;
+		if (lost)
+			usec += lost * (1000000 / HZ);
+	}
+	sec = xtime.tv_sec;
+	usec += xtime.tv_usec;
+	read_unlock_irqrestore(&xtime_lock, flags);
+
+	while (usec >= 1000000) {
+		usec -= 1000000;
+		sec++;
 	}
+
+	tv->tv_sec = sec;
+	tv->tv_usec = usec;
 }
 
 void do_settimeofday(struct timeval *tv)
 {
-	cli();
+	write_lock_irq(&xtime_lock);
 	/* This is revolting. We need to set the xtime.tv_usec
 	 * correctly. However, the value in this location is
 	 * is value at the last tick.
@@ -269,7 +292,7 @@
 	time_state = TIME_BAD;
 	time_maxerror = MAXPHASE;
 	time_esterror = MAXPHASE;
-	sti();
+	write_unlock_irq(&xtime_lock);
 }
 
 /*
@@ -344,7 +367,7 @@
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-static inline void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static inline void do_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	do_timer(regs);
 /*
@@ -373,13 +396,6 @@
 		else
 			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */
 	}
-#if 0
-	/* As we return to user mode fire off the other CPU schedulers.. this is 
-	   basically because we don't yet share IRQ's around. This message is
-	   rigged to be safe on the 386 - basically it's a hack, so don't look
-	   closely for now.. */
-	smp_message_pass(MSG_ALL_BUT_SELF, MSG_RESCHEDULE, 0L, 0);
-#endif
 	    
 #ifdef CONFIG_MCA
 	if( MCA_bus ) {
@@ -398,37 +414,56 @@
 #endif
 }
 
+static int use_tsc = 0;
+
 /*
  * This is the same as the above, except we _also_ save the current
  * Time Stamp Counter value at the time of the timer interrupt, so that
  * we later on can estimate the time of day more exactly.
  */
-static void pentium_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	int count;
 
-	/* It is important that these two operations happen almost at the
-	 * same time. We do the RDTSC stuff first, since it's faster. To
-         * avoid any inconsistencies, we need interrupts disabled locally.
-         */
-
 	/*
-	 * Interrupts are just disabled locally since the timer irq has the
-	 * SA_INTERRUPT flag set. -arca
+	 * Here we are in the timer irq handler. We just have irqs locally
+	 * disabled but we don't know if the timer_bh is running on the other
+	 * CPU. We need to avoid to SMP race with it. NOTE: we don' t need
+	 * the irq version of write_lock because as just said we have irq
+	 * locally disabled. -arca
 	 */
+	write_lock(&xtime_lock);
+
+	if (use_tsc)
+	{
+		/*
+		 * It is important that these two operations happen almost at
+		 * the same time. We do the RDTSC stuff first, since it's
+		 * faster. To avoid any inconsistencies, we need interrupts
+		 * disabled locally.
+		 */
+
+		/*
+		 * Interrupts are just disabled locally since the timer irq
+		 * has the SA_INTERRUPT flag set. -arca
+		 */
 	
-	/* read Pentium cycle counter */
-	__asm__("rdtsc" : "=a" (last_tsc_low) : : "edx");
+		/* read Pentium cycle counter */
+		__asm__("rdtsc" : "=a" (last_tsc_low) : : "edx");
 
-	outb_p(0x00, 0x43);     /* latch the count ASAP */
+		outb_p(0x00, 0x43);     /* latch the count ASAP */
 
-	count = inb_p(0x40);    /* read the latched count */
-	count |= inb(0x40) << 8;
+		count = inb_p(0x40);    /* read the latched count */
+		count |= inb(0x40) << 8;
 
-	count = ((LATCH-1) - count) * TICK_SIZE;
-	delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+		count = ((LATCH-1) - count) * TICK_SIZE;
+		delay_at_last_interrupt = (count + LATCH/2) / LATCH;
+	}
  
-	timer_interrupt(irq, NULL, regs);
+	do_timer_interrupt(irq, NULL, regs);
+
+	write_unlock(&xtime_lock);
+
 }
 
 /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
@@ -599,9 +634,11 @@
  * smart.  See arch/i386/kernel/apm.c.
  */
 	if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) {
+#ifndef do_gettimeoffset
 		do_gettimeoffset = do_fast_gettimeoffset;
+#endif
 		do_get_fast_time = do_gettimeofday;
-		irq0.handler = pentium_timer_interrupt;
+		use_tsc = 1;
 		fast_gettimeoffset_quotient = calibrate_tsc();
 		
 		/* report CPU clock rate in Hz.
diff -u --recursive --new-file v2.1.132/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.1.132/linux/arch/i386/kernel/traps.c	Thu Nov 12 16:21:18 1998
+++ linux/arch/i386/kernel/traps.c	Sun Dec 27 10:32:09 1998
@@ -499,15 +499,18 @@
 }
 
 #define _set_gate(gate_addr,type,dpl,addr) \
-__asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
-	"movw %2,%%dx\n\t" \
+do { \
+  int __d0, __d1; \
+  __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
+	"movw %4,%%dx\n\t" \
 	"movl %%eax,%0\n\t" \
 	"movl %%edx,%1" \
 	:"=m" (*((long *) (gate_addr))), \
-	 "=m" (*(1+(long *) (gate_addr))) \
+	 "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
 	:"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
-	 "d" ((char *) (addr)),"a" (__KERNEL_CS << 16) \
-	:"ax","dx")
+	 "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \
+} while (0)
+
 
 /*
  * This needs to use 'idt_table' rather than 'idt', and
diff -u --recursive --new-file v2.1.132/linux/arch/i386/lib/Makefile linux/arch/i386/lib/Makefile
--- v2.1.132/linux/arch/i386/lib/Makefile	Tue Jul 28 14:21:07 1998
+++ linux/arch/i386/lib/Makefile	Sun Dec 27 10:33:13 1998
@@ -6,6 +6,7 @@
 	$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
 
 L_TARGET = lib.a
-L_OBJS  = checksum.o semaphore.o delay.o usercopy.o getuser.o putuser.o
+L_OBJS  = checksum.o old-checksum.o semaphore.o delay.o \
+	usercopy.o getuser.o putuser.o
 
 include $(TOPDIR)/Rules.make
diff -u --recursive --new-file v2.1.132/linux/arch/i386/lib/checksum.S linux/arch/i386/lib/checksum.S
--- v2.1.132/linux/arch/i386/lib/checksum.S	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/lib/checksum.S	Sun Dec 27 10:32:09 1998
@@ -0,0 +1,450 @@
+/*
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the  BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		IP/TCP/UDP checksumming routines
+ *
+ * Authors:	Jorge Cwik, <jorge@laser.satlink.net>
+ *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
+ *		Tom May, <ftom@netcom.com>
+ *              Pentium Pro/II routines:
+ *              Alexander Kjeldaas <astor@guardian.no>
+ *              Finn Arne Gangstad <finnag@guardian.no>
+ *		Lots of code moved from tcp.c and ip.c; see those files
+ *		for more names.
+ *
+ * Changes:     Ingo Molnar, converted csum_partial_copy() to 2.1 exception
+ *			     handling.
+ *		Andi Kleen,  add zeroing on error
+ *                   converted to pure assembler
+ *
+ *		This program is free software; you can redistribute it and/or
+ *		modify it under the terms of the GNU General Public License
+ *		as published by the Free Software Foundation; either version
+ *		2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/errno.h>
+				
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+/*	
+unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum)
+ */
+		
+.text
+.align 4
+.globl csum_partial								
+		
+#if CPU!=686
+
+	  /*		
+	   * Experiments with Ethernet and SLIP connections show that buff
+	   * is aligned on either a 2-byte or 4-byte boundary.  We get at
+	   * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
+	   * Fortunately, it is easy to convert 2-byte alignment to 4-byte
+	   * alignment for the unrolled loop.
+	   */		
+csum_partial:	
+	pushl %esi
+	pushl %ebx
+	movl 20(%esp),%eax	# Function arg: unsigned int sum
+	movl 16(%esp),%ecx	# Function arg: int len
+	movl 12(%esp),%esi	# Function arg: unsigned char *buff
+	testl $2, %esi		# Check alignment.
+	jz 2f			# Jump if alignment is ok.
+	subl $2, %ecx		# Alignment uses up two bytes.
+	jae 1f			# Jump if we had at least two bytes.
+	addl $2, %ecx		# ecx was < 2.  Deal with it.
+	jmp 4f
+1:	movw (%esi), %bx
+	addl $2, %esi
+	addw %bx, %ax
+	adcl $0, %eax
+2:
+	movl %ecx, %edx
+	shrl $5, %ecx
+	jz 2f
+	testl %esi, %esi
+1:	movl (%esi), %ebx
+	adcl %ebx, %eax
+	movl 4(%esi), %ebx
+	adcl %ebx, %eax
+	movl 8(%esi), %ebx
+	adcl %ebx, %eax
+	movl 12(%esi), %ebx
+	adcl %ebx, %eax
+	movl 16(%esi), %ebx
+	adcl %ebx, %eax
+	movl 20(%esi), %ebx
+	adcl %ebx, %eax
+	movl 24(%esi), %ebx
+	adcl %ebx, %eax
+	movl 28(%esi), %ebx
+	adcl %ebx, %eax
+	lea 32(%esi), %esi
+	dec %ecx
+	jne 1b
+	adcl $0, %eax
+2:	movl %edx, %ecx
+	andl $0x1c, %edx
+	je 4f
+	shrl $2, %edx		# This clears CF
+3:	adcl (%esi), %eax
+	lea 4(%esi), %esi
+	dec %edx
+	jne 3b
+	adcl $0, %eax
+4:	andl $3, %ecx
+	jz 7f
+	cmpl $2, %ecx
+	jb 5f
+	movw (%esi),%cx
+	leal 2(%esi),%esi
+	je 6f
+	shll $16,%ecx
+5:	movb (%esi),%cl
+6:	addl %ecx,%eax
+	adcl $0, %eax 
+7:	
+	popl %ebx
+	popl %esi
+	ret
+
+#else /* CPU==686 */
+
+csum_partial:
+	movl 12(%esp),%eax	# Function arg: unsigned int sum
+	movl 8(%esp),%ecx	# Function arg: int len
+	movl 4(%esp),%esi	# Function arg:	const unsigned char *buf
+
+	testl $2, %esi         
+	jnz 30f                 
+10:
+	movl %ecx, %edx
+	movl %ecx, %ebx
+	andl $0x7c, %ebx
+	shrl $7, %ecx
+	addl %ebx,%esi
+	shrl $2, %ebx  
+	negl %ebx
+	lea 45f(%ebx,%ebx,2), %ebx
+	testl %esi, %esi
+	jmp *%ebx
+
+	# Handle 2-byte-aligned regions
+20:	addw (%esi), %ax
+	lea 2(%esi), %esi
+	adcl $0, %eax
+	jmp 10b
+
+30:	subl $2, %ecx          
+	ja 20b                 
+	je 32f
+	movzbl (%esi),%ebx	# csumming 1 byte, 2-aligned
+	addl %ebx, %eax
+	adcl $0, %eax
+	jmp 80f
+32:
+	addw (%esi), %ax	# csumming 2 bytes, 2-aligned
+	adcl $0, %eax
+	jmp 80f
+
+40: 
+	addl -128(%esi), %eax
+	adcl -124(%esi), %eax
+	adcl -120(%esi), %eax
+	adcl -116(%esi), %eax   
+	adcl -112(%esi), %eax   
+	adcl -108(%esi), %eax
+	adcl -104(%esi), %eax
+	adcl -100(%esi), %eax
+	adcl -96(%esi), %eax
+	adcl -92(%esi), %eax
+	adcl -88(%esi), %eax
+	adcl -84(%esi), %eax
+	adcl -80(%esi), %eax
+	adcl -76(%esi), %eax
+	adcl -72(%esi), %eax
+	adcl -68(%esi), %eax
+	adcl -64(%esi), %eax     
+	adcl -60(%esi), %eax     
+	adcl -56(%esi), %eax     
+	adcl -52(%esi), %eax   
+	adcl -48(%esi), %eax   
+	adcl -44(%esi), %eax
+	adcl -40(%esi), %eax
+	adcl -36(%esi), %eax
+	adcl -32(%esi), %eax
+	adcl -28(%esi), %eax
+	adcl -24(%esi), %eax
+	adcl -20(%esi), %eax
+	adcl -16(%esi), %eax
+	adcl -12(%esi), %eax
+	adcl -8(%esi), %eax
+	adcl -4(%esi), %eax
+45:
+	lea 128(%esi), %esi
+	adcl $0, %eax
+	dec %ecx
+	jge 40b
+	movl %edx, %ecx
+50:	andl $3, %ecx
+	jz 80f
+
+	# Handle the last 1-3 bytes without jumping
+	notl %ecx		# 1->2, 2->1, 3->0, higher bits are masked
+	movl $0xffffff,%ebx	# by the shll and shrl instructions
+	shll $3,%ecx
+	shrl %cl,%ebx
+	andl -128(%esi),%ebx	# esi is 4-aligned so should be ok
+	addl %ebx,%eax
+	adcl $0,%eax
+80: 
+	ret
+				
+#endif /* CPU==686 */ 
+
+/*
+unsigned int csum_partial_copy_generic (const char *src, char *dst,
+				  int len, int sum, int *src_err_ptr, int *dst_err_ptr)
+ */ 
+
+/*
+ * Copy from ds while checksumming, otherwise like csum_partial
+ *
+ * The macros SRC and DST specify the type of access for the instruction.
+ * thus we can call a custom exception handler for all access types.
+ *
+ * FIXME: could someone double-check whether I haven't mixed up some SRC and
+ *	  DST definitions? It's damn hard to trigger all cases.  I hope I got
+ *	  them all but there's no guarantee.
+ */
+
+#define SRC(y...)			\
+	9999: y;			\
+	.section __ex_table, "a";	\
+	.long 9999b, 6001f	;	\
+	.previous
+
+#define DST(y...)			\
+	9999: y;			\
+	.section __ex_table, "a";	\
+	.long 9999b, 6002f	;	\
+	.previous
+
+.align 4
+.globl csum_partial_copy_generic
+				
+#if CPU!=686
+
+#define ARGBASE 16		
+#define FP		12
+		
+csum_partial_copy_generic:
+	subl  $4,%esp	
+	pushl %edi
+	pushl %esi
+	pushl %ebx
+	movl ARGBASE+16(%esp),%eax	# sum
+	movl ARGBASE+12(%esp),%ecx	# len
+	movl ARGBASE+4(%esp),%esi	# src
+	movl ARGBASE+8(%esp),%edi	# dst
+
+	testl $2, %edi			# Check alignment. 
+	jz 2f				# Jump if alignment is ok.
+	subl $2, %ecx			# Alignment uses up two bytes.
+	jae 1f				# Jump if we had at least two bytes.
+	addl $2, %ecx			# ecx was < 2.  Deal with it.
+	jmp 4f
+SRC(1:	movw (%esi), %bx	)
+	addl $2, %esi
+DST(	movw %bx, (%edi)	)
+	addl $2, %edi
+	addw %bx, %ax	
+	adcl $0, %eax
+2:
+	movl %ecx, FP(%esp)
+	shrl $5, %ecx
+	jz 2f
+	testl %esi, %esi
+SRC(1:	movl (%esi), %ebx	)
+SRC(	movl 4(%esi), %edx	)
+	adcl %ebx, %eax
+DST(	movl %ebx, (%edi)	)
+	adcl %edx, %eax
+DST(	movl %edx, 4(%edi)	)
+
+SRC(	movl 8(%esi), %ebx	)
+SRC(	movl 12(%esi), %edx	)
+	adcl %ebx, %eax
+DST(	movl %ebx, 8(%edi)	)
+	adcl %edx, %eax
+DST(	movl %edx, 12(%edi)	)
+
+SRC(	movl 16(%esi), %ebx 	)
+SRC(	movl 20(%esi), %edx	)
+	adcl %ebx, %eax
+DST(	movl %ebx, 16(%edi)	)
+	adcl %edx, %eax
+DST(	movl %edx, 20(%edi)	)
+
+SRC(	movl 24(%esi), %ebx	)
+SRC(	movl 28(%esi), %edx	)
+	adcl %ebx, %eax
+DST(	movl %ebx, 24(%edi)	)
+	adcl %edx, %eax
+DST(	movl %edx, 28(%edi)	)
+
+SRC(	lea 32(%esi), %esi	)
+DST(	lea 32(%edi), %edi	)
+	dec %ecx
+	jne 1b
+	adcl $0, %eax
+2:	movl FP(%esp), %edx
+	movl %edx, %ecx
+	andl $0x1c, %edx
+	je 4f
+	shrl $2, %edx			# This clears CF
+SRC(3:	movl (%esi), %ebx	)
+	adcl %ebx, %eax
+DST(	movl %ebx, (%edi)	)
+SRC(	lea 4(%esi), %esi	)
+DST(	lea 4(%edi), %edi	)
+	dec %edx
+	jne 3b
+	adcl $0, %eax
+4:	andl $3, %ecx
+	jz 7f
+	cmpl $2, %ecx
+	jb 5f
+SRC(	movw (%esi), %cx	)
+SRC(	leal 2(%esi), %esi	)
+DST(	movw %cx, (%edi)	)
+DST(	leal 2(%edi), %edi	)
+	je 6f
+	shll $16,%ecx
+SRC(5:	movb (%esi), %cl	)
+DST(	movb %cl, (%edi)	)
+6:	addl %ecx, %eax
+	adcl $0, %eax
+7:
+5000:
+
+# Exception handler:
+.section .fixup, "ax"							
+
+6000:
+
+	movl $-EFAULT, (%ebx)
+
+	# zero the complete destination - computing the rest
+	# is too much work 
+	movl ARGBASE+8(%esp), %edi	# dst
+	movl ARGBASE+12(%esp), %ecx	# len
+	xorl %eax,%eax
+	rep ; stosb
+
+	jmp 5000b
+
+6001:
+	movl ARGBASE+20(%esp), %ebx	# src_err_ptr
+	jmp 6000b
+
+6002:
+	movl ARGBASE+24(%esp), %ebx	# dst_err_ptr
+	jmp 6000b
+
+.previous
+
+	popl %ebx
+	popl %esi
+	popl %edi
+	popl %ecx			# equivalent to addl $4,%esp
+	ret	
+
+#else
+
+/* Version for PentiumII/PPro */
+
+#define ROUND1(x) \
+	SRC(movl x(%esi), %ebx	)	;	\
+	addl %ebx, %eax\n		;	\
+	DST(movl %ebx, x(%edi)	)	; 
+
+#define ROUND(x) \
+	SRC(movl x(%esi), %ebx	)	;	\
+	adcl %ebx, %eax			;	\
+	DST(movl %ebx, x(%edi)	)	;
+
+#define ARGBASE 12
+		
+csum_partial_copy_generic:
+	pushl %ebx
+	pushl %edi
+	pushl %esi
+	movl ARGBASE+4(%esp),%esi	#src
+	movl ARGBASE+8(%esp),%edi	#dst	
+	movl ARGBASE+12(%esp),%ecx	#len
+	movl ARGBASE+16(%esp),%eax	#sum
+	movl %ecx, %edx  
+	movl %ecx, %ebx  
+	shrl $6, %ecx     
+	andl $0x3c, %ebx  
+	negl %ebx
+	subl %ebx, %esi  
+	subl %ebx, %edi  
+	lea 3f(%ebx,%ebx), %ebx
+	testl %esi, %esi 
+	jmp *%ebx         
+1:	addl $64,%esi
+	addl $64,%edi 
+	ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)	
+	ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)	
+	ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)	
+	ROUND (-16) ROUND(-12) ROUND(-8)  ROUND(-4)	
+3:	adcl $0,%eax
+	dec %ecx
+	jge 1b
+4:      andl $3, %edx
+	jz 7f
+	cmpl $2, %edx
+	jb 5f
+SRC(	movw (%esi), %dx         )
+	leal 2(%esi), %esi
+DST(	movw %dx, (%edi)         )
+	leal 2(%edi), %edi
+	je 6f
+	shll $16,%edx
+5:
+SRC(	movb (%esi), %dl         )
+DST(	movb %dl, (%edi)         )
+6:	addl %edx, %eax
+	adcl $0, %eax
+7:
+.section .fixup, "ax"
+6000:	movl $-EFAULT, (%ebx)
+	# zero the complete destination (computing the rest is too much work)
+	movl ARGBASE+8(%esp),%edi	# dst
+	movl ARGBASE+12(%esp),%ecx	# len
+	xorl %eax,%eax
+	rep; stosb
+	jmp 7b
+6001:	movl ARGBASE+20(%esp), %ebx	# src_err_ptr
+	jmp 6000b	
+6002:	movl ARGBASE+24(%esp), %ebx	# dst_err_ptr
+	jmp 6000b
+.previous				
+
+	popl %esi
+	popl %edi
+	popl %ebx
+	ret
+				
+#undef ROUND
+#undef ROUND1		
+		
+#endif	/* CPU==i686 */ 
diff -u --recursive --new-file v2.1.132/linux/arch/i386/lib/checksum.c linux/arch/i386/lib/checksum.c
--- v2.1.132/linux/arch/i386/lib/checksum.c	Thu Sep 17 17:53:34 1998
+++ linux/arch/i386/lib/checksum.c	Wed Dec 31 16:00:00 1969
@@ -1,459 +0,0 @@
-/*
- * INET		An implementation of the TCP/IP protocol suite for the LINUX
- *		operating system.  INET is implemented using the  BSD Socket
- *		interface as the means of communication with the user level.
- *
- *		IP/TCP/UDP checksumming routines
- *
- * Authors:	Jorge Cwik, <jorge@laser.satlink.net>
- *		Arnt Gulbrandsen, <agulbra@nvg.unit.no>
- *		Tom May, <ftom@netcom.com>
- *              Pentium Pro/II routines:
- *              Alexander Kjeldaas <astor@guardian.no>
- *              Finn Arne Gangstad <finnag@guardian.no>
- *		Lots of code moved from tcp.c and ip.c; see those files
- *		for more names.
- *
- * Changes:     Ingo Molnar, converted csum_partial_copy() to 2.1 exception
- *			     handling.
- *		Andi Kleen,  add zeroing on error, fix constraints.
- *
- * To fix:
- *		Convert to pure asm, because this file is too hard
- *		for gcc's register allocator and it is not clear if the
- *	 	contraints are correct.
- *
- *		This program is free software; you can redistribute it and/or
- *		modify it under the terms of the GNU General Public License
- *		as published by the Free Software Foundation; either version
- *		2 of the License, or (at your option) any later version.
- */
-
-#include <net/checksum.h>
-
-/*
- * computes a partial checksum, e.g. for TCP/UDP fragments
- */
-
-#if CPU!=686
-
-unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) {
-	  /*
-	   * Experiments with Ethernet and SLIP connections show that buff
-	   * is aligned on either a 2-byte or 4-byte boundary.  We get at
-	   * least a twofold speedup on 486 and Pentium if it is 4-byte aligned.
-	   * Fortunately, it is easy to convert 2-byte alignment to 4-byte
-	   * alignment for the unrolled loop.
-	   */
-	__asm__("
-	    testl $2, %%esi		# Check alignment.
-	    jz 2f			# Jump if alignment is ok.
-	    subl $2, %%ecx		# Alignment uses up two bytes.
-	    jae 1f			# Jump if we had at least two bytes.
-	    addl $2, %%ecx		# ecx was < 2.  Deal with it.
-	    jmp 4f
-1:	    movw (%%esi), %%bx
-	    addl $2, %%esi
-	    addw %%bx, %%ax
-	    adcl $0, %%eax
-2:
-	    movl %%ecx, %%edx
-	    shrl $5, %%ecx
-	    jz 2f
-	    testl %%esi, %%esi
-1:	    movl (%%esi), %%ebx
-	    adcl %%ebx, %%eax
-	    movl 4(%%esi), %%ebx
-	    adcl %%ebx, %%eax
-	    movl 8(%%esi), %%ebx
-	    adcl %%ebx, %%eax
-	    movl 12(%%esi), %%ebx
-	    adcl %%ebx, %%eax
-	    movl 16(%%esi), %%ebx
-	    adcl %%ebx, %%eax
-	    movl 20(%%esi), %%ebx
-	    adcl %%ebx, %%eax
-	    movl 24(%%esi), %%ebx
-	    adcl %%ebx, %%eax
-	    movl 28(%%esi), %%ebx
-	    adcl %%ebx, %%eax
-	    lea 32(%%esi), %%esi
-	    dec %%ecx
-	    jne 1b
-	    adcl $0, %%eax
-2:	    movl %%edx, %%ecx
-	    andl $0x1c, %%edx
-	    je 4f
-	    shrl $2, %%edx	# This clears CF
-3:	    adcl (%%esi), %%eax
-	    lea 4(%%esi), %%esi
-	    dec %%edx
-	    jne 3b
-	    adcl $0, %%eax
-4:	    andl $3, %%ecx
-	    jz 7f
-	    cmpl $2, %%ecx
-	    jb 5f
-	    movw (%%esi),%%cx
-	    leal 2(%%esi),%%esi
-	    je 6f
-	    shll $16,%%ecx
-5:	    movb (%%esi),%%cl
-6:	    addl %%ecx,%%eax
-	    adcl $0, %%eax 
-7:	    "
-	: "=a"(sum)
-	: "0"(sum), "c"(len), "S"(buff)
-	: "bx", "dx", "si", "cx", "memory");
-	return(sum);
-}
-
-#else  /* 686 */
-
-unsigned int csum_partial(const unsigned char * buf, int len, unsigned int sum) {
-         __asm__ ("
-            testl $2, %%esi         
-            jnz 30f                 
-10:
-            movl %%ecx, %%edx
-            movl %%ecx, %%ebx
-            andl $0x7c, %%ebx
-            shrl $7, %%ecx
-            addl %%ebx,%%esi
-            shrl $2, %%ebx  
-            negl %%ebx
-            lea 45f(%%ebx,%%ebx,2), %%ebx
-            testl %%esi, %%esi
-            jmp *%%ebx
-
-            # Handle 2-byte-aligned regions
-20:         addw (%%esi), %%ax
-            lea 2(%%esi), %%esi
-            adcl $0, %%eax
-            jmp 10b
-
-30:         subl $2, %%ecx          
-            ja 20b                 
-            je 32f
-            movzbl (%%esi),%%ebx # csumming 1 byte, 2-aligned
-            addl %%ebx, %%eax
-            adcl $0, %%eax
-            jmp 80f
-32:
-            addw (%%esi), %%ax # csumming 2 bytes, 2-aligned
-            adcl $0, %%eax
-            jmp 80f
-
-40: 
-	    addl -128(%%esi), %%eax
-            adcl -124(%%esi), %%eax
-            adcl -120(%%esi), %%eax
-            adcl -116(%%esi), %%eax   
-	    adcl -112(%%esi), %%eax   
-            adcl -108(%%esi), %%eax
-            adcl -104(%%esi), %%eax
-            adcl -100(%%esi), %%eax
-            adcl -96(%%esi), %%eax
-            adcl -92(%%esi), %%eax
-            adcl -88(%%esi), %%eax
-            adcl -84(%%esi), %%eax
-            adcl -80(%%esi), %%eax
-            adcl -76(%%esi), %%eax
-            adcl -72(%%esi), %%eax
-            adcl -68(%%esi), %%eax
-	    adcl -64(%%esi), %%eax     
-            adcl -60(%%esi), %%eax     
-            adcl -56(%%esi), %%eax     
-            adcl -52(%%esi), %%eax   
-            adcl -48(%%esi), %%eax   
-            adcl -44(%%esi), %%eax
-            adcl -40(%%esi), %%eax
-            adcl -36(%%esi), %%eax
-            adcl -32(%%esi), %%eax
-            adcl -28(%%esi), %%eax
-            adcl -24(%%esi), %%eax
-            adcl -20(%%esi), %%eax
-            adcl -16(%%esi), %%eax
-            adcl -12(%%esi), %%eax
-            adcl -8(%%esi), %%eax
-            adcl -4(%%esi), %%eax
-45:
-            lea 128(%%esi), %%esi
-            adcl $0, %%eax
-            dec %%ecx
-            jge 40b
-            movl %%edx, %%ecx
-50:         andl $3, %%ecx
-            jz 80f
-
-            # Handle the last 1-3 bytes without jumping
-            notl %%ecx            # 1->2, 2->1, 3->0, higher bits are masked
-	    movl $0xffffff,%%ebx  # by the shll and shrl instructions
-	    shll $3,%%ecx
-	    shrl %%cl,%%ebx
-	    andl -128(%%esi),%%ebx # esi is 4-aligned so should be ok
-	    addl %%ebx,%%eax
-	    adcl $0,%%eax
-80:          "
-        : "=a"(sum)
-        : "0"(sum), "c"(len), "S"(buf)
-        : "bx", "dx", "cx", "si", "memory");
-        return(sum);
-}
-
-#endif
-
-/*
- * Copy from ds while checksumming, otherwise like csum_partial
- *
- * The macros SRC and DST specify the type of access for the instruction.
- * thus we can call a custom exception handler for all access types.
- *
- * FIXME: could someone double-check whether I haven't mixed up some SRC and
- *	  DST definitions? It's damn hard to trigger all cases.  I hope I got
- *	  them all but there's no guarantee.
- */
-
-#define SRC(y...)			\
-"	9999: "#y";			\n \
-	.section __ex_table, \"a\";	\n \
-	.long 9999b, 6001f		\n \
-	.previous\n"
-
-#define DST(y...)			\
-"	9999: "#y";			\n \
-	.section __ex_table, \"a\";	\n \
-	.long 9999b, 6002f		\n \
-	.previous\n"
-
-#if CPU!=686
-
-unsigned int csum_partial_copy_generic (const char *src, char *dst,
-				  int len, int sum, int *src_err_ptr, int *dst_err_ptr)
-{
-    __u32 tmp_var;
-
-    __asm__ __volatile__ ( "
-		movl  %6,%%edi
-		testl $2, %%edi		# Check alignment. 
-		jz 2f			# Jump if alignment is ok.
-		subl $2, %%ecx		# Alignment uses up two bytes.
-		jae 1f			# Jump if we had at least two bytes.
-		addl $2, %%ecx		# ecx was < 2.  Deal with it.
-		jmp 4f
-"SRC(	1:	movw (%%esi), %%bx				)"
-		addl $2, %%esi
-"DST(		movw %%bx, (%%edi)				)"
-		addl $2, %%edi
-		addw %%bx, %%ax	
-		adcl $0, %%eax
-	2:
-		movl %%ecx, %8
-		shrl $5, %%ecx
-		jz 2f
-		testl %%esi, %%esi
-"SRC(	1:	movl (%%esi), %%ebx				)"
-"SRC(		movl 4(%%esi), %%edx				)"
-		adcl %%ebx, %%eax
-"DST(		movl %%ebx, (%%edi)				)"
-		adcl %%edx, %%eax
-"DST(		movl %%edx, 4(%%edi)				)"
-
-"SRC(		movl 8(%%esi), %%ebx				)"
-"SRC(		movl 12(%%esi), %%edx				)"
-		adcl %%ebx, %%eax
-"DST(		movl %%ebx, 8(%%edi)				)"
-		adcl %%edx, %%eax
-"DST(		movl %%edx, 12(%%edi)				)"
-
-"SRC(		movl 16(%%esi), %%ebx 				)"
-"SRC(		movl 20(%%esi), %%edx				)"
-		adcl %%ebx, %%eax
-"DST(		movl %%ebx, 16(%%edi)				)"
-		adcl %%edx, %%eax
-"DST(		movl %%edx, 20(%%edi)				)"
-
-"SRC(		movl 24(%%esi), %%ebx				)"
-"SRC(		movl 28(%%esi), %%edx				)"
-		adcl %%ebx, %%eax
-"DST(		movl %%ebx, 24(%%edi)				)"
-		adcl %%edx, %%eax
-"DST(		movl %%edx, 28(%%edi)				)"
-
-"SRC(		lea 32(%%esi), %%esi				)"
-"DST(		lea 32(%%edi), %%edi				)"
-		dec %%ecx
-		jne 1b
-		adcl $0, %%eax
-	2:	movl %8, %%edx
-		movl %%edx, %%ecx
-		andl $0x1c, %%edx
-		je 4f
-		shrl $2, %%edx		# This clears CF
-"SRC(	3:	movl (%%esi), %%ebx				)"
-		adcl %%ebx, %%eax
-"DST(		movl %%ebx, (%%edi)				)"
-"SRC(		lea 4(%%esi), %%esi				)"
-"DST(		lea 4(%%edi), %%edi				)"
-		dec %%edx
-		jne 3b
-		adcl $0, %%eax
-	4:	andl $3, %%ecx
-		jz 7f
-		cmpl $2, %%ecx
-		jb 5f
-"SRC(		movw (%%esi), %%cx				)"
-"SRC(		leal 2(%%esi), %%esi				)"
-"DST(		movw %%cx, (%%edi)				)"
-"DST(		leal 2(%%edi), %%edi				)"
-		je 6f
-		shll $16,%%ecx
-"SRC(	5:	movb (%%esi), %%cl				)"
-"DST(		movb %%cl, (%%edi)				)"
-	6:	addl %%ecx, %%eax
-		adcl $0, %%eax
-	7:
-
-5000:
-
-# Exception handler:
-################################################
-						#
-.section .fixup, \"ax\"				#
-						#
-6000:						#
-						#
-	movl	%7, (%%ebx)			#
-						#
-# zero the complete destination - computing the rest
-# is too much work 
-	movl	%6, %%edi
-	movl	%9, %%ecx
-	xorl	%%eax,%%eax
-	rep ; stosb
-						#
-	jmp	5000b				#
-						#
-6001:						#
-	movl    %1, %%ebx			#
-	jmp	6000b				#
-						#
-6002:						#
-	movl    %2, %%ebx			#
-	jmp	6000b				#
-						#
-.previous					#
-						#
-################################################
-
-"
-	: "=a" (sum)
-	: "m" (src_err_ptr), "m" (dst_err_ptr),
-	  "0" (sum), "c" (len), "S" (src), "m" (dst),
-		"i" (-EFAULT), "m"(tmp_var),
-		"m" (len)
-	: "bx", "dx", "si", "di", "cx", "memory" );
-
-    return(sum);
-}
-
-#else /* CPU == 686 */
-
-#define ROUND1(x) \
-        SRC(movl x(%%esi), %%ebx         ) \
-        "addl %%ebx, %%eax\n" \
-        DST(movl %%ebx, x(%%edi)         )
-
-#define ROUND(x) \
-        SRC(movl x(%%esi), %%ebx         ) \
-        "adcl %%ebx, %%eax\n" \
-        DST(movl %%ebx, x(%%edi)         )
-
-unsigned int csum_partial_copy_generic (const char *src, char *dst,
-				  int len, int sum, int *src_err_ptr, int *dst_err_ptr)
-{
-	__asm__ __volatile__ ("
-	movl %4,%%ecx
-        movl %%ecx, %%edx  
-        movl %%ecx, %%ebx  
-        shrl $6, %%ecx     
-        andl $0x3c, %%ebx  
-        negl %%ebx
-        subl %%ebx, %%esi  
-        subl %%ebx, %%edi  
-        lea 3f(%%ebx,%%ebx), %%ebx
-        testl %%esi, %%esi 
-        jmp *%%ebx         
-1:      addl $64,%%esi
-        addl $64,%%edi\n" 
-ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52)
-ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36)
-ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20)
-ROUND (-16) ROUND(-12) ROUND(-8)  ROUND(-4)
-"3:     adcl $0,%%eax
-        dec %%ecx
-        jge 1b
-4:      andl $3, %%edx
-        jz 7f
-        cmpl $2, %%edx
-        jb 5f
-  " SRC(movw (%%esi), %%dx         )"
-        leal 2(%%esi), %%esi
-  " DST(movw %%dx, (%%edi)         )"
-        leal 2(%%edi), %%edi
-        je 6f
-        shll $16,%%edx
-5:" SRC(movb (%%esi), %%dl         )"
-  " DST(movb %%dl, (%%edi)         )"
-6:      addl %%edx, %%eax
-        adcl $0, %%eax
-7:
-.section .fixup, \"ax\"
-6000:	movl	%7, (%%ebx)
-# zero the complete destination (computing the rest is too much work)
-	movl	%8,%%edi
-	movl	%4,%%ecx
-	xorl	%%eax,%%eax
-	rep ; stosb
-	jmp	7b
-6001:	movl    %1, %%ebx	
-	jmp	6000b	
-6002:	movl    %2, %%ebx
-	jmp	6000b
-.previous
-        "
-	: "=a"(sum)
-        : "m"(src_err_ptr), "m"(dst_err_ptr), 
-	  "0"(sum), "m"(len), "S"(src), "D" (dst),
-	  "i" (-EFAULT),
-	  "m" (dst)
-        : "bx", "cx", "si", "di", "dx", "memory" );
-	return(sum);
-}
-
-#undef ROUND
-#undef ROUND1
-
-#endif
-
-
-#undef SRC
-#undef DST
-
-/*
- * FIXME: old compatibility stuff, will be removed soon.
- */
-
-unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum)
-{
-	int src_err=0, dst_err=0;
-
-	sum = csum_partial_copy_generic ( src, dst, len, sum, &src_err, &dst_err);
-
-	if (src_err || dst_err)
-		printk("old csum_partial_copy_fromuser(), tell mingo to convert me.\n");
-
-	return sum;
-}
-
-
diff -u --recursive --new-file v2.1.132/linux/arch/i386/lib/delay.c linux/arch/i386/lib/delay.c
--- v2.1.132/linux/arch/i386/lib/delay.c	Fri Oct  9 13:27:05 1998
+++ linux/arch/i386/lib/delay.c	Sun Dec 27 10:36:38 1998
@@ -19,23 +19,23 @@
 
 void __delay(unsigned long loops)
 {
+	int d0;
 	__asm__ __volatile__(
 		"\tjmp 1f\n"
 		".align 16\n"
 		"1:\tjmp 2f\n"
 		".align 16\n"
 		"2:\tdecl %0\n\tjns 2b"
-		:/* no outputs */
-		:"a" (loops)
-		:"ax");
+		:"=&a" (d0)
+		:"0" (loops));
 }
 
 inline void __const_udelay(unsigned long xloops)
 {
+	int d0;
 	__asm__("mull %0"
-		:"=d" (xloops)
-		:"a" (xloops),"0" (current_cpu_data.loops_per_sec)
-		:"ax");
+		:"=d" (xloops), "=&a" (d0)
+		:"1" (xloops),"0" (current_cpu_data.loops_per_sec));
         __delay(xloops);
 }
 
diff -u --recursive --new-file v2.1.132/linux/arch/i386/lib/old-checksum.c linux/arch/i386/lib/old-checksum.c
--- v2.1.132/linux/arch/i386/lib/old-checksum.c	Wed Dec 31 16:00:00 1969
+++ linux/arch/i386/lib/old-checksum.c	Sun Dec 27 10:32:09 1998
@@ -0,0 +1,19 @@
+/*
+ * FIXME: old compatibility stuff, will be removed soon.
+ */
+
+#include <net/checksum.h>
+
+unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum)
+{
+	int src_err=0, dst_err=0;
+
+	sum = csum_partial_copy_generic ( src, dst, len, sum, &src_err, &dst_err);
+
+	if (src_err || dst_err)
+		printk("old csum_partial_copy_fromuser(), tell mingo to convert me.\n");
+
+	return sum;
+}
+
+
diff -u --recursive --new-file v2.1.132/linux/arch/i386/lib/usercopy.c linux/arch/i386/lib/usercopy.c
--- v2.1.132/linux/arch/i386/lib/usercopy.c	Wed Aug 26 11:37:33 1998
+++ linux/arch/i386/lib/usercopy.c	Sun Dec 27 10:36:38 1998
@@ -29,6 +29,8 @@
  */
 
 #define __do_strncpy_from_user(dst,src,count,res)			   \
+do {									   \
+	int __d0, __d1, __d2;						   \
 	__asm__ __volatile__(						   \
 		"	testl %1,%1\n"					   \
 		"	jz 2f\n"					   \
@@ -41,16 +43,18 @@
 		"1:	subl %1,%0\n"					   \
 		"2:\n"							   \
 		".section .fixup,\"ax\"\n"				   \
-		"3:	movl %2,%0\n"					   \
+		"3:	movl %5,%0\n"					   \
 		"	jmp 2b\n"					   \
 		".previous\n"						   \
 		".section __ex_table,\"a\"\n"				   \
 		"	.align 4\n"					   \
 		"	.long 0b,3b\n"					   \
 		".previous"						   \
-		: "=d"(res), "=c"(count)				   \
-		: "i"(-EFAULT), "0"(count), "1"(count), "S"(src), "D"(dst) \
-		: "si", "di", "ax", "memory")
+		: "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1),	   \
+		  "=&D" (__d2)						   \
+		: "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \
+		: "memory");						   \
+} while (0)
 
 long
 __strncpy_from_user(char *dst, const char *src, long count)
@@ -74,14 +78,16 @@
  * Zero Userspace
  */
 
-#define __do_clear_user(addr,size)						\
-	__asm__ __volatile__(						\
+#define __do_clear_user(addr,size)					\
+do {									\
+	int __d0;							\
+  	__asm__ __volatile__(						\
 		"0:	rep; stosl\n"					\
-		"	movl %1,%0\n"					\
+		"	movl %2,%0\n"					\
 		"1:	rep; stosb\n"					\
 		"2:\n"							\
 		".section .fixup,\"ax\"\n"				\
-		"3:	lea 0(%1,%0,4),%0\n"				\
+		"3:	lea 0(%2,%0,4),%0\n"				\
 		"	jmp 2b\n"					\
 		".previous\n"						\
 		".section __ex_table,\"a\"\n"				\
@@ -89,9 +95,9 @@
 		"	.long 0b,3b\n"					\
 		"	.long 1b,2b\n"					\
 		".previous"						\
-		: "=&c"(size)						\
-		: "r"(size & 3), "0"(size / 4), "D"(addr), "a"(0)	\
-		: "di")
+		: "=&c"(size), "=&D" (__d0)				\
+		: "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0));	\
+} while (0)
 
 unsigned long
 clear_user(void *to, unsigned long n)
diff -u --recursive --new-file v2.1.132/linux/arch/i386/mm/init.c linux/arch/i386/mm/init.c
--- v2.1.132/linux/arch/i386/mm/init.c	Wed Dec 16 10:32:54 1998
+++ linux/arch/i386/mm/init.c	Sun Dec 27 10:39:50 1998
@@ -119,24 +119,28 @@
 pte_t * __bad_pagetable(void)
 {
 	extern char empty_bad_page_table[PAGE_SIZE];
+	int d0, d1;
 
-	__asm__ __volatile__("cld ; rep ; stosl":
-		:"a" (pte_val(BAD_PAGE)),
-		 "D" ((long) empty_bad_page_table),
-		 "c" (PAGE_SIZE/4)
-		:"di","cx");
+	__asm__ __volatile__("cld ; rep ; stosl"
+			     : "=&D" (d0), "=&c" (d1)
+			     : "a" (pte_val(BAD_PAGE)),
+			     "0" ((long) empty_bad_page_table),
+			     "1" (PAGE_SIZE/4)
+			     : "memory");
 	return (pte_t *) empty_bad_page_table;
 }
 
 pte_t __bad_page(void)
 {
 	extern char empty_bad_page[PAGE_SIZE];
+	int d0, d1;
 
-	__asm__ __volatile__("cld ; rep ; stosl":
-		:"a" (0),
-		 "D" ((long) empty_bad_page),
-		 "c" (PAGE_SIZE/4)
-		:"di","cx");
+	__asm__ __volatile__("cld ; rep ; stosl"
+			     : "=&D" (d0), "=&c" (d1)
+			     : "a" (0),
+			     "0" ((long) empty_bad_page),
+			     "1" (PAGE_SIZE/4)
+			     : "memory");
 	return pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED));
 }
 
@@ -298,7 +302,8 @@
 		 * NOTE! There are Linux loaders that will corrupt the EBDA
 		 * area, and as such this kind of SMP config may be less
 		 * trustworthy, simply because the SMP table may have been
-		 * stomped on during early boot.
+		 * stomped on during early boot. These loaders are buggy and
+		 * should be fixed.
 		 */
 		address = *(unsigned short *)phys_to_virt(0x40E);
 		address<<=4;
diff -u --recursive --new-file v2.1.132/linux/arch/i386/vmlinux.lds linux/arch/i386/vmlinux.lds
--- v2.1.132/linux/arch/i386/vmlinux.lds	Wed Sep  9 14:51:06 1998
+++ linux/arch/i386/vmlinux.lds	Sun Dec 27 22:45:13 1998
@@ -45,8 +45,12 @@
   . = ALIGN(4096);
   __init_end = .;
 
+  . = ALIGN(32);
+  .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+
   . = ALIGN(4096);
   .data.page_aligned : { *(.data.idt) }
+
 
   __bss_start = .;		/* BSS */
   .bss : {
diff -u --recursive --new-file v2.1.132/linux/arch/mips/kernel/irq.c linux/arch/mips/kernel/irq.c
--- v2.1.132/linux/arch/mips/kernel/irq.c	Fri Oct 23 22:01:19 1998
+++ linux/arch/mips/kernel/irq.c	Wed Dec 23 09:44:40 1998
@@ -287,7 +287,7 @@
 	}
 
 	/* wait for spurious interrupts to mask themselves out again */
-	for (delay = jiffies + HZ/10; delay > jiffies; )
+	for (delay = jiffies + HZ/10; time_before(jiffies, delay); )
 		/* about 100ms delay */;
 
 	/* now filter out any obviously spurious interrupts */
diff -u --recursive --new-file v2.1.132/linux/arch/ppc/8xx_io/uart.c linux/arch/ppc/8xx_io/uart.c
--- v2.1.132/linux/arch/ppc/8xx_io/uart.c	Sun Nov  8 14:02:44 1998
+++ linux/arch/ppc/8xx_io/uart.c	Wed Dec 23 09:44:40 1998
@@ -1692,7 +1692,7 @@
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
-		if (timeout && ((orig_jiffies + timeout) < jiffies))
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 		bdp = info->tx_cur;
 	} while (bdp->cbd_sc & BD_SC_READY);
diff -u --recursive --new-file v2.1.132/linux/arch/ppc/apus_defconfig linux/arch/ppc/apus_defconfig
--- v2.1.132/linux/arch/ppc/apus_defconfig	Thu Nov 19 09:56:27 1998
+++ linux/arch/ppc/apus_defconfig	Wed Dec 23 07:34:11 1998
@@ -14,6 +14,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
+# CONFIG_SMP is not set
 CONFIG_MACH_SPECIFIC=y
 
 #
diff -u --recursive --new-file v2.1.132/linux/arch/ppc/chrp_defconfig linux/arch/ppc/chrp_defconfig
--- v2.1.132/linux/arch/ppc/chrp_defconfig	Sun Nov  8 14:02:44 1998
+++ linux/arch/ppc/chrp_defconfig	Wed Dec 23 07:34:11 1998
@@ -14,6 +14,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
+# CONFIG_SMP is not set
 CONFIG_MACH_SPECIFIC=y
 
 #
diff -u --recursive --new-file v2.1.132/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig
--- v2.1.132/linux/arch/ppc/common_defconfig	Tue Dec 22 14:16:54 1998
+++ linux/arch/ppc/common_defconfig	Wed Dec 23 07:34:11 1998
@@ -14,6 +14,7 @@
 CONFIG_ALL_PPC=y
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
+# CONFIG_SMP is not set
 
 #
 # General setup
diff -u --recursive --new-file v2.1.132/linux/arch/ppc/config.in linux/arch/ppc/config.in
--- v2.1.132/linux/arch/ppc/config.in	Thu Nov 19 09:56:27 1998
+++ linux/arch/ppc/config.in	Wed Dec 23 07:34:11 1998
@@ -22,6 +22,9 @@
 if [ "$CONFIG_ALL_PPC" != "y" ];then
   define_bool CONFIG_MACH_SPECIFIC y
 fi
+
+bool 'Symmetric multi-processing support' CONFIG_SMP
+
 endmenu
 
 if [ "$CONFIG_MBX" = "y" ];then
diff -u --recursive --new-file v2.1.132/linux/arch/ppc/defconfig linux/arch/ppc/defconfig
--- v2.1.132/linux/arch/ppc/defconfig	Thu Nov 19 09:56:27 1998
+++ linux/arch/ppc/defconfig	Wed Dec 23 07:34:11 1998
@@ -14,6 +14,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
+# CONFIG_SMP is not set
 CONFIG_MACH_SPECIFIC=y
 
 #
diff -u --recursive --new-file v2.1.132/linux/arch/ppc/kernel/Makefile linux/arch/ppc/kernel/Makefile
--- v2.1.132/linux/arch/ppc/kernel/Makefile	Tue Dec 22 14:16:54 1998
+++ linux/arch/ppc/kernel/Makefile	Wed Dec 23 07:34:11 1998
@@ -42,7 +42,7 @@
 endif
 endif
 
-ifdef SMP
+ifdef CONFIG_SMP
 O_OBJS += smp.o
 endif
 
diff -u --recursive --new-file v2.1.132/linux/arch/ppc/lib/Makefile linux/arch/ppc/lib/Makefile
--- v2.1.132/linux/arch/ppc/lib/Makefile	Mon Jan 12 15:18:13 1998
+++ linux/arch/ppc/lib/Makefile	Wed Dec 23 07:34:11 1998
@@ -8,7 +8,7 @@
 O_TARGET = lib.o
 O_OBJS  = checksum.o string.o strcase.o
 
-ifdef SMP
+ifdef CONFIG_SMP
 O_OBJS += locks.o
 endif
 
diff -u --recursive --new-file v2.1.132/linux/arch/ppc/mbx_defconfig linux/arch/ppc/mbx_defconfig
--- v2.1.132/linux/arch/ppc/mbx_defconfig	Tue Dec 22 14:16:54 1998
+++ linux/arch/ppc/mbx_defconfig	Wed Dec 23 07:34:11 1998
@@ -14,6 +14,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 CONFIG_MBX=y
+CONFIG_SMP=n
 CONFIG_MACH_SPECIFIC=y
 CONFIG_SERIAL_CONSOLE=y
 
diff -u --recursive --new-file v2.1.132/linux/arch/ppc/pmac_defconfig linux/arch/ppc/pmac_defconfig
--- v2.1.132/linux/arch/ppc/pmac_defconfig	Thu Nov 19 09:56:27 1998
+++ linux/arch/ppc/pmac_defconfig	Wed Dec 23 07:34:11 1998
@@ -14,6 +14,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
+# CONFIG_SMP is not set
 CONFIG_MACH_SPECIFIC=y
 
 #
diff -u --recursive --new-file v2.1.132/linux/arch/ppc/prep_defconfig linux/arch/ppc/prep_defconfig
--- v2.1.132/linux/arch/ppc/prep_defconfig	Thu Nov 19 09:56:27 1998
+++ linux/arch/ppc/prep_defconfig	Wed Dec 23 07:34:11 1998
@@ -14,6 +14,7 @@
 # CONFIG_ALL_PPC is not set
 # CONFIG_APUS is not set
 # CONFIG_MBX is not set
+# CONFIG_SMP is not set
 CONFIG_MACH_SPECIFIC=y
 
 #
diff -u --recursive --new-file v2.1.132/linux/arch/sparc/ap1000/util.c linux/arch/sparc/ap1000/util.c
--- v2.1.132/linux/arch/sparc/ap1000/util.c	Sun Jun  7 11:16:28 1998
+++ linux/arch/sparc/ap1000/util.c	Wed Dec 23 09:44:40 1998
@@ -393,7 +393,7 @@
     unsigned end = jiffies + 20*HZ;
     /* we are booting from another cell */
     printk("waiting for the master cell\n");
-    while (jiffies < end) ;
+    while (time_before(jiffies, end)) ;
     printk("continuing\n");
   }
 }
diff -u --recursive --new-file v2.1.132/linux/drivers/acorn/block/fd1772.c linux/drivers/acorn/block/fd1772.c
--- v2.1.132/linux/drivers/acorn/block/fd1772.c	Wed Aug 26 11:37:34 1998
+++ linux/drivers/acorn/block/fd1772.c	Wed Dec 23 09:44:40 1998
@@ -1090,7 +1090,7 @@
 	NeedSeek = 0;
 
 	if ((timer_active & (1 << FLOPPY_TIMER)) &&
-	    timer_table[FLOPPY_TIMER].expires < jiffies + 5)
+	    time_after(jiffies + 5, timer_table[FLOPPY_TIMER].expires)) 
 		/* If the check for a disk change is done too early after this
 		 * last seek command, the WP bit still reads wrong :-((
 		 */
@@ -1424,7 +1424,7 @@
 	FDC1772_WRITE(FDC1772REG_CMD, FDC1772CMD_RESTORE | FDC1772CMDADD_H | FDC1772STEP_6);
 
 	/*printk("fd_test_drive_present: Going into timeout loop\n"); */
-	for (ok = 0, timeout = jiffies + 2 * HZ + HZ / 2; jiffies < timeout;) {
+	for (ok = 0, timeout = jiffies + 2 * HZ + HZ / 2; time_before(jiffies, timeout);) {
 		/*  What does this piece of atariism do? - query for an interrupt? */
 		/*  if (!(mfp.par_dt_reg & 0x20))
 		   break; */
diff -u --recursive --new-file v2.1.132/linux/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c
--- v2.1.132/linux/drivers/acorn/net/ether1.c	Wed Apr  8 19:36:25 1998
+++ linux/drivers/acorn/net/ether1.c	Wed Dec 23 09:44:41 1998
@@ -519,7 +519,7 @@
 	/* 586 should now unset iscp.busy */
 	i = jiffies + HZ/2;
 	while (ether1_inw (dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) {
-		if (jiffies > i) {
+		if (time_after(jiffies, i)) {
 			printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name);
 			return 1;
 		}
@@ -529,7 +529,7 @@
 	i += HZ/10;
 	while (((status = ether1_inw (dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS))
 			& STAT_COMPLETE) == 0) {
-		if (jiffies > i)
+		if (time_after(jiffies, i))
 			break;
 	}
 
@@ -546,7 +546,7 @@
 	i += HZ/10;
 	while (((status = ether1_inw (dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS))
 			& STAT_COMPLETE) == 0) {
-		if (jiffies > i)
+		if (time_after(jiffies, i))
 			break;
 	}
 
@@ -563,7 +563,7 @@
 	i += HZ/10;
 	while (((status = ether1_inw (dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS))
 			& STAT_COMPLETE) == 0) {
-		if (jiffies > i)
+		if (time_after(jiffies, i))
 			break;
 	}
 
@@ -580,7 +580,7 @@
 	i += HZ;
 	while (((status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS))
 			& STAT_COMPLETE) == 0) {
-		if (jiffies > i)
+		if (time_after(jiffies, i))
 			break;
 	}
 
diff -u --recursive --new-file v2.1.132/linux/drivers/acorn/scsi/acornscsi.c linux/drivers/acorn/scsi/acornscsi.c
--- v2.1.132/linux/drivers/acorn/scsi/acornscsi.c	Tue Dec 22 14:16:55 1998
+++ linux/drivers/acorn/scsi/acornscsi.c	Wed Dec 23 09:44:41 1998
@@ -323,7 +323,7 @@
     save_flags (flags);
     sti ();
 
-    while (jiffies < target_jiffies) barrier();
+    while (time_before(jiffies, target_jiffies)) barrier();
 
     restore_flags (flags);
 }
diff -u --recursive --new-file v2.1.132/linux/drivers/acorn/scsi/fas216.c linux/drivers/acorn/scsi/fas216.c
--- v2.1.132/linux/drivers/acorn/scsi/fas216.c	Tue Jul 21 00:15:30 1998
+++ linux/drivers/acorn/scsi/fas216.c	Wed Dec 23 09:44:41 1998
@@ -2049,7 +2049,7 @@
 	save_flags(flags);
 	sti();
 
-	while (jiffies < target_jiffies) barrier();
+	while (time_before(jiffies, target_jiffies)) barrier();
 
 	restore_flags(flags);
 
diff -u --recursive --new-file v2.1.132/linux/drivers/ap1000/ddv_util.c linux/drivers/ap1000/ddv_util.c
--- v2.1.132/linux/drivers/ap1000/ddv_util.c	Sun Jan 26 02:07:10 1997
+++ linux/drivers/ap1000/ddv_util.c	Wed Dec 23 09:44:41 1998
@@ -92,7 +92,7 @@
 		return(-1);
 	}
 	for (timeout=jiffies + 10; 
-	     (jiffies < timeout) || (OPT_IO(PBUF0) == 0);
+	     time_before(jiffies, timeout) || (OPT_IO(PBUF0) == 0);
 	     ) /* wait */ ;
 	if (OPT_IO(PBUF0) == 0) {
 		printk("WARNING: option kernel didn't startup\n");
diff -u --recursive --new-file v2.1.132/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.1.132/linux/drivers/block/genhd.c	Thu Nov 19 09:56:28 1998
+++ linux/drivers/block/genhd.c	Sun Dec 27 10:44:45 1998
@@ -317,11 +317,50 @@
 #endif
 
 #ifdef CONFIG_BSD_DISKLABEL
+static void check_and_add_bsd_partition(struct gendisk *hd, struct bsd_partition *bsd_p)
+{
+	struct hd_struct *lin_p;
+		/* check relative position of partitions.  */
+	for (lin_p = hd->part + 1; lin_p - hd->part < 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)
+			continue;	
+			/* equal -> no need to add */
+		if (lin_p->start_sect == bsd_p->p_offset && 
+			lin_p->nr_sects == bsd_p->p_size) 
+			return;
+			/* bsd living within dos partition */
+		if (lin_p->start_sect <= bsd_p->p_offset && lin_p->start_sect 
+			+ lin_p->nr_sects >= bsd_p->p_offset + bsd_p->p_size) {
+#ifdef DEBUG_BSD_DISKLABEL
+			printk("w: %d %ld+%ld,%d+%d", 
+				lin_p - hd->part, 
+				lin_p->start_sect, lin_p->nr_sects, 
+				bsd_p->p_offset, bsd_p->p_size);
+#endif
+			break;
+		}
+	 /* ouch: bsd and linux overlap. Don't even try for that partition */
+#ifdef DEBUG_BSD_DISKLABEL
+		printk("???: %d %ld+%ld,%d+%d",
+			lin_p - hd->part, lin_p->start_sect, lin_p->nr_sects,
+			bsd_p->p_offset, bsd_p->p_size);
+#endif
+		printk("???");
+		return;
+	} /* if the bsd partition is not currently known to linux, we end
+	   * up here 
+	   */
+	add_partition(hd, current_minor, bsd_p->p_offset, bsd_p->p_size);
+	current_minor++;
+}
 /* 
  * Create devices for BSD partitions listed in a disklabel, under a
  * dos-like partition. See extended_partition() for more information.
  */
-static void bsd_disklabel_partition(struct gendisk *hd, kdev_t dev)
+static void bsd_disklabel_partition(struct gendisk *hd, kdev_t dev, 
+   int max_partitions)
 {
 	struct buffer_head *bh;
 	struct bsd_disklabel *l;
@@ -337,19 +376,56 @@
 		return;
 	}
 
-	p = &l->d_partitions[0];
-	while (p - &l->d_partitions[0] <= BSD_MAXPARTITIONS) {
+	if (l->d_npartitions < max_partitions)
+		max_partitions = l->d_npartitions;
+	for (p = l->d_partitions; p - l->d_partitions <  max_partitions; p++) {
 		if ((current_minor & mask) >= (4 + hd->max_p))
 			break;
 
-		if (p->p_fstype != BSD_FS_UNUSED) {
-			add_partition(hd, current_minor, p->p_offset, p->p_size);
+		if (p->p_fstype != BSD_FS_UNUSED) 
+			check_and_add_bsd_partition(hd, p);
+	}
+	brelse(bh);
+
+}
+#endif
+
+#ifdef CONFIG_UNIXWARE_DISKLABEL
+/*
+ * Create devices for Unixware partitions listed in a disklabel, under a
+ * dos-like partition. See extended_partition() for more information.
+ */
+static void unixware_partition(struct gendisk *hd, kdev_t dev)
+{
+	struct buffer_head *bh;
+	struct unixware_disklabel *l;
+	struct unixware_slice *p;
+	int mask = (1 << hd->minor_shift) - 1;
+
+	if (!(bh = bread(dev, 14, get_ptable_blocksize(dev))))
+		return;
+	bh->b_state = 0;
+	l = (struct unixware_disklabel *) (bh->b_data+512);
+	if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
+	    le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
+		brelse(bh);
+		return;
+	}
+	printk(" <unixware:");
+	p = &l->vtoc.v_slice[1];
+	/* I omit the 0th slice as it is the same as whole disk. */
+	while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
+		if ((current_minor & mask) == 0)
+			break;
+
+		if (p->s_label != UNIXWARE_FS_UNUSED) {
+			add_partition(hd, current_minor, START_SECT(p), NR_SECTS(p));
 			current_minor++;
 		}
 		p++;
 	}
 	brelse(bh);
-
+	printk(" >");
 }
 #endif
 
@@ -360,6 +436,11 @@
 	struct partition *p;
 	unsigned char *data;
 	int mask = (1 << hd->minor_shift) - 1;
+#ifdef CONFIG_BSD_DISKLABEL
+	/* no bsd disklabel as a default */
+	kdev_t bsd_kdev = 0;
+	int bsd_maxpart;
+#endif
 #ifdef CONFIG_BLK_DEV_IDE
 	int tested_for_xlate = 0;
 
@@ -476,12 +557,25 @@
 				hd->part[minor].nr_sects = 2;
 		}
 #ifdef CONFIG_BSD_DISKLABEL
+			/* tag first disklabel for late recognition */
 		if (SYS_IND(p) == BSD_PARTITION) {
-			printk(" <");
-			bsd_disklabel_partition(hd, MKDEV(hd->major, minor));
-			printk(" >");
+			printk("!");
+			if (!bsd_kdev) {
+				bsd_kdev = MKDEV(hd->major, minor);
+				bsd_maxpart = BSD_MAXPARTITIONS;
+			}
+		} else if (SYS_IND(p) == OPENBSD_PARTITION) {
+			printk("!");
+			if (!bsd_kdev) {
+				bsd_kdev = MKDEV(hd->major, minor);
+				bsd_maxpart = OPENBSD_MAXPARTITIONS;
+			}
 		}
 #endif
+#ifdef CONFIG_UNIXWARE_DISKLABEL
+		if (SYS_IND(p) == UNIXWARE_PARTITION)
+			unixware_partition(hd, MKDEV(hd->major, minor));
+#endif
 #ifdef CONFIG_SOLARIS_X86_PARTITION
 
 		/* james@bpgc.com: Solaris has a nasty indicator: 0x82
@@ -495,6 +589,13 @@
 		}
 #endif
 	}
+#ifdef CONFIG_BSD_DISKLABEL
+	if (bsd_kdev) {
+		printk(" <");
+		bsd_disklabel_partition(hd, bsd_kdev, bsd_maxpart);
+		printk(" >");
+	}
+#endif
 	/*
 	 *  Check for old-style Disk Manager partition table
 	 */
diff -u --recursive --new-file v2.1.132/linux/drivers/block/ide-cd.c linux/drivers/block/ide-cd.c
--- v2.1.132/linux/drivers/block/ide-cd.c	Sun Nov  8 14:02:51 1998
+++ linux/drivers/block/ide-cd.c	Wed Dec 23 07:56:01 1998
@@ -1,4 +1,3 @@
-#define VERBOSE_IDE_CD_ERRORS	1
 /*
  * linux/drivers/block/ide-cd.c
  * Copyright (C) 1994, 1995, 1996  scott snyder  <snyder@fnald0.fnal.gov>
@@ -28,7 +27,6 @@
  *   This will allow us to get automagically notified when the media changes
  *   on ATAPI drives (something the stock ATAPI spec is lacking).  Looks
  *   very cool.  I discovered its existance the other day at work...
- * -Fix ide_cdrom_reset so that it works (it does nothing right now)
  * -Query the drive to find what features are available before trying to
  *   use them (like trying to close the tray in drives that can't).
  * -Make it so that Pioneer CD DR-A24X and friends don't get screwed up on
@@ -36,9 +34,6 @@
  * -Handle older drives that can't report their speed. (i.e. check if they
  *   support a version of ATAPI where they can report their speed before
  *   checking their speed and believing what they return).
- * -It seems we do not always honor it when Uniform gets a request to change 
- *   the cdi->options.  We should _always_ check the options before doing stuff.
- *   This must be fixed.
  *
  *
  * ----------------------------------
@@ -226,9 +221,16 @@
  *                         Jens Axboe <axboe@image.dk>
  *                         Chris Zwilling <chris@cloudnet.com>
  *
+ * 4.51  Dec 23, 1998  -- Jens Axboe <axboe@image.dk>
+ *                      - ide_cdrom_reset enabled since the ide subsystem
+ *                         handles resets fine now. <axboe@image.dk>
+ *                      - Transfer size fix for Samsung CD-ROMs, thanks to
+ *                        "Ville Hallik" <ville.hallik@mail.ee>.
+ *                      - other minor stuff.
+ *
  *************************************************************************/
 
-#define IDECD_VERSION "4.50"
+#define IDECD_VERSION "4.51"
 
 #include <linux/module.h>
 #include <linux/types.h>
@@ -456,7 +458,7 @@
 	len *= 4;
 
 	pc->c[0] = REQUEST_SENSE;
-	pc->c[4] = len;
+	pc->c[4] = (unsigned char) len;
 	pc->buffer = (char *)reqbuf;
 	pc->buflen = len;
 	pc->sense_data = (struct atapi_request_sense *)failed_command;
@@ -856,7 +858,12 @@
 	if ((len % SECTOR_SIZE) != 0) {
 		printk ("%s: cdrom_read_intr: Bad transfer size %d\n",
 			drive->name, len);
-		printk ("  This drive is not supported by this version of the driver\n");
+		if (CDROM_CONFIG_FLAGS (drive)->limit_nframes)
+			printk ("  This drive is not supported by this version of the driver\n");
+		else {
+			printk ("  Trying to limit transfer sizes\n");
+			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
+		}
 		cdrom_end_request (0, drive);
 		return;
 	}
@@ -992,7 +999,6 @@
 {
 	struct packet_command pc;
 	struct request *rq = HWGROUP(drive)->rq;
-
 	int nsect, sector, nframes, frame, nskip;
 
 	/* Number of sectors to transfer. */
@@ -1029,8 +1035,10 @@
 	nframes = (nsect + SECTORS_PER_FRAME-1) / SECTORS_PER_FRAME;
 	frame = sector / SECTORS_PER_FRAME;
 
-	/* Largest number of frames was can transfer at once is 64k-1. */
-	nframes = MIN (nframes, 65535);
+	/* Largest number of frames was can transfer at once is 64k-1. For
+	   some drives we need to limit this even more. */
+	nframes = MIN (nframes, (CDROM_CONFIG_FLAGS (drive)->limit_nframes) ?
+		(65534 / CD_FRAMESIZE) : 65535);
 
 	/* Set up the command */
 	memset (&pc.c, 0, sizeof (pc.c));
@@ -1328,7 +1336,7 @@
 			struct atapi_request_sense *reqbuf = pc->sense_data;
 
 			if (reqbuf->sense_key == UNIT_ATTENTION)
-				;
+				cdrom_saw_media_change (drive);
 			else if (reqbuf->sense_key == NOT_READY &&
 				 reqbuf->asc == 4) {
 				/* The drive is in the process of loading
@@ -2477,19 +2485,12 @@
 int ide_cdrom_reset (struct cdrom_device_info *cdi)
 {
 
-/* This doesn't work reliably yet, and so it is currently just a stub. */
-
-#if 0 
 	ide_drive_t *drive = (ide_drive_t*) cdi->handle;
 	struct request req;
+
 	ide_init_drive_cmd (&req);
 	req.cmd = RESET_DRIVE_COMMAND;
 	return ide_do_drive_cmd (drive, &req, ide_wait);
-#endif
-
-/* For now, just return 0, as if things had worked...	*/
-	return 0;
-
 
 }
 
@@ -2916,10 +2917,10 @@
 	int major = HWIF(drive)->major;
 	int minor = drive->select.b.unit << PARTN_BITS;
 
-	ide_add_setting(drive,	"breada_readahead",	SETTING_RW,					BLKRAGET,		BLKRASET,		TYPE_INT,	0,	255,				1,	2,	&read_ahead[major],		NULL);
-	ide_add_setting(drive,	"file_readahead",	SETTING_RW,					BLKFRAGET,		BLKFRASET,		TYPE_INTA,	0,	INT_MAX,			1,	1024,	&max_readahead[major][minor],	NULL);
-	ide_add_setting(drive,	"max_kb_per_request",	SETTING_RW,					BLKSECTGET,		BLKSECTSET,		TYPE_INTA,	1,	255,				1,	2,	&max_sectors[major][minor],	NULL);
-	ide_add_setting(drive,	"dsc_overlap",		SETTING_RW,					-1,			-1,			TYPE_BYTE,	0,	1,				1,	1,	&drive->dsc_overlap,		NULL);
+	ide_add_setting(drive,	"breada_readahead",	SETTING_RW, BLKRAGET, BLKRASET, TYPE_INT, 0, 255, 1, 2, &read_ahead[major], NULL);
+	ide_add_setting(drive,	"file_readahead",	SETTING_RW, BLKFRAGET, BLKFRASET, TYPE_INTA, 0, INT_MAX, 1, 1024, &max_readahead[major][minor],	NULL);
+	ide_add_setting(drive,	"max_kb_per_request",	SETTING_RW, BLKSECTGET, BLKSECTSET, TYPE_INTA, 1, 255, 1, 2, &max_sectors[major][minor], NULL);
+	ide_add_setting(drive,	"dsc_overlap",		SETTING_RW, -1, -1, TYPE_BYTE, 0, 1, 1,	1, &drive->dsc_overlap, NULL);
 }
 
 static
@@ -2959,6 +2960,13 @@
 	CDROM_CONFIG_FLAGS (drive)->cd_rw = 0;
 	CDROM_CONFIG_FLAGS (drive)->no_eject = 1;
 	CDROM_CONFIG_FLAGS (drive)->supp_disc_present = 0;
+	
+	/* limit transfer size per interrupt. currently only one Samsung
+	   drive needs this. */
+	CDROM_CONFIG_FLAGS (drive)->limit_nframes = 0;
+	if (drive->id != NULL)
+		if (strcmp (drive->id->model, "SAMSUNG CD-ROM SCR-2432") == 0)
+			CDROM_CONFIG_FLAGS (drive)->limit_nframes = 1;
 
 #if ! STANDARD_ATAPI
 	/* by default Sanyo 3 CD changer support is turned off and
diff -u --recursive --new-file v2.1.132/linux/drivers/block/ide-cd.h linux/drivers/block/ide-cd.h
--- v2.1.132/linux/drivers/block/ide-cd.h	Sun Nov  8 14:02:51 1998
+++ linux/drivers/block/ide-cd.h	Mon Dec 28 14:09:30 1998
@@ -14,7 +14,7 @@
    memory, though. */
 
 #ifndef VERBOSE_IDE_CD_ERRORS
-#define VERBOSE_IDE_CD_ERRORS 0
+#define VERBOSE_IDE_CD_ERRORS 1
 #endif
 
 
@@ -130,6 +130,9 @@
 	__u8 cd_rw            : 1; /* Drive can write to CD-R/W media . */
 	__u8 supp_disc_present: 1; /* Changer can report exact contents
 				      of slots. */
+	__u8 limit_nframes    : 1; /* Drive does not provide data in
+				      multiples of SECTOR_SIZE when more
+				      than one interrupt is needed. */
 	__u8 seeking          : 1; /* Seeking in progress */
 	__u8 reserved         : 6;
 	byte max_speed; 	   /* Max speed of the drive */
diff -u --recursive --new-file v2.1.132/linux/drivers/block/ide-floppy.c linux/drivers/block/ide-floppy.c
--- v2.1.132/linux/drivers/block/ide-floppy.c	Fri Oct 23 22:01:20 1998
+++ linux/drivers/block/ide-floppy.c	Wed Dec 23 07:54:22 1998
@@ -633,6 +633,9 @@
 	}
 	if (error)
 		floppy->failed_pc = NULL;
+	/* Why does this happen? */
+	if (!rq)
+		return;
 	if (!IDEFLOPPY_RQ_CMD (rq->cmd)) {
 		ide_end_request (uptodate, hwgroup);
 		return;
diff -u --recursive --new-file v2.1.132/linux/drivers/block/ide-probe.c linux/drivers/block/ide-probe.c
--- v2.1.132/linux/drivers/block/ide-probe.c	Thu Nov 19 09:56:28 1998
+++ linux/drivers/block/ide-probe.c	Wed Dec 23 09:44:41 1998
@@ -291,7 +291,7 @@
 			delay_50ms();
 			OUT_BYTE(WIN_SRST, IDE_COMMAND_REG);
 			timeout = jiffies;
-			while ((GET_STAT() & BUSY_STAT) && jiffies < timeout + WAIT_WORSTCASE)
+			while ((GET_STAT() & BUSY_STAT) && time_before(jiffies, timeout + WAIT_WORSTCASE))
 				delay_50ms();
 			rc = try_to_identify(drive, cmd);
 		}
diff -u --recursive --new-file v2.1.132/linux/drivers/block/ll_rw_blk.c linux/drivers/block/ll_rw_blk.c
--- v2.1.132/linux/drivers/block/ll_rw_blk.c	Thu Nov 12 16:21:18 1998
+++ linux/drivers/block/ll_rw_blk.c	Mon Dec 28 11:19:19 1998
@@ -644,91 +644,12 @@
 		if (bh[i]) {
 			clear_bit(BH_Dirty, &bh[i]->b_state);
 			clear_bit(BH_Uptodate, &bh[i]->b_state);
+			bh[i]->b_end_io(bh[i], 0);
 		}
 	}
 	return;
 }
 
-void ll_rw_swap_file(int rw, kdev_t dev, unsigned int *b, int nb, char *buf)
-{
-	int i, j;
-	int buffersize;
-	int max_req;
-	unsigned long rsector;
-	kdev_t rdev;
-	struct request * req[8];
-	unsigned int major = MAJOR(dev);
-	struct semaphore sem = MUTEX_LOCKED;
-
-	if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
-		printk(KERN_NOTICE "ll_rw_swap_file: trying to swap to"
-                                   " nonexistent block-device\n");
-		return;
-	}
-	max_req = NR_REQUEST;
-	switch (rw) {
-		case READ:
-			break;
-		case WRITE:
-			max_req = (NR_REQUEST * 2) / 3;
-			if (is_read_only(dev)) {
-				printk(KERN_NOTICE
-                                       "Can't swap to read-only device %s\n",
-					kdevname(dev));
-				return;
-			}
-			break;
-		default:
-			panic("ll_rw_swap: bad block dev cmd, must be R/W");
-	}
-	buffersize = PAGE_SIZE / nb;
-
-	if ((major == LOOP_MAJOR) || (major == NBD_MAJOR))
-	     max_req >>= 1;
-	for (j=0, i=0; i<nb;)
-	{
-		for (; j < 8 && i < nb; j++, i++, buf += buffersize)
-		{
-		        rdev = dev;
-			rsector = b[i] * (buffersize >> 9);
-#ifdef CONFIG_BLK_DEV_MD
-			if (major==MD_MAJOR &&
-			    md_map (MINOR(dev), &rdev,
-				    &rsector, buffersize >> 9)) {
-			        printk (KERN_ERR
-                                        "Bad md_map in ll_rw_swap_file\n");
-				return;
-			}
-#endif
-			
-			if (j == 0) {
-				req[j] = get_request_wait(max_req, rdev);
-			} else {
-				unsigned long flags;
-				spin_lock_irqsave(&io_request_lock,flags);
-				req[j] = get_request(max_req, rdev);
-				spin_unlock_irqrestore(&io_request_lock,flags);
-				if (req[j] == NULL)
-					break;
-			}
-			req[j]->cmd = rw;
-			req[j]->errors = 0;
-			req[j]->sector = rsector;
-			req[j]->nr_sectors = buffersize >> 9;
-			req[j]->current_nr_sectors = buffersize >> 9;
-			req[j]->buffer = buf;
-			req[j]->sem = &sem;
-			req[j]->bh = NULL;
-			req[j]->next = NULL;
-			add_request(MAJOR(rdev)+blk_dev,req[j]);
-		}
-		run_task_queue(&tq_disk);
-		while (j > 0) {
-			j--;
-			down(&sem);
-		}
-	}
-}
 #ifdef CONFIG_STRAM_SWAP
 extern int stram_device_init( void );
 #endif
diff -u --recursive --new-file v2.1.132/linux/drivers/block/paride/pg.c linux/drivers/block/paride/pg.c
--- v2.1.132/linux/drivers/block/paride/pg.c	Sun Nov  8 14:02:51 1998
+++ linux/drivers/block/paride/pg.c	Wed Dec 23 09:44:41 1998
@@ -367,21 +367,21 @@
 	PG.status = 0;
 
 	j = 0;
-	while ((((r=RR(1,6))&go)||(stop&&(!(r&stop))))&&(jiffies<tmo)) {
+	while ((((r=RR(1,6))&go)||(stop&&(!(r&stop))))&&(time_before(jiffies,tmo))) {
 		if (j++ < PG_SPIN) udelay(PG_SPIN_DEL);
 		else pg_sleep(1);
 	}
 
-	if ((r&(STAT_ERR&stop))||(jiffies>=tmo)) {
+	if ((r&(STAT_ERR&stop))||time_after_eq(jiffies, tmo)) {
 	   s = RR(0,7);
 	   e = RR(0,1);
 	   p = RR(0,2);
 	   if (verbose > 1)
 	     printk("%s: %s: stat=0x%x err=0x%x phase=%d%s\n",
-		   PG.name,msg,s,e,p,(jiffies>=tmo)?" timeout":"");
+		   PG.name,msg,s,e,p,time_after_eq(jiffies, tmo)?" timeout":"");
 
 
-	   if (jiffies>=tmo) e |= 0x100;
+	   if (time_after_eq(jiffies, tmo)) e |= 0x100;
 	   PG.status = (e >> 4) & 0xff;
 	   return -1;
 	}
diff -u --recursive --new-file v2.1.132/linux/drivers/block/paride/pseudo.h linux/drivers/block/paride/pseudo.h
--- v2.1.132/linux/drivers/block/paride/pseudo.h	Tue Dec 22 14:16:55 1998
+++ linux/drivers/block/paride/pseudo.h	Sun Dec 27 11:25:58 1998
@@ -47,7 +47,7 @@
 static int ps_tq_active = 0;
 static int ps_nice = 0;
 
-static spinlock_t ps_spinlock = SPIN_LOCK_UNLOCKED;
+static spinlock_t ps_spinlock __attribute__((unused)) = SPIN_LOCK_UNLOCKED;
 
 static struct timer_list ps_timer = {0,0,0,0,ps_timer_int};
 static struct tq_struct ps_tq = {0,0,ps_tq_int,NULL};
diff -u --recursive --new-file v2.1.132/linux/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- v2.1.132/linux/drivers/cdrom/cdrom.c	Thu Nov 19 09:56:28 1998
+++ linux/drivers/cdrom/cdrom.c	Wed Dec 23 07:56:01 1998
@@ -87,15 +87,20 @@
   Thanks to Grant R. Guenther <grant@torque.net> for spotting this bug.
   -- Made a few things more pedanticly correct.
 
- 2.50  Oct 19, 1998 - Jens Axboe <axboe@image.dk>
+2.50 Oct 19, 1998 - Jens Axboe <axboe@image.dk>
   -- New maintainers! Erik was too busy to continue the work on the driver,
   so now Chris Zwilling <chris@cloudnet.com> and Jens Axboe <axboe@image.dk>
   will do their best to follow in his footsteps
+  
+  2.51 Dec 20, 1998 - Jens Axboe <axboe@image.dk>
+  -- Check if drive is capable of doing what we ask before blindly changing
+  cdi->options in various ioctl.
+  -- Added version to proc entry.
 
 -------------------------------------------------------------------------*/
 
-#define REVISION "Revision: 2.50"
-#define VERSION "Id: cdrom.c 2.50 1998/10/19"
+#define REVISION "Revision: 2.51"
+#define VERSION "Id: cdrom.c 2.51 1998/12/20"
 
 /* I use an error-log mask to give fine grain control over the type of
    messages dumped to the system logs.  The available masks include: */
@@ -211,6 +216,8 @@
         struct cdrom_device_ops *cdo = cdi->ops;
         int *change_capability = (int *)&cdo->capability; /* hack */
 
+	cdinfo(CD_OPEN, "entering register_cdrom\n"); 
+
 	if (major < 0 || major >= MAX_BLKDEV)
 		return -1;
 	if (cdo->open == NULL || cdo->release == NULL)
@@ -236,9 +243,10 @@
 	cdi->mc_flags = 0;
 	cdo->n_minors = 0;
         cdi->options = CDO_USE_FFLAGS;
-	if (autoclose==1)
+	
+	if (autoclose==1 && cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)
 		cdi->options |= (int) CDO_AUTO_CLOSE;
-	if (autoeject==1)
+	if (autoeject==1 && cdo->capability & ~cdi->mask & CDC_OPEN_TRAY)
 		cdi->options |= (int) CDO_AUTO_EJECT;
 	if (lockdoor==1)
 		cdi->options |= (int) CDO_LOCK;
@@ -257,6 +265,8 @@
 	struct cdrom_device_info *cdi, *prev;
 	int major = MAJOR (unreg->dev);
 
+	cdinfo(CD_OPEN, "entering unregister_cdrom\n"); 
+
 	if (major < 0 || major >= MAX_BLKDEV)
 		return -1;
 
@@ -713,6 +723,8 @@
 
 	case CDROMEJECT_SW:
 		cdinfo(CD_DO_IOCTL, "entering CDROMEJECT_SW\n"); 
+		if (!(cdo->capability & ~cdi->mask & CDC_OPEN_TRAY))
+			return -ENOSYS;
 		cdi->options &= ~(CDO_AUTO_CLOSE | CDO_AUTO_EJECT);
 		if (arg)
 			cdi->options |= CDO_AUTO_CLOSE | CDO_AUTO_EJECT;
@@ -733,6 +745,8 @@
 
 	case CDROM_SET_OPTIONS:
 		cdinfo(CD_DO_IOCTL, "entering CDROM_SET_OPTIONS\n"); 
+		if (cdo->capability & arg & ~cdi->mask)
+			return -ENOSYS;
 		cdi->options |= (int) arg;
 		return cdi->options;
 
@@ -984,7 +998,7 @@
         int retv,pos;
 	struct cdrom_device_info *cdi;
 
-        pos = sprintf(cdrom_drive_info, "CD-ROM information\n");
+	pos = sprintf(cdrom_drive_info, "CD-ROM information, " VERSION "\n");
 	
 	pos += sprintf(cdrom_drive_info+pos, "\ndrive name:\t");
 	for (cdi=topCdromPtr;cdi!=NULL;cdi=cdi->next)
diff -u --recursive --new-file v2.1.132/linux/drivers/char/Config.in linux/drivers/char/Config.in
--- v2.1.132/linux/drivers/char/Config.in	Tue Dec 22 14:16:55 1998
+++ linux/drivers/char/Config.in	Sun Dec 27 10:48:46 1998
@@ -56,12 +56,15 @@
 
 bool 'Mouse Support (not serial mice)' CONFIG_MOUSE
 if [ "$CONFIG_MOUSE" = "y" ]; then
+	mainmenu_option next_comment
+	comment 'Mice'
 	tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE
 	tristate 'Logitech busmouse support' CONFIG_BUSMOUSE
 	tristate 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE
 	bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE
 	tristate 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE
 	tristate 'PC110 digitizer pad support' CONFIG_PC110_PAD
+	endmenu
 fi
 
 tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE
@@ -72,12 +75,14 @@
   else
     comment '   Setting runtime QIC-02 configuration is done with qic02conf'
     comment '   from the tpqic02-support package.  It is available at'
-    comment '   sunsite.unc.edu or ftp://titus.cfw.com/pub/Linux/util/'
+    comment '   metalab.unc.edu or ftp://titus.cfw.com/pub/Linux/util/'
   fi
 fi
 
 bool 'Watchdog Timer Support'	CONFIG_WATCHDOG
 if [ "$CONFIG_WATCHDOG" != "n" ]; then
+  mainmenu_option next_comment
+  comment 'Watchdog Cards'
   bool '   Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT
   tristate '   WDT Watchdog timer' CONFIG_WDT
   if [ "$CONFIG_WDT" != "n" ]; then
@@ -89,12 +94,19 @@
   tristate '   Software Watchdog' CONFIG_SOFT_WATCHDOG
   tristate '   Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
   tristate '   Acquire SBC Watchdog Timer' CONFIG_ACQUIRE_WDT
+  endmenu
 fi
+
+
+tristate '/dev/nvram support' CONFIG_NVRAM
 bool 'Enhanced Real Time Clock Support' CONFIG_RTC
 if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then
   bool 'Tadpole ANA H8 Support'  CONFIG_H8
 fi
 
+mainmenu_option next_comment
+comment 'Video For Linux'
+
 tristate 'Video For Linux' CONFIG_VIDEO_DEV
 if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
   dep_tristate 'AIMSlab RadioTrack (aka RadioReveal) support' CONFIG_RADIO_RTRACK $CONFIG_VIDEO_DEV
@@ -110,6 +122,10 @@
     hex '  Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
   fi
   dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
+  dep_tristate 'GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
+  if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
+    hex '  GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
+  fi
   if [ "$CONFIG_PCI" != "n" ]; then
     dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
   fi
@@ -128,11 +144,18 @@
     hex '  ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
   fi
 fi
-tristate '/dev/nvram support' CONFIG_NVRAM
+
+endmenu
+
+mainmenu_option next_comment
+comment 'Joystick support'
+
 tristate 'Joystick support' CONFIG_JOYSTICK
 if [ "$CONFIG_JOYSTICK" != "n" ]; then
   source drivers/char/joystick/Config.in
 fi
+endmenu
+
 mainmenu_option next_comment
 comment 'Ftape, the floppy tape device driver'
 tristate 'Ftape (QIC-80/Travan) support' CONFIG_FTAPE
diff -u --recursive --new-file v2.1.132/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.1.132/linux/drivers/char/Makefile	Tue Dec 22 14:16:55 1998
+++ linux/drivers/char/Makefile	Sun Dec 27 10:49:06 1998
@@ -380,6 +380,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_RADIO_GEMTEK),y)
+L_OBJS += radio-gemtek.o
+else
+  ifeq ($(CONFIG_RADIO_GEMTEK),m)
+  M_OBJS += radio-gemtek.o
+  endif
+endif                                             
+
 ifeq ($(CONFIG_QIC02_TAPE),y)
 L_OBJS += tpqic02.o
 else
diff -u --recursive --new-file v2.1.132/linux/drivers/char/isicom.c linux/drivers/char/isicom.c
--- v2.1.132/linux/drivers/char/isicom.c	Tue Dec 22 14:16:55 1998
+++ linux/drivers/char/isicom.c	Wed Dec 23 09:44:41 1998
@@ -152,12 +152,12 @@
 								
 			inw(base+0x8);
 			
-			for(i=jiffies+HZ/100;i>jiffies;);
+			for(i=jiffies+HZ/100;time_before(jiffies, i););
 				
 			outw(0,base+0x8); /* Reset */
 			
 			for(j=1;j<=3;j++) {
-				for(i=jiffies+HZ;i>jiffies;);
+				for(i=jiffies+HZ;time_before(jiffies, i););
 				printk(".");
 			}	
 			signature=(inw(base+0x4)) & 0xff;	
diff -u --recursive --new-file v2.1.132/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.1.132/linux/drivers/char/pc_keyb.c	Tue Dec 22 14:16:55 1998
+++ linux/drivers/char/pc_keyb.c	Mon Dec 28 11:04:00 1998
@@ -761,6 +761,11 @@
 }
 
 
+/*
+ * Random magic cookie for the aux device
+ */
+#define AUX_DEV ((void *)queue)
+
 static int release_aux(struct inode * inode, struct file * file)
 {
 	fasync_aux(-1, file, 0);
@@ -768,11 +773,7 @@
 		return 0;
 	kbd_write_cmd(AUX_INTS_OFF);			    /* Disable controller ints */
 	kbd_write(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG);
-#ifdef CONFIG_MCA
-	free_irq(AUX_IRQ, inode);
-#else
-	free_irq(AUX_IRQ, NULL);
-#endif
+	free_irq(AUX_IRQ, AUX_DEV);
 	return 0;
 }
 
@@ -787,11 +788,7 @@
 		return 0;
 	}
 	queue->head = queue->tail = 0;		/* Flush input queue */
-#ifdef CONFIG_MCA
-	if (request_irq(AUX_IRQ, keyboard_interrupt, MCA_bus ? SA_SHIRQ : 0, "PS/2 Mouse", inode)) {
-#else
-	if (request_irq(AUX_IRQ, keyboard_interrupt, 0, "PS/2 Mouse", NULL)) {
-#endif
+	if (request_irq(AUX_IRQ, keyboard_interrupt, SA_SHIRQ, "PS/2 Mouse", AUX_DEV)) {
 		aux_count--;
 		return -EBUSY;
 	}
diff -u --recursive --new-file v2.1.132/linux/drivers/char/radio-gemtek.c linux/drivers/char/radio-gemtek.c
--- v2.1.132/linux/drivers/char/radio-gemtek.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/radio-gemtek.c	Sun Dec 27 10:49:06 1998
@@ -0,0 +1,310 @@
+/* GemTek radio card driver for Linux (C) 1998 Jonas Munsin <jmunsin@iki.fi>
+ *
+ * GemTek hasn't released any specs on the card, so the protocol had to
+ * be reverse engineered with dosemu.
+ *
+ * Besides the protocol changes, this is mostly a copy of:
+ *
+ *    RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
+ * 
+ *    Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
+ *    Coverted to new API by Alan Cox <Alan.Cox@linux.org>
+ *    Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
+ *
+ * TODO: Allow for more than one of these foolish entities :-)
+ *
+ */
+
+#include <linux/module.h>	/* Modules 			*/
+#include <linux/init.h>		/* Initdata			*/
+#include <linux/ioport.h>	/* check_region, request_region	*/
+#include <linux/delay.h>	/* udelay			*/
+#include <asm/io.h>		/* outb, outb_p			*/
+#include <asm/uaccess.h>	/* copy to/from user		*/
+#include <linux/videodev.h>	/* kernel radio structs		*/
+#include <linux/config.h>	/* CONFIG_RADIO_GEMTEK_PORT 	*/
+
+#ifndef CONFIG_RADIO_GEMTEK_PORT
+#define CONFIG_RADIO_GEMTEK_PORT -1
+#endif
+
+static int io = CONFIG_RADIO_GEMTEK_PORT; 
+static int users = 0;
+
+struct gemtek_device
+{
+	int port;
+	unsigned long curfreq;
+	int muted;
+};
+
+
+/* local things */
+
+/* the correct way to mute the gemtek may be to write the last written
+ * frequency || 0x10, but just writing 0x10 once seems to do it as well
+ */
+static void gemtek_mute(struct gemtek_device *dev)
+{
+        if(dev->muted)
+		return;
+	outb(0x10, io);
+	dev->muted = 1;
+}
+
+static void gemtek_unmute(struct gemtek_device *dev)
+{
+	if(dev->muted == 0)
+		return;
+	outb(0x20, io);
+	dev->muted = 0;
+}
+
+static void zero(void)
+{
+	outb_p(0x04, io);
+	udelay(5);
+	outb_p(0x05, io);
+	udelay(5);
+}
+
+static void one(void)
+{
+	outb_p(0x06, io);
+	udelay(5);
+	outb_p(0x07, io);
+	udelay(5);
+}
+
+static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
+{
+	int i;
+
+/*        freq = 78.25*((float)freq/16000.0 + 10.52); */
+
+	freq /= 16;
+	freq += 10520;
+	freq *= 7825;
+	freq /= 100000;
+
+	/* 2 start bits */
+	outb_p(0x03, io);
+	udelay(5);
+	outb_p(0x07, io);
+	udelay(5);
+
+        /* 28 frequency bits (lsb first) */
+	for (i = 0; i < 14; i++)
+		if (freq & (1 << i))
+			one();
+		else
+			zero();
+        /* 36 unknown bits */
+	for (i = 0; i < 11; i++)
+		zero();
+	one();
+	for (i = 0; i < 4; i++)
+		zero();
+	one();
+	zero();
+
+	/* 2 end bits */
+	outb_p(0x03, io);
+	udelay(5);
+	outb_p(0x07, io);
+	udelay(5);
+
+	return 0;
+}
+
+int gemtek_getsigstr(struct gemtek_device *dev)
+{
+	inb(io);
+	udelay(5);
+	if (inb(io) & 8)		/* bit set = no signal present */
+		return 0;
+	return 1;		/* signal present */
+}
+
+static int gemtek_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+	struct gemtek_device *rt=dev->priv;
+
+	switch(cmd)
+	{
+		case VIDIOCGCAP:
+		{
+			struct video_capability v;
+			v.type=VID_TYPE_TUNER;
+			v.channels=1;
+			v.audios=1;
+			/* No we don't do pictures */
+			v.maxwidth=0;
+			v.maxheight=0;
+			v.minwidth=0;
+			v.minheight=0;
+			strcpy(v.name, "GemTek");
+			if(copy_to_user(arg,&v,sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCGTUNER:
+		{
+			struct video_tuner v;
+			if(copy_from_user(&v, arg,sizeof(v))!=0) 
+				return -EFAULT;
+			if(v.tuner)	/* Only 1 tuner */ 
+				return -EINVAL;
+			v.rangelow=87*16000;
+			v.rangehigh=108*16000;
+			v.flags=VIDEO_TUNER_LOW;
+			v.mode=VIDEO_MODE_AUTO;
+			v.signal=0xFFFF*gemtek_getsigstr(rt);
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;
+		}
+		case VIDIOCSTUNER:
+		{
+			struct video_tuner v;
+			if(copy_from_user(&v, arg, sizeof(v)))
+				return -EFAULT;
+			if(v.tuner!=0)
+				return -EINVAL;
+			/* Only 1 tuner so no setting needed ! */
+			return 0;
+		}
+		case VIDIOCGFREQ:
+			if(copy_to_user(arg, &rt->curfreq, sizeof(rt->curfreq)))
+				return -EFAULT;
+			return 0;
+		case VIDIOCSFREQ:
+			if(copy_from_user(&rt->curfreq, arg,sizeof(rt->curfreq)))
+				return -EFAULT;
+		/* needs to be called twice in order for getsigstr to work */
+			gemtek_setfreq(rt, rt->curfreq);
+			gemtek_setfreq(rt, rt->curfreq);
+			return 0;
+		case VIDIOCGAUDIO:
+		{	
+			struct video_audio v;
+			memset(&v,0, sizeof(v));
+			v.flags|=VIDEO_AUDIO_MUTABLE;
+			v.volume=1;
+			v.step=65535;
+			strcpy(v.name, "Radio");
+			if(copy_to_user(arg,&v, sizeof(v)))
+				return -EFAULT;
+			return 0;			
+		}
+		case VIDIOCSAUDIO:
+		{
+			struct video_audio v;
+			if(copy_from_user(&v, arg, sizeof(v))) 
+				return -EFAULT;	
+			if(v.audio) 
+				return -EINVAL;
+
+			if(v.flags&VIDEO_AUDIO_MUTE) 
+				gemtek_mute(rt);
+			else
+			        gemtek_unmute(rt);
+
+			return 0;
+		}
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+static int gemtek_open(struct video_device *dev, int flags)
+{
+	if(users)
+		return -EBUSY;
+	users++;
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+static void gemtek_close(struct video_device *dev)
+{
+	users--;
+	MOD_DEC_USE_COUNT;
+}
+
+static struct gemtek_device gemtek_unit;
+
+static struct video_device gemtek_radio=
+{
+	"GemTek radio",
+	VID_TYPE_TUNER,
+	VID_HARDWARE_GEMTEK,
+	gemtek_open,
+	gemtek_close,
+	NULL,	/* Can't read  (no capture ability) */
+	NULL,	/* Can't write */
+	NULL,	/* Can't poll */
+	gemtek_ioctl,
+	NULL,
+	NULL
+};
+
+__initfunc(int gemtek_init(struct video_init *v))
+{
+	if (check_region(io, 4)) 
+	{
+		printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
+		return -EBUSY;
+	}
+
+	gemtek_radio.priv=&gemtek_unit;
+	
+	if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO)==-1)
+		return -EINVAL;
+		
+	request_region(io, 4, "gemtek");
+	printk(KERN_INFO "GemTek Radio Card driver.\n");
+
+ 	/* mute card - prevents noisy bootups */
+	outb(0x10, io);
+	udelay(5);
+	gemtek_unit.muted = 1;
+
+	/* this is _maybe_ unnecessary */
+	outb(0x01, io);
+
+	return 0;
+}
+
+#ifdef MODULE
+
+MODULE_AUTHOR("Jonas Munsin");
+MODULE_DESCRIPTION("A driver for the GemTek Radio Card");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c)");
+
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+	if(io==-1)
+	{
+		printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c\n");
+		return -EINVAL;
+	}
+	return gemtek_init(NULL);
+}
+
+void cleanup_module(void)
+{
+	video_unregister_device(&gemtek_radio);
+	release_region(io,4);
+}
+
+#endif
+
+/*
+  Local variables:
+  compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c"
+  End:
+*/
diff -u --recursive --new-file v2.1.132/linux/drivers/char/serial.c linux/drivers/char/serial.c
--- v2.1.132/linux/drivers/char/serial.c	Tue Dec 22 14:16:55 1998
+++ linux/drivers/char/serial.c	Wed Dec 23 09:44:41 1998
@@ -2369,7 +2369,7 @@
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
-		if (timeout && ((orig_jiffies + timeout) < jiffies))
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 	}
 	current->state = TASK_RUNNING;
diff -u --recursive --new-file v2.1.132/linux/drivers/char/tpqic02.c linux/drivers/char/tpqic02.c
--- v2.1.132/linux/drivers/char/tpqic02.c	Sun Nov  8 14:02:56 1998
+++ linux/drivers/char/tpqic02.c	Wed Dec 23 09:44:41 1998
@@ -571,7 +571,7 @@
 	timeout -= spin_t;
 	spin_t += jiffies;
 
-	while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && (jiffies<spin_t))
+	while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && time_before(jiffies, spin_t))
 		schedule();		/* don't waste all the CPU time */
 	if ((stat & QIC02_STAT_READY) == 0)
 		return TE_OK;
@@ -586,7 +586,7 @@
 	TPQDEB({printk("wait_for_ready: additional timeout: %d\n", spin_t);})
 
 		/* not ready and no exception && timeout not expired yet */
-	while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && (jiffies<spin_t)) {
+	while (((stat = inb_p(QIC02_STAT_PORT) & QIC02_STAT_MASK) == QIC02_STAT_MASK) && time_before(jiffies, spin_t)) {
 		/* be `nice` to other processes on long operations... */
 		current->state = TASK_INTERRUPTIBLE;
 		/* nap 0.30 sec between checks, */
diff -u --recursive --new-file v2.1.132/linux/drivers/char/videodev.c linux/drivers/char/videodev.c
--- v2.1.132/linux/drivers/char/videodev.c	Thu Nov 12 16:21:19 1998
+++ linux/drivers/char/videodev.c	Sun Dec 27 10:49:06 1998
@@ -68,6 +68,9 @@
 #ifdef CONFIG_RADIO_MIROPCM20
 extern int pcm20_init(struct video_init *);
 #endif
+#ifdef CONFIG_RADIO_GEMTEK
+extern int gemtek_init(struct video_init *);
+#endif
 #ifdef CONFIG_VIDEO_PMS
 extern int init_pms_cards(struct video_init *);
 #endif
@@ -103,6 +106,9 @@
 #endif
 #ifdef CONFIG_RADIO_MIROPCM20
 	{"PCM20", pcm20_init}, 
+#endif	
+#ifdef CONFIG_RADIO_GEMTEK
+	{"GemTek", gemtek_init}, 
 #endif	
 	{"end", NULL}
 };
diff -u --recursive --new-file v2.1.132/linux/drivers/isdn/avmb1/b1lli.c linux/drivers/isdn/avmb1/b1lli.c
--- v2.1.132/linux/drivers/isdn/avmb1/b1lli.c	Wed Apr  1 20:11:49 1998
+++ linux/drivers/isdn/avmb1/b1lli.c	Wed Dec 23 09:44:41 1998
@@ -173,7 +173,7 @@
 static inline unsigned char B1_get_byte(unsigned short base)
 {
 	unsigned long i = jiffies + 5 * HZ;	/* maximum wait time 5 sec */
-	while (!B1_rx_full(base) && i > jiffies);
+	while (!B1_rx_full(base) && time_before(jiffies, i));
 	if (B1_rx_full(base))
 		return inb(base + B1_READ);
 	printk(KERN_CRIT "b1lli: rx not full after 5 second\n");
@@ -477,7 +477,7 @@
 
 	if (loaddebug)
 		printk(KERN_DEBUG "b1capi: loaded: wait 1 ..\n");
-	for (i = jiffies + 10 * HZ; i > jiffies;) {
+	for (i = jiffies + 10 * HZ; time_before(jiffies, i);) {
 		if (B1_tx_empty(base))
 			break;
 	}
@@ -487,7 +487,7 @@
 	}
 	B1_put_byte(base, SEND_POLL);
 	printk(KERN_DEBUG "b1capi: loaded: wait 2 ..\n");
-	for (i = jiffies + 10 * HZ; i > jiffies;) {
+	for (i = jiffies + 10 * HZ; time_before(jiffies, i);) {
 		if (B1_rx_full(base)) {
 			if ((ans = B1_get_byte(base)) == RECEIVE_POLL) {
 				if (loaddebug)
diff -u --recursive --new-file v2.1.132/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c
--- v2.1.132/linux/drivers/isdn/hisax/callc.c	Wed Apr  1 20:11:50 1998
+++ linux/drivers/isdn/hisax/callc.c	Sun Dec 27 10:44:45 1998
@@ -62,7 +62,7 @@
 #include "hisax.h"
 
 #ifdef MODULE
-#define MOD_USE_COUNT ((&__this_module)->usecount)
+#define MOD_USE_COUNT ( GET_USE_COUNT (&__this_module))
 #endif				/* MODULE */
 
 const char *lli_revision = "$Revision: 2.13 $";
@@ -2055,7 +2055,7 @@
 			if (csta->channel[0].debug & 0x400) {
 				jiftime(tmp, jiffies);
 				i = strlen(tmp);
-				sprintf(tmp + i, "   LOCK modcnt %lx\n", MOD_USE_COUNT);
+				sprintf(tmp + i, "   LOCK modcnt %d\n", MOD_USE_COUNT);
 				HiSax_putstatus(csta, tmp);
 			}
 #endif				/* MODULE */
@@ -2066,7 +2066,7 @@
 			if (csta->channel[0].debug & 0x400) {
 				jiftime(tmp, jiffies);
 				i = strlen(tmp);
-				sprintf(tmp + i, " UNLOCK modcnt %lx\n", MOD_USE_COUNT);
+				sprintf(tmp + i, " UNLOCK modcnt %d\n", MOD_USE_COUNT);
 				HiSax_putstatus(csta, tmp);
 			}
 #endif				/* MODULE */
@@ -2128,7 +2128,8 @@
 					break;
 #ifdef MODULE
 				case (55):
-					MOD_USE_COUNT = 0;
+					while ( MOD_USE_COUNT > 0)
+                                           MOD_DEC_USE_COUNT;
 					HiSax_mod_inc_use_count();
 					break;
 #endif				/* MODULE */
diff -u --recursive --new-file v2.1.132/linux/drivers/macintosh/macserial.c linux/drivers/macintosh/macserial.c
--- v2.1.132/linux/drivers/macintosh/macserial.c	Thu Nov 19 09:56:28 1998
+++ linux/drivers/macintosh/macserial.c	Wed Dec 23 09:44:41 1998
@@ -1328,7 +1328,7 @@
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
-		if (timeout && ((orig_jiffies + timeout) < jiffies))
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 	}
 	current->state = TASK_RUNNING;
diff -u --recursive --new-file v2.1.132/linux/drivers/macintosh/via-pmu.c linux/drivers/macintosh/via-pmu.c
--- v2.1.132/linux/drivers/macintosh/via-pmu.c	Tue Dec 22 14:16:55 1998
+++ linux/drivers/macintosh/via-pmu.c	Wed Dec 23 09:44:41 1998
@@ -894,7 +894,7 @@
 		pmu_enable_backlight(0);
 
 	/* Give the disks a little time to actually finish writing */
-	for (wait = jiffies + (HZ/4); jiffies < wait; )
+	for (wait = jiffies + (HZ/4); time_before(jiffies, wait); )
 		mb();
 
 	/* Disable all interrupts except pmu */
diff -u --recursive --new-file v2.1.132/linux/drivers/net/3c523.c linux/drivers/net/3c523.c
--- v2.1.132/linux/drivers/net/3c523.c	Tue Dec 22 14:16:55 1998
+++ linux/drivers/net/3c523.c	Sun Dec 27 10:53:45 1998
@@ -539,7 +539,7 @@
 	}
 	dev->mem_end = dev->mem_start + size;	/* set mem_end showed by 'ifconfig' */
 
-	((struct priv *) (dev->priv))->base = phys_to_virt(dev->mem_start + size - 0x01000000);
+	((struct priv *) (dev->priv))->base = (unsigned long)phys_to_virt(dev->mem_start + size - 0x01000000);
 	alloc586(dev);
 
 	elmc_id_reset586();	/* make sure it doesn't generate spurious ints */
diff -u --recursive --new-file v2.1.132/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- v2.1.132/linux/drivers/net/8390.c	Fri Nov 27 13:09:23 1998
+++ linux/drivers/net/8390.c	Mon Dec 28 11:04:21 1998
@@ -37,7 +37,7 @@
   			  68K Macintosh. Support >16bit I/O spaces
   Paul Gortmaker	: add kmod support for auto-loading of the 8390
 			  module by all drivers that require it.
-
+  Alan Cox		: Spinlocking work, added 'BUG_83C690'
 
   Sources:
   The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
@@ -72,6 +72,8 @@
 #define NS8390_CORE
 #include "8390.h"
 
+#define BUG_83C690
+
 /* These are the operational function interfaces to board-specific
    routines.
 	void reset_8390(struct device *dev)
@@ -110,6 +112,34 @@
 static void NS8390_trigger_send(struct device *dev, unsigned int length,
 								int start_page);
 static void set_multicast_list(struct device *dev);
+static void do_set_multicast_list(struct device *dev);
+
+/*
+ *	SMP and the 8390 setup.
+ *
+ *	The 8390 isnt exactly designed to be multithreaded on RX/TX. There is
+ *	a page register that controls bank and packet buffer access. We guard
+ *	this with ei_local->page_lock. Nobody should assume or set the page other
+ *	than zero when the lock is not held. Lock holders must restore page 0
+ *	before unlocking. Even pure readers must take the lock to protect in 
+ *	page 0.
+ *
+ *	To make life difficult the chip can also be very slow. We therefore can't
+ *	just use spinlocks. For the longer lockups we disable the irq the device
+ *	sits on and hold the lock. We must hold the lock because there is a dual
+ *	processor case other than interrupts (get stats/set multicast list in
+ *	parallel with each other and transmit).
+ *
+ *	Note: in theory we can just disable the irq on the card _but_ there is
+ *	a latency on SMP irq delivery. So we can easily go "disable irq" "sync irqs"
+ *	enter lock, take the queued irq. So we waddle instead of flying.
+ *
+ *	Finally by special arrangement for the purpose of being generally 
+ *	annoying the transmit function is called bh atomic. That places
+ *	restrictions on the user context callers as disable_irq won't save
+ *	them.
+ */
+ 
 
 
 /* Open/initialize the board.  This routine goes all-out, setting everything
@@ -118,6 +148,7 @@
    */
 int ei_open(struct device *dev)
 {
+	unsigned long flags;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 
 	/* This can't happen unless somebody forgot to call ethdev_init(). */
@@ -127,7 +158,14 @@
 		return -ENXIO;
 	}
     
+	/*
+	 *	Grab the page lock so we own the register set, then call
+	 *	the init function.
+	 */
+      
+      	spin_lock_irqsave(&ei_local->page_lock, flags);
 	NS8390_init(dev, 1);
+      	spin_unlock_irqrestore(&ei_local->page_lock, flags);
 	dev->start = 1;
 	ei_local->irqlock = 0;
 	return 0;
@@ -136,7 +174,16 @@
 /* Opposite of above. Only used when "ifconfig <devname> down" is done. */
 int ei_close(struct device *dev)
 {
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	unsigned long flags;
+
+	/*
+	 *	Hold the page lock during close
+	 */
+	 	
+      	spin_lock_irqsave(&ei_local->page_lock, flags);
 	NS8390_init(dev, 0);
+      	spin_unlock_irqrestore(&ei_local->page_lock, flags);
 	dev->start = 0;
 	return 0;
 }
@@ -146,24 +193,39 @@
 	int e8390_base = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	int length, send_length, output_page;
+	unsigned long flags;
 
 	/*
 	 *  We normally shouldn't be called if dev->tbusy is set, but the
 	 *  existing code does anyway. If it has been too long since the
-	 *  last Tx, we assume the board has died and kick it.
+	 *  last Tx, we assume the board has died and kick it. We are
+	 *  bh_atomic here.
 	 */
  
 	if (dev->tbusy) 
 	{	/* Do timeouts, just like the 8003 driver. */
-		int txsr = inb(e8390_base+EN0_TSR), isr;
+		int txsr;
+		int isr;
 		int tickssofar = jiffies - dev->trans_start;
+
+		/*
+		 *	Need the page lock. Now see what went wrong. This bit is
+		 *	fast.
+		 */
+		 		
+		spin_lock_irqsave(&ei_local->page_lock, flags);
+		txsr = inb(e8390_base+EN0_TSR);
 		if (tickssofar < TX_TIMEOUT ||	(tickssofar < (TX_TIMEOUT+5) && ! (txsr & ENTSR_PTX))) 
+		{
+			spin_unlock_irqrestore(&ei_local->page_lock, flags);
 			return 1;
+		}
 
 		ei_local->stat.tx_errors++;
 		isr = inb(e8390_base+EN0_ISR);
 		if (dev->start == 0) 
 		{
+			spin_unlock_irqrestore(&ei_local->page_lock, flags);
 			printk(KERN_WARNING "%s: xmit on stopped card\n", dev->name);
 			return 1;
 		}
@@ -184,22 +246,54 @@
 			ei_local->interface_num ^= 1;   /* Try a different xcvr.  */
 		}
 
+		/*
+		 *	Play shuffle the locks, a reset on some chips takes a few
+		 *	mS. We very rarely hit this point.
+		 */
+		 
+		spin_unlock_irqrestore(&ei_local->page_lock, flags);
+
+		/* Ugly but a reset can be slow, yet must be protected */
+		
+		disable_irq(dev->irq);
+		synchronize_irq();
+		spin_lock(&ei_local->page_lock);
+		
 		/* Try to restart the card.  Perhaps the user has fixed something. */
 		ei_reset_8390(dev);
 		NS8390_init(dev, 1);
+		
+		spin_unlock(&ei_local->page_lock);
+		enable_irq(dev->irq);
 		dev->trans_start = jiffies;
 	}
     
 	length = skb->len;
 
-	/* Mask interrupts from the ethercard. */
+	/* Mask interrupts from the ethercard. 
+	   SMP: We have to grab the lock here otherwise the IRQ handler
+	   on another CPU can flip window and race the IRQ mask set. We end
+	   up trashing the mcast filter not disabling irqs if we dont lock */
+	   
+	spin_lock_irqsave(&ei_local->page_lock, flags);
 	outb_p(0x00, e8390_base + EN0_IMR);
+	spin_unlock_irqrestore(&ei_local->page_lock, flags);
+	
+	
+	/*
+	 *	Slow phase with lock held.
+	 */
+	 
 	disable_irq(dev->irq);
 	synchronize_irq();
+	
+	spin_lock(&ei_local->page_lock);
+	
 	if (dev->interrupt) 
 	{
 		printk(KERN_WARNING "%s: Tx request while isr active.\n",dev->name);
 		outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+		spin_unlock(&ei_local->page_lock);
 		enable_irq(dev->irq);
 		ei_local->stat.tx_errors++;
 		dev_kfree_skb(skb);
@@ -243,6 +337,7 @@
 		ei_local->irqlock = 0;
 		dev->tbusy = 1;
 		outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+		spin_unlock(&ei_local->page_lock);
 		enable_irq(dev->irq);
 		ei_local->stat.tx_errors++;
 		return 1;
@@ -294,6 +389,8 @@
 	/* Turn 8390 interrupts back on. */
 	ei_local->irqlock = 0;
 	outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+	
+	spin_unlock(&ei_local->page_lock);
 	enable_irq(dev->irq);
 
 	dev_kfree_skb (skb);
@@ -320,6 +417,13 @@
     
 	e8390_base = dev->base_addr;
 	ei_local = (struct ei_device *) dev->priv;
+
+	/*
+	 *	Protect the irq test too.
+	 */
+	 
+	spin_lock(&ei_local->page_lock);
+
 	if (dev->interrupt || ei_local->irqlock) 
 	{
 #if 1 /* This might just be an interrupt for a PCI device sharing this line */
@@ -330,15 +434,17 @@
 			   dev->name, inb_p(e8390_base + EN0_ISR),
 			   inb_p(e8390_base + EN0_IMR));
 #endif
+		spin_unlock(&ei_local->page_lock);
 		return;
 	}
     
+	
 	dev->interrupt = 1;
     
 	/* Change to page 0 and read the intr status reg. */
 	outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
 	if (ei_debug > 3)
-		printk("%s: interrupt(isr=%#2.2x).\n", dev->name,
+		printk(KERN_DEBUG "%s: interrupt(isr=%#2.2x).\n", dev->name,
 			   inb_p(e8390_base + EN0_ISR));
     
 	/* !!Assumption!! -- we stay in page 0.	 Don't break this. */
@@ -386,15 +492,16 @@
 		outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
 		if (nr_serviced >= MAX_SERVICE) 
 		{
-			printk("%s: Too much work at interrupt, status %#2.2x\n",
+			printk(KERN_WARNING "%s: Too much work at interrupt, status %#2.2x\n",
 				   dev->name, interrupts);
 			outb_p(ENISR_ALL, e8390_base + EN0_ISR); /* Ack. most intrs. */
 		} else {
-			printk("%s: unknown interrupt %#2x\n", dev->name, interrupts);
+			printk(KERN_WARNING "%s: unknown interrupt %#2x\n", dev->name, interrupts);
 			outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
 		}
 	}
 	dev->interrupt = 0;
+	spin_unlock(&ei_local->page_lock);
 	return;
 }
 
@@ -405,6 +512,8 @@
  * letting the failed packet sit and collect dust in the Tx buffer. This
  * is a much better solution as it avoids kernel based Tx timeouts, and
  * an unnecessary card reset.
+ *
+ * Called with lock held
  */
 
 static void ei_tx_err(struct device *dev)
@@ -443,7 +552,7 @@
 }
 
 /* We have finished a transmit: check for errors and then trigger the next
-   packet to be sent. */
+   packet to be sent. Called with lock held */
 
 static void ei_tx_intr(struct device *dev)
 {
@@ -532,7 +641,8 @@
 	mark_bh (NET_BH);
 }
 
-/* We have a good packet(s), get it/them out of the buffers. */
+/* We have a good packet(s), get it/them out of the buffers. 
+   Called with lock held */
 
 static void ei_receive(struct device *dev)
 {
@@ -659,6 +769,8 @@
  * the updated datasheets, or "the NIC may act in an unpredictable manner."
  * This includes causing "the NIC to defer indefinitely when it is stopped
  * on a busy network."  Ugh.
+ * Called with lock held. Don't call this with the interrupts off or your
+ * computer will hate you - it takes 10mS or so. 
  */
 
 static void ei_rx_overrun(struct device *dev)
@@ -726,19 +838,26 @@
     		outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
 }
 
+/*
+ *	Collect the stats. This is called unlocked and from several contexts.
+ */
+ 
 static struct net_device_stats *get_stats(struct device *dev)
 {
 	int ioaddr = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	unsigned long flags;
     
 	/* If the card is stopped, just return the present stats. */
 	if (dev->start == 0) 
 		return &ei_local->stat;
 
+	spin_lock_irqsave(&ei_local->page_lock,flags);
 	/* Read the counter registers, assuming we are in page 0. */
 	ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
 	ei_local->stat.rx_crc_errors   += inb_p(ioaddr + EN0_COUNTER1);
 	ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
+	spin_unlock_irqrestore(&ei_local->page_lock, flags);
     
 	return &ei_local->stat;
 }
@@ -794,14 +913,14 @@
 }
 
 /*
- *	Set or clear the multicast filter for this adaptor.
+ *	Set or clear the multicast filter for this adaptor. May be called
+ *	from a BH in 2.1.x. Must be called with lock held. 
  */
  
-static void set_multicast_list(struct device *dev)
+static void do_set_multicast_list(struct device *dev)
 {
 	int e8390_base = dev->base_addr;
 	int i;
-	unsigned long flags;
 	struct ei_device *ei_local = (struct ei_device*)dev->priv;
 
 	if (!(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) 
@@ -825,21 +944,19 @@
 	 * them as r/w so this is a bug.  The SMC 83C790 (SMC Ultra and
 	 * Ultra32 EISA) appears to have this bug fixed.
 	 */
+	 
 	if (dev->start)
 		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
-	save_flags(flags);
-	cli();
 	outb_p(E8390_NODMA + E8390_PAGE1, e8390_base + E8390_CMD);
 	for(i = 0; i < 8; i++) 
 	{
 		outb_p(ei_local->mcfilter[i], e8390_base + EN1_MULT_SHIFT(i));
-#ifdef NOT_83C690
+#ifndef BUG_83C690
 		if(inb_p(e8390_base + EN1_MULT_SHIFT(i))!=ei_local->mcfilter[i])
 			printk(KERN_ERR "Multicast filter read/write mismap %d\n",i);
 #endif
 	}
 	outb_p(E8390_NODMA + E8390_PAGE0, e8390_base + E8390_CMD);
-	restore_flags(flags);
 
   	if(dev->flags&IFF_PROMISC)
   		outb_p(E8390_RXCONFIG | 0x18, e8390_base + EN0_RXCR);
@@ -847,12 +964,29 @@
   		outb_p(E8390_RXCONFIG | 0x08, e8390_base + EN0_RXCR);
   	else
   		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR);
-}
+ }
+
+/*
+ *	Called without lock held. This is invoked from user context and may
+ *	be parallel to just about everything else. Its also fairly quick and
+ *	not called too often. Must protect against both bh and irq users
+ */
+ 
+static void set_multicast_list(struct device *dev)
+{
+	unsigned long flags;
+	struct ei_device *ei_local = (struct ei_device*)dev->priv;
+	
+	spin_lock_irqsave(&ei_local->page_lock, flags);
+	do_set_multicast_list(dev);
+	spin_unlock_irqrestore(&ei_local->page_lock, flags);
+}	
 
 /*
  * Initialize the rest of the 8390 device structure.  Do NOT __initfunc
  * this, as it is used by 8390 based modular drivers too.
  */
+
 int ethdev_init(struct device *dev)
 {
 	if (ei_debug > 1)
@@ -867,6 +1001,7 @@
 			return -ENOMEM;
 		memset(dev->priv, 0, sizeof(struct ei_device));
 		ei_local = (struct ei_device *)dev->priv;
+		spin_lock_init(&ei_local->page_lock);
 	}
     
 	dev->hard_start_xmit = &ei_start_xmit;
@@ -883,13 +1018,16 @@
 /* This page of functions should be 8390 generic */
 /* Follow National Semi's recommendations for initializing the "NIC". */
 
+/*
+ *	Must be called with lock held.
+ */
+
 void NS8390_init(struct device *dev, int startp)
 {
 	int e8390_base = dev->base_addr;
 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
 	int i;
 	int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
-	unsigned long flags;
     
 	if(sizeof(struct e8390_pkt_hdr)!=4)
     		panic("8390.c: header struct mispacked\n");    
@@ -914,8 +1052,7 @@
 	outb_p(0x00,  e8390_base + EN0_IMR);
     
 	/* Copy the station address into the DS8390 registers. */
-	save_flags(flags);
-	cli();
+
 	outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base+E8390_CMD); /* 0x61 */
 	for(i = 0; i < 6; i++) 
 	{
@@ -926,7 +1063,7 @@
 
 	outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
 	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
-	restore_flags(flags);
+
 	dev->tbusy = 0;
 	dev->interrupt = 0;
 	ei_local->tx1 = ei_local->tx2 = 0;
@@ -940,18 +1077,20 @@
 		outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
 		/* 3c503 TechMan says rxconfig only after the NIC is started. */
 		outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on,  */
-		set_multicast_list(dev);	/* (re)load the mcast table */
+		do_set_multicast_list(dev);	/* (re)load the mcast table */
 	}
 	return;
 }
 
-/* Trigger a transmit start, assuming the length is valid. */
+/* Trigger a transmit start, assuming the length is valid. 
+   Always called with the page lock held */
+   
 static void NS8390_trigger_send(struct device *dev, unsigned int length,
 								int start_page)
 {
 	int e8390_base = dev->base_addr;
-	struct ei_device *ei_local = (struct ei_device *) dev->priv;
-
+ 	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+   
 	outb_p(E8390_NODMA+E8390_PAGE0, e8390_base+E8390_CMD);
     
 	if (inb_p(e8390_base) & E8390_TRANS) 
diff -u --recursive --new-file v2.1.132/linux/drivers/net/8390.h linux/drivers/net/8390.h
--- v2.1.132/linux/drivers/net/8390.h	Mon Oct  5 13:13:39 1998
+++ linux/drivers/net/8390.h	Mon Dec 28 11:04:21 1998
@@ -155,30 +155,30 @@
    things in there should be here!) */
 /* You have one of these per-board */
 struct ei_device {
-  const char *name;
-  void (*reset_8390)(struct device *);
-  void (*get_8390_hdr)(struct device *, struct e8390_pkt_hdr *, int);
-  void (*block_output)(struct device *, int, const unsigned char *, int);
-  void (*block_input)(struct device *, int, struct sk_buff *, int);
-  unsigned char mcfilter[8];
-  unsigned open:1;
-  unsigned word16:1;  /* We have the 16-bit (vs 8-bit) version of the card. */
-  unsigned txing:1;		/* Transmit Active */
-  unsigned irqlock:1;		/* 8390's intrs disabled when '1'. */
-  unsigned dmaing:1;		/* Remote DMA Active */
-  unsigned char tx_start_page, rx_start_page, stop_page;
-  unsigned char current_page;	/* Read pointer in buffer  */
-  unsigned char interface_num;	/* Net port (AUI, 10bT.) to use. */
-  unsigned char txqueue;	/* Tx Packet buffer queue length. */
-  short tx1, tx2;		/* Packet lengths for ping-pong tx. */
-  short lasttx;			/* Alpha version consistency check. */
-  unsigned char reg0;		/* Register '0' in a WD8013 */
-  unsigned char reg5;		/* Register '5' in a WD8013 */
-  unsigned char saved_irq;	/* Original dev->irq value. */
-  /* The new statistics table. */
-  struct net_device_stats stat;
-  unsigned char *reg_offset;    /* Register mapping table */
-  unsigned long priv;		/* Private field to store bus IDs etc. */
+	const char *name;
+	void (*reset_8390)(struct device *);
+	void (*get_8390_hdr)(struct device *, struct e8390_pkt_hdr *, int);
+	void (*block_output)(struct device *, int, const unsigned char *, int);
+	void (*block_input)(struct device *, int, struct sk_buff *, int);
+	unsigned char mcfilter[8];
+	unsigned open:1;
+	unsigned word16:1;  		/* We have the 16-bit (vs 8-bit) version of the card. */
+	unsigned txing:1;		/* Transmit Active */
+	unsigned irqlock:1;		/* 8390's intrs disabled when '1'. */
+	unsigned dmaing:1;		/* Remote DMA Active */
+	unsigned char tx_start_page, rx_start_page, stop_page;
+	unsigned char current_page;	/* Read pointer in buffer  */
+	unsigned char interface_num;	/* Net port (AUI, 10bT.) to use. */
+	unsigned char txqueue;		/* Tx Packet buffer queue length. */
+	short tx1, tx2;			/* Packet lengths for ping-pong tx. */
+	short lasttx;			/* Alpha version consistency check. */
+	unsigned char reg0;		/* Register '0' in a WD8013 */
+	unsigned char reg5;		/* Register '5' in a WD8013 */
+	unsigned char saved_irq;	/* Original dev->irq value. */
+	struct net_device_stats stat;	/* The new statistics table. */
+	u32 *reg_offset;		/* Register mapping table */
+	spinlock_t page_lock;		/* Page register locks */
+	unsigned long priv;		/* Private field to store bus IDs etc. */
 };
 
 /* The maximum number of 8390 interrupt service routines called per IRQ. */
@@ -190,12 +190,12 @@
 #define ei_status (*(struct ei_device *)(dev->priv))
 
 /* Some generic ethernet register configurations. */
-#define E8390_TX_IRQ_MASK 0xa	/* For register EN0_ISR */
-#define E8390_RX_IRQ_MASK  0x5
-#define E8390_RXCONFIG 0x4	/* EN0_RXCR: broadcasts, no multicast,errors */
-#define E8390_RXOFF 0x20	/* EN0_RXCR: Accept no packets */
-#define E8390_TXCONFIG 0x00	/* EN0_TXCR: Normal transmit mode */
-#define E8390_TXOFF 0x02	/* EN0_TXCR: Transmitter off */
+#define E8390_TX_IRQ_MASK	0xa	/* For register EN0_ISR */
+#define E8390_RX_IRQ_MASK	0x5
+#define E8390_RXCONFIG		0x4	/* EN0_RXCR: broadcasts, no multicast,errors */
+#define E8390_RXOFF		0x20	/* EN0_RXCR: Accept no packets */
+#define E8390_TXCONFIG		0x00	/* EN0_TXCR: Normal transmit mode */
+#define E8390_TXOFF		0x02	/* EN0_TXCR: Transmitter off */
 
 /*  Register accessed at EN_CMD, the 8390 base addr.  */
 #define E8390_STOP	0x01	/* Stop and reset the chip */
@@ -208,6 +208,10 @@
 #define E8390_PAGE1	0x40	/* using the two high-order bits */
 #define E8390_PAGE2	0x80	/* Page 3 is invalid. */
 
+/*
+ *	Only generate indirect loads given a machine that needs them.
+ */
+ 
 #if defined(CONFIG_MAC) || defined(CONFIG_AMIGA_PCMCIA) || \
     defined(CONFIG_ARIADNE2) || defined(CONFIG_ARIADNE2_MODULE)
 #define EI_SHIFT(x)	(ei_local->reg_offset[x])
diff -u --recursive --new-file v2.1.132/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.1.132/linux/drivers/net/Config.in	Fri Nov 27 13:09:23 1998
+++ linux/drivers/net/Config.in	Wed Dec 23 14:41:03 1998
@@ -224,6 +224,10 @@
 #
 dep_tristate 'Comtrol Hostess SV-11 support' CONFIG_HOSTESS_SV11 m
 #
+# The COSA/SRP driver has not been tested as non-modular yet.
+#
+dep_tristate 'COSA/SRP sync serial boards support' CONFIG_COSA m
+#
 if [ "$CONFIG_WAN_ROUTER" != "n" ]; then
   bool 'WAN drivers' CONFIG_WAN_DRIVERS
   if [ "$CONFIG_WAN_DRIVERS" = "y" ]; then
diff -u --recursive --new-file v2.1.132/linux/drivers/net/cosa.c linux/drivers/net/cosa.c
--- v2.1.132/linux/drivers/net/cosa.c	Tue Dec 22 14:16:55 1998
+++ linux/drivers/net/cosa.c	Mon Dec 28 11:05:14 1998
@@ -1,4 +1,4 @@
-/* $Id: cosa.c,v 1.9 1998/12/08 02:24:23 kas Exp $ */
+/* $Id: cosa.c,v 1.11 1998/12/24 23:44:23 kas Exp $ */
 
 /*
  *  Copyright (C) 1995-1997  Jan "Yenya" Kasprzak <kas@fi.muni.cz>
@@ -357,7 +357,7 @@
 #endif
 {
 	int i;
-	printk(KERN_INFO "cosa v1.02 (c) 1997-8 Jan Kasprzak <kas@fi.muni.cz>\n");
+	printk(KERN_INFO "cosa v1.03 (c) 1997-8 Jan Kasprzak <kas@fi.muni.cz>\n");
 #ifdef __SMP__
 	printk(KERN_INFO "cosa: SMP found. Please mail any success/failure reports to the author.\n");
 #endif
@@ -995,7 +995,9 @@
 	get_user_ret(len, &(d->len), -EFAULT);
 	get_user_ret(code, &(d->code), -EFAULT);
 
-	if (d->len < 0)
+	if (d->addr < 0 || d->addr > COSA_MAX_FIRMWARE_SIZE)
+		return -EINVAL;
+	if (d->len < 0 || d->len > COSA_MAX_FIRMWARE_SIZE)
 		return -EINVAL;
 
 	if ((i=download(cosa, d->code, len, addr)) < 0) {
@@ -1555,6 +1557,15 @@
  * separate functions to make it more readable. These functions are inline,
  * so there should be no overhead of function call.
  */
+
+/*
+ * Transmit interrupt routine - called when COSA is willing to obtain
+ * data from the OS. The most tricky part of the routine is selection
+ * of channel we (OS) want to send packet for. For SRP we should probably
+ * use the round-robin approach. The newer COSA firmwares have a simple
+ * flow-control - in the status word has bits 2 and 3 set to 1 means that the
+ * channel 0 or 1 doesn't want to receive data.
+ */
 static inline void tx_interrupt(struct cosa_data *cosa, int status)
 {
 	unsigned long flags, flags1;
@@ -1564,16 +1575,24 @@
 #endif
 	spin_lock_irqsave(&cosa->lock, flags);
 	set_bit(TXBIT, &cosa->rxtx);
-	/*
-	 * Using a round-robin algorithm select a first channel that has
-	 * data ready for transmit.
-	 */
 	if (!test_bit(IRQBIT, &cosa->rxtx)) {
+		/* flow control */
+		int i=0;
 		do {
+			if (i++ > cosa->nchannels) {
+				printk(KERN_WARNING
+					"%s: No channel wants data in TX IRQ\n",
+					cosa->name);
+				clear_bit(TXBIT, &cosa->rxtx);
+				spin_unlock_irqrestore(&cosa->lock, flags);
+				return;
+			}
 			cosa->txchan++;
 			if (cosa->txchan >= cosa->nchannels)
 				cosa->txchan = 0;
-		} while(!(cosa->txbitmap & (1<<cosa->txchan)));
+		} while ((!(cosa->txbitmap & (1<<cosa->txchan)))
+			|| status & (1<<(cosa->txchan+DRIVER_TXMAP_SHIFT)));
+
 		cosa->txsize = cosa->chan[cosa->txchan].txsize;
 		if (cosa_dma_able(cosa->chan+cosa->txchan,
 			cosa->chan[cosa->txchan].txbuf, cosa->txsize)) {
diff -u --recursive --new-file v2.1.132/linux/drivers/net/cosa.h linux/drivers/net/cosa.h
--- v2.1.132/linux/drivers/net/cosa.h	Tue Dec 22 14:16:55 1998
+++ linux/drivers/net/cosa.h	Mon Dec 28 11:05:14 1998
@@ -1,4 +1,4 @@
-/* $Id: cosa.h,v 1.8 1998/11/09 03:54:49 kas Exp $ */
+/* $Id: cosa.h,v 1.5 1998/12/24 12:40:18 kas Exp $ */
 
 /*
  *  Copyright (C) 1995-1997  Jan "Yenya" Kasprzak <kas@fi.muni.cz>
@@ -61,7 +61,7 @@
 #define SR_START_ADDR   0x4400  /* SRP microcode start address */
 
 #define COSA_LOAD_ADDR    0x400  /* SRP microcode load address */
-
+#define COSA_MAX_FIRMWARE_SIZE	0x10000
 
 /* ioctls */
 struct cosa_download {
diff -u --recursive --new-file v2.1.132/linux/drivers/net/lance.c linux/drivers/net/lance.c
--- v2.1.132/linux/drivers/net/lance.c	Tue Dec 22 14:16:55 1998
+++ linux/drivers/net/lance.c	Mon Dec 28 11:05:14 1998
@@ -303,6 +303,10 @@
 static int dma[MAX_CARDS] = { 0, };
 static int irq[MAX_CARDS]  = { 0, };
 
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_CARDS) "i");
+MODULE_PARM(dma, "1-" __MODULE_STRING(MAX_CARDS) "i");
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_CARDS) "i");
+
 static char ifnames[MAX_CARDS][IF_NAMELEN] = { {0, }, };
 static struct device dev_lance[MAX_CARDS] =
 {{
@@ -363,11 +367,12 @@
 {
 	int *port, result;
 
-	if (high_memory <= 16*1024*1024)
+	if (high_memory <= phys_to_virt(16*1024*1024))
 		lance_need_isa_bounce_buffers = 0;
 
 #if defined(CONFIG_PCI)
-    if (pci_present()) {
+	if (pci_present()) 
+	{
 		struct pci_dev *pdev = NULL;
 		if (lance_debug > 1)
 			printk("lance.c: PCI bios is present, checking for devices...\n");
diff -u --recursive --new-file v2.1.132/linux/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c
--- v2.1.132/linux/drivers/net/sdlamain.c	Fri Oct 23 22:01:21 1998
+++ linux/drivers/net/sdlamain.c	Mon Dec 28 11:05:14 1998
@@ -29,10 +29,6 @@
 * Jan 02, 1997	Gene Kozin	Initial version.
 *****************************************************************************/
 
-#if	!defined(__KERNEL__) || !defined(MODULE)
-#error	This code MUST be compiled as a kernel module!
-#endif
-
 #include <linux/config.h>	/* OS configuration options */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
@@ -122,7 +118,12 @@
  *		< 0	error.
  * Context:	process
  */
+ 
+#ifdef MODULE
 int init_module (void)
+#else
+int wanpipe_init(void)
+#endif
 {
 	int cnt, err = 0;
 
@@ -173,6 +174,7 @@
 	return err;
 }
 
+#ifdef MODULE
 /*============================================================================
  * Module 'remove' entry point.
  * o unregister all adapters from the WAN router
@@ -189,6 +191,8 @@
 	}
 	kfree(card_array);
 }
+
+#endif
 
 /******* WAN Device Driver Entry Points *************************************/
 
diff -u --recursive --new-file v2.1.132/linux/drivers/net/via-rhine.c linux/drivers/net/via-rhine.c
--- v2.1.132/linux/drivers/net/via-rhine.c	Tue Dec 22 14:16:56 1998
+++ linux/drivers/net/via-rhine.c	Mon Dec 28 11:06:11 1998
@@ -66,6 +66,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/errno.h>
diff -u --recursive --new-file v2.1.132/linux/drivers/pci/oldproc.c linux/drivers/pci/oldproc.c
--- v2.1.132/linux/drivers/pci/oldproc.c	Tue Dec 22 14:16:56 1998
+++ linux/drivers/pci/oldproc.c	Sun Dec 27 11:01:34 1998
@@ -886,7 +886,7 @@
 		if (len + 40 > size) {
 			return -1;
 		}
-		len += sprintf(buf + len, "IRQ %x.  ", dev->irq);
+		len += sprintf(buf + len, "IRQ %d.  ", dev->irq);
 	}
 
 	if (dev->master) {
diff -u --recursive --new-file v2.1.132/linux/drivers/sbus/char/bpp.c linux/drivers/sbus/char/bpp.c
--- v2.1.132/linux/drivers/sbus/char/bpp.c	Mon Oct  5 13:13:40 1998
+++ linux/drivers/sbus/char/bpp.c	Wed Dec 23 09:44:41 1998
@@ -337,8 +337,8 @@
        * responds real good. The first while loop guesses an expire
        * time accounting for possible wraparound of jiffies.
        */
-      while (extime <= jiffies) extime = jiffies + 1;
-      while ( (jiffies < extime)
+      while (time_after_eq(jiffies, extime) extime = jiffies + 1;
+      while ( (time_before(jiffies, extime))
               && (((pins & set) != set) || ((pins & clr) != 0)) ) {
             pins = get_pins(minor);
       }
diff -u --recursive --new-file v2.1.132/linux/drivers/sbus/char/sab82532.c linux/drivers/sbus/char/sab82532.c
--- v2.1.132/linux/drivers/sbus/char/sab82532.c	Thu Nov 19 09:56:28 1998
+++ linux/drivers/sbus/char/sab82532.c	Wed Dec 23 09:44:41 1998
@@ -1676,7 +1676,7 @@
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
-		if (timeout && (orig_jiffies + timeout) < jiffies)
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 	}
 	current->state = TASK_RUNNING;
diff -u --recursive --new-file v2.1.132/linux/drivers/sbus/char/su.c linux/drivers/sbus/char/su.c
--- v2.1.132/linux/drivers/sbus/char/su.c	Thu Nov 19 09:56:28 1998
+++ linux/drivers/sbus/char/su.c	Wed Dec 23 09:44:41 1998
@@ -1818,7 +1818,7 @@
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
-		if (timeout && ((orig_jiffies + timeout) < jiffies))
+		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 	}
 	current->state = TASK_RUNNING;
diff -u --recursive --new-file v2.1.132/linux/drivers/scsi/README.tmscsim linux/drivers/scsi/README.tmscsim
--- v2.1.132/linux/drivers/scsi/README.tmscsim	Sun Nov  8 14:03:02 1998
+++ linux/drivers/scsi/README.tmscsim	Fri Dec 25 16:41:39 1998
@@ -17,6 +17,7 @@
 chip. AM53C974 based SCSI adapters include: 
  Tekram DC390, DC390T
  Dawicontrol 2974
+ QLogic Fast! PCI Basic
  some on-board adapters
 (This is most probably not a complete list)
 
@@ -44,7 +45,8 @@
 1.12, then 1.20a to 1.20t. Finally I decided to use the ncr53c8xx scheme. So
 the next revisions will be 2.0a to 2.0X (stable), 2.1a to 2.1X (experimental),
 2.2a to 2.2X (stable, again) etc. (X = anything between a and z.) If I send
-fixes to people for testing, those will have a digit appended, e.g. 2.0a1.
+fixes to people for testing, I create intermediate versions with a digit 
+appended, e.g. 2.0c3.
 
 
 2. Installation
@@ -55,32 +57,36 @@
 support into your kernel or as module when configuring your kernel for
 compiling.
 
-If you got an older kernel with an old version of this driver included, you
-should copy the files (dc390.h, tmscsim.h, tmscsim.c, scsiiom.c and
-README.tmscsim) from this directory to linux/drivers/scsi. You have to
-recompile your kernel/module of course.
-
-You should apply the three patches included in dc390-20-kernel.diff
-(Applying them: cd /usr/src; patch -p0 <~/dc390-20-kernel.diff)
-The patches are against 2.1.103, so you might have to manually resolve
-rejections when applying to another kernel version.
-
-The patches will update the kernel startup code to allow boot parameters to
-be passed to the driver, update the Documentation and finally offer you the
-possibility to omit the non-DC390 parts of the driver.
-(By selecting "Omit support for non DC390" you basically disable the
-emulation of a DC390 EEPROM for non DC390 adapters. This saves a few bytes
-of memory.)
+ If you got an old kernel (pre 2.1.127, pre 2.0.37p1) with an old version of
+ this driver: Get dc390-21125-20b.diff.gz or dc390-2036p21-20b1.diff.gz from
+ my website and apply the patch. 
+
+ If you want to do it manually, you should copy the files (dc390.h,
+ tmscsim.h, tmscsim.c, scsiiom.c and README.tmscsim) from this directory to
+ linux/drivers/scsi. You have to recompile your kernel/module of course.
+
+ You should apply the three patches included in dc390-120-kernel.diff
+ (Applying them: cd /usr/src; patch -p0 <~/dc390-120-kernel.diff)
+ The patches are against 2.1.125, so you might have to manually resolve
+ rejections when applying to another kernel version.
+
+ The patches will update the kernel startup code to allow boot parameters to
+ be passed to the driver, update the Documentation and finally offer you the
+ possibility to omit the non-DC390 parts of the driver.
+ (By selecting "Omit support for non DC390" you basically disable the
+ emulation of a DC390 EEPROM for non DC390 adapters. This saves a few bytes
+ of memory.)
 
 If you got a very old kernel without the tmscsim driver (pre 2.0.31)
 I recommend upgrading your kernel. However, if you don't want to, please
 contact me to get the appropriate patches.
 
-Testing a SCSI driver is always a delicate thing to do. The 2.0 driver has
+
+Upgrading a SCSI driver is always a delicate thing to do. The 2.0 driver has
 proven stable on many systems, but it's still a good idea to take some
 precautions. In an ideal world you would have a full backup of your disks.
 The world isn't ideal and most people don't have full backups (me neither).
-So take at least the following two measures:
+So take at least the following measures:
 * make your kernel remount the FS read-only on detecting an error:
   tune2fs -e remount-ro /dev/sd??
 * have copies of your SCSI disk's partition tables on some safe location:
@@ -103,18 +109,19 @@
 3.Features
 ----------
 - SCSI
- * Tagged queueing
+ * Tagged command queueing
  * Sync speed up to 10 MHz
  * Disconnection
  * Multiple LUNs
 
 - General / Linux interface
- * Support for up to 4 adapters.
+ * Support for up to 4 AM53C974 adapters.
  * DC390 EEPROM usage or boot/module params
  * Information via cat /proc/scsi/tmscsim/?
  * Dynamically configurable by writing to /proc/scsi/tmscsim/?
  * Dynamic allocation of resources
- * SMP support: Adapter specific locks (Linux 2.1.x)
+ * SMP support: Locking on io_request lock (Linux 2.1/2.2) or adapter 
+    specific locks (Linux 2.3)
  * Uniform source code for Linux-2.x.y
  * Support for dyn. addition/removal of devices via add/remove-single-device
    (Try: echo "scsi add-single-device H C I L" >/proc/scsi/scsi 
@@ -336,9 +343,7 @@
 
 Further investigation on these problems:
 
-* TagQ and Disconnection (Resel: SRB Tag Seleection)
-* Problems with IRQ sharing (IO-APIC on SMP Systems) (??)
-* Driver crashes with readcdda (xcdroast)
+* Driver hangs with sync readcdda (xcdroast) (most probably VIA PCI error)
 
 Known problems:
 
@@ -362,12 +367,9 @@
   Richard Waltham <dormouse@farsrobt.demon.co.uk> or Doug Ledford
   <dledford@dialnet.net>, if you want to help further debugging it.
 * 2.0.35: CD changers (e.g. NAKAMICHI MBR-7.{0,2}) have problems because
-  the mid-level code doesn't handle BLIST_SINGLELUN correctly. Apply
-  the patch 2035-scsi-singlelun.diff. Thanks to Chiaki Ishikawa.
-  I was told that this fix will be in 2.0.36, so you don't need it for
-  2.0.36. 
-[The patch file is contained in the dc390-XXX.tar.gz files which can be found
-on the ftp server. See below.]
+  the mid-level code doesn't handle BLIST_SINGLELUN correctly. There used
+  to be a patch included here to fix this, but I was told that it is fixed
+  in 2.0.36.
 
 
 7. Bug reports, debugging and updates
@@ -379,7 +381,7 @@
 Please append the output of /proc/scsi/scsi, /proc/scsi/tmscsim/? and
 maybe the DC390 log messages to the report. 
 
-Bug reports should be send to me (Kurt Garloff <K.Garloff@ping.de>) as well
+Bug reports should be send to me (Kurt Garloff <dc390@garloff.de>) as well
 as to the linux-scsi list (<linux-scsi@vger.rutgers.edu>), as sometimes bugs
 are caused by the SCSI mid-level code.
 
@@ -391,7 +393,10 @@
 having your box spending most of its time doing the logging.
 
 The latest version of the driver can be found at:
-ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/
+ http://www.garloff.de/kurt/linux/dc390/
+and
+ ftp://student.physik.uni-dortmund.de/pub/linux/kernel/dc390/
+(The latter might shut down some day.)
 
 
 8. Acknowledgements
@@ -408,6 +413,6 @@
 
 
 -------------------------------------------------------------------------
-Written by Kurt Garloff <K.Garloff@ping.de> 1998/06/11
-Last updated 1998/10/15, driver revision 2.0b
-$Id: README.tmscsim,v 2.4 1998/10/24 08:45:02 garloff Exp $
+Written by Kurt Garloff <kurt@garloff.de> 1998/06/11
+Last updated 1998/12/25, driver revision 2.0d
+$Id: README.tmscsim,v 2.9 1998/12/25 18:04:20 garloff Exp $
diff -u --recursive --new-file v2.1.132/linux/drivers/scsi/advansys.c linux/drivers/scsi/advansys.c
--- v2.1.132/linux/drivers/scsi/advansys.c	Wed Sep  9 14:51:08 1998
+++ linux/drivers/scsi/advansys.c	Wed Dec 23 09:44:41 1998
@@ -5785,8 +5785,8 @@
         }
         scp->result = HOST_BYTE(DID_ERROR);
         ret = SCSI_RESET_ERROR;
-    } else if (jiffies >= boardp->last_reset &&
-               jiffies < (boardp->last_reset + (10 * HZ))) {
+    } else if (time_after_eq(jiffies, boardp->last_reset) &&
+               time_before(jiffies, boardp->last_reset + (10 * HZ))) {
         /*
          * Don't allow a reset to be attempted within 10 seconds
          * of the last reset.
diff -u --recursive --new-file v2.1.132/linux/drivers/scsi/dc390.h linux/drivers/scsi/dc390.h
--- v2.1.132/linux/drivers/scsi/dc390.h	Sun Nov  8 14:03:02 1998
+++ linux/drivers/scsi/dc390.h	Mon Dec 28 14:10:17 1998
@@ -4,7 +4,7 @@
  *	Description: Device Driver for Tekram DC-390(T) PCI SCSI       *
  *		     Bus Master Host Adapter			       *
  ***********************************************************************/
-/* $Id: dc390.h,v 2.3 1998/10/24 08:45:02 garloff Exp $ */
+/* $Id: dc390.h,v 2.12 1998/12/25 17:33:27 garloff Exp $ */
 
 #include <linux/version.h>
 
@@ -16,7 +16,7 @@
 #define DC390_H
 
 #define DC390_BANNER "Tekram DC390/AM53C974"
-#define DC390_VERSION "2.0b 1998/10/24"
+#define DC390_VERSION "2.0d 1998/12/25"
 
 #if defined(HOSTS_C) || defined(MODULE)
 
diff -u --recursive --new-file v2.1.132/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c
--- v2.1.132/linux/drivers/scsi/g_NCR5380.c	Tue Jun  9 11:57:30 1998
+++ linux/drivers/scsi/g_NCR5380.c	Sun Dec 27 10:53:45 1998
@@ -495,7 +495,7 @@
 	    dst[start+i] = NCR5380_read(C400_HOST_BUFFER);
 #else
 	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	memmove(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
+	memcpy(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
 #endif
 	start+=128;
 	blocks--;
@@ -516,7 +516,7 @@
 	    dst[start+i] = NCR5380_read(C400_HOST_BUFFER);
 #else
 	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	memmove(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
+	memcpy(dst+start,NCR53C400_host_buffer+NCR5380_map_name,128);
 #endif
 	start+=128;
 	blocks--;
@@ -603,7 +603,7 @@
 	    NCR5380_write(C400_HOST_BUFFER, src[start+i]);
 #else
 	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	memmove(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
+	memcpy(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
 #endif
 	start+=128;
 	blocks--;
@@ -623,7 +623,7 @@
 	    NCR5380_write(C400_HOST_BUFFER, src[start+i]);
 #else
 	/* implies CONFIG_SCSI_G_NCR5380_MEM */
-	memmove(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
+	memcpy(NCR53C400_host_buffer+NCR5380_map_name,src+start,128);
 #endif
 	start+=128;
 	blocks--;
diff -u --recursive --new-file v2.1.132/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c
--- v2.1.132/linux/drivers/scsi/gdth.c	Wed Sep  9 14:51:08 1998
+++ linux/drivers/scsi/gdth.c	Wed Dec 23 09:44:41 1998
@@ -268,7 +268,7 @@
 #endif
 
 #define PTR2USHORT(a)   (ushort)(ulong)(a)
-#define JIFFYWAIT(a)    {ulong gdtjf;gdtjf=jiffies+(a);while(gdtjf>jiffies);}
+#define JIFFYWAIT(a)    {ulong gdtjf;gdtjf=jiffies+(a);while(time_before(jiffies,gdtjf));}
 #define GDTOFFSOF(a,b)  (size_t)&(((a*)0)->b)   
 #define INDEX_OK(i,t)   ((i)<sizeof(t)/sizeof((t)[0]))
 
diff -u --recursive --new-file v2.1.132/linux/drivers/scsi/i91uscsi.c linux/drivers/scsi/i91uscsi.c
--- v2.1.132/linux/drivers/scsi/i91uscsi.c	Tue Dec 22 14:16:56 1998
+++ linux/drivers/scsi/i91uscsi.c	Wed Dec 23 09:44:41 1998
@@ -234,7 +234,7 @@
 	 */
 	spin_lock_irq(&io_request_lock);
 #else
-	while (jiffies < the_time);
+	while (time_before(jiffies, the_time));
 #endif
 }
 
diff -u --recursive --new-file v2.1.132/linux/drivers/scsi/ppa.c linux/drivers/scsi/ppa.c
--- v2.1.132/linux/drivers/scsi/ppa.c	Tue Dec 22 14:16:56 1998
+++ linux/drivers/scsi/ppa.c	Mon Dec 28 11:06:11 1998
@@ -389,9 +389,11 @@
      * In case you are wondering what the last line of the asm does...
      * <output allocation> : <input allocation> : <trashed registers>
      */
+    register int d0;
+
     asm("shr $2,%%ecx\n" \
 	"	jz .no_more_bulk_bo\n" \
-	"	.align 4\n" \
+	"	.p2align 4,,7\n" \
 	".loop_bulk_bo:\n" \
 	"	movl (%%esi),%%ebx\n" \
 	BYTE_OUT(%%bl) \
@@ -401,19 +403,23 @@
 	BYTE_OUT(%%bh) \
 	"	addl $4,%%esi\n" \
 	"	loop .loop_bulk_bo\n" \
-	"	.align 4\n" \
+	"	.p2align 4,,7\n" \
 	".no_more_bulk_bo:" \
-  : "=S"(buffer): "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+  : "=S"(buffer), "=c"(d0)
+  : "1"(len), "d"(base), "0"(buffer)
+  : "eax", "ebx");
 
     asm("andl $3,%%ecx\n" \
 	"	jz .no_more_loose_bo\n" \
-	"	.align 4\n" \
+	"	.p2align 4,,7\n" \
 	".loop_loose_bo:\n" \
 	BYTE_OUT((%%esi)) \
 	"	incl %%esi\n" \
 	"	loop .loop_loose_bo\n" \
 	".no_more_loose_bo:\n" \
-  : /* no output */ : "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+  : "=c"(d0)
+  : "0"(len), "d"(base), "S"(buffer)
+  : "eax", "ebx");
     return 1;			/* All went well - we hope! */
 }
 
@@ -439,9 +445,11 @@
      * In case you are wondering what the last line of the asm does...
      * <output allocation> : <input allocation> : <trashed registers>
      */
+    register int d0;
+
     asm("shr $2,%%ecx\n" \
 	"	jz .no_more_bulk_bi\n" \
-	"	.align 4\n" \
+	"	.p2align 4,,7\n" \
 	".loop_bulk_bi:\n" \
 	BYTE_IN(%%bl) \
 	BYTE_IN(%%bh) \
@@ -452,19 +460,23 @@
 	"	movl %%ebx,(%%esi)\n" \
 	"	addl $4,%%esi\n" \
 	"	loop .loop_bulk_bi\n" \
-	"	.align 4\n" \
+	"	.p2align 4,,7\n" \
 	".no_more_bulk_bi:" \
-  : "=S"(buffer): "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+  : "=S"(buffer), "=c"(d0)
+  : "1"(len), "d"(base), "0"(buffer)
+  : "eax", "ebx");
 
     asm("andl $3,%%ecx\n" \
 	"	jz .no_more_loose_bi\n" \
-	"	.align 4\n" \
+	"	.p2align 4,,7\n" \
 	".loop_loose_bi:\n" \
 	BYTE_IN((%%esi)) \
 	"	incl %%esi\n" \
 	"	loop .loop_loose_bi\n" \
 	".no_more_loose_bi:\n" \
-  : /* no output */ : "c"(len), "d"(base), "S"(buffer):"eax", "ebx", "ecx");
+  : "=c"(d0)
+  : "0"(len), "d"(base), "S"(buffer)
+  : "eax", "ebx");
     return 1;			/* All went well - we hope! */
 }
 
@@ -496,9 +508,11 @@
      * In case you are wondering what the last line of the asm does...
      * <output allocation> : <input allocation> : <trashed registers>
      */
+    register int d0;
+
     asm("shr $2,%%ecx\n" \
 	"	jz .no_more_bulk_ni\n" \
-	"	.align 4\n" \
+	"	.p2align 4,,7\n" \
 	".loop_bulk_ni:\n" \
 	NIBBLE_IN(%%bl) \
 	NIBBLE_IN(%%bh) \
@@ -509,19 +523,23 @@
 	"	movl %%ebx,(%%esi)\n" \
 	"	addl $4,%%esi\n" \
 	"	loop .loop_bulk_ni\n" \
-	"	.align 4\n" \
+	"	.p2align 4,,7\n" \
 	".no_more_bulk_ni:" \
-  : "=S"(buffer): "c"(len), "d"(str_p), "S"(buffer):"eax", "ebx", "ecx");
+  : "=S"(buffer), "=c"(d0)
+  : "1"(len), "d"(str_p), "0"(buffer)
+  : "eax", "ebx");
 
     asm("andl $3,%%ecx\n" \
 	"	jz .no_more_loose_ni\n" \
-	"	.align 4\n" \
+	"	.p2align 4,,7\n" \
 	".loop_loose_ni:\n" \
 	NIBBLE_IN((%%esi)) \
 	"	incl %%esi\n" \
 	"	loop .loop_loose_ni\n" \
 	".no_more_loose_ni:\n" \
-  : /* no output */ : "c"(len), "d"(str_p), "S"(buffer):"eax", "ebx", "ecx");
+  : "=c"(d0)
+  : "0"(len), "d"(str_p), "S"(buffer)
+  : "eax", "ebx");
     return 1;			/* All went well - we hope! */
 }
 #else				/* Old style C routines */
diff -u --recursive --new-file v2.1.132/linux/drivers/scsi/scsi_error.c linux/drivers/scsi/scsi_error.c
--- v2.1.132/linux/drivers/scsi/scsi_error.c	Tue Dec 22 14:16:56 1998
+++ linux/drivers/scsi/scsi_error.c	Sun Dec 27 10:18:34 1998
@@ -1182,14 +1182,14 @@
       }
 
     if (SCpnt->sense_buffer[2] & 0xe0)
-	return FAILED;
+	return SUCCESS;
 
     switch (SCpnt->sense_buffer[2] & 0xf)
     {
     case NO_SENSE:
 	return SUCCESS;
     case RECOVERED_ERROR:
-	return SOFT_ERROR;
+	return /* SOFT_ERROR */ SUCCESS;
 
     case ABORTED_COMMAND:
 	return NEEDS_RETRY;
@@ -1212,18 +1212,17 @@
     case COPY_ABORTED:
     case VOLUME_OVERFLOW:
     case MISCOMPARE:
+        return SUCCESS;
 
     case MEDIUM_ERROR:
-	return FAILED;
+	return NEEDS_RETRY;
 
     case ILLEGAL_REQUEST:
-	return SUCCESS;
-
     case BLANK_CHECK:
     case DATA_PROTECT:
     case HARDWARE_ERROR:
     default:
-	return FAILED;
+	return SUCCESS;
     }
 }
 
diff -u --recursive --new-file v2.1.132/linux/drivers/scsi/scsiiom.c linux/drivers/scsi/scsiiom.c
--- v2.1.132/linux/drivers/scsi/scsiiom.c	Sun Nov  8 14:03:02 1998
+++ linux/drivers/scsi/scsiiom.c	Fri Dec 25 16:41:39 1998
@@ -4,7 +4,7 @@
  *	Description: Device Driver for Tekram DC-390 (T) PCI SCSI      *
  *		     Bus Master Host Adapter			       *
  ***********************************************************************/
-/* $Id: scsiiom.c,v 2.3 1998/10/24 09:10:28 garloff Exp $ */
+/* $Id: scsiiom.c,v 2.15 1998/12/25 17:33:27 garloff Exp $ */
 
 UCHAR
 dc390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
@@ -36,7 +36,7 @@
 	    DC390_write8 (ScsiFifo, bval);
 	    bval1 = SEL_W_ATN;
 	    pSRB->SRBState = SRB_START_;
-	    DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
+	    DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
 	    if( pDCB->SyncMode & SYNC_ENABLE )
 		{
 		if( !(pDCB->IdentifyMsg & 7) ||		/* LUN == 0 || Cmd != INQUIRY */
@@ -53,21 +53,21 @@
 	    if(pDCB->SyncMode & EN_TAG_QUEUEING)
 	    {
 	        DC390_write8 (ScsiFifo, MSG_SIMPLE_QTAG);
-		    DEBUG1(printk ("DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);)
+		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN3, pDCB->TagMask);)
 	        bval = 0; wlval = 1;
 	        while (wlval & pDCB->TagMask)
 		  { bval++; wlval <<= 1; };
 		pDCB->TagMask |= wlval;
 	        DC390_write8 (ScsiFifo, bval);
 		pSRB->TagNumber = bval;
-		DEBUG1(printk ("DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
+		DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
 		bval1 = SEL_W_ATN3;
 		pSRB->SRBState = SRB_START_;
 	    }
 	    else	/* No TagQ */
 	    {
 		bval1 = SEL_W_ATN;
-		    DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
+		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
 		pSRB->SRBState = SRB_START_;
 	    }
 	}
@@ -82,7 +82,7 @@
 	    bval &= 0xBF;	/* No DisConn */
 	    DC390_write8 (ScsiFifo, bval);
 	    bval1 = SEL_W_ATN;
-	    DEBUG1(printk ("DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
+	    DEBUG1(printk (KERN_DEBUG "DC390: No DisCn, No TagQ (%02x, %02x)\n", bval, bval1);)
 	    pSRB->SRBState = SRB_START_;
 	      /* ??? */
 	    if( pDCB->SyncMode & SYNC_ENABLE )
@@ -101,13 +101,13 @@
 	    if(pDCB->SyncMode & EN_TAG_QUEUEING)
 	    {
 		pSRB->MsgOutBuf[0] = MSG_SIMPLE_QTAG;
-		DEBUG1(printk ("DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);)
+		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, SEL_W_ATN_STOP, pDCB->TagMask);)
 		bval = 0; wlval = 1;
 	        while (wlval & pDCB->TagMask)
 		  { bval++; wlval <<= 1; };
 		pDCB->TagMask |= wlval;
 		pSRB->TagNumber = bval;
-		DEBUG1(printk ("DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
+		DEBUG1(printk (KERN_DEBUG "DC390: SRB %p (Cmd %li), Tag %02x queued\n", pSRB, pSRB->pcmd->pid, bval);)
 		pSRB->MsgOutBuf[1] = bval;
 		pSRB->MsgCnt = 2;
 		bval1 = SEL_W_ATN_STOP;
@@ -119,7 +119,7 @@
 		pSRB->MsgCnt = 1;
 		pSRB->SRBState = SRB_START_;
 		bval1 = SEL_W_ATN_STOP;
-		DEBUG1(printk ("DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
+		DEBUG1(printk (KERN_DEBUG "DC390: %sDisCn, No TagQ (%02x, %02x, %08lx)\n", (bval&0x40?"":"No "), bval, bval1, pDCB->TagMask);)
 	    };
 	}
     }
@@ -134,7 +134,7 @@
 	    DC390_write8 (ScsiFifo, bval);
 	    DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
 	    DC390_write8 (ScsiFifo, bval);
-	    DEBUG1(printk ("DC390: AutoReqSense !\n");)
+	    DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n");)
 	  }
 	else	/* write cmnd to bus */ 
 	  {
@@ -150,16 +150,16 @@
     {
 	pSRB->SRBState = SRB_READY;
 	pDCB->TagMask &= ~( 1 << pSRB->TagNumber );
-	DEBUG0(printk ("DC390: Interrupt during StartSCSI!\n");)
+	DEBUG0(printk (KERN_WARNING "DC390: Interrupt during StartSCSI!\n");)
 	return 1;
     }
     else
     {
 	pSRB->ScsiPhase = SCSI_NOP1;
 	DEBUG0(if (pACB->pActiveDCB)	\
-		    printk ("DC390: ActiveDCB != 0\n");)
+		    printk (KERN_WARNING "DC390: ActiveDCB != 0\n");)
 	DEBUG0(if (pDCB->pActiveSRB)	\
-		    printk ("DC390: ActiveSRB != 0\n");)
+		    printk (KERN_WARNING "DC390: ActiveSRB != 0\n");)
 	pACB->pActiveDCB = pDCB;
 	pDCB->pActiveSRB = pSRB;
 	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
@@ -183,12 +183,10 @@
   DEBUG0(PDEVSET1;)
   DEBUG0(PCI_READ_CONFIG_WORD (PDEV, PCI_STATUS, &pstate);)
   DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\
-	{ printk("DC390: PCI state = %04x!\n", pstate); \
+	{ printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \
 	  PCI_WRITE_CONFIG_WORD (PDEV, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));};)
 
-  dstate = DC390_read8 (DMA_Status);
-  DC390_write8 (DMA_Status, dstate);	/* clear */
-  //DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
+  dstate = DC390_read8 (DMA_Status); 
 
   if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate;
   else pSRB  = pACB->pActiveDCB->pActiveSRB;
@@ -207,12 +205,11 @@
 	      {
 		DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n");)
 		dstate = DC390_read8 (DMA_Status);
-		DC390_write8 (DMA_Status, dstate);	/* clear */
 		residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 |
 		  DC390_read8 (CtcReg_High) << 16;
 		residual += DC390_read8 (Current_Fifo) & 0x1f;
 	      } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr);
-	    if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr));
+	    if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
 	    /* residual =  ... */
 	  }
 	else
@@ -231,6 +228,7 @@
 	
 	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
     }
+  dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
   return dstate;
 };
 #endif
@@ -245,14 +243,16 @@
     UCHAR  phase, i;
     void   (*stateV)( PACB, PSRB, PUCHAR );
     UCHAR  istate, istatus;
+#if DMA_INT
     UCHAR  dstatus;
+#endif
     DC390_AFLAGS DC390_IFLAGS DC390_DFLAGS
 
     pACB = dc390_pACB_start;
 
     if (pACB == 0)
     {
-	printk(KERN_ERR "DC390: Interrupt on uninitialized adapter!\n");
+	printk(KERN_WARNING "DC390: Interrupt on uninitialized adapter!\n");
 	return;
     }
     DC390_LOCK_DRV;
@@ -275,8 +275,8 @@
 
     DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus);)
 
-    if( pACB == (PACB )-1) { DC390_UNLOCK_DRV; return; };
-   
+    if( !pACB ) { DC390_UNLOCK_DRV; return; };
+
 #if DMA_INT
     DC390_LOCK_IO;
     DC390_LOCK_ACB;
@@ -284,15 +284,17 @@
     DC390_UNLOCK_ACB;
     DC390_UNLOCK_IO;
 
-    DEBUG1(printk ("dstatus=%02x,", dstatus);)
+    DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus);)
     if (! (dstatus & SCSI_INTERRUPT))
       {
-	DEBUG0(printk ("DC390 Int w/o SCSI actions (only DMA?)\n");)
+	DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n");)
 	DC390_UNLOCK_DRV;
 	return;
       };
 #else
-    dstatus = DC390_read8 (DMA_Status);
+    //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
+    //dstatus = DC390_read8 (DMA_Status);
+    //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
 #endif
 
     DC390_LOCK_IO;
@@ -302,14 +304,15 @@
     istate = DC390_read8 (Intern_State);
     istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */
 
-    DEBUG1(printk ("Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus);)
-    dc390_laststatus = dstatus<<24 | sstatus<<16 | istate<<8 | istatus;
+    DEBUG1(printk (KERN_INFO "Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus);)
+    dc390_laststatus &= ~0x00ffffff;
+    dc390_laststatus |= /* dstatus<<24 | */ sstatus<<16 | istate<<8 | istatus;
 
     if (sstatus & ILLEGAL_OP_ERR)
-       {
-	       printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus);
-	       dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB);
-       };
+    {
+	printk ("DC390: Illegal Operation detected (%08lx)!\n", dc390_laststatus);
+	dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB);
+    };
 	
     if(istatus &  DISCONNECTED)
     {
@@ -323,18 +326,6 @@
 	goto unlock;
     }
 
-    if(istatus &  INVALID_CMD)
-    {
-	dc390_InvalidCmd( pACB );
-	goto unlock;
-    }
-
-    if(istatus &  SCSI_RESET)
-    {
-	dc390_ScsiRstDetect( pACB );
-	goto unlock;
-    }
-
     if( istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) )
     {
 	pDCB = pACB->pActiveDCB;
@@ -345,7 +336,7 @@
 	};
 	pSRB = pDCB->pActiveSRB;
 	if( pDCB->DCBFlag & ABORT_DEV_ )
-		dc390_EnableMsgOut( pACB, pSRB );
+	  dc390_EnableMsgOut_Abort (pACB, pSRB);
 
 	phase = pSRB->ScsiPhase;
 	DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus);)
@@ -357,7 +348,21 @@
 	DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus);)
 	stateV = (void *) dc390_phase1[phase];
 	( *stateV )( pACB, pSRB, &sstatus );
+	goto unlock;
     }
+
+    if(istatus &  INVALID_CMD)
+    {
+	dc390_InvalidCmd( pACB );
+	goto unlock;
+    }
+
+    if(istatus &  SCSI_RESET)
+    {
+	dc390_ScsiRstDetect( pACB );
+	goto unlock;
+    }
+
  unlock:
     DC390_LOCK_DRV_NI;
     DC390_UNLOCK_ACB;
@@ -380,6 +385,7 @@
     UCHAR   sstatus;
     PSGL    psgl;
     ULONG   ResidCnt, xferCnt;
+    UCHAR   dstate = 0;
 
     sstatus = *psstatus;
 
@@ -391,10 +397,9 @@
 	if( sstatus & COUNT_2_ZERO )
 	{
 	    int ctr = 5000000; /* only try for about a tenth of a second */
-	    while( --ctr && !(DC390_read8 (DMA_Status) & DMA_XFER_DONE) && pSRB->SGToBeXferLen )
-		DC390_write8 (DMA_Status,  DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
-	    if (!ctr) printk (KERN_CRIT "DC390: DataOut_0: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr));
-	    DC390_write8 (DMA_Status,  DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
+	    while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen );
+	    if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
+	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
 	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
 	    pSRB->SGIndex++;
 	    if( pSRB->SGIndex < pSRB->SGcount )
@@ -443,15 +448,14 @@
 	{
 	    int ctr = 5000000; /* only try for about a tenth of a second */
 	    int dstate = 0;
-	    while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen )
-		DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
-	    if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA aborted unfinished: %06x bytes remain!\n", DC390_read32 (DMA_Wk_ByteCntr));
+	    while( --ctr && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE) && pSRB->SGToBeXferLen );
+	    if (!ctr) printk (KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
 	    if (!ctr) printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate);
+	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
 	    DEBUG1(ResidCnt = ((ULONG) DC390_read8 (CtcReg_High) << 16)	\
 		+ ((ULONG) DC390_read8 (CtcReg_Mid) << 8)		\
 		+ ((ULONG) DC390_read8 (CtcReg_Low));)
-	    DEBUG1(printk ("Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);)
-	    DC390_write8 (DMA_Status, DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
+	    DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%li,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen);)
 
 	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
 
@@ -474,7 +478,7 @@
 	    bval = DC390_read8 (Current_Fifo);
 	    while( bval & 0x1f )
 	    {
-		DEBUG1(printk ("Check for residuals,");)
+		DEBUG1(printk (KERN_DEBUG "Check for residuals,");)
 		if( (bval & 0x1f) == 1 )
 		{
 		    for(i=0; i < 0x100; i++)
@@ -494,17 +498,18 @@
 	    }
 din_1:
 	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD);
-	    for (i=0; i<0x8000; i++)
+	    for (i = 0xa000; i; i--)
 	    {
 		bval = DC390_read8 (DMA_Status);
-		DC390_write8 (DMA_Status, BLAST_COMPLETE | DMA_XFER_DONE | DMA_XFER_ABORT | DMA_XFER_ERROR | PCI_MS_ABORT);	/* clear */
 		if (bval & BLAST_COMPLETE)
 		    break;
 	    }
-	    if (i == 0x8000) printk (KERN_CRIT "DC390: DMA Blast aborted unfinished!!\n");
+	    /* It seems a DMA Blast abort isn't that bad ... */
+	    if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n");
 	    //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24;
 
-	    DEBUG1(printk ("Blast: Read %i times DMA_Status %02x", i, bval);)
+	    DEBUG1(printk (KERN_DEBUG "Blast: Read %li times DMA_Status %02x", 0xa000-i, bval);)
 	    ResidCnt = (ULONG) DC390_read8 (CtcReg_High);
 	    ResidCnt <<= 8;
 	    ResidCnt |= (ULONG) DC390_read8 (CtcReg_Mid);
@@ -525,7 +530,7 @@
 		pSRB->TotalXferredLen++;
 		pSRB->SGToBeXferLen--;
 	    }
-	    DEBUG1(printk ("Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
+	    DEBUG1(printk (KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
 			   pSRB->TotalXferredLen, pSRB->SGToBeXferLen);)
 
 	}
@@ -558,164 +563,278 @@
     //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
-void
-dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+
+static void __inline__
+dc390_reprog (PACB pACB, PDCB pDCB)
 {
-    UCHAR  bval;
-    USHORT wval, wval1;
-    PDCB   pDCB;
-    PSRB   psrb;
+  DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+  DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+  DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+  DC390_write8 (CtrlReg4, pDCB->CtrlR4);
+  dc390_SetXferRate (pACB, pDCB);
+};
 
-    pDCB = pACB->pActiveDCB;
 
-    bval = DC390_read8 (ScsiFifo);
-    if( !(pSRB->SRBState & SRB_MSGIN_MULTI) )
+#ifdef DC390_DEBUG0
+static void
+dc390_printMsg (UCHAR *MsgBuf, UCHAR len)
+{
+  int i;
+  printk (" %02x", MsgBuf[0]);
+  for (i = 1; i < len; i++)
+    printk (" %02x", MsgBuf[i]);
+  printk ("\n");
+};
+#endif
+
+#define DC390_ENABLE_MSGOUT DC390_write8 (ScsiCmd, SET_ATN_CMD)
+
+/* reject_msg */
+static void __inline__
+dc390_MsgIn_reject (PACB pACB, PSRB pSRB)
+{
+  pSRB->MsgOutBuf[0] = MSG_REJECT_;
+  pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
+  DEBUG0 (printk (KERN_INFO "DC390: Reject message\n");)
+}
+
+/* abort command */
+static void __inline__
+dc390_EnableMsgOut_Abort ( PACB pACB, PSRB pSRB )
+{
+    pSRB->MsgOutBuf[0] = MSG_ABORT; 
+    pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
+    pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
+}
+
+static PSRB
+dc390_MsgIn_QTag (PACB pACB, PDCB pDCB, UCHAR tag)
+{
+  PSRB lastSRB = pDCB->pGoingLast;
+  PSRB pSRB = pDCB->pGoingSRB;
+
+  if (pSRB)
     {
-	if(bval == MSG_DISCONNECT)
-	{
-	    pSRB->SRBState = SRB_DISCONNECT;
-	}
-	else if( bval == MSG_SAVE_PTR )
-	    goto  min6;
-	else if( (bval == MSG_EXTENDED) || ((bval >= MSG_SIMPLE_QTAG) &&
-					    (bval <= MSG_ORDER_QTAG)) )
+      for( ;pSRB ; )
 	{
-	    pSRB->SRBState |= SRB_MSGIN_MULTI;
-	    pSRB->MsgInBuf[0] = bval;
-	    pSRB->MsgCnt = 1;
-	    pSRB->pMsgPtr = &(pSRB->MsgInBuf[1]);
+	  if (pSRB->TagNumber == tag) break;
+	  if (pSRB == lastSRB) goto mingx0;
+	  pSRB = pSRB->pNextSRB;
 	}
-	else if(bval == MSG_REJECT_)
+
+      if( pDCB->DCBFlag & ABORT_DEV_ )
 	{
-	    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
-	    pDCB->NegoPeriod = 50;
-	    if( pSRB->SRBState & DO_SYNC_NEGO)
-		goto  set_async;
+	  pSRB->SRBState = SRB_ABORT_SENT;
+	  dc390_EnableMsgOut_Abort( pACB, pSRB );
 	}
-	else if( bval == MSG_RESTORE_PTR)
-	    goto  min6;
-	else
-	    goto  min6;
+
+      if( !(pSRB->SRBState & SRB_DISCONNECT) )
+	goto  mingx0;
+
+      pDCB->pActiveSRB = pSRB;
+      pSRB->SRBState = SRB_DATA_XFER;
     }
-    else
-    {	/* minx: */
+  else
+    {
+    mingx0:
+      pSRB = pACB->pTmpSRB;
+      pSRB->SRBState = SRB_UNEXPECT_RESEL;
+      pDCB->pActiveSRB = pSRB;
+      pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
+      pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
+    }
+  return pSRB;
+}
 
-	*pSRB->pMsgPtr = bval;
-	pSRB->MsgCnt++;
-	pSRB->pMsgPtr++;
-	if( (pSRB->MsgInBuf[0] >= MSG_SIMPLE_QTAG) &&
-	    (pSRB->MsgInBuf[0] <= MSG_ORDER_QTAG) )
-	{
-	    if( pSRB->MsgCnt == 2)
-	    {
-		pSRB->SRBState = 0;
-		bval = pSRB->MsgInBuf[1];
-		pSRB = pDCB->pGoingSRB;
-		psrb = pDCB->pGoingLast;
-		if( pSRB )
-		{
-		    for( ;pSRB ; )
-		    {
-			if(pSRB->TagNumber != bval)
-			{
-			    if( pSRB == psrb )
-				goto  mingx0;
-			    pSRB = pSRB->pNextSRB;
-			}
-			else
-			    break;
-		    }
-		    if( pDCB->DCBFlag & ABORT_DEV_ )
-		    {
-			pSRB->SRBState = SRB_ABORT_SENT;
-			dc390_EnableMsgOut( pACB, pSRB );
-		    }
-		    if( !(pSRB->SRBState & SRB_DISCONNECT) )
-			goto  mingx0;
-		    pDCB->pActiveSRB = pSRB;
-		    pSRB->SRBState = SRB_DATA_XFER;
-		}
-		else
-		{
-mingx0:
-		    pSRB = pACB->pTmpSRB;
-		    pSRB->SRBState = SRB_UNEXPECT_RESEL;
-		    pDCB->pActiveSRB = pSRB;
-		    pSRB->MsgOutBuf[0] = MSG_ABORT_TAG;
-		    dc390_EnableMsgOut2( pACB, pSRB );
-		}
-	    }
-	}
-	else if( (pSRB->MsgInBuf[0] == MSG_EXTENDED) && (pSRB->MsgCnt == 5) )
-	{	/* Note: This will fail for target initiated SDTR ? */
-	    pSRB->SRBState &= ~(SRB_MSGIN_MULTI);
-	    if( (pSRB->MsgInBuf[1] != 3) || (pSRB->MsgInBuf[2] != EXTENDED_SDTR) )
-	    {	/* reject_msg: */
-		pSRB->MsgCnt = 1;
-		pSRB->MsgInBuf[0] = MSG_REJECT_;
-		DC390_write8 (ScsiCmd, SET_ATN_CMD);
-	    }
-	    else if( !(pSRB->MsgInBuf[3]) || !(pSRB->MsgInBuf[4]) )
-	    {
-set_async:
-		pDCB = pSRB->pSRBDCB;
-		if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
-			printk ("DC390: Target (%i,%i) initiates Non-Sync?\n", pDCB->UnitSCSIID, pDCB->UnitSCSILUN);
-		pSRB->SRBState &= ~DO_SYNC_NEGO;
-		pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
-		pDCB->SyncPeriod = 0;
-		pDCB->SyncOffset = 0;
-		pDCB->CtrlR3 = FAST_CLK;	/* fast clock / normal scsi */
-		pDCB->CtrlR4 &= 0x3f;
-		pDCB->CtrlR4 |= pACB->glitch_cfg;	/* glitch eater */
-		goto re_prog;
-	    }
-	    else
-	    {	/* set_sync: */
 
-		pDCB = pSRB->pSRBDCB;
-		if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
-			printk ("DC390: Target (%i,%i) initiates Sync: %ins %i ?\n", 
-				pDCB->UnitSCSIID, pDCB->UnitSCSILUN, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
-		pSRB->SRBState &= ~DO_SYNC_NEGO;
-		pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
-		pDCB->SyncOffset &= 0x0f0;
-		pDCB->SyncOffset |= pSRB->MsgInBuf[4];
-		pDCB->NegoPeriod = pSRB->MsgInBuf[3];
-		wval = (USHORT) pSRB->MsgInBuf[3];
-		wval = wval << 2; wval -= 3; wval1 = wval / 25;	/* compute speed */
-		if( (wval1 * 25) != wval)
-		    wval1++;
-		bval = FAST_CLK+FAST_SCSI;	/* fast clock / fast scsi */
-		pDCB->CtrlR4 &= 0x3f;		/* Glitch eater: 12ns less than normal */
-		if (pACB->glitch_cfg != NS_TO_GLITCH(0))
-			pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1));
-		else
-			pDCB->CtrlR4 |= NS_TO_GLITCH(0);
-		if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */
-		if (wval1 >= 8)
-		{
-		    wval1--;	/* Timing computation differs by 1 from FAST_SCSI */
-		    bval = FAST_CLK;		/* fast clock / normal scsi */
-		    pDCB->CtrlR4 |= pACB->glitch_cfg; 	/* glitch eater */
-		}
-		pDCB->CtrlR3 = bval;
-		pDCB->SyncPeriod = (UCHAR)wval1;
-re_prog:
-	        DC390_write8 (Sync_Period, pDCB->SyncPeriod);
-	        DC390_write8 (Sync_Offset, pDCB->SyncOffset);
-	        DC390_write8 (CtrlReg3, pDCB->CtrlR3);
-	        DC390_write8 (CtrlReg4, pDCB->CtrlR4);
-		dc390_SetXferRate (pACB, pDCB);
-	    }
+/* set async transfer mode */
+static void 
+dc390_MsgIn_set_async (PACB pACB, PSRB pSRB)
+{
+  PDCB pDCB = pSRB->pSRBDCB;
+  if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
+    printk ("DC390: Target %i initiates Non-Sync?\n", pDCB->UnitSCSIID);
+  pSRB->SRBState &= ~DO_SYNC_NEGO;
+  pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
+  pDCB->SyncPeriod = 0;
+  pDCB->SyncOffset = 0;
+  //pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
+  pDCB->CtrlR3 = FAST_CLK;	/* fast clock / normal scsi */
+  pDCB->CtrlR4 &= 0x3f;
+  pDCB->CtrlR4 |= pACB->glitch_cfg;	/* glitch eater */
+  dc390_reprog (pACB, pDCB);
+}
+
+/* set sync transfer mode */
+static void
+dc390_MsgIn_set_sync (PACB pACB, PSRB pSRB)
+{
+  UCHAR bval;
+  USHORT wval, wval1;
+  PDCB pDCB = pSRB->pSRBDCB;
+  UCHAR oldsyncperiod = pDCB->SyncPeriod;
+  UCHAR oldsyncoffset = pDCB->SyncOffset;
+  
+  if (!(pSRB->SRBState & DO_SYNC_NEGO))
+    {
+      printk ("DC390: Target %i initiates Sync: %ins %i ... answer ...\n", 
+	      pDCB->UnitSCSIID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
+
+      /* reject */
+      //dc390_MsgIn_reject (pACB, pSRB);
+      //return dc390_MsgIn_set_async (pACB, pSRB);
+
+      /* Reply with corrected SDTR Message */
+      if (pSRB->MsgInBuf[4] > 15)
+	{ 
+	  printk ("DC390: Lower Sync Offset to 15\n");
+	  pSRB->MsgInBuf[4] = 15;
 	}
+      if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod)
+	{
+	  printk ("DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2);
+	  pSRB->MsgInBuf[3] = pDCB->NegoPeriod;
+	};
+      memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5);
+      pSRB->MsgCnt = 5;
+      DC390_ENABLE_MSGOUT;
+    };
+
+  pSRB->SRBState &= ~DO_SYNC_NEGO;
+  pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
+  pDCB->SyncOffset &= 0x0f0;
+  pDCB->SyncOffset |= pSRB->MsgInBuf[4];
+  pDCB->NegoPeriod = pSRB->MsgInBuf[3];
+
+  wval = (USHORT) pSRB->MsgInBuf[3];
+  wval = wval << 2; wval -= 3; wval1 = wval / 25;	/* compute speed */
+  if( (wval1 * 25) != wval) wval1++;
+  bval = FAST_CLK+FAST_SCSI;	/* fast clock / fast scsi */
+
+  pDCB->CtrlR4 &= 0x3f;		/* Glitch eater: 12ns less than normal */
+  if (pACB->glitch_cfg != NS_TO_GLITCH(0))
+    pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1));
+  else
+    pDCB->CtrlR4 |= NS_TO_GLITCH(0);
+  if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */
+
+  if (wval1 >= 8)
+    {
+      wval1--;	/* Timing computation differs by 1 from FAST_SCSI */
+      bval = FAST_CLK;		/* fast clock / normal scsi */
+      pDCB->CtrlR4 |= pACB->glitch_cfg; 	/* glitch eater */
     }
-min6:
+
+  pDCB->CtrlR3 = bval;
+  pDCB->SyncPeriod = (UCHAR)wval1;
+  
+  if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->UnitSCSILUN == 0)
+    {
+      if (! (bval & FAST_SCSI)) wval1++;
+      printk ("DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->UnitSCSIID, 
+	      40/wval1, ((40%wval1)*10+wval1/2)/wval1, pDCB->SyncOffset & 0x0f);
+    }
+  
+  dc390_reprog (pACB, pDCB);
+};
+
+
+/* According to the docs, the AM53C974 reads the message and 
+ * generates a Succesful Operation IRQ before asserting ACK for
+ * the last byte (how does it know whether it's the last ?) */
+/* The old code handled it in another way, indicating, that on
+ * every message byte an IRQ is generated and every byte has to
+ * be manually ACKed. Hmmm ?  (KG, 98/11/28) */
+/* The old implementation was correct. Sigh! */
+
+/* Check if the message is complete */
+static UCHAR __inline__
+dc390_MsgIn_complete (UCHAR *msgbuf, ULONG len)
+{ 
+  if (*msgbuf == MSG_EXTENDED)
+    {
+      if (len < 2) return 0;
+      if (len < msgbuf[1] + 2) return 0;
+    }
+  else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages
+    if (len < 2) return 0;
+  return 1;
+}
+
+
+
+/* read and eval received messages */
+void
+dc390_MsgIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
+{
+    PDCB   pDCB = pACB->pActiveDCB;
+
+    /* Read the msg */
+
+    pSRB->MsgInBuf[pACB->MsgLen++] = DC390_read8 (ScsiFifo);
+    //pSRB->SRBState = 0;
+
+    /* Msg complete ? */
+    if (dc390_MsgIn_complete (pSRB->MsgInBuf, pACB->MsgLen))
+      {
+	DEBUG0 (printk (KERN_INFO "DC390: MsgIn:"); dc390_printMsg (pSRB->MsgInBuf, pACB->MsgLen);)
+	/* Now eval the msg */
+	switch (pSRB->MsgInBuf[0]) 
+	  {
+	  case MSG_DISCONNECT: 
+	    pSRB->SRBState = SRB_DISCONNECT; break;
+	    
+	  case MSG_SIMPLE_QTAG:
+	  case MSG_HEAD_QTAG:
+	  case MSG_ORDER_QTAG:
+	    pSRB = dc390_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]);
+	    break;
+	    
+	  case MSG_REJECT_: 
+	    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+	    pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
+	    if( pSRB->SRBState & DO_SYNC_NEGO)
+	      dc390_MsgIn_set_async (pACB, pSRB);
+	    break;
+	    
+	  case MSG_EXTENDED:
+	    /* reject every extended msg but SDTR */
+	    if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR)
+	      dc390_MsgIn_reject (pACB, pSRB);
+	    else
+	      {
+		if (pSRB->MsgInBuf[3] == 0 || pSRB->MsgInBuf[4] == 0)
+		  dc390_MsgIn_set_async (pACB, pSRB);
+		else
+		  dc390_MsgIn_set_sync (pACB, pSRB);
+	      };
+	    
+	    // nothing has to be done
+	  case MSG_COMPLETE: break;
+	    
+	    // SAVE POINTER my be ignored as we have the PSRB associated with the
+	    // scsi command. Thanks, Gerard, for pointing it out.
+	  case MSG_SAVE_PTR: break;
+	    // The device might want to restart transfer with a RESTORE
+	  case MSG_RESTORE_PTR: 
+	    printk ("DC390: RESTORE POINTER message received ... reject\n");
+	    // fall through
+
+	    // reject unknown messages
+	  default: dc390_MsgIn_reject (pACB, pSRB);
+	  }
+	
+	/* Clear counter and MsgIn state */
+	pSRB->SRBState &= ~SRB_MSGIN;
+	pACB->MsgLen = 0;
+      };
+
     *psstatus = SCSI_NOP0;
     DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
     //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
 }
 
+
 void
 dc390_DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
 {
@@ -730,10 +849,10 @@
 	    psgl = pSRB->pSegmentList;
 	    pSRB->SGBusAddr = virt_to_bus( psgl->address );
 	    pSRB->SGToBeXferLen = (ULONG) psgl->length;
-	    DEBUG1(printk (" DC390: Next SG segment.");)
+	    DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment.");)
 	}
 	lval = pSRB->SGToBeXferLen;
-	DEBUG1(printk (" DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);)
+	DEBUG1(printk (KERN_DEBUG " DC390: Transfer %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr);)
 	DC390_write8 (CtcReg_Low, (UCHAR) lval);
 	lval >>= 8;
 	DC390_write8 (CtcReg_Mid, (UCHAR) lval);
@@ -749,21 +868,22 @@
 	DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD);
 
 	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
-	//DEBUG1(printk ("DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));)
+	//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);)
+	//DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status));)
+	//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);)
     }
     else    /* xfer pad */
     {
-	UCHAR bval = 0;
 	if( pSRB->SGcount )
 	{
 	    pSRB->AdaptStatus = H_OVER_UNDER_RUN;
 	    pSRB->SRBStatus |= OVER_RUN;
-	    DEBUG0(printk (" DC390: Overrun -");)
+	    DEBUG0(printk (KERN_WARNING " DC390: Overrun -");)
 	}
-	DEBUG0(printk (" Clear transfer pad \n");)
-	DC390_write8 (CtcReg_Low, bval);
-	DC390_write8 (CtcReg_Mid, bval);
-	DC390_write8 (CtcReg_High, bval);
+	DEBUG0(printk (KERN_WARNING " Clear transfer pad \n");)
+	DC390_write8 (CtcReg_Low, 0);
+	DC390_write8 (CtcReg_Mid, 0);
+	DC390_write8 (CtcReg_High, 0);
 
 	pSRB->SRBState |= SRB_XFERPAD;
 	DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE);
@@ -1017,7 +1137,7 @@
 	    dc390_SRBdone( pACB, pDCB, pSRB);
 	}
     }
-    return;
+    pACB->MsgLen = 0;
 }
 
 
@@ -1032,7 +1152,7 @@
     DEBUG0(printk(KERN_INFO "RSEL,");)
     pDCB = pACB->pActiveDCB;
     if( pDCB )
-    {	/* Arbitration lost but Reselection win */
+    {	/* Arbitration lost but Reselection won */
 	DEBUG0(printk ("(ActiveDCB != 0)");)
 	pSRB = pDCB->pActiveSRB;
 	if( !( pACB->scan_devices ) )
@@ -1075,23 +1195,23 @@
 	    printk (KERN_ERR "DC390: Reselect without outstanding cmnd (ID %02x, LUN %02x)\n",
 		    wval & 0xff, (wval & 0xff00) >> 8);
 	    pDCB->pActiveSRB = pSRB;
-	    dc390_EnableMsgOut( pACB, pSRB );
+	    dc390_EnableMsgOut_Abort ( pACB, pSRB );
 	}
 	else
 	{
 	    if( pDCB->DCBFlag & ABORT_DEV_ )
 	    {
 		pSRB->SRBState = SRB_ABORT_SENT;
-		printk (KERN_NOTICE "DC390: Reselect: Abort (ID %02x, LUN %02x)\n",
+		printk (KERN_INFO "DC390: Reselect: Abort (ID %02x, LUN %02x)\n",
 			wval & 0xff, (wval & 0xff00) >> 8);
-		dc390_EnableMsgOut( pACB, pSRB );
+		dc390_EnableMsgOut_Abort( pACB, pSRB );
 	    }
 	    else
 		pSRB->SRBState = SRB_DATA_XFER;
 	}
     }
 
-    DEBUG1(printk ("Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);)
+    DEBUG1(printk (KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber);)
     pSRB->ScsiPhase = SCSI_NOP0;
     DC390_write8 (Scsi_Dest_ID, pDCB->UnitSCSIID);
     DC390_write8 (Sync_Period, pDCB->SyncPeriod);
@@ -1244,7 +1364,7 @@
 	    else
 		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) |
 				SCSI_STAT_CHECKCOND;
-	    REMOVABLEDEBUG(printk("Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\
+	    REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x,Result=%08x,XferL=%08x\n",pSRB->CmdBlock[0],\
 		(UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
 	    goto ckc_e;
 	}
@@ -1260,7 +1380,7 @@
 	    {
 		pcmd->result = (DRIVER_SENSE << 24) | (DRIVER_OK << 16) 
 			    | SCSI_STAT_CHECKCOND;
-		REMOVABLEDEBUG(printk("Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[0],\
+		REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->CmdBlock[0],\
 		       (UINT) pcmd->result, (UINT) pSRB->TotalXferredLen);)
 		goto ckc_e;
 	    }
@@ -1299,7 +1419,7 @@
 		    swlval += ptr2->length;
 		    ptr2++;
 		}
-		REMOVABLEDEBUG(printk("XferredLen=%08x,NotXferLen=%08x\n",\
+		REMOVABLEDEBUG(printk(KERN_INFO "XferredLen=%08x,NotXferLen=%08x\n",\
 			(UINT) pSRB->TotalXferredLen, (UINT) swlval);)
 	    }
 	    dc390_RequestSense( pACB, pDCB, pSRB );
@@ -1586,22 +1706,6 @@
 	dc390_RewaitSRB( pDCB, pSRB );
 }
 
-
-static void __inline__
-dc390_EnableMsgOut2( PACB pACB, PSRB pSRB )
-{
-    pSRB->MsgCnt = 1;
-    DC390_write8 (ScsiCmd, SET_ATN_CMD);
-}
-
-
-static void __inline__
-dc390_EnableMsgOut( PACB pACB, PSRB pSRB )
-{
-    pSRB->MsgOutBuf[0] = MSG_ABORT;
-    dc390_EnableMsgOut2( pACB, pSRB );
-    pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
-}
 
 
 static void __inline__
diff -u --recursive --new-file v2.1.132/linux/drivers/scsi/st.c linux/drivers/scsi/st.c
--- v2.1.132/linux/drivers/scsi/st.c	Mon Sep 28 10:51:34 1998
+++ linux/drivers/scsi/st.c	Sun Dec 27 10:18:55 1998
@@ -11,7 +11,7 @@
   Copyright 1992 - 1998 Kai Makisara
 		 email Kai.Makisara@metla.fi
 
-  Last modified: Sun Sep  6 09:34:49 1998 by root@home
+  Last modified: Thu Dec  3 20:27:46 1998 by makisara@home
   Some small formal changes - aeb, 950809
 */
 
@@ -707,7 +707,7 @@
       STp->density = 0;   	/* Clear the erroneous "residue" */
       STp->write_prot = 0;
       STp->block_size = 0;
-      STp->ps[0].drv_file = STp->ps[0].drv_block = 0;
+      STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
       STp->partition = STp->new_partition = 0;
       STp->door_locked = ST_UNLOCKED;
       STp->in_use = 1;
@@ -785,6 +785,7 @@
 	  !enlarge_buffer(STp->buffer, STp->block_size, STp->restr_dma)) {
 	printk(KERN_NOTICE "st%d: Blocksize %d too large for buffer.\n", dev,
 	       STp->block_size);
+	scsi_release_command(SCpnt);
 	(STp->buffer)->in_use = 0;
 	STp->buffer = NULL;
 	if (scsi_tapes[dev].device->host->hostt->module)
@@ -3414,8 +3415,8 @@
      STps->eof = ST_NOEOF;
      STps->at_sm = 0;
      STps->last_block_valid = FALSE;
-     STps->drv_block = 0;
-     STps->drv_file = 0;
+     STps->drv_block = (-1);
+     STps->drv_file = (-1);
    }
 
    tpnt->current_mode = 0;
diff -u --recursive --new-file v2.1.132/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c
--- v2.1.132/linux/drivers/scsi/tmscsim.c	Sun Nov  8 14:03:02 1998
+++ linux/drivers/scsi/tmscsim.c	Fri Dec 25 16:41:39 1998
@@ -5,9 +5,11 @@
  *		     Bus Master Host Adapter			       *
  * (C)Copyright 1995-1996 Tekram Technology Co., Ltd.		       *
  ***********************************************************************/
-/* $Id: tmscsim.c,v 2.4 1998/10/24 08:50:47 garloff Exp $		*/
+/* (C) Copyright: put under GNU GPL in 10/96				*
+*************************************************************************/
+/* $Id: tmscsim.c,v 2.16 1998/12/25 17:54:44 garloff Exp $		*/
 /*	Enhancements and bugfixes by					*
- *	Kurt Garloff <K.Garloff@ping.de>				*
+ *	Kurt Garloff <kurt@garloff.de>					*
  ***********************************************************************/
 /*	HISTORY:							*
  *									*
@@ -90,6 +92,11 @@
  *				bios_param() now respects part. table.	*
  *	2.0b  98/10/24	KG	Docu fixes. Timeout Msg in DMA Blast.	*
  *				Disallow illegal idx in INQUIRY/REMOVE	*
+ *	2.0c  98/11/19	KG	Cleaned up detect/init for SMP boxes, 	*
+ *				Write Erase DMA (1.20t) caused problems	*
+ *	2.0d  98/12/25	KG	Christmas release ;-) Message handling  *
+ *				competely reworked. Handle target ini-	*
+ *				tiated SDTR correctly.			*
  ***********************************************************************/
 
 /* Uncomment SA_INTERRUPT, if the driver refuses to share its IRQ with other devices */
@@ -206,9 +213,9 @@
 # if USE_SPINLOCKS == 3 /* both */
 
 #  if defined (__SMP__) || DEBUG_SPINLOCKS > 0
-#   define DC390_LOCK_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
+#   define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
 #  else
-#   define DC390_LOCK_INIT
+#   define DC390_LOCKA_INIT
 #  endif
    spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
 
@@ -228,16 +235,16 @@
 #  define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags)
 #  define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock))
 #  define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock))
-//#  define DC390_LOCK_INIT spin_lock_init (&(pACB->lock))
+//#  define DC390_LOCKA_INIT spin_lock_init (&(pACB->lock))
 
 # else
 
 #  if USE_SPINLOCKS == 2 /* adapter specific locks */
 
 #   if defined (__SMP__) || DEBUG_SPINLOCKS > 0
-#    define DC390_LOCK_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
+#    define DC390_LOCKA_INIT { spinlock_t __unlocked = SPIN_LOCK_UNLOCKED; pACB->lock = __unlocked; };
 #   else
-#    define DC390_LOCK_INIT
+#    define DC390_LOCKA_INIT
 #   endif
     spinlock_t dc390_drvlock = SPIN_LOCK_UNLOCKED;
 #   define DC390_AFLAGS unsigned long aflags;
@@ -253,7 +260,7 @@
 #   define DC390_UNLOCK_ACB spin_unlock_irqrestore (&(pACB->lock), aflags)
 #   define DC390_LOCK_ACB_NI spin_lock (&(pACB->lock))
 #   define DC390_UNLOCK_ACB_NI spin_unlock (&(pACB->lock))
-//#   define DC390_LOCK_INIT spin_lock_init (&(pACB->lock))
+//#   define DC390_LOCKA_INIT spin_lock_init (&(pACB->lock))
 
 #  else /* USE_SPINLOCKS == 1: global lock io_request_lock */
 
@@ -271,7 +278,7 @@
 #   define DC390_UNLOCK_ACB /* DC390_UNLOCK_IO */
 #   define DC390_LOCK_ACB_NI /* spin_lock (&(pACB->lock)) */
 #   define DC390_UNLOCK_ACB_NI /* spin_unlock (&(pACB->lock)) */
-#   define DC390_LOCK_INIT /* DC390_LOCK_INIT */
+#   define DC390_LOCKA_INIT /* DC390_LOCKA_INIT */
 
 #  endif /* 2 */
 # endif /* 3 */
@@ -291,7 +298,7 @@
 # define DC390_UNLOCK_ACB restore_flags (aflags)
 # define DC390_LOCK_ACB_NI
 # define DC390_UNLOCK_ACB_NI
-# define DC390_LOCK_INIT
+# define DC390_LOCKA_INIT
 #endif /* def */
 
 
@@ -365,9 +372,8 @@
 static void dc390_ScsiRstDetect( PACB pACB );
 static void dc390_ResetSCSIBus( PACB pACB );
 static void __inline__ dc390_RequestSense( PACB pACB, PDCB pDCB, PSRB pSRB );
-static void __inline__ dc390_EnableMsgOut2( PACB pACB, PSRB pSRB );
-static void __inline__ dc390_EnableMsgOut( PACB pACB, PSRB pSRB );
 static void __inline__ dc390_InvalidCmd( PACB pACB );
+static void __inline__ dc390_EnableMsgOut_Abort (PACB, PSRB);
 static void dc390_remove_dev (PACB pACB, PDCB pDCB);
 void do_DC390_Interrupt( int, void *, struct pt_regs *);
 
@@ -481,9 +487,190 @@
        S_IFDIR | S_IRUGO | S_IXUGO, 2
        };
 
+
 /***********************************************************************
+ * Functions for access to DC390 EEPROM
+ * and some to emulate it
  *
- *
+ **********************************************************************/
+
+
+static void __init dc390_EnDisableCE( UCHAR mode, PDEVDECL, PUCHAR regval )
+{
+    UCHAR bval;
+
+    bval = 0;
+    if(mode == ENABLE_CE)
+	*regval = 0xc0;
+    else
+	*regval = 0x80;
+    PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
+    if(mode == DISABLE_CE)
+        PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
+    udelay(160);
+}
+
+#ifndef CONFIG_SCSI_DC390T_NOGENSUPP
+static void __init dc390_EEpromDefaults (UCHAR index)
+{
+    PUCHAR ptr;
+    UCHAR  id;
+    ptr = (PUCHAR) dc390_eepromBuf[index];
+    
+    /* Adapter Settings */
+    ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */
+    ptr[EE_MODE2] = (UCHAR)tmscsim[3];
+    ptr[EE_DELAY] = 0; /* ?? */
+    ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Comds */
+    
+    /* Device Settings */
+    for (id = 0; id < MAX_SCSI_ID; id++)
+    {
+      ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */
+      ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */
+    };
+    dc390_adapname = "AM53C974";
+}
+
+static void __init dc390_checkparams (void)
+{
+	PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x\n", tmscsim[0],\
+		      tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4]);)
+	if (tmscsim[0] < 0 || tmscsim[0] > 7) /* modules-2.0.0 passes -1 as string */
+	{
+		tmscsim[0] = 7; tmscsim[1] = 4; 
+		tmscsim[2] = 9; tmscsim[3] = 15;
+		tmscsim[4] = 2;
+		printk (KERN_INFO "DC390: Using safe settings.\n");
+	}
+	else
+	{
+		/* if (tmscsim[0] < 0 || tmscsim[0] > 7) tmscsim[0] = 7; */
+		if (tmscsim[1] < 0 || tmscsim[1] > 7) tmscsim[1] = 4;
+		if (tmscsim[4] < 0 || tmscsim[4] > 5) tmscsim[4] = 4;
+	};
+};
+/* Override defaults on cmdline:
+ * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped)
+ */
+void __init dc390_setup (char *str, int *ints)
+{
+	int i;
+	for (i = 0; i < ints[0]; i++)
+		tmscsim[i] = ints[i+1];
+	if (ints[0] > 5)
+		printk (KERN_NOTICE "DC390: ignore extra params!\n");
+	/* dc390_checkparams (); */
+};
+#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */
+
+
+static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry )
+{
+    UCHAR bval;
+
+    bval = 0;
+    if(Carry)
+    {
+	bval = 0x40;
+	*regval = 0x80;
+	PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
+    }
+    udelay(160);
+    bval |= 0x80;
+    PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
+    udelay(160);
+    bval = 0;
+    PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
+    udelay(160);
+}
+
+
+static UCHAR __init dc390_EEpromInDO( PDEVDECL )
+{
+    UCHAR bval;
+
+    PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x80);
+    udelay(160);
+    PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x40);
+    udelay(160);
+    PCI_READ_CONFIG_BYTE(PDEV, 0x00, &bval);
+    if(bval == 0x22)
+	return(1);
+    else
+	return(0);
+}
+
+
+static USHORT __init dc390_EEpromGetData1( PDEVDECL )
+{
+    UCHAR i;
+    UCHAR carryFlag;
+    USHORT wval;
+
+    wval = 0;
+    for(i=0; i<16; i++)
+    {
+	wval <<= 1;
+	carryFlag = dc390_EEpromInDO(PDEV);
+	wval |= carryFlag;
+    }
+    return(wval);
+}
+
+
+static void __init dc390_Prepare( PDEVDECL, PUCHAR regval, UCHAR EEpromCmd )
+{
+    UCHAR i,j;
+    UCHAR carryFlag;
+
+    carryFlag = 1;
+    j = 0x80;
+    for(i=0; i<9; i++)
+    {
+	dc390_EEpromOutDI(PDEV,regval,carryFlag);
+	carryFlag = (EEpromCmd & j) ? 1 : 0;
+	j >>= 1;
+    }
+}
+
+
+static void __init dc390_ReadEEprom( PDEVDECL, PUSHORT ptr)
+{
+    UCHAR   regval,cmd;
+    UCHAR   i;
+
+    cmd = EEPROM_READ;
+    for(i=0; i<0x40; i++)
+    {
+	dc390_EnDisableCE(ENABLE_CE, PDEV, &regval);
+	dc390_Prepare(PDEV, &regval, cmd++);
+	*ptr++ = dc390_EEpromGetData1(PDEV);
+	dc390_EnDisableCE(DISABLE_CE, PDEV, &regval);
+    }
+}
+
+
+static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index )
+{
+    UCHAR  i;
+    char  EEbuf[128];
+    USHORT wval, *ptr = (PUSHORT)EEbuf;
+
+    dc390_ReadEEprom( PDEV, ptr );
+    memcpy (dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID);
+    memcpy (&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID], 
+	    &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID);
+    wval = 0;
+    for(i=0; i<0x40; i++, ptr++)
+	wval += *ptr;
+    return (wval == 0x1234 ? 0 : 1);
+}
+
+
+/***********************************************************************
+ * Functions for the management of the internal structures 
+ * (DCBs, SRBs, Queueing)
  *
  **********************************************************************/
 static PDCB __inline__ dc390_findDCB ( PACB pACB, Scsi_Cmnd *cmd)
@@ -494,7 +681,7 @@
 	pDCB = pDCB->pNextDCB;
 	if (pDCB == pACB->pLinkDCB)
 	  {
-	     printk (KERN_ERR "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n",
+	     printk (KERN_WARNING "DC390: DCB not found (DCB=%08x, DCBmap[%2x]=%2x)\n",
 		     (int)pDCB, cmd->target, pACB->DCBmap[cmd->target]);
 	     return 0;
 	  }
@@ -578,7 +765,7 @@
     UCHAR  bval;
 
     pDCB->GoingSRBCnt--; pDCB->pDCBACB->SelLost++;
-    DEBUG0(printk("DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);)
+    DEBUG0(printk(KERN_INFO "DC390: RewaitSRB (%p, %p) pid = %li\n", pDCB, pSRB, pSRB->pcmd->pid);)
     psrb1 = pDCB->pGoingSRB;
     if( pSRB == psrb1 )
     {
@@ -678,6 +865,13 @@
 }
 
 
+/***********************************************************************
+ * Function: static void dc390_SendSRB (PACB pACB, PSRB pSRB)
+ *
+ * Purpose: Send SCSI Request Block (pSRB) to adapter (pACB)
+ *
+ ***********************************************************************/
+
 static void dc390_SendSRB( PACB pACB, PSRB pSRB )
 {
     PDCB   pDCB;
@@ -720,6 +914,14 @@
     return;
 }
 
+/***********************************************************************
+ * Function: static void dc390_BuildSRB (Scsi_Cmd *pcmd, PDCB pDCB, 
+ * 					 PSRB pSRB)
+ *
+ * Purpose: Prepare SRB for being sent to Device DCB w/ command *pcmd
+ *
+ ***********************************************************************/
+
 static void dc390_BuildSRB (Scsi_Cmnd* pcmd, PDCB pDCB, PSRB pSRB)
 {
     pSRB->pSRBDCB = pDCB;
@@ -790,7 +992,7 @@
 
 
     DEBUG0(/*  if(pACB->scan_devices) */	\
-	printk(KERN_DEBUG "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\
+	printk(KERN_INFO "DC390: Queue Cmd=%02x,ID=%d,LUN=%d (pid=%li)\n",\
 		cmd->cmnd[0],cmd->target,cmd->lun,cmd->pid);)
 
     DC390_LOCK_ACB;
@@ -1056,15 +1258,17 @@
     printk ("   %02x   %02x   %02x   %02x   %02x   %02x\n",
 	    DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1),
 	    DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4));
+    DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
     printk ("DC390: Register dump: DMA engine:\n");
     printk ("DC390: Cmd   STrCnt    SBusA    WrkBC    WrkAC Stat SBusCtrl\n");
     printk ("DC390:  %02x %08x %08x %08x %08x   %02x %08x\n",
 	    DC390_read8(DMA_Cmd), DC390_read32(DMA_XferCnt), DC390_read32(DMA_XferAddr),
 	    DC390_read32(DMA_Wk_ByteCntr), DC390_read32(DMA_Wk_AddrCntr),
 	    DC390_read8(DMA_Status), DC390_read32(DMA_ScsiBusCtrl));
+    DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
     PDEVSET1; PCI_READ_CONFIG_WORD(PDEV, PCI_STATUS, &pstat);
     printk ("DC390: Register dump: PCI Status: %04x\n", pstat);
-    printk ("DC390: Please report driver trouble to K.Garloff@ping.de\n");
+    printk ("DC390: In case of driver trouble read linux/drivers/scsi/README.tmscsim\n");
 };
 
 
@@ -1076,6 +1280,8 @@
  * Inputs : cmd - command to abort
  *
  * Returns : 0 on success, -1 on failure.
+ *
+ * Status: Buggy !
  ***********************************************************************/
 
 int DC390_abort (Scsi_Cmnd *cmd)
@@ -1347,13 +1553,13 @@
 
 
 /***********************************************************************
- * Function : static void dc390_initDCB
+ * Function : static void dc390_initDCB()
  *
  * Purpose :  initialize the internal structures for a given DCB
  *
  * Inputs : cmd - pointer to this scsi cmd request block structure
- *
  ***********************************************************************/
+
 void dc390_initDCB( PACB pACB, PDCB *ppDCB, PSCSICMD cmd )
 {
     PEEprom	prom;
@@ -1412,11 +1618,11 @@
 }
 
 /***********************************************************************
- * Function : static void dc390_updateDCB
+ * Function : static void dc390_updateDCB()
  *
  * Purpose :  Set the configuration dependent DCB parameters
- *
  ***********************************************************************/
+
 void dc390_updateDCB (PACB pACB, PDCB pDCB)
 {
   pDCB->IdentifyMsg = IDENTIFY (pDCB->DevMode & EN_DISCONNECT_, pDCB->UnitSCSILUN);
@@ -1441,11 +1647,11 @@
 
 
 /***********************************************************************
- * Function : static void dc390_updateDCBs
+ * Function : static void dc390_updateDCBs ()
  *
  * Purpose :  Set the configuration dependent DCB params for all DCBs
- *
  ***********************************************************************/
+
 static void dc390_updateDCBs (PACB pACB)
 {
   int i;
@@ -1459,13 +1665,13 @@
   
 
 /***********************************************************************
- * Function : static void dc390_initSRB
+ * Function : static void dc390_initSRB()
  *
  * Purpose :  initialize the internal structures for a given SRB
  *
  * Inputs : psrb - pointer to this scsi request block structure
- *
  ***********************************************************************/
+
 static void __inline__ dc390_initSRB( PSRB psrb )
 {
   /* psrb->PhysSRB = virt_to_phys( psrb ); */
@@ -1489,13 +1695,14 @@
 
 
 /***********************************************************************
- * Function : static void dc390_initACB
+ * Function : static void dc390_initACB ()
  *
  * Purpose :  initialize the internal structures for a given SCSI host
  *
  * Inputs : psh - pointer to this host adapter's structure
- *
+ *	    io_port, Irq, index: Resources and adapter index
  ***********************************************************************/
+
 void __init dc390_initACB (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
 {
     PACB    pACB;
@@ -1510,14 +1717,14 @@
     psh->irq = Irq;
 
     pACB = (PACB) psh->hostdata;
-    DC390_LOCK_INIT;
+    DC390_LOCKA_INIT;
     DC390_LOCK_ACB;
 
     pACB->pScsiHost = psh;
     pACB->IOPortBase = (USHORT) io_port;
     pACB->IRQLevel = Irq;
 
-    DEBUG0(printk (KERN_DEBUG "DC390: Adapter index %i, ID %i, IO 0x%08x, IRQ 0x%02x\n",	\
+    DEBUG0(printk (KERN_INFO "DC390: Adapter index %i, ID %i, IO 0x%08x, IRQ 0x%02x\n",	\
 	    index, psh->this_id, (int)io_port, Irq);)
    
     psh->max_id = 8;
@@ -1541,6 +1748,8 @@
     pACB->TagMaxNum = 2 << dc390_eepromBuf[index][EE_TAG_CMD_NUM];
     pACB->ACBFlag = 0;
     pACB->scan_devices = 1;
+    pACB->MsgLen = 0;
+    pACB->Ignore_IRQ = 0;
     pACB->Gmode2 = dc390_eepromBuf[index][EE_MODE2];
     dc390_linkSRB( pACB );
     pACB->pTmpSRB = &pACB->TmpSRB;
@@ -1554,33 +1763,44 @@
 
 
 /***********************************************************************
- * Function : static int dc390_initAdapter
+ * Function : static int dc390_initAdapter ()
  *
  * Purpose :  initialize the SCSI chip ctrl registers
  *
  * Inputs : psh - pointer to this host adapter's structure
+ *	    io_port, Irq, index: Resources
  *
+ * Outputs: 0 on success, -1 on error
  ***********************************************************************/
+
 int __init dc390_initAdapter (PSH psh, ULONG io_port, UCHAR Irq, UCHAR index)
 {
-    PACB   pACB, pacb;
+    PACB   pACB, pACB2;
     UCHAR  used_irq = 0, dstate;
     int    i;
+    
+    pACB = (PACB) psh->hostdata;
+    
+    for ( pACB2 = dc390_pACB_start; pACB2 ; )
+      {
+	if( pACB2->IRQLevel == Irq )
+	  {
+	    used_irq = 1;
+	    break;
+	  }
+	else
+	  pACB2 = pACB2->pNextACB;
+      }
 
-    pacb = dc390_pACB_start;
-    if( pacb != NULL )
-    {
-	for ( ; (pacb != (PACB) -1) ; )
+    if (check_region (io_port, psh->n_io_port))
 	{
-	    if( pacb->IRQLevel == Irq )
-	    {
-		used_irq = 1;
-		break;
-	    }
-	    else
-		pacb = pacb->pNextACB;
+	    printk(KERN_ERR "DC390: register IO ports error!\n");
+	    return( -1 );
 	}
-    }
+    else
+	request_region (io_port, psh->n_io_port, "tmscsim");
+
+    DC390_read8_ (INT_Status, io_port);		/* Reset Pending INT */
 
     if( !used_irq )
     {
@@ -1591,18 +1811,22 @@
 	    }
     }
 
-    if (check_region (io_port, psh->n_io_port))
-	{
-	    printk(KERN_ERR "DC390: register IO ports error!\n");
-	    return( -1 );
-	}
+    if( !dc390_pACB_start )
+      {
+	pACB2 = NULL;
+	dc390_pACB_start = pACB;
+	dc390_pACB_current = pACB;
+	pACB->pNextACB = NULL;
+      }
     else
-	request_region (io_port, psh->n_io_port, "tmscsim");
-   
-    pACB = (PACB) psh->hostdata;
-    /* pACB->IOPortBase = (USHORT) io_port; */
+      {
+	pACB2 = dc390_pACB_current;
+	dc390_pACB_current->pNextACB = pACB;
+	dc390_pACB_current = pACB;
+	pACB->pNextACB = NULL;
+      };
 
-    DC390_write8_ (CtrlReg1, DIS_INT_ON_SCSI_RST | psh->this_id, io_port);	/* Disable SCSI bus reset interrupt */
+    DC390_write8 (CtrlReg1, DIS_INT_ON_SCSI_RST | psh->this_id);	/* Disable SCSI bus reset interrupt */
 
     if (pACB->Gmode2 & RST_SCSI_BUS)
     {
@@ -1612,6 +1836,7 @@
 		udelay(1000);
     };
     pACB->ACBFlag = 0;
+    DC390_read8 (INT_Status);				/* Reset Pending INT */
     
     DC390_write8 (Scsi_TimeOut, SEL_TIMEOUT);		/* 250ms selection timeout */
     DC390_write8 (Clk_Factor, CLK_FREQ_40MHZ);		/* Conversion factor = 0 , 40MHz clock */
@@ -1622,7 +1847,7 @@
 		(dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ? NEGATE_REQACKDATA : 0);	/* Negation */
     DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
     DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
-    DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
+    DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
     dstate = DC390_read8 (DMA_Status);
     DC390_write8 (DMA_Status, dstate);	/* clear */
 
@@ -1630,194 +1855,24 @@
 }
 
 
-static void __init dc390_EnDisableCE( UCHAR mode, PDEVDECL, PUCHAR regval )
-{
-    UCHAR bval;
-
-    bval = 0;
-    if(mode == ENABLE_CE)
-	*regval = 0xc0;
-    else
-	*regval = 0x80;
-    PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
-    if(mode == DISABLE_CE)
-        PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
-    udelay(160);
-}
-
-#ifndef CONFIG_SCSI_DC390T_NOGENSUPP
-static void __init dc390_EEpromDefaults (UCHAR index)
-{
-    PUCHAR ptr;
-    UCHAR  id;
-    ptr = (PUCHAR) dc390_eepromBuf[index];
-    
-    /* Adapter Settings */
-    ptr[EE_ADAPT_SCSI_ID] = (UCHAR)tmscsim[0]; /* Adapter ID */
-    ptr[EE_MODE2] = (UCHAR)tmscsim[3];
-    ptr[EE_DELAY] = 0; /* ?? */
-    ptr[EE_TAG_CMD_NUM] = (UCHAR)tmscsim[4]; /* Tagged Comds */
-    
-    /* Device Settings */
-    for (id = 0; id < MAX_SCSI_ID; id++)
-    {
-      ptr[id<<2] = (UCHAR)tmscsim[2]; /* EE_MODE1 */
-      ptr[(id<<2) + 1] = (UCHAR)tmscsim[1]; /* EE_Speed */
-    };
-    dc390_adapname = "AM53C974";
-}
-
-static void __init dc390_checkparams (void)
-{
-	PARSEDEBUG(printk(KERN_INFO "DC390: setup %08x %08x %08x %08x %08x\n", tmscsim[0],\
-		      tmscsim[1], tmscsim[2], tmscsim[3], tmscsim[4]);)
-	if (tmscsim[0] < 0 || tmscsim[0] > 7) /* modules-2.0.0 passes -1 as string */
-	{
-		tmscsim[0] = 7; tmscsim[1] = 4; 
-		tmscsim[2] = 9; tmscsim[3] = 15;
-		tmscsim[4] = 2;
-		printk (KERN_INFO "DC390: Using safe settings.\n");
-	}
-	else
-	{
-		/* if (tmscsim[0] < 0 || tmscsim[0] > 7) tmscsim[0] = 7; */
-		if (tmscsim[1] < 0 || tmscsim[1] > 7) tmscsim[1] = 4;
-		if (tmscsim[4] < 0 || tmscsim[4] > 5) tmscsim[4] = 4;
-	};
-};
-/* Override defaults on cmdline:
- * tmscsim: AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped)
- */
-void __init dc390_setup (char *str, int *ints)
-{
-	int i;
-	for (i = 0; i < ints[0]; i++)
-		tmscsim[i] = ints[i+1];
-	if (ints[0] > 5)
-		printk (KERN_NOTICE "DC390: ignore extra params!\n");
-	/* dc390_checkparams (); */
-};
-#endif /* CONFIG_SCSI_DC390T_NOGENSUPP */
-
-
-static void __init dc390_EEpromOutDI( PDEVDECL, PUCHAR regval, UCHAR Carry )
-{
-    UCHAR bval;
-
-    bval = 0;
-    if(Carry)
-    {
-	bval = 0x40;
-	*regval = 0x80;
-	PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
-    }
-    udelay(160);
-    bval |= 0x80;
-    PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
-    udelay(160);
-    bval = 0;
-    PCI_WRITE_CONFIG_BYTE(PDEV, *regval, bval);
-    udelay(160);
-}
-
-
-static UCHAR __init dc390_EEpromInDO( PDEVDECL )
-{
-    UCHAR bval;
-
-    PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x80);
-    udelay(160);
-    PCI_WRITE_CONFIG_BYTE(PDEV, 0x80, 0x40);
-    udelay(160);
-    PCI_READ_CONFIG_BYTE(PDEV, 0x00, &bval);
-    if(bval == 0x22)
-	return(1);
-    else
-	return(0);
-}
-
-
-static USHORT __init dc390_EEpromGetData1( PDEVDECL )
-{
-    UCHAR i;
-    UCHAR carryFlag;
-    USHORT wval;
-
-    wval = 0;
-    for(i=0; i<16; i++)
-    {
-	wval <<= 1;
-	carryFlag = dc390_EEpromInDO(PDEV);
-	wval |= carryFlag;
-    }
-    return(wval);
-}
-
-
-static void __init dc390_Prepare( PDEVDECL, PUCHAR regval, UCHAR EEpromCmd )
-{
-    UCHAR i,j;
-    UCHAR carryFlag;
-
-    carryFlag = 1;
-    j = 0x80;
-    for(i=0; i<9; i++)
-    {
-	dc390_EEpromOutDI(PDEV,regval,carryFlag);
-	carryFlag = (EEpromCmd & j) ? 1 : 0;
-	j >>= 1;
-    }
-}
-
-
-static void __init dc390_ReadEEprom( PDEVDECL, PUSHORT ptr)
-{
-    UCHAR   regval,cmd;
-    UCHAR   i;
-
-    cmd = EEPROM_READ;
-    for(i=0; i<0x40; i++)
-    {
-	dc390_EnDisableCE(ENABLE_CE, PDEV, &regval);
-	dc390_Prepare(PDEV, &regval, cmd++);
-	*ptr++ = dc390_EEpromGetData1(PDEV);
-	dc390_EnDisableCE(DISABLE_CE, PDEV, &regval);
-    }
-}
-
-
-static UCHAR __init dc390_CheckEEpromCheckSum( PDEVDECL, UCHAR index )
-{
-    UCHAR  i;
-    char  EEbuf[128];
-    USHORT wval, *ptr = (PUSHORT)EEbuf;
-
-    dc390_ReadEEprom( PDEV, ptr );
-    memcpy (dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID);
-    memcpy (&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID], 
-	    &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID);
-    wval = 0;
-    for(i=0; i<0x40; i++, ptr++)
-	wval += *ptr;
-    return (wval == 0x1234 ? 0 : 1);
-}
-
-
 /***********************************************************************
- * Function : static int DC390_init (struct Scsi_Host *host)
+ * Function : static int DC390_init (struct Scsi_Host *host, ...)
  *
  * Purpose :  initialize the internal structures for a given SCSI host
  *
- * Inputs : host - pointer to this host adapter's structure/
+ * Inputs : host - pointer to this host adapter's structure
+ *	    io_port - IO ports mapped to this adapter
+ *	    Irq - IRQ assigned to this adpater
+ *	    PDEVDECL - PCI access handle
+ *	    index - Adapter index
  *
- * Preconditions : when this function is called, the chip_type
- *	field of the pACB structure MUST have been set.
+ * Outputs: 0 on success, -1 on error
  *
  * Note: written in capitals, because the locking is only done here,
  *	not in DC390_detect, called from outside 
  ***********************************************************************/
 
-static int __init DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, PDEVDECL, int index)
+static int __init DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, PDEVDECL, UCHAR index)
 {
     PSH   psh;
     PACB  pACB;
@@ -1846,7 +1901,7 @@
     if( !psh ) return( -1 );
 	
     pACB = (PACB) psh->hostdata;
-    DC390_LOCK_INIT;
+    DC390_LOCKA_INIT;
     DC390_LOCK_ACB;
 
 #if 0
@@ -1862,37 +1917,21 @@
     }
 #endif
 
-    DEBUG0(printk("DC390: pSH = %8x,", (UINT) psh);)
-    DEBUG0(printk("DC390: Index %02i,", index);)
+    DEBUG0(printk(KERN_INFO "DC390: pSH = %8x,", (UINT) psh);)
+    DEBUG0(printk(" Index %02i,", index);)
 
     dc390_initACB( psh, io_port, Irq, index );
+    pACB = (PACB) psh->hostdata;
+        
     PDEVSET;
 
-    DC390_read8_ (INT_Status, io_port);		/* Reset Pending INT */
-
     if( !dc390_initAdapter( psh, io_port, Irq, index ) )
     {
-	pACB = (PACB) psh->hostdata;
-	if( !dc390_pACB_start )
-	{
-	    dc390_pACB_start = pACB;
-	    dc390_pACB_current = pACB;
-	    pACB->pNextACB = (PACB) -1;
-	}
-	else
-	{
-	    dc390_pACB_current->pNextACB = pACB;
-	    dc390_pACB_current = pACB;
-	    pACB->pNextACB = (PACB)  -1;
-	}
-        
-	DEBUG0(printk("DC390: pACB = %8x, pDCBmap = %8x, pSRB_array = %8x\n",\
+	DEBUG0(printk("\nDC390: pACB = %8x, pDCBmap = %8x, pSRB_array = %8x\n",\
 		(UINT) pACB, (UINT) pACB->DCBmap, (UINT) pACB->SRB_array);)
 	DEBUG0(printk("DC390: ACB size= %4x, DCB size= %4x, SRB size= %4x\n",\
 		sizeof(DC390_ACB), sizeof(DC390_DCB), sizeof(DC390_SRB) );)
 
-	DC390_read8_ (INT_Status, io_port);		/* Reset Pending INT */
-
 	DC390_UNLOCK_ACB;
         return (0);
     }
@@ -1960,7 +1999,6 @@
     PDEVDECL0;
     UCHAR   irq;
     UINT    io_port;
-    UCHAR   adaptCnt = 0;	/* Number of boards detected */
     DC390_IFLAGS DC390_DFLAGS
 
     DC390_LOCK_DRV;
@@ -1972,29 +2010,36 @@
 	{
 	    DC390_LOCK_IO;		/* Remove this when going to new eh */
 	    PCI_GET_IO_AND_IRQ;
-	    DEBUG0(printk(KERN_DEBUG "DC390(%i): IO_PORT=%04x,IRQ=%x\n", adaptCnt, (UINT) io_port, irq);)
+	    DEBUG0(printk(KERN_INFO "DC390(%i): IO_PORT=%04x,IRQ=%x\n", dc390_adapterCnt, (UINT) io_port, irq);)
 
-	    if( !DC390_init(psht, io_port, irq, PDEV, adaptCnt))
+	    if( !DC390_init(psht, io_port, irq, PDEV, dc390_adapterCnt))
 	    {
 		PCI_SET_MASTER;
 		dc390_set_pci_cfg (PDEV);
-		adaptCnt++;
+		dc390_adapterCnt++;
 	    };
 	    DC390_UNLOCK_IO;		/* Remove when going to new eh */
 	}
     else
 	printk (KERN_ERR "DC390: No PCI BIOS found!\n");
    
-    if (adaptCnt)
+    if (dc390_adapterCnt)
 	psht->proc_dir = &DC390_proc_scsi_tmscsim;
 
-    printk(KERN_INFO "DC390: %i adapters found\n", adaptCnt);
-    dc390_adapterCnt = adaptCnt;
+    printk(KERN_INFO "DC390: %i adapters found\n", dc390_adapterCnt);
     DC390_UNLOCK_DRV;
-    return( adaptCnt );
+    return( dc390_adapterCnt );
 }
 
 
+/***********************************************************************
+ * Functions: dc390_inquiry(), dc390_inquiry_done()
+ *
+ * Purpose: When changing speed etc., we have to issue an INQUIRY
+ *	    command to make sure, we agree upon the nego parameters
+ *	    with the device
+ ***********************************************************************/
+
 static void dc390_inquiry_done (Scsi_Cmnd* cmd)
 {
    printk (KERN_INFO "DC390: INQUIRY (ID %02x LUN %02x) returned %08x\n",
@@ -2211,7 +2256,7 @@
       /* NegoPeriod */
       if (*pos != '-')
 	{
-	  SCANF (pos, p0, dum, 76, 800); 
+	  SCANF (pos, p0, dum, 72, 800); 
 	  pDCB->NegoPeriod = dum >> 2;
 	  if (pDCB->NegoPeriod != olddevmode) needs_inquiry++;
 	  if (!pos) goto ok;
@@ -2367,8 +2412,6 @@
  *
  ********************************************************************/
 
-/* KG: proc_info taken from driver aha152x.c */
-
 #undef SPRINTF
 #define SPRINTF(args...) pos += sprintf(pos, ## args)
 
@@ -2529,14 +2572,14 @@
     if (host->irq != IRQ_NONE)
     {
 	for (irq_count = 0, pACB = dc390_pACB_start; 
-	     pACB && pACB != (PACB)-1; pACB = pACB->pNextACB)
+	     pACB; pACB = pACB->pNextACB)
 	{
 	    if ( pACB->IRQLevel == host->irq )
 		++irq_count;
 	}
 	if (irq_count == 1)
 	 {
-	    DEBUG0(printk(KERN_DEBUG "DC390: Free IRQ %i\n",host->irq);)
+	    DEBUG0(printk(KERN_INFO "DC390: Free IRQ %i\n",host->irq);)
 	    free_irq(host->irq,NULL);
 	 }
     }
diff -u --recursive --new-file v2.1.132/linux/drivers/scsi/tmscsim.h linux/drivers/scsi/tmscsim.h
--- v2.1.132/linux/drivers/scsi/tmscsim.h	Sun Nov  8 14:03:02 1998
+++ linux/drivers/scsi/tmscsim.h	Fri Dec 25 16:41:39 1998
@@ -3,7 +3,7 @@
 ;*		    TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter  *
 ;*		    Device Driver				       *
 ;***********************************************************************/
-/* $Id: tmscsim.h,v 2.1 1998/10/14 10:31:48 garloff Exp $ */
+/* $Id: tmscsim.h,v 2.4 1998/12/25 17:33:27 garloff Exp $ */
 
 #ifndef _TMSCSIM_H
 #define _TMSCSIM_H
@@ -95,15 +95,13 @@
 /* 0x48: */
 SGL		Segmentx;	/* make a one entry of S/G list table */
 
-PUCHAR		pMsgPtr;
-
 UCHAR		ScsiCmdLen;
 UCHAR		ScsiPhase;
 
 UCHAR		AdaptStatus;
 UCHAR		TargetStatus;
 
-/* 0x5c: */
+/* 0x58: */
 UCHAR		MsgCnt;
 UCHAR		EndMessage;
 UCHAR		RetryCnt;
@@ -115,7 +113,7 @@
 UCHAR		SRBStatus;
   //UCHAR		IORBFlag;	/*;81h-Reset, 2-retry */
 
-/* 0x64: */
+/* 0x60: */
 };
 
 
@@ -218,14 +216,16 @@
 UCHAR		sel_timeout;
 UCHAR		glitch_cfg;
 
-UCHAR		reserved[2];	/* alignment */
+UCHAR		MsgLen;
+UCHAR		Ignore_IRQ;	/* Not used */
 
 PDEVDECL1;			/* Pointer to PCI cfg. space */
-/* 0x44/0x40: */
+/* 0x40/0x3c: */
 ULONG		Cmds;
 ULONG		CmdInQ;
 ULONG		CmdOutOfSRB;
 ULONG		SelLost;
+
 	
 /* 0x50/0x4c: */	
 DC390_SRB	TmpSRB;
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/Config.in linux/drivers/sound/Config.in
--- v2.1.132/linux/drivers/sound/Config.in	Tue Dec 22 14:16:56 1998
+++ linux/drivers/sound/Config.in	Sun Dec 27 10:53:45 1998
@@ -131,7 +131,7 @@
       int 'PSS MIDI IRQ 3, 4, 5, 7, 9, 10, 11, 12' CONFIG_PSS_MPU_IRQ 9
       bool '  Have DSPxxx.LD firmware file' CONFIG_PSS_HAVE_BOOT
       if [ "$CONFIG_PSS_HAVE_BOOT" = "y" ]; then
-         string '  Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE
+         string '  Full pathname of DSPxxx.LD firmware file' CONFIG_PSS_BOOT_FILE /etc/sound/dsp001.ld
       fi
   fi
   if [ "$CONFIG_SOUND_PSS" = "y" -o "$CONFIG_SOUND_PSS" = "m" ]; then
@@ -168,7 +168,7 @@
       int 'TRIX SB DMA 1 or 3' CONFIG_TRIX_SB_DMA 1
       bool '  Have TRXPRO.HEX firmware file' CONFIG_TRIX_HAVE_BOOT
       if [ "$CONFIG_TRIX_HAVE_BOOT" = "y" ]; then
-  	string '  Full pathname of TRXPRO.HEX firmware file' CONFIG_TRIX_BOOT_FILE
+  	string '  Full pathname of TRXPRO.HEX firmware file' CONFIG_TRIX_BOOT_FILE /etc/sound/trxpro.hex
       fi
   fi
   
@@ -185,7 +185,7 @@
       int 'MAD16 MIDI IRQ 5, 7, 9 or 10' CONFIG_MAD16_MPU_IRQ 9
   fi
   
-  dep_tristate 'Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) synth/soundcards' CONFIG_SOUND_WAVEFRONT $CONFIG_SOUND_OSS
+  dep_tristate 'Full support for Turtle Beach WaveFront (Tropez Plus, Tropez, Maui) synth/soundcards' CONFIG_SOUND_WAVEFRONT $CONFIG_SOUND_OSS m
   if [ "$CONFIG_SOUND_WAVEFRONT" = "y" ]; then
       hex 'I/O base for WaveFront 210, 230, 260, 290, 300, 320, 338 or 330' CONFIG_WAVEFRONT_BASE 330
       int 'WaveFront IRQ 5, 9, 12 or 15' CONFIG_WAVEFRONT_IRQ 9
@@ -218,7 +218,7 @@
       int 'Maui IRQ 5, 9, 12 or 15' CONFIG_MAUI_IRQ 9
       bool '  Have OSWF.MOT firmware file' CONFIG_MAUI_HAVE_BOOT
       if [ "$CONFIG_MAUI_HAVE_BOOT" = "y" ]; then
-  	string '  Full pathname of OSWF.MOT firmware file' CONFIG_MAUI_BOOT_FILE
+  	string '  Full pathname of OSWF.MOT firmware file' CONFIG_MAUI_BOOT_FILE /etc/sound/oswf.mot
       fi
   fi
 
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/ad1848.c linux/drivers/sound/ad1848.c
--- v2.1.132/linux/drivers/sound/ad1848.c	Tue Dec 22 14:16:56 1998
+++ linux/drivers/sound/ad1848.c	Sun Dec 27 10:53:45 1998
@@ -71,6 +71,7 @@
 #define MD_4232		5
 #define MD_C930		6
 #define MD_IWAVE	7
+#define MD_4235         8 /* Crystal Audio CS4235 */
 
 	/* Mixer parameters */
 	int             recmask;
@@ -111,7 +112,7 @@
 
 #endif
 
-static int ad_format_mask[8 /*devc->model */ ] =
+static int ad_format_mask[9 /*devc->model */ ] =
 {
 	0,
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,
@@ -120,7 +121,8 @@
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW,	/* AD1845 */
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
 	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
-	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM
+	AFMT_U8 | AFMT_S16_LE | AFMT_MU_LAW | AFMT_A_LAW | AFMT_S16_BE | AFMT_IMA_ADPCM,
+	AFMT_U8 | AFMT_S16_LE /* CS4235 */
 };
 
 static ad1848_info adev_info[MAX_AUDIO_DEV];
@@ -1594,103 +1596,107 @@
 			ad_write(devc, 25, ~tmp1);	/* Invert all bits */
 			if ((ad_read(devc, 25) & 0xe7) == (tmp1 & 0xe7))
 			{
-				int id, full_id;
+				int id;
 
 				/*
 				 *      It's at least CS4231
 				 */
 				
-				devc->chip_name = "CS4231";
-				devc->model = MD_4231;
-
 				/*
 				 * It could be an AD1845 or CS4231A as well.
 				 * CS4231 and AD1845 report the same revision info in I25
 				 * while the CS4231A reports different.
 				 */
 
-				id = ad_read(devc, 25) & 0xe7;
-				full_id = ad_read(devc, 25);
-				if (id == 0x80)	/* Device busy??? */
-					id = ad_read(devc, 25) & 0xe7;
-				if (id == 0x80)	/* Device still busy??? */
-					id = ad_read(devc, 25) & 0xe7;
+				id = ad_read(devc, 25);
+				if ((id & 0xe7) == 0x80)	/* Device busy??? */
+					id = ad_read(devc, 25);
+				if ((id & 0xe7) == 0x80)	/* Device still busy??? */
+					id = ad_read(devc, 25);
 				DDB(printk("ad1848_detect() - step J (%02x/%02x)\n", id, ad_read(devc, 25)));
 
-				switch (id)
+                                if ((id & 0xe7) == 0x80) {
+					/* 
+					 * It must be a CS4231 or AD1845. The register I23 of
+					 * CS4231 is undefined and it appears to be read only.
+					 * AD1845 uses I23 for setting sample rate. Assume
+					 * the chip is AD1845 if I23 is changeable.
+					 */
+
+					unsigned char   tmp = ad_read(devc, 23);
+					ad_write(devc, 23, ~tmp);
+
+					if (interwave)
+					{
+						devc->model = MD_IWAVE;
+						devc->chip_name = "IWave";
+					}
+					else if (ad_read(devc, 23) != tmp)	/* AD1845 ? */
+					{
+						devc->chip_name = "AD1845";
+						devc->model = MD_1845;
+					}
+					else if (cs4248_flag)
+					{
+						if (ad_flags)
+							  *ad_flags |= AD_F_CS4248;
+						devc->chip_name = "CS4248";
+						devc->model = MD_1848;
+						ad_write(devc, 12, ad_read(devc, 12) & ~0x40);	/* Mode2 off */
+					}
+					ad_write(devc, 23, tmp);	/* Restore */
+				}
+				else
 				{
-
-					case 0xa0:
-						devc->chip_name = "CS4231A";
-						devc->model = MD_4231A;
+					switch (id & 0x1f) {
+					case 3: /* CS4236/CS4235 */
+						{
+							int xid;
+							ad_write(devc, 12, ad_read(devc, 12) | 0x60); /* switch to mode 3 */
+							ad_write(devc, 23, 0x9c); /* select extended register 25 */
+							xid = inb(io_Indexed_Data(devc));
+							ad_write(devc, 12, ad_read(devc, 12) & ~0x60); /* back to mode 0 */
+							if ((xid & 0x1f) == 0x1d) {
+								devc->chip_name = "CS4235";
+								devc->model = MD_4235;
+							} else {
+								devc->chip_name = "CS4236";
+								devc->model = MD_4232;
+							}
+						}
 						break;
 
-					case 0xa2:
+					case 2: /* CS4232/CS4232A */
 						devc->chip_name = "CS4232";
 						devc->model = MD_4232;
 						break;
-
-					case 0xb2:
-						devc->chip_name = "CS4232A";
-						devc->model = MD_4232;
-						break;
-
-					case 0x03:
-					case 0x83:
-						devc->chip_name = "CS4236";
-						devc->model = MD_4232;
-						break;
-
-					case 0x41:
-						devc->chip_name = "CS4236B";
-						devc->model = MD_4232;
-						break;
-
-					case 0x80:
+				
+					case 0:
+						if ((id & 0xe0) == 0xa0)
 						{
-							/* 
-							 * It must be a CS4231 or AD1845. The register I23 of
-							 * CS4231 is undefined and it appears to be read only.
-							 * AD1845 uses I23 for setting sample rate. Assume
-							 * the chip is AD1845 if I23 is changeable.
-							 */
-
-							unsigned char   tmp = ad_read(devc, 23);
-							ad_write(devc, 23, ~tmp);
-
-							if (interwave)
-							{
-								devc->model = MD_IWAVE;
-								devc->chip_name = "IWave";
-							}
-							else if (ad_read(devc, 23) != tmp)	/* AD1845 ? */
-							{
-								devc->chip_name = "AD1845";
-								devc->model = MD_1845;
-							}
-							else if (cs4248_flag)
-							{
-								if (ad_flags)
-									  *ad_flags |= AD_F_CS4248;
-								devc->chip_name = "CS4248";
-								devc->model = MD_1848;
-								ad_write(devc, 12, ad_read(devc, 12) & ~0x40);	/* Mode2 off */
-							}
-							ad_write(devc, 23, tmp);	/* Restore */
+							devc->chip_name = "CS4231A";
+							devc->model = MD_4231A;
+						}
+						else
+						{
+							devc->chip_name = "CS4321";
+							devc->model = MD_4231;
 						}
 						break;
 
-					default:	/* Assume CS4231 or OPTi 82C930 */
+					default: /* maybe */
 						DDB(printk("ad1848: I25 = %02x/%02x\n", ad_read(devc, 25), ad_read(devc, 25) & 0xe7));
-						if (optiC930)
-						{
-							devc->chip_name = "82C930";
-							devc->model = MD_C930;
-						}
+                                                if (optiC930)
+                                                {
+                                                        devc->chip_name = "82C930";
+                                                        devc->model = MD_C930;
+                                                }
 						else
 						{
+							devc->chip_name = "CS4231";
 							devc->model = MD_4231;
 						}
+					}
 				}
 			}
 			ad_write(devc, 25, tmp1);	/* Restore bits */
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/cs4232.c linux/drivers/sound/cs4232.c
--- v2.1.132/linux/drivers/sound/cs4232.c	Tue Dec 22 14:16:56 1998
+++ linux/drivers/sound/cs4232.c	Sun Dec 27 10:53:45 1998
@@ -369,9 +369,6 @@
 	cfg.dma = dma;
 	cfg.dma2 = dma2;
 
-	if (probe_cs4232(&cfg) == 0)
-		return -ENODEV;
-
 	mpu_cfg.io_base = -1;
 	mpu_cfg.irq = -1;
 
@@ -380,6 +377,9 @@
 		mpu_cfg.irq = mpuirq;
 		probe_cs4232_mpu(&mpu_cfg); /* Bug always returns 0 not OK -- AC */
 	}
+
+	if (probe_cs4232(&cfg) == 0)
+		return -ENODEV;
 
 	attach_cs4232(&cfg);
 
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- v2.1.132/linux/drivers/sound/es1370.c	Tue Dec 22 14:16:56 1998
+++ linux/drivers/sound/es1370.c	Sun Dec 27 10:53:45 1998
@@ -80,6 +80,7 @@
  *    08.10.98   0.14  Joystick support fixed
  *		       -- Oliver Neukum <c188@org.chemie.uni-muenchen.de>
  *    10.12.98   0.15  Fix drain_dac trying to wait on not yet initialized DMA
+ *    16.12.98   0.16  Don't wake up app until there are fragsize bytes to read/write
  *
  * some important things missing in Ensoniq documentation:
  *
@@ -603,17 +604,14 @@
 		diff = get_hwptr(s, &s->dma_adc, ES1370_REG_ADC_FRAMECNT);
 		s->dma_adc.total_bytes += diff;
 		s->dma_adc.count += diff;
-		if (s->dma_adc.mapped) {
-			if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 
-				wake_up(&s->dma_adc.wait);
-		} else {
+		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 
+			wake_up(&s->dma_adc.wait);
+		if (!s->dma_adc.mapped) {
 			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
 				s->ctrl &= ~CTRL_ADC_EN;
 				outl(s->ctrl, s->io+ES1370_REG_CONTROL);
 				s->dma_adc.error++;
 			}
-			if (s->dma_adc.count > 0)
-				wake_up(&s->dma_adc.wait);
 		}
 	}
 	/* update DAC1 pointer */
@@ -635,7 +633,7 @@
 					      s->dma_dac1.fragsize, (s->sctrl & SCTRL_P1SEB) ? 0 : 0x80);
 				s->dma_dac1.endcleared = 1;
 			}
-			if (s->dma_dac1.count < (signed)s->dma_dac1.dmasize)
+			if (s->dma_dac1.count + (signed)s->dma_dac1.fragsize <= (signed)s->dma_dac1.dmasize)
 				wake_up(&s->dma_dac1.wait);
 		}
 	}
@@ -658,7 +656,7 @@
 					      s->dma_dac2.fragsize, (s->sctrl & SCTRL_P2SEB) ? 0 : 0x80);
 				s->dma_dac2.endcleared = 1;
 			}
-			if (s->dma_dac2.count < (signed)s->dma_dac2.dmasize)
+			if (s->dma_dac2.count + (signed)s->dma_dac2.fragsize <= (signed)s->dma_dac2.dmasize)
 				wake_up(&s->dma_dac2.wait);
 		}
 	}
@@ -1186,20 +1184,15 @@
 	spin_lock_irqsave(&s->lock, flags);
 	es1370_update_ptr(s);
 	if (file->f_mode & FMODE_READ) {
-		if (s->dma_adc.mapped) {
-			if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
-				mask |= POLLIN | POLLRDNORM;
-		} else {
-			if (s->dma_adc.count > 0)
-				mask |= POLLIN | POLLRDNORM;
-		}
+		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+			mask |= POLLIN | POLLRDNORM;
 	}
 	if (file->f_mode & FMODE_WRITE) {
 		if (s->dma_dac2.mapped) {
 			if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) 
 				mask |= POLLOUT | POLLWRNORM;
 		} else {
-			if ((signed)s->dma_dac2.dmasize > s->dma_dac2.count)
+			if ((signed)s->dma_dac2.dmasize >= s->dma_dac2.count + (signed)s->dma_dac2.fragsize)
 				mask |= POLLOUT | POLLWRNORM;
 		}
 	}
@@ -1704,7 +1697,7 @@
 		if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize)
 			mask |= POLLOUT | POLLWRNORM;
 	} else {
-		if ((signed)s->dma_dac1.dmasize > s->dma_dac1.count)
+		if ((signed)s->dma_dac1.dmasize >= s->dma_dac1.count + (signed)s->dma_dac1.fragsize)
 			mask |= POLLOUT | POLLWRNORM;
 	}
 	spin_unlock_irqrestore(&s->lock, flags);
@@ -2277,7 +2270,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1370: version v0.15 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1370: version v0.16 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1370, pcidev))) {
 		if (pcidev->base_address[0] == 0 || 
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- v2.1.132/linux/drivers/sound/es1371.c	Tue Dec 22 14:16:56 1998
+++ linux/drivers/sound/es1371.c	Mon Dec 28 11:06:11 1998
@@ -50,6 +50,8 @@
  *    27.10.98   0.5   Fix joystick support
  *                     -- Oliver Neukum (c188@org.chemie.uni-muenchen.de)
  *    10.12.98   0.6   Fix drain_dac trying to wait on not yet initialized DMA
+ *    23.12.98   0.7   Fix a few f_file & FMODE_ bugs
+ *                     Don't wake up app until there are fragsize bytes to read/write
  *
  */
 
@@ -837,17 +839,14 @@
 		diff = get_hwptr(s, &s->dma_adc, ES1371_REG_ADC_FRAMECNT);
 		s->dma_adc.total_bytes += diff;
 		s->dma_adc.count += diff;
-		if (s->dma_adc.mapped) {
-			if (s->dma_adc.count >= s->dma_adc.fragsize) 
-				wake_up(&s->dma_adc.wait);
-		} else {
+		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 
+			wake_up(&s->dma_adc.wait);
+		if (!s->dma_adc.mapped) {
 			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
 				s->ctrl &= ~CTRL_ADC_EN;
 				outl(s->ctrl, s->io+ES1371_REG_CONTROL);
 				s->dma_adc.error++;
 			}
-			if (s->dma_adc.count > 0)
-				wake_up(&s->dma_adc.wait);
 		}
 	}
 	/* update DAC1 pointer */
@@ -869,7 +868,7 @@
 					      s->dma_dac1.fragsize, (s->sctrl & SCTRL_P1SEB) ? 0 : 0x80);
 				s->dma_dac1.endcleared = 1;
 			}
-			if (s->dma_dac1.count < (signed)s->dma_dac1.dmasize)
+			if (s->dma_dac1.count + (signed)s->dma_dac1.fragsize <= (signed)s->dma_dac1.dmasize)
 				wake_up(&s->dma_dac1.wait);
 		}
 	}
@@ -892,7 +891,7 @@
 					      s->dma_dac2.fragsize, (s->sctrl & SCTRL_P2SEB) ? 0 : 0x80);
 				s->dma_dac2.endcleared = 1;
 			}
-			if (s->dma_dac2.count < (signed)s->dma_dac2.dmasize)
+			if (s->dma_dac2.count + (signed)s->dma_dac2.fragsize <= (signed)s->dma_dac2.dmasize)
 				wake_up(&s->dma_dac2.wait);
 		}
 	}
@@ -1625,27 +1624,22 @@
 	unsigned int mask = 0;
 
 	VALIDATE_STATE(s);
-	if (file->f_flags & FMODE_WRITE)
+	if (file->f_mode & FMODE_WRITE)
 		poll_wait(file, &s->dma_dac2.wait, wait);
-	if (file->f_flags & FMODE_READ)
+	if (file->f_mode & FMODE_READ)
 		poll_wait(file, &s->dma_adc.wait, wait);
 	spin_lock_irqsave(&s->lock, flags);
 	es1371_update_ptr(s);
-	if (file->f_flags & FMODE_READ) {
-		if (s->dma_adc.mapped) {
+	if (file->f_mode & FMODE_READ) {
 			if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
 				mask |= POLLIN | POLLRDNORM;
-		} else {
-			if (s->dma_adc.count > 0)
-				mask |= POLLIN | POLLRDNORM;
-		}
 	}
-	if (file->f_flags & FMODE_WRITE) {
+	if (file->f_mode & FMODE_WRITE) {
 		if (s->dma_dac2.mapped) {
 			if (s->dma_dac2.count >= (signed)s->dma_dac2.fragsize) 
 				mask |= POLLOUT | POLLWRNORM;
 		} else {
-			if ((signed)s->dma_dac2.dmasize > s->dma_dac2.count)
+			if ((signed)s->dma_dac2.dmasize >= s->dma_dac2.count + (signed)s->dma_dac2.fragsize)
 				mask |= POLLOUT | POLLWRNORM;
 		}
 	}
@@ -2046,11 +2040,11 @@
 	if (file->f_mode & FMODE_WRITE)
 		drain_dac2(s, file->f_flags & O_NONBLOCK);
 	down(&s->open_sem);
-	if (file->f_flags & FMODE_WRITE) {
+	if (file->f_mode & FMODE_WRITE) {
 		stop_dac2(s);
 		dealloc_dmabuf(&s->dma_dac2);
 	}
-	if (file->f_flags & FMODE_READ) {
+	if (file->f_mode & FMODE_READ) {
 		stop_adc(s);
 		dealloc_dmabuf(&s->dma_adc);
 	}
@@ -2150,7 +2144,7 @@
 		if (s->dma_dac1.count >= (signed)s->dma_dac1.fragsize)
 			mask |= POLLOUT | POLLWRNORM;
 	} else {
-		if ((signed)s->dma_dac1.dmasize > s->dma_dac1.count)
+		if ((signed)s->dma_dac1.dmasize >= s->dma_dac1.count + (signed)s->dma_dac1.fragsize)
 			mask |= POLLOUT | POLLWRNORM;
 	}
 	spin_unlock_irqrestore(&s->lock, flags);
@@ -2540,16 +2534,16 @@
 	unsigned int mask = 0;
 
 	VALIDATE_STATE(s);
-	if (file->f_flags & FMODE_WRITE)
+	if (file->f_mode & FMODE_WRITE)
 		poll_wait(file, &s->midi.owait, wait);
-	if (file->f_flags & FMODE_READ)
+	if (file->f_mode & FMODE_READ)
 		poll_wait(file, &s->midi.iwait, wait);
 	spin_lock_irqsave(&s->lock, flags);
-	if (file->f_flags & FMODE_READ) {
+	if (file->f_mode & FMODE_READ) {
 		if (s->midi.icnt > 0)
 			mask |= POLLIN | POLLRDNORM;
 	}
-	if (file->f_flags & FMODE_WRITE) {
+	if (file->f_mode & FMODE_WRITE) {
 		if (s->midi.ocnt < MIDIOUTBUF)
 			mask |= POLLOUT | POLLWRNORM;
 	}
@@ -2684,7 +2678,7 @@
 
 /* --------------------------------------------------------------------- */
 
-static const struct initvol {
+static struct initvol {
 	int mixch;
 	int vol;
 } initvol[] __initdata = {
@@ -2716,7 +2710,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "es1371: version v0.6 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "es1371: version v0.7 time " __TIME__ " " __DATE__ "\n");
 	while (index < NR_DEVICE && 
 	       (pcidev = pci_find_device(PCI_VENDOR_ID_ENSONIQ, PCI_DEVICE_ID_ENSONIQ_ES1371, pcidev))) {
 		if (pcidev->base_address[0] == 0 || 
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/lowlevel/Config.in linux/drivers/sound/lowlevel/Config.in
--- v2.1.132/linux/drivers/sound/lowlevel/Config.in	Tue Jun  9 11:57:30 1998
+++ linux/drivers/sound/lowlevel/Config.in	Sun Dec 27 10:53:45 1998
@@ -6,6 +6,7 @@
     dep_tristate 'Gallant Audio Cards (SC-6000 and SC-6600 based)' CONFIG_AEDSP16 $CONFIG_SOUND_OSS
     if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then
 	hex '  I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
+        hex 'I/O base for MPU401 Check from manual of the card' CONFIG_MPU_BASE 330
     fi
 
     if [ "$CONFIG_AEDSP16" = "y" -o "$CONFIG_AEDSP16" = "m" ]; then
@@ -23,9 +24,9 @@
 		bool 'Audio Excel DSP 16 (SBPro emulation)' CONFIG_AEDSP16_SBPRO
 		if [ "$CONFIG_AEDSP16_SBPRO" = "y" ]; then
 		    comment 'Audio Excel DSP 16 [Sound Blaster Pro]'
-		    hex 'I/O base for Audio Excel DSP 16 220, 240' CONFIG_AEDSP16_BASE $CONFIG_SB_BASE
-		    int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' CONFIG_AEDSP16_SB_IRQ $CONFIG_SB_IRQ
-		    int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_SB_DMA $CONFIG_SB_DMA
+		    hex 'I/O base for Audio Excel DSP 16 220, 240' CONFIG_AEDSP16_BASE $CONFIG_SB_BASE 220
+		    int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' CONFIG_AEDSP16_SB_IRQ $CONFIG_SB_IRQ 5
+		    int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_SB_DMA $CONFIG_SB_DMA 0
 		fi
 	    fi
 	fi
@@ -36,8 +37,8 @@
 		if [ "$CONFIG_AEDSP16_MSS" = "y" ]; then
 		    comment 'Audio Excel DSP 16 [Microsoft Sound System]'
 		    hex 'I/O base for Audio Excel DSP 16 220 or 240' CONFIG_AEDSP16_BASE 220
-		    int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' CONFIG_AEDSP16_MSS_IRQ $CONFIG_MSS_IRQ
-		    int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_MSS_DMA $CONFIG_MSS_DMA
+		    int 'Audio Excel DSP 16 IRQ 5, 7, 9, 10, 11' CONFIG_AEDSP16_MSS_IRQ $CONFIG_MSS_IRQ 5
+		    int 'Audio Excel DSP 16 DMA 0, 1 or 3' CONFIG_AEDSP16_MSS_DMA $CONFIG_MSS_DMA 1
 		fi
 	    fi
 	fi
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/mad16.c linux/drivers/sound/mad16.c
--- v2.1.132/linux/drivers/sound/mad16.c	Thu Nov 12 16:21:22 1998
+++ linux/drivers/sound/mad16.c	Mon Dec 28 11:06:11 1998
@@ -65,6 +65,8 @@
  *				Improved debugging support.	16-May-1998
  *				Fixed bug.			16-Jun-1998
  *
+ *     Torsten Duwe            Made Opti924 PnP support non-destructive
+ *                                                             1998-12-23
  */
 
 #include "sound_config.h"
@@ -279,19 +281,21 @@
 	if ((mad_read(MC0_PORT+13) & 0x80) == 0)
 		return 1;
 	
+#if 0	
 	/* Force off PnP mode. This is not recommended because
 	 * the PnP bios will not recognize the chip on the next
 	 * warm boot and may assignd different resources to other
 	 * PnP/PCI cards.
 	 */
 	mad_write(MC0_PORT+17, 0x04);
+#endif
 	return 1;
 }
 
 static int detect_mad16(void)
 {
-	unsigned char tmp, tmp2;
-	int i;
+	unsigned char tmp, tmp2, bit;
+	int i, port;
 
 	/*
 	 * Check that reading a register doesn't return bus float (0xff)
@@ -323,14 +327,19 @@
 		DDB(printk("MC1_PORT didn't close after read (0x%02x)\n", tmp2));
 		return 0;
 	}
-	mad_write(MC1_PORT, tmp ^ 0x80);	/* Toggle a bit */
-	if ((tmp2 = mad_read(MC1_PORT)) != (tmp ^ 0x80))	/* Compare the bit */
+
+	bit  = (c924pnp) ?     0x20 : 0x80;
+	port = (c924pnp) ? MC2_PORT : MC1_PORT;
+
+	tmp = mad_read(port);
+	mad_write(port, tmp ^ bit);	/* Toggle a bit */
+	if ((tmp2 = mad_read(port)) != (tmp ^ bit))	/* Compare the bit */
 	{
-		mad_write(MC1_PORT, tmp);	/* Restore */
+		mad_write(port, tmp);	/* Restore */
 		DDB(printk("Bit revert test failed (0x%02x, 0x%02x)\n", tmp, tmp2));
 		return 0;
 	}
-	mad_write(MC1_PORT, tmp);	/* Restore */
+	mad_write(port, tmp);	/* Restore */
 	return 1;		/* Bingo */
 }
 
@@ -456,14 +465,8 @@
 
 	DDB(printk("Detect using password = 0xE5\n"));
 	
-	if (!detect_mad16()) {
-		c924pnp++;
-		DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n"));
-	}
-
 	if (!detect_mad16())	/* No luck. Try different model */
 	{
-		c924pnp=0;
 		board_type = C928;
 
 		DDB(printk("Detect using password = 0xE2\n"));
@@ -493,10 +496,19 @@
 				for (i = 0xf8d; i <= 0xf93; i++)
 					DDB(printk("port %03x = %02x\n", i, mad_read(i)));
 
-				if (!detect_mad16())
-					return 0;
-
-				DDB(printk("mad16.c: 82C930 detected\n"));
+				if (!detect_mad16()) {
+				  board_type = C924;
+				  c924pnp++;
+				  DDB(printk("Detect using password = 0xE5 (again), port offset -0x80\n"));
+				  if (!detect_mad16()) {
+				    c924pnp=0;
+				    return 0;
+				  }
+				  
+				  DDB(printk("mad16.c: 82C924 PnP detected\n"));
+				}
+				else
+				  DDB(printk("mad16.c: 82C930 detected\n"));
 			} else
 				DDB(printk("mad16.c: 82C929 detected\n"));
 		} else {
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/sb.h linux/drivers/sound/sb.h
--- v2.1.132/linux/drivers/sound/sb.h	Thu Nov 12 16:21:22 1998
+++ linux/drivers/sound/sb.h	Mon Dec 28 11:06:11 1998
@@ -48,6 +48,7 @@
 #define MDL_ES1868MIDI	14	/* MIDI port of ESS1868 */
 #define MDL_AEDSP	15	/* Audio Excel DSP 16 */
 
+#define SUBMDL_ES188X	0x10	/* Subtype ES188X for specific handling */
 #define SUBMDL_ALS007	42	/* ALS-007 differs from SB16 only in mixer */
 				/* register assignment */
 /*
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/sb_common.c linux/drivers/sound/sb_common.c
--- v2.1.132/linux/drivers/sound/sb_common.c	Tue Dec 22 14:16:56 1998
+++ linux/drivers/sound/sb_common.c	Mon Dec 28 11:06:11 1998
@@ -13,6 +13,8 @@
 /*
  * Daniel J. Rodriksson: Modified sbintr to handle 8 and 16 bit interrupts
  *                       for full duplex support ( only sb16 by now )
+ * Rolf Fokkens:	 Added (BETA?) support for ES188x chips.
+ * (fokkensr@vertis.nl)	 Which means: You can adjust the recording levels.
  */
 #include <linux/config.h>
 #include <linux/delay.h>
@@ -484,6 +486,24 @@
 #endif
 }
 
+/*
+ * ESS technology describes a detection scheme in their docs. It involves
+ * fiddling with the bits in certain mixer registers. ess_probe is supposed
+ * to help.
+ */
+static int ess_probe (sb_devc * devc, int reg, int xorval)
+{
+	int  val1, val2, val3;
+
+	val1 = sb_getmixer (devc, reg);
+	val2 = val1 ^ xorval;
+	sb_setmixer (devc, reg, val2);
+	val3 = sb_getmixer (devc, reg); 
+	sb_setmixer (devc, reg, val1);
+
+	return (val2 == val3);
+}
+
 static int ess_init(sb_devc * devc, struct address_info *hw_config)
 {
 	unsigned char cfg, irq_bits = 0, dma_bits = 0;
@@ -522,12 +542,31 @@
 		devc->model = MDL_SBPRO;
 		return 1;
 	}
-	else if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
+
+	/*
+	 * This the detection heuristic of ESS technology, though somewhat
+	 * changed to actually make it work.
+	 * This is the most BETA part of the software: Will the detection
+         * always work?
+	 */
+	devc->model = MDL_ESS;
+	devc->submodel = ess_minor & 0x0f;
+
+	if (ess_major == 0x68 && (ess_minor & 0xf0) == 0x80)
 	{
 		char *chip = "ES688";
 
-		if ((ess_minor & 0x0f) >= 8)
-			chip = "ES1688";
+		if ((ess_minor & 0x0f) >= 8) {
+			if (  !ess_probe (devc, 0x64, (1 << 3))
+			    && ess_probe (devc, 0x70, 0x7f)) {
+				chip = "ES188x";
+				devc->submodel = SUBMDL_ES188X;
+			} else {
+				chip = "ES1688";
+			};
+		} else {
+			chip = "ES688";
+		};
 
 		sprintf(name,"ESS %s AudioDrive (rev %d)",
 			chip, ess_minor & 0x0f);
@@ -535,8 +574,6 @@
 	else
 		strcpy(name, "Jazz16");
 
-	devc->model = MDL_ESS;
-	devc->submodel = ess_minor & 0x0f;
 	hw_config->name = name;
 	sb_dsp_reset(devc);	/* Turn on extended mode */
 
@@ -998,19 +1035,28 @@
 
 /*
  *	Mixer access routines
+ *
+ *	ES188x modifications: some mixer registers reside in the
+ *	range above 0xa0. These must be accessed in another way.
  */
 
 void sb_setmixer(sb_devc * devc, unsigned int port, unsigned int value)
 {
 	unsigned long flags;
 
+	/* MDB(printk("ESS: write port %x: %x\n", port, value)); */
+
 	save_flags(flags);
 	cli();
-	outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
-
-	udelay(20);
-	outb(((unsigned char) (value & 0xff)), MIXER_DATA);
-	udelay(20);
+	if (devc->model == MDL_ESS && port >= 0xa0 && port <= 0xbf) {
+		ess_write (devc, port, value);
+	} else {
+		outb(((unsigned char) (port & 0xff)), MIXER_ADDR);
+
+		udelay(20);
+		outb(((unsigned char) (value & 0xff)), MIXER_DATA);
+		udelay(20);
+	};
 	restore_flags(flags);
 }
 
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/sb_mixer.c linux/drivers/sound/sb_mixer.c
--- v2.1.132/linux/drivers/sound/sb_mixer.c	Fri Oct 23 22:01:22 1998
+++ linux/drivers/sound/sb_mixer.c	Mon Dec 28 11:06:11 1998
@@ -13,6 +13,24 @@
  *
  *
  * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ * Rolf Fokkens    : ES188x recording level support
+ */
+
+/*
+ * About ES188x support:
+ *
+ * The standard ES1688 support doesn't take care of the ES188x recording
+ * levels very well. Whenever a device is selected (recmask) for recording
+ * it's recording level is loud, and it cannot be changed.
+ *
+ * The ES188x has separate registers to control the recording levels. The
+ * ES188x specific software makes these level the same as their corresponding
+ * playback levels, unless recmask says they aren't recorded. In the latter
+ * case the recording volumes are 0.
+ *
+ * Now recording levels of inputs can be controlled, by changing the playback
+ * levels. Futhermore several devices can be recorded together (which is not
+ * possible with the ES1688.
  */
 
 #include <linux/config.h>
@@ -78,22 +96,62 @@
 	sb_mixer_reset(devc);
 }
 
-static int smw_mixer_set(sb_devc * devc, int dev, int value)
+static int common_mixer_set(sb_devc * devc, int dev, int left, int right)
 {
-	int left = value & 0x000000ff;
-	int right = (value & 0x0000ff00) >> 8;
-	int reg, val;
+	int regoffs;
+	unsigned char val;
 
-	if (left > 100)
-		left = 100;
-	if (right > 100)
-		right = 100;
+	regoffs = (*devc->iomap)[dev][LEFT_CHN].regno;
 
-	if (dev > 31)
+	if (regoffs == 0)
 		return -EINVAL;
 
-	if (!(devc->supported_devices & (1 << dev)))	/* Not supported */
-		return -EINVAL;
+	val = sb_getmixer(devc, regoffs);
+	change_bits(devc, &val, dev, LEFT_CHN, left);
+
+	devc->levels[dev] = left | (left << 8);
+
+	if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs)	/*
+								 * Change register
+								 */
+	{
+		sb_setmixer(devc, regoffs, val);	/*
+							 * Save the old one
+							 */
+		regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno;
+
+		if (regoffs == 0)
+			return left | (left << 8);	/*
+							 * Just left channel present
+							 */
+
+		val = sb_getmixer(devc, regoffs);	/*
+							 * Read the new one
+							 */
+	}
+	change_bits(devc, &val, dev, RIGHT_CHN, right);
+
+	sb_setmixer(devc, regoffs, val);
+
+	devc->levels[dev] = left | (right << 8);
+	return left | (right << 8);
+}
+
+/*
+ * Changing playback levels at ES188x means having to take care of recording
+ * levels of recorded inputs (devc->recmask) too!
+ */
+static int es188x_mixer_set(sb_devc * devc, int dev, int left, int right)
+{
+	if (devc->recmask & (1 << dev)) {
+		common_mixer_set(devc, dev + ES188X_MIXER_RECDIFF, left, right);
+	}
+	return common_mixer_set(devc, dev, left, right);
+}
+
+static int smw_mixer_set(sb_devc * devc, int dev, int left, int right)
+{
+	int reg, val;
 
 	switch (dev)
 	{
@@ -134,12 +192,6 @@
 	int left = value & 0x000000ff;
 	int right = (value & 0x0000ff00) >> 8;
 
-	int regoffs;
-	unsigned char   val;
-
-	if (devc->model == MDL_SMW)
-		return smw_mixer_set(devc, dev, value);
-
 	if (left > 100)
 		left = 100;
 	if (right > 100)
@@ -153,47 +205,60 @@
 							 */
 		return -EINVAL;
 
-	regoffs = (*devc->iomap)[dev][LEFT_CHN].regno;
-
-	if (regoffs == 0)
-		return -EINVAL;
-
-	val = sb_getmixer(devc, regoffs);
-	change_bits(devc, &val, dev, LEFT_CHN, left);
-
-	devc->levels[dev] = left | (left << 8);
-
-	if ((*devc->iomap)[dev][RIGHT_CHN].regno != regoffs)	/*
-								 * Change register
-								 */
-	{
-		sb_setmixer(devc, regoffs, val);	/*
-							 * Save the old one
-							 */
-		regoffs = (*devc->iomap)[dev][RIGHT_CHN].regno;
-
-		if (regoffs == 0)
-			return left | (left << 8);	/*
-							 * Just left channel present
-							 */
-
-		val = sb_getmixer(devc, regoffs);	/*
-							 * Read the new one
-							 */
+	/* Differentiate dependong on the chipsets */
+	switch (devc->model) {
+	case MDL_SMW:
+		return smw_mixer_set(devc, dev, left, right);
+		break;
+	case MDL_ESS:
+		if (devc->submodel == SUBMDL_ES188X) {
+			return es188x_mixer_set(devc, dev, left, right);
+		}
+		break;
 	}
-	change_bits(devc, &val, dev, RIGHT_CHN, right);
 
-	sb_setmixer(devc, regoffs, val);
-
-	devc->levels[dev] = left | (right << 8);
-	return left | (right << 8);
+	return common_mixer_set(devc, dev, left, right);
 }
 
+/*
+ * set_recsrc doesn't apply to ES188x
+ */
 static void set_recsrc(sb_devc * devc, int src)
 {
 	sb_setmixer(devc, RECORD_SRC, (sb_getmixer(devc, RECORD_SRC) & ~7) | (src & 0x7));
 }
 
+/*
+ * Changing the recmask on a ES188x means:
+ * (1) Find the differences
+ * (2) For "turned-on"  inputs: make the recording level the playback level
+ * (3) For "turned-off" inputs: make the recording level zero
+ */
+static int es188x_set_recmask(sb_devc * devc, int mask)
+{
+	int i, i_mask, cur_mask, diff_mask;
+	int value, left, right;
+
+	cur_mask  = devc->recmask;
+	diff_mask = (cur_mask ^ mask);
+
+	for (i = 0; i < 32; i++) {
+		i_mask = (1 << i);
+		if (diff_mask & i_mask) {	/* Difference? (1)	*/
+			if (mask & i_mask) {	/* Turn it on  (2)	*/
+				value = devc->levels[i];
+				left  = value & 0x000000ff;
+    				right = (value & 0x0000ff00) >> 8;
+			} else {		/* Turn it off (3)	*/
+				left  = 0;
+				right = 0;
+			}
+			common_mixer_set(devc, i + ES188X_MIXER_RECDIFF, left, right);
+		}
+	}
+	return mask;
+}
+
 static int set_recmask(sb_devc * devc, int mask)
 {
 	int devmask, i;
@@ -207,6 +272,14 @@
 		case MDL_ESS:
 		case MDL_JAZZ:
 		case MDL_SMW:
+			if (devc->model == MDL_ESS &&
+				devc->submodel == SUBMDL_ES188X) {
+				/*
+				 * ES188x needs a separate approach
+				 */
+				devmask = es188x_set_recmask(devc, devmask);
+				break;
+			};
 
 			if (devmask != SOUND_MASK_MIC &&
 				devmask != SOUND_MASK_LINE &&
@@ -423,7 +496,7 @@
 static void sb_mixer_reset(sb_devc * devc)
 {
 	char name[32];
-	int i;
+	int i, regval;
 	extern int sm_games;
 
 	sprintf(name, "SB_%d", devc->sbmixnum);
@@ -435,6 +508,24 @@
 
 	for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
 		sb_mixer_set(devc, i, devc->levels[i]);
+
+	/*
+	 * Separate actions for ES188x:
+	 * Change registers 7a and 1c to make the record mixer the
+	 * actual recording source.
+	 * Then call set_recmask twice to do extra ES188x initializations
+	 */
+	if (devc->model == MDL_ESS && devc->submodel == SUBMDL_ES188X) {
+	        regval = sb_getmixer(devc, 0x7a);
+		regval = (regval & 0xe7) | 0x08;
+	        sb_setmixer(devc, 0x7a, regval);
+		regval = sb_getmixer(devc, 0x1c);
+		regval = (regval & 0xf8) | 0x07;
+		sb_setmixer(devc, 0x1c, regval);
+
+		set_recmask(devc, ES188X_RECORDING_DEVICES);
+		set_recmask(devc, 0);
+	}
 	set_recmask(devc, SOUND_MASK_MIC);
 }
 
@@ -464,9 +555,26 @@
 
 		case MDL_ESS:
 			devc->mixer_caps = SOUND_CAP_EXCL_INPUT;
-			devc->supported_devices = ES688_MIXER_DEVICES;
-			devc->supported_rec_devices = ES688_RECORDING_DEVICES;
-			devc->iomap = &es688_mix;
+
+			/*
+			 * Take care of ES188x specifics...
+			 */
+			switch (devc->submodel) {
+			case SUBMDL_ES188X:
+				devc->supported_devices
+					= ES188X_MIXER_DEVICES;
+				devc->supported_rec_devices
+					= ES188X_RECORDING_DEVICES;
+				devc->iomap = &es188x_mix;
+				break;
+			default:
+				devc->supported_devices
+					= ES688_MIXER_DEVICES;
+				devc->supported_rec_devices
+					= ES688_RECORDING_DEVICES;
+				devc->iomap = &es688_mix;
+			}
+
 			break;
 
 		case MDL_SMW:
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/sb_mixer.h linux/drivers/sound/sb_mixer.h
--- v2.1.132/linux/drivers/sound/sb_mixer.h	Thu Nov 12 16:21:22 1998
+++ linux/drivers/sound/sb_mixer.h	Mon Dec 28 11:06:11 1998
@@ -15,7 +15,11 @@
  * Modified:
  *	Hunyue Yau	Jan 6 1994
  *	Added defines for the Sound Galaxy NX Pro mixer.
- * 
+ *
+ *	Rolf Fokkens	Dec 20 1998
+ *	Added (BETA?) support for ES188x chips.
+ *	Which means: you can adjust the recording levels.
+ *
  */
 #include <linux/config.h>
 #include "legacy.h"
@@ -47,6 +51,10 @@
 #define ES688_RECORDING_DEVICES SBPRO_RECORDING_DEVICES
 #define ES688_MIXER_DEVICES (SBPRO_MIXER_DEVICES|SOUND_MASK_LINE2|SOUND_MASK_SPEAKER)
 
+#define ES188X_RECORDING_DEVICES	(ES688_RECORDING_DEVICES | SOUND_MASK_LINE2 \
+					 |SOUND_MASK_SYNTH)
+#define ES188X_MIXER_DEVICES (ES688_MIXER_DEVICES)
+
 #define SB16_MIXER_DEVICES		(SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \
 					 SOUND_MASK_CD | \
 					 SOUND_MASK_IGAIN | SOUND_MASK_OGAIN | \
@@ -110,6 +118,31 @@
 #define RIGHT_CHN	1
 
 /*
+ * Mixer registers of ES188x
+ *
+ * These register specifically take care of recording levels. To make the
+ * mapping from playback devices to recording devices every recording
+ * devices = playback device + ES188X_MIXER_RECDIFF
+ */
+#define ES188X_MIXER_RECBASE	(SOUND_MIXER_LINE3 + 1)
+#define ES188X_MIXER_RECDIFF	(ES188X_MIXER_RECBASE - SOUND_MIXER_SYNTH)
+
+#define ES188X_MIXER_RECSYNTH	(SOUND_MIXER_SYNTH	+ ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECPCM	(SOUND_MIXER_PCM	+ ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECSPEAKER	(SOUND_MIXER_SPEAKER	+ ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECLINE	(SOUND_MIXER_LINE	+ ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECMIC	(SOUND_MIXER_MIC	+ ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECCD	(SOUND_MIXER_CD		+ ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECIMIX	(SOUND_MIXER_IMIX	+ ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECALTPCM	(SOUND_MIXER_ALTPCM	+ ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECRECLEV	(SOUND_MIXER_RECLEV	+ ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECIGAIN	(SOUND_MIXER_IGAIN	+ ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECOGAIN	(SOUND_MIXER_OGAIN	+ ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECLINE1	(SOUND_MIXER_LINE1	+ ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECLINE2	(SOUND_MIXER_LINE2	+ ES188X_MIXER_RECDIFF)
+#define ES188X_MIXER_RECLINE3	(SOUND_MIXER_LINE3	+ ES188X_MIXER_RECDIFF)
+
+/*
  * Mixer registers of ALS007
  */
 #define ALS007_RECORD_SRC	0x6c
@@ -152,6 +185,50 @@
 MIX_ENT(SOUND_MIXER_LINE1,	0x00, 0, 0, 0x00, 0, 0),
 MIX_ENT(SOUND_MIXER_LINE2,	0x3a, 7, 4, 0x3a, 3, 4),
 MIX_ENT(SOUND_MIXER_LINE3,	0x00, 0, 0, 0x00, 0, 0)
+};
+
+/*
+ * The ES188x specifics.
+ * Note that de master volume unlike ES688 is now controlled by two 6 bit
+ * registers. These seem to work OK on 1868 too, but I have no idea if it's
+ * compatible to 688 or 1688....
+ * Also Note that the recording levels (ES188X_MIXER_REC...) have own 
+ * entries as if they were playback devices. They are used internally in the
+ * driver only!
+ */
+static mixer_tab es188x_mix = {
+MIX_ENT(SOUND_MIXER_VOLUME,	0x60, 5, 6, 0x62, 5, 6),
+MIX_ENT(SOUND_MIXER_BASS,       0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_TREBLE,     0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_SYNTH,      0x36, 7, 4, 0x36, 3, 4),
+MIX_ENT(SOUND_MIXER_PCM,        0x14, 7, 4, 0x14, 3, 4),
+MIX_ENT(SOUND_MIXER_SPEAKER,    0x3c, 2, 3, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE,       0x3e, 7, 4, 0x3e, 3, 4),
+MIX_ENT(SOUND_MIXER_MIC,        0x1a, 7, 4, 0x1a, 3, 4),
+MIX_ENT(SOUND_MIXER_CD,         0x38, 7, 4, 0x38, 3, 4),
+MIX_ENT(SOUND_MIXER_IMIX,       0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_ALTPCM,     0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_RECLEV,     0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_IGAIN,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_OGAIN,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE1,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(SOUND_MIXER_LINE2,      0x3a, 7, 4, 0x3a, 3, 4),
+MIX_ENT(SOUND_MIXER_LINE3,      0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECSYNTH,	0x6b, 7, 4, 0x6b, 3, 4),
+MIX_ENT(ES188X_MIXER_RECPCM,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECSPEAKER,0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECLINE,	0x6e, 7, 4, 0x6e, 3, 4),
+MIX_ENT(ES188X_MIXER_RECMIC,	0x68, 7, 4, 0x68, 3, 4),
+MIX_ENT(ES188X_MIXER_RECCD,	0x6a, 7, 4, 0x6a, 3, 4),
+
+MIX_ENT(ES188X_MIXER_RECIMIX,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECALTPCM,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECRECLEV,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECIGAIN,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECOGAIN,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECLINE1,	0x00, 0, 0, 0x00, 0, 0),
+MIX_ENT(ES188X_MIXER_RECLINE2,	0x6c, 7, 4, 0x6c, 3, 4),
+MIX_ENT(ES188X_MIXER_RECLINE3,	0x00, 0, 0, 0x00, 0, 0)
 };
 
 #ifdef	__SGNXPRO__
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/softoss_rs.c linux/drivers/sound/softoss_rs.c
--- v2.1.132/linux/drivers/sound/softoss_rs.c	Thu May 14 19:47:42 1998
+++ linux/drivers/sound/softoss_rs.c	Sun Dec 27 10:53:45 1998
@@ -49,7 +49,7 @@
 #endif
 				/* Interpolation (resolution of 512 steps) */
 				{
-					int fract = v->ptr & 0x1f;	/* 9 bits */
+					int fract = v->ptr & 0x1ff;	/* 9 bits */
 
 					/* This method works with less arithmetic operations */
 					register int v1 = v->wave[ix];
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- v2.1.132/linux/drivers/sound/sonicvibes.c	Tue Dec 22 14:16:56 1998
+++ linux/drivers/sound/sonicvibes.c	Sun Dec 27 10:53:45 1998
@@ -48,6 +48,7 @@
  *                     "OSS documented" and "OSS actual" behaviour
  *    31.08.98   0.7   Fix realplayer problems - dac.count issues
  *    10.12.98   0.8   Fix drain_dac trying to wait on not yet initialized DMA
+ *    16.12.98   0.9   Fix a few f_file & FMODE_ bugs
  *
  */
 
@@ -764,17 +765,14 @@
 		s->dma_adc.hwptr = hwptr;
 		s->dma_adc.total_bytes += diff;
 		s->dma_adc.count += diff;
-		if (s->dma_adc.mapped) {
-			if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 
-				wake_up(&s->dma_adc.wait);
-		} else {
+		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize) 
+			wake_up(&s->dma_adc.wait);
+		if (!s->dma_adc.mapped) {
 			if (s->dma_adc.count > (signed)(s->dma_adc.dmasize - ((3 * s->dma_adc.fragsize) >> 1))) {
 				s->enable &= ~SV_CENABLE_RE;
 				wrindir(s, SV_CIENABLE, s->enable);
 				s->dma_adc.error++;
 			}
-			if (s->dma_adc.count > 0)
-				wake_up(&s->dma_adc.wait);
 		}
 	}
 	/* update DAC pointer */
@@ -797,7 +795,7 @@
 				clear_advance(s);
 				s->dma_dac.endcleared = 1;
 			}
-			if (s->dma_dac.count < (signed)s->dma_dac.dmasize)
+			if (s->dma_dac.count + (signed)s->dma_dac.fragsize <= (signed)s->dma_dac.dmasize)
 				wake_up(&s->dma_dac.wait);
 		}
 	}
@@ -1382,27 +1380,22 @@
 	unsigned int mask = 0;
 
 	VALIDATE_STATE(s);
-	if (file->f_flags & FMODE_WRITE)
+	if (file->f_mode & FMODE_WRITE)
 		poll_wait(file, &s->dma_dac.wait, wait);
-	if (file->f_flags & FMODE_READ)
+	if (file->f_mode & FMODE_READ)
 		poll_wait(file, &s->dma_adc.wait, wait);
 	spin_lock_irqsave(&s->lock, flags);
 	sv_update_ptr(s);
-	if (file->f_flags & FMODE_READ) {
-		if (s->dma_adc.mapped) {
-			if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
-				mask |= POLLIN | POLLRDNORM;
-		} else {
-			if (s->dma_adc.count > 0)
-				mask |= POLLIN | POLLRDNORM;
-		}
+	if (file->f_mode & FMODE_READ) {
+		if (s->dma_adc.count >= (signed)s->dma_adc.fragsize)
+			mask |= POLLIN | POLLRDNORM;
 	}
-	if (file->f_flags & FMODE_WRITE) {
+	if (file->f_mode & FMODE_WRITE) {
 		if (s->dma_dac.mapped) {
 			if (s->dma_dac.count >= (signed)s->dma_dac.fragsize) 
 				mask |= POLLOUT | POLLWRNORM;
 		} else {
-			if ((signed)s->dma_dac.dmasize > s->dma_dac.count)
+			if ((signed)s->dma_dac.dmasize >= s->dma_dac.count + (signed)s->dma_dac.fragsize)
 				mask |= POLLOUT | POLLWRNORM;
 		}
 	}
@@ -1786,11 +1779,11 @@
 	if (file->f_mode & FMODE_WRITE)
 		drain_dac(s, file->f_flags & O_NONBLOCK);
 	down(&s->open_sem);
-	if (file->f_flags & FMODE_WRITE) {
+	if (file->f_mode & FMODE_WRITE) {
 		stop_dac(s);
 		dealloc_dmabuf(&s->dma_dac);
 	}
-	if (file->f_flags & FMODE_READ) {
+	if (file->f_mode & FMODE_READ) {
 		stop_adc(s);
 		dealloc_dmabuf(&s->dma_adc);
 	}
@@ -1923,16 +1916,16 @@
 	unsigned int mask = 0;
 
 	VALIDATE_STATE(s);
-	if (file->f_flags & FMODE_WRITE)
+	if (file->f_mode & FMODE_WRITE)
 		poll_wait(file, &s->midi.owait, wait);
-	if (file->f_flags & FMODE_READ)
+	if (file->f_mode & FMODE_READ)
 		poll_wait(file, &s->midi.iwait, wait);
 	spin_lock_irqsave(&s->lock, flags);
-	if (file->f_flags & FMODE_READ) {
+	if (file->f_mode & FMODE_READ) {
 		if (s->midi.icnt > 0)
 			mask |= POLLIN | POLLRDNORM;
 	}
-	if (file->f_flags & FMODE_WRITE) {
+	if (file->f_mode & FMODE_WRITE) {
 		if (s->midi.ocnt < MIDIOUTBUF)
 			mask |= POLLOUT | POLLWRNORM;
 	}
@@ -2278,7 +2271,7 @@
 
 	if (!pci_present())   /* No PCI bus in this machine! */
 		return -ENODEV;
-	printk(KERN_INFO "sv: version v0.8 time " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "sv: version v0.9 time " __TIME__ " " __DATE__ "\n");
 #if 0
 	if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
 		printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
diff -u --recursive --new-file v2.1.132/linux/drivers/sound/trix.c linux/drivers/sound/trix.c
--- v2.1.132/linux/drivers/sound/trix.c	Thu Sep 17 17:53:37 1998
+++ linux/drivers/sound/trix.c	Sun Dec 27 10:53:45 1998
@@ -26,6 +26,7 @@
 #ifdef CONFIG_TRIX
 
 #ifdef INCLUDE_TRIX_BOOT
+#include <linux/init.h>
 #include "trix_boot.h"
 #else
 static unsigned char *trix_boot = NULL;
diff -u --recursive --new-file v2.1.132/linux/fs/Config.in linux/fs/Config.in
--- v2.1.132/linux/fs/Config.in	Thu Nov 19 09:56:28 1998
+++ linux/fs/Config.in	Sun Dec 27 10:50:12 1998
@@ -5,23 +5,53 @@
 comment 'Filesystems'
 
 bool	 'Quota support' CONFIG_QUOTA
+tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
 
-tristate 'Minix fs support' CONFIG_MINIX_FS
-tristate 'Second extended fs support' CONFIG_EXT2_FS
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'ADFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_ADFS_FS
+fi
+tristate 'Amiga FFS filesystem support' CONFIG_AFFS_FS
+tristate 'Apple Macintosh filesystem support (experimental)' CONFIG_HFS_FS
+# msdos filesystems
+tristate 'DOS FAT fs support' CONFIG_FAT_FS
+dep_tristate '  MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
+dep_tristate '  UMSDOS: Unix-like filesystem on top of standard MSDOS filesystem' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
+dep_tristate '  VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
 
 tristate 'ISO 9660 CDROM filesystem support' CONFIG_ISO9660_FS
 if [ "$CONFIG_ISO9660_FS" != "n" ]; then
   bool 'Microsoft Joliet CDROM extensions' CONFIG_JOLIET
 fi
 
-# msdos filesystems
-tristate 'DOS FAT fs support' CONFIG_FAT_FS
-dep_tristate 'MSDOS fs support' CONFIG_MSDOS_FS $CONFIG_FAT_FS
-dep_tristate 'UMSDOS: Unix-like filesystem on top of standard MSDOS filesystem' CONFIG_UMSDOS_FS $CONFIG_MSDOS_FS
-dep_tristate 'VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS
-
+tristate 'Minix fs support' CONFIG_MINIX_FS
+tristate 'NTFS filesystem support (read only)' CONFIG_NTFS_FS
+if [ "$CONFIG_NTFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool '   NTFS read-write support (experimental)' CONFIG_NTFS_RW
+fi
+tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
 bool '/proc filesystem support' CONFIG_PROC_FS
+if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
+  tristate '/dev/pts filesystem for Unix98 PTYs' CONFIG_DEVPTS_FS
+fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'QNX filesystem support (EXPERIMENTAL)' CONFIG_QNX4FS_FS
+  if [ "$CONFIG_QNX4FS_FS" != "n" ]; then
+    bool '   QNXFS read-write support (FOR TESTING ONLY)' CONFIG_QNX4FS_RW
+  fi    
+fi
+tristate 'ROM filesystem support' CONFIG_ROMFS_FS
+tristate 'Second extended fs support' CONFIG_EXT2_FS
+tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
+tristate 'UFS filesystem support' CONFIG_UFS_FS
+
+
+
+mainmenu_option next_comment
+comment 'Network File Systems'
+
 if [ "$CONFIG_INET" = "y" ]; then
+  tristate 'Coda filesystem support (advanced network fs)' CONFIG_CODA_FS
   tristate 'NFS filesystem support' CONFIG_NFS_FS
   if [ "$CONFIG_NFS_FS" = "y" -a "$CONFIG_IP_PNP" = "y" ]; then
     bool '   Root file system on NFS' CONFIG_ROOT_NFS
@@ -42,7 +72,6 @@
       define_bool CONFIG_LOCKD n
     fi
   fi
-  tristate 'Coda filesystem support (advanced network fs)' CONFIG_CODA_FS
   tristate 'SMB filesystem support (to mount WfW shares etc.)' CONFIG_SMB_FS
   if [ "$CONFIG_SMB_FS" != "n" ]; then
     bool 'SMB Win95 bug work-around' CONFIG_SMB_WIN95
@@ -54,34 +83,23 @@
     source fs/ncpfs/Config.in
   fi
 fi
-tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
 
-tristate 'NTFS filesystem support (read only)' CONFIG_NTFS_FS
-if [ "$CONFIG_NTFS_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  bool '   NTFS read-write support (experimental)' CONFIG_NTFS_RW
-fi
+endmenu
 
-tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
-tristate 'Amiga FFS filesystem support' CONFIG_AFFS_FS
-tristate 'Apple Macintosh filesystem support (experimental)' CONFIG_HFS_FS
-tristate 'ROM filesystem support' CONFIG_ROMFS_FS
-tristate 'Kernel automounter support' CONFIG_AUTOFS_FS
 if [ "$CONFIG_AFFS_FS" != "n" ]; then
   define_bool CONFIG_AMIGA_PARTITION y
 fi
-tristate 'UFS filesystem support' CONFIG_UFS_FS
+
+mainmenu_option next_comment
+comment 'Partition Types'
+
 bool 'BSD disklabel (BSD partition tables) support' CONFIG_BSD_DISKLABEL
+bool 'Macintosh partition map support' CONFIG_MAC_PARTITION
 bool 'SMD disklabel (Sun partition tables) support' CONFIG_SMD_DISKLABEL
 bool 'Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
-if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then
-  tristate '/dev/pts filesystem for Unix98 PTYs' CONFIG_DEVPTS_FS
-fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  tristate 'ADFS filesystem support (read only) (EXPERIMENTAL)' CONFIG_ADFS_FS
-  tristate 'QNX filesystem support (EXPERIMENTAL)' CONFIG_QNX4FS_FS
-  if [ "$CONFIG_QNX4FS_FS" != "n" ]; then
-    bool '   QNXFS read-write support (FOR TESTING ONLY)' CONFIG_QNX4FS_RW
-  fi    
+  bool 'Unixware slices support (EXPERIMENTAL)' CONFIG_UNIXWARE_DISKLABEL
 fi
-bool 'Macintosh partition map support' CONFIG_MAC_PARTITION
+endmenu
+
 endmenu
diff -u --recursive --new-file v2.1.132/linux/fs/autofs/waitq.c linux/fs/autofs/waitq.c
--- v2.1.132/linux/fs/autofs/waitq.c	Thu Nov 19 09:56:28 1998
+++ linux/fs/autofs/waitq.c	Mon Dec 28 00:47:48 1998
@@ -103,6 +103,10 @@
 	struct autofs_wait_queue *wq;
 	int status;
 
+	/* In catatonic mode, we don't wait for nobody */
+	if ( sbi->catatonic )
+		return -ENOENT;
+
 	for ( wq = sbi->queues ; wq ; wq = wq->next ) {
 		if ( wq->hash == name->hash &&
 		     wq->len == name->len &&
@@ -137,6 +141,15 @@
 		wq->wait_ctr++;
 
 	/* wq->name is NULL if and only if the lock is already released */
+
+	if ( sbi->catatonic ) {
+		/* We might have slept, so check again for catatonic mode */
+		wq->status = -ENOENT;
+		if ( wq->name ) {
+			kfree(wq->name);
+			wq->name = NULL;
+		}
+	}
 
 	if ( wq->name ) {
 		/* Block all but "shutdown" signals while waiting */
diff -u --recursive --new-file v2.1.132/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- v2.1.132/linux/fs/binfmt_misc.c	Wed Aug 26 11:37:40 1998
+++ linux/fs/binfmt_misc.c	Sun Dec 27 10:52:09 1998
@@ -15,6 +15,7 @@
  *  1997-08-09 removed extension stripping, locking cleanup
  */
 
+#include <linux/config.h>
 #include <linux/module.h>
 
 #include <linux/kernel.h>
@@ -451,7 +452,9 @@
  */
 static void entry_proc_cleanup(struct binfmt_entry *e)
 {
+#ifdef CONFIG_PROC_FS
 	remove_proc_entry(e->proc_name, bm_dir);
+#endif
 }
 
 /*
@@ -459,6 +462,7 @@
  */
 static int entry_proc_setup(struct binfmt_entry *e)
 {
+#ifdef CONFIG_PROC_FS
 	if (!(e->proc_dir = create_proc_entry(e->proc_name,
 			 	S_IFREG | S_IRUGO | S_IWUSR, bm_dir)))
 		return -ENOMEM;
@@ -466,7 +470,7 @@
 	e->proc_dir->data = (void *) (e->id);
 	e->proc_dir->read_proc = proc_read_status;
 	e->proc_dir->write_proc = proc_write_status;
-
+#endif
 	return 0;
 }
 
@@ -490,8 +494,9 @@
 
 int __init init_misc_binfmt(void)
 {
-	struct proc_dir_entry *status = NULL, *reg;
 	int error = -ENOMEM;
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry *status = NULL, *reg;
 
 	bm_dir = create_proc_entry("sys/fs/binfmt_misc", S_IFDIR, NULL);
 	if (!bm_dir)
@@ -511,6 +516,7 @@
 	if (!reg)
 		goto cleanup_status;
 	reg->write_proc = proc_write_register;
+#endif /* CONFIG_PROC_FS */
 
 	error = register_binfmt(&misc_format);
 out:
diff -u --recursive --new-file v2.1.132/linux/fs/buffer.c linux/fs/buffer.c
--- v2.1.132/linux/fs/buffer.c	Tue Dec 22 14:16:57 1998
+++ linux/fs/buffer.c	Wed Dec 23 09:44:41 1998
@@ -1836,7 +1836,8 @@
 				 if (buffer_locked(bh) || !buffer_dirty(bh))
 					  continue;
 				 ndirty++;
-				 if(bh->b_flushtime > jiffies) continue;
+				 if(time_before(jiffies, bh->b_flushtime))
+					continue;
 				 nwritten++;
 				 next->b_count++;
 				 bh->b_count++;
diff -u --recursive --new-file v2.1.132/linux/fs/dcache.c linux/fs/dcache.c
--- v2.1.132/linux/fs/dcache.c	Tue Dec 22 14:16:57 1998
+++ linux/fs/dcache.c	Mon Dec 28 00:35:12 1998
@@ -592,9 +592,10 @@
 	struct list_head *head = d_hash(parent,hash);
 	struct list_head *tmp = head->next;
 
-	while (tmp != head) {
+	for (;;) {
 		struct dentry * dentry = list_entry(tmp, struct dentry, d_hash);
-
+		if (tmp == head)
+			break;
 		tmp = tmp->next;
 		if (dentry->d_name.hash != hash)
 			continue;
diff -u --recursive --new-file v2.1.132/linux/fs/devices.c linux/fs/devices.c
--- v2.1.132/linux/fs/devices.c	Wed Aug 26 11:37:40 1998
+++ linux/fs/devices.c	Wed Dec 23 11:39:49 1998
@@ -210,11 +210,11 @@
 		return 0;
 
 	printk(KERN_DEBUG "VFS: Disk change detected on device %s\n",
-		kdevname(dev));
+		bdevname(dev));
 
 	sb = get_super(dev);
 	if (sb && invalidate_inodes(sb))
-		printk("VFS: busy inodes on changed media..\n");
+		printk("VFS: busy inodes on changed media.\n");
 
 	invalidate_buffers(dev);
 
@@ -338,13 +338,35 @@
 };
 
 /*
- * Print device name (in decimal, hexadecimal or symbolic) -
- * at present hexadecimal only.
+ * Print device name (in decimal, hexadecimal or symbolic)
  * Note: returns pointer to static data!
  */
 char * kdevname(kdev_t dev)
 {
 	static char buffer[32];
 	sprintf(buffer, "%02x:%02x", MAJOR(dev), MINOR(dev));
+	return buffer;
+}
+
+char * bdevname(kdev_t dev)
+{
+	static char buffer[32];
+	const char * name = blkdevs[MAJOR(dev)].name;
+
+	if (!name)
+		name = "unknown-block";
+
+	sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
+	return buffer;
+}
+
+char * cdevname(kdev_t dev)
+{
+	static char buffer[32];
+	const char * name = chrdevs[MAJOR(dev)].name;
+
+	if (!name)
+		name = "unknown-char";
+	sprintf(buffer, "%s(%d,%d)", name, MAJOR(dev), MINOR(dev));
 	return buffer;
 }
diff -u --recursive --new-file v2.1.132/linux/fs/fat/file.c linux/fs/fat/file.c
--- v2.1.132/linux/fs/fat/file.c	Wed Aug 26 11:37:40 1998
+++ linux/fs/fat/file.c	Sun Dec 27 10:47:18 1998
@@ -375,6 +375,12 @@
 		*ppos = inode->i_size;
 	if (count == 0)
 		return 0;
+	if (*ppos + count > 0x7FFFFFFFLL) {
+		count = 0x7FFFFFFFLL-*ppos;
+		if (!count)
+			return -EFBIG;
+	}
+
 	error = carry = 0;
 	for (start = buf; count || carry; count -= size) {
 		while (!(sector = fat_smap(inode,*ppos >> SECTOR_BITS)))
diff -u --recursive --new-file v2.1.132/linux/fs/fat/inode.c linux/fs/fat/inode.c
--- v2.1.132/linux/fs/fat/inode.c	Thu Nov 19 09:56:28 1998
+++ linux/fs/fat/inode.c	Mon Dec 28 13:56:29 1998
@@ -428,7 +428,7 @@
 		       MSDOS_SB(sb)->fat_bits,opts.name_check,
 		       opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
 		       MSDOS_CAN_BMAP(MSDOS_SB(sb)) ? ",bmap" : "");
-		printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d,"
+		printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%ld,ds=%ld,de=%d,data=%ld,"
 		       "se=%d,ts=%ld,ls=%d,rc=%ld,fc=%u]\n",
 			b->media,MSDOS_SB(sb)->cluster_size,
 			MSDOS_SB(sb)->fats,MSDOS_SB(sb)->fat_start,
diff -u --recursive --new-file v2.1.132/linux/fs/file_table.c linux/fs/file_table.c
--- v2.1.132/linux/fs/file_table.c	Thu Nov 19 09:56:28 1998
+++ linux/fs/file_table.c	Wed Dec 23 11:57:17 1998
@@ -20,7 +20,7 @@
 /* Free list management, if you are here you must have f_count == 0 */
 static struct file * free_filps = NULL;
 
-void insert_file_free(struct file *file)
+static void insert_file_free(struct file *file)
 {
 	if((file->f_next = free_filps) != NULL)
 		free_filps->f_pprev = &file->f_next;
@@ -40,6 +40,15 @@
 	file->f_pprev = &inuse_filps;
 }
 
+/* It does not matter which list it is on. */
+static inline void remove_filp(struct file *file)
+{
+	if(file->f_next)
+		file->f_next->f_pprev = file->f_pprev;
+	*file->f_pprev = file->f_next;
+}
+
+
 void __init file_table_init(void)
 {
 	filp_cache = kmem_cache_create("filp", sizeof(struct file),
@@ -115,4 +124,26 @@
 		return filp->f_op->open(dentry->d_inode, filp);
 	else
 		return 0;
+}
+
+void fput(struct file *file)
+{
+	int count = file->f_count-1;
+
+	if (!count) {
+		locks_remove_flock(file);
+		__fput(file);
+		file->f_count = 0;
+		remove_filp(file);
+		insert_file_free(file);
+	} else
+		file->f_count = count;
+}
+
+void put_filp(struct file *file)
+{
+	if(--file->f_count == 0) {
+		remove_filp(file);
+		insert_file_free(file);
+	}
 }
diff -u --recursive --new-file v2.1.132/linux/fs/hfs/ChangeLog linux/fs/hfs/ChangeLog
--- v2.1.132/linux/fs/hfs/ChangeLog	Fri Nov 27 13:09:28 1998
+++ linux/fs/hfs/ChangeLog	Wed Dec 23 14:10:36 1998
@@ -1,3 +1,24 @@
+1998-12-20  a sun  <asun@hecate.darksunrising.blah>
+
+	* bdelete.c (del_root): assign bthLNode and bthFNode only if the
+	root node becomes a leaf node. Disk First Aid no longer
+	complains. Norton Utilities, of course, has decided that it
+	doesn't like the root node number. bleah. i think that it might be
+	due to Norton Utilities not expecting the root node to have moved.
+
+1998-12-16  a sun  <asun@hecate.darksunrising.blah>
+
+	* sysdep.c (hfs_revalidate_dentry): fix inode dates when there's a
+	timezone change.
+
+1998-12-15  root  <root@hecate.darksunrising.blah>
+
+	* extent.c (new_extent): expand block size variables to handle
+	u32. 
+
+	* mdb.c (hfs_mdb_get): AlBlkSiz shouldn't be capped at 65535. we
+	should be able to handle much larger volumes now.
+
 1998-11-21  a sun  <asun@hecate.darksunrising.blah>
 
 	* hfs_sysdep.h, hfs_fs.h: added hfs_from_utc/to_utc to deal with
diff -u --recursive --new-file v2.1.132/linux/fs/hfs/bdelete.c linux/fs/hfs/bdelete.c
--- v2.1.132/linux/fs/hfs/bdelete.c	Sun Jan  4 10:40:17 1998
+++ linux/fs/hfs/bdelete.c	Wed Dec 23 14:10:36 1998
@@ -135,11 +135,16 @@
 
 		tree->bthRoot = child.bn->node;
 		tree->root = child.bn;
+
+		/* re-assign bthFNode and bthLNode if the new root is
+                   a leaf node. */
+		if (child.bn->ndType == ndLeafNode) {
+			tree->bthFNode = node;
+			tree->bthLNode = node;
+		}
 		hfs_bnode_relse(&child);
 
 		tree->bthRoot = node;
-		tree->bthFNode = node;
-		tree->bthLNode = node;
 		--tree->bthDepth;
 		tree->dirt = 1;
 		if (!tree->bthDepth) {
diff -u --recursive --new-file v2.1.132/linux/fs/hfs/extent.c linux/fs/hfs/extent.c
--- v2.1.132/linux/fs/hfs/extent.c	Thu Nov 19 09:56:28 1998
+++ linux/fs/hfs/extent.c	Wed Dec 23 14:10:36 1998
@@ -354,7 +354,7 @@
  *   hfs_u16 ablock: the number of allocation blocks in 'fork'.
  *   hfs_u16 start: first allocation block to add to 'fork'.
  *   hfs_u16 len: the number of allocation blocks to add to 'fork'.
- *   hfs_u16 ablksz: number of sectors in an allocation block.
+ *   hfs_u32 ablksz: number of sectors in an allocation block.
  * Output Variable(s):
  *   NONE
  * Returns:
@@ -471,7 +471,7 @@
 	struct hfs_mdb *mdb = fork->entry->mdb;
 	struct hfs_extent *ext;
 	int i, error, next, count;
-	hfs_u16 ablksz = mdb->alloc_blksz;
+	hfs_u32 ablksz = mdb->alloc_blksz;
 
 	next =  (fork->psize / ablksz) - 1;
 	ext = find_ext(fork, next);
@@ -530,7 +530,7 @@
 	struct hfs_extent *ext;
 	int i, start, err;
 	hfs_u16 need, len=0;
-	hfs_u16 ablksz = mdb->alloc_blksz;
+	hfs_u32 ablksz = mdb->alloc_blksz;
 	hfs_u32 blocks, clumpablks;
 
 	blocks = fork->psize;
@@ -681,8 +681,7 @@
 void hfs_extent_adj(struct hfs_fork *fork)
 {
 	if (fork) {
-		hfs_u32 blks, ablocks;
-		hfs_u16 ablksz;
+		hfs_u32 blks, ablocks, ablksz;
 
 		if (fork->lsize > HFS_FORK_MAX) {
 			fork->lsize = HFS_FORK_MAX;
diff -u --recursive --new-file v2.1.132/linux/fs/hfs/hfs.h linux/fs/hfs/hfs.h
--- v2.1.132/linux/fs/hfs/hfs.h	Sun Nov  8 14:03:06 1998
+++ linux/fs/hfs/hfs.h	Wed Dec 23 14:10:36 1998
@@ -252,7 +252,7 @@
 	hfs_u16			free_ablocks;	/* The number of unused
 						   allocation blocks
 						   in the filesystem */
-	hfs_u16			alloc_blksz;	/* The number of
+	hfs_u32			alloc_blksz;	/* The number of
 						   512-byte blocks per
 						   "allocation block" */
 	hfs_u16			attrib;		/* Attribute word */
diff -u --recursive --new-file v2.1.132/linux/fs/hfs/inode.c linux/fs/hfs/inode.c
--- v2.1.132/linux/fs/hfs/inode.c	Sun Nov  8 14:03:06 1998
+++ linux/fs/hfs/inode.c	Wed Dec 23 14:10:36 1998
@@ -260,6 +260,7 @@
 		memset(HFS_I(inode), 0, sizeof(struct hfs_inode_info));
 		HFS_I(inode)->magic = HFS_INO_MAGIC;
 		HFS_I(inode)->entry = entry;
+		HFS_I(inode)->tz_secondswest = hfs_to_utc(0);
 
 		hsb->s_ifill(inode, type);
 		if (!hsb->s_afpd && (entry->type == HFS_CDR_FIL) &&
diff -u --recursive --new-file v2.1.132/linux/fs/hfs/mdb.c linux/fs/hfs/mdb.c
--- v2.1.132/linux/fs/hfs/mdb.c	Thu Nov 19 09:56:28 1998
+++ linux/fs/hfs/mdb.c	Wed Dec 23 14:10:36 1998
@@ -118,7 +118,7 @@
 	mdb->buf = buf;
 	
 	bs = hfs_get_hl(raw->drAlBlkSiz);
-	if (!bs || bs > HFS_USHRT_MAX || (bs & (HFS_SECTOR_SIZE-1))) {
+	if (!bs || (bs & (HFS_SECTOR_SIZE-1))) {
 		hfs_warn("hfs_fs: bad allocation block size %d != 512\n", bs);
 		hfs_buffer_put(buf);
 		HFS_DELETE(mdb);
diff -u --recursive --new-file v2.1.132/linux/fs/hfs/sysdep.c linux/fs/hfs/sysdep.c
--- v2.1.132/linux/fs/hfs/sysdep.c	Sun Nov  8 14:03:06 1998
+++ linux/fs/hfs/sysdep.c	Wed Dec 23 14:10:36 1998
@@ -18,12 +18,13 @@
 #include <linux/hfs_fs_i.h>
 #include <linux/hfs_fs.h>
 
+static int hfs_revalidate_dentry(struct dentry *);
 static int hfs_hash_dentry(struct dentry *, struct qstr *);
 static int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *);
 static void hfs_dentry_iput(struct dentry *, struct inode *);
 struct dentry_operations hfs_dentry_operations =
 {
-	NULL,	                /* d_validate(struct dentry *) */
+	hfs_revalidate_dentry,	/* d_revalidate(struct dentry *) */
 	hfs_hash_dentry,	/* d_hash */
 	hfs_compare_dentry,    	/* d_compare */
 	NULL,	                /* d_delete(struct dentry *) */
@@ -86,4 +87,20 @@
 
 	entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE(inode->i_ino))] = NULL;
 	iput(inode);
+}
+
+static int hfs_revalidate_dentry(struct dentry *dentry)
+{
+	struct inode *inode = dentry->d_inode;
+	int diff;
+
+	/* fix up inode on a timezone change */
+	if (inode && 
+	    (diff = (hfs_to_utc(0) - HFS_I(inode)->tz_secondswest))) {
+		inode->i_ctime += diff;
+		inode->i_atime += diff;
+		inode->i_mtime += diff;
+		HFS_I(inode)->tz_secondswest += diff;
+	}
+	return 1;
 }
diff -u --recursive --new-file v2.1.132/linux/fs/lockd/host.c linux/fs/lockd/host.c
--- v2.1.132/linux/fs/lockd/host.c	Wed Apr 23 19:01:26 1997
+++ linux/fs/lockd/host.c	Wed Dec 23 09:44:42 1998
@@ -92,7 +92,7 @@
 	/* Lock hash table */
 	down(&nlm_host_sema);
 
-	if (next_gc < jiffies)
+	if (time_after(jiffies, next_gc))
 		nlm_gc_hosts();
 
 	for (hp = &nlm_hosts[hash]; (host = *hp); hp = &host->h_next) {
@@ -173,7 +173,7 @@
 	/* If we've already created an RPC client, check whether
 	 * RPC rebind is required */
 	if ((clnt = host->h_rpcclnt) != NULL) {
-		if (host->h_nextrebind < jiffies) {
+		if (time_after(jiffies, host->h_nextrebind)) {
 			clnt->cl_port = 0;
 			host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 			dprintk("lockd: next rebind in %ld jiffies\n",
@@ -219,7 +219,7 @@
 nlm_rebind_host(struct nlm_host *host)
 {
 	dprintk("lockd: rebind host %s\n", host->h_name);
-	if (host->h_rpcclnt && host->h_nextrebind < jiffies) {
+	if (host->h_rpcclnt && time_after(jiffies, host->h_nextrebind)) {
 		host->h_rpcclnt->cl_port = 0;
 		host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 	}
@@ -298,7 +298,7 @@
 		q = &nlm_hosts[i];
 		while ((host = *q) != NULL) {
 			if (host->h_count || host->h_inuse
-			 || host->h_expires >= jiffies) {
+			 || time_before_eq(jiffies, host->h_expires)) {
 				q = &host->h_next;
 				continue;
 			}
diff -u --recursive --new-file v2.1.132/linux/fs/lockd/svc.c linux/fs/lockd/svc.c
--- v2.1.132/linux/fs/lockd/svc.c	Thu Nov 12 16:21:22 1998
+++ linux/fs/lockd/svc.c	Wed Dec 23 09:44:42 1998
@@ -136,7 +136,7 @@
 		 */
 		if (!nlmsvc_grace_period) {
 			timeout = nlmsvc_retry_blocked();
-		} else if (nlmsvc_grace_period < jiffies)
+		} else if (time_after(jiffies, nlmsvc_grace_period))
 			nlmsvc_grace_period = 0;
 
 		/*
diff -u --recursive --new-file v2.1.132/linux/fs/locks.c linux/fs/locks.c
--- v2.1.132/linux/fs/locks.c	Thu Nov 19 09:56:28 1998
+++ linux/fs/locks.c	Wed Dec 23 12:11:45 1998
@@ -154,10 +154,10 @@
 static inline void locks_free_lock(struct file_lock *fl)
 {
 	if (waitqueue_active(&fl->fl_wait))
-		panic("Aarggh: attempting to free lock with active wait queue - shoot Andy");
+		panic("Attempting to free lock with active wait queue");
 
 	if (fl->fl_nextblock != NULL || fl->fl_prevblock != NULL)
-		panic("Aarggh: attempting to free lock with active block list - shoot Andy");
+		panic("Attempting to free lock with active block list");
 		
 	kfree(fl);
 	return;
diff -u --recursive --new-file v2.1.132/linux/fs/namei.c linux/fs/namei.c
--- v2.1.132/linux/fs/namei.c	Tue Dec 22 14:16:57 1998
+++ linux/fs/namei.c	Wed Dec 23 12:52:39 1998
@@ -95,18 +95,6 @@
  * [10-Sep-98 Alan Modra] Another symlink change.
  */
 
-static inline char * get_page(void)
-{
-	char * res;
-	res = (char*)__get_free_page(GFP_KERNEL);
-	return res;
-}
-
-inline void putname(char * name)
-{
-	free_page((unsigned long) name); 
-}
-
 /* In order to reduce some races, while at the same time doing additional
  * checking and hopefully speeding things up, we copy filenames to the
  * kernel data space before using them..
@@ -139,7 +127,7 @@
 	char *tmp, *result;
 
 	result = ERR_PTR(-ENOMEM);
-	tmp = get_page();
+	tmp = __getname();
 	if (tmp)  {
 		int retval = do_getname(filename, tmp);
 
diff -u --recursive --new-file v2.1.132/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.1.132/linux/fs/ncpfs/inode.c	Mon Apr  6 17:41:01 1998
+++ linux/fs/ncpfs/inode.c	Wed Dec 23 11:57:17 1998
@@ -382,7 +382,12 @@
 out_no_server:
 	printk(KERN_ERR "ncp_read_super: could not alloc ncp_server\n");
 out_unlock:
-	put_filp(ncp_filp);
+	/* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>:
+	 * 
+	 * The previously used put_filp(ncp_filp); was bogous, since
+	 * it doesn't proper unlocking.
+	 */
+	fput(ncp_filp);
 	unlock_super(sb);
 	goto out;
 
diff -u --recursive --new-file v2.1.132/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.1.132/linux/fs/nfs/dir.c	Tue Dec 22 14:16:57 1998
+++ linux/fs/nfs/dir.c	Mon Dec 28 13:18:10 1998
@@ -438,6 +438,7 @@
 
 	/* Ok, remeber that we successfully checked it.. */
 	nfs_renew_times(dentry);
+	nfs_refresh_inode(inode, &fattr);
 
 out_valid:
 	return 1;
@@ -571,11 +572,6 @@
 			error = 0;
 		}
 	}
-#ifdef NFS_PARANOIA
-if (error)
-printk("nfs_lookup: %s/%s failed, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, error);
-#endif
 out:
 	return error;
 }
diff -u --recursive --new-file v2.1.132/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.1.132/linux/fs/nfs/inode.c	Tue Dec 22 14:16:57 1998
+++ linux/fs/nfs/inode.c	Mon Dec 28 13:40:23 1998
@@ -701,12 +701,6 @@
 #endif
 		goto out;
 	}
-	if (fattr.mtime.seconds == NFS_OLDMTIME(inode)) {
-		/* Update attrtimeo value */
-		if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode))
-			NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode);
-	}
-	NFS_OLDMTIME(inode) = fattr.mtime.seconds;
 	dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 out:
@@ -791,6 +785,14 @@
 
 	if (invalid)
 		goto out_invalid;
+
+	/* Update attrtimeo value */
+	if (fattr->mtime.seconds == NFS_OLDMTIME(inode)) {
+		if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode))
+			NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode);
+	}
+	NFS_OLDMTIME(inode) = fattr->mtime.seconds;
+
 out:
 	return error;
 
diff -u --recursive --new-file v2.1.132/linux/fs/nfsd/nfsfh.c linux/fs/nfsd/nfsfh.c
--- v2.1.132/linux/fs/nfsd/nfsfh.c	Sun Nov  8 14:03:07 1998
+++ linux/fs/nfsd/nfsfh.c	Wed Dec 23 09:44:42 1998
@@ -1001,7 +1001,7 @@
 	 * Perform any needed housekeeping ...
 	 * N.B. move this into one of the daemons ...
 	 */
-	if (jiffies >= nfsd_next_expire) {
+	if (time_after_eq(jiffies, nfsd_next_expire)) {
 		expire_old(NFSD_FILE_CACHE,  5*HZ);
 		expire_old(NFSD_DIR_CACHE , 60*HZ);
 		nfsd_next_expire = jiffies + 5*HZ;
diff -u --recursive --new-file v2.1.132/linux/fs/open.c linux/fs/open.c
--- v2.1.132/linux/fs/open.c	Wed Dec 16 10:32:56 1998
+++ linux/fs/open.c	Wed Dec 23 13:02:05 1998
@@ -6,14 +6,11 @@
 
 #include <linux/mm.h>
 #include <linux/utime.h>
-#include <linux/fcntl.h>
-#include <linux/stat.h>
 #include <linux/file.h>
 #include <linux/smp_lock.h>
 #include <linux/quotaops.h>
 
 #include <asm/uaccess.h>
-#include <asm/bitops.h>
 
 asmlinkage int sys_statfs(const char * path, struct statfs * buf)
 {
@@ -671,18 +668,6 @@
 	return ERR_PTR(error);
 }
 
-/* should probably go into sys_open() */
-static int do_open(const char * filename, int flags, int mode, int fd)
-{
-	struct file * f;
-
-	f = filp_open(filename, flags, mode);
-	if (IS_ERR(f))
-		return PTR_ERR(f);
-	fd_install(fd, f);
-	return 0;
-}
-
 /*
  * Find an empty file descriptor entry, and mark it busy.
  */
@@ -727,24 +712,25 @@
 	char * tmp;
 	int fd, error;
 
-	lock_kernel();
-	fd = get_unused_fd();
-	if (fd < 0)
-		goto out;
-
 	tmp = getname(filename);
-	error = PTR_ERR(tmp);
-	if (IS_ERR(tmp))
-		goto out_fail;
-	error = do_open(tmp, flags, mode, fd);
-	putname(tmp);
-	if (error)
-		goto out_fail;
+	fd = PTR_ERR(tmp);
+	if (!IS_ERR(tmp)) {
+		lock_kernel();
+		fd = get_unused_fd();
+		if (fd >= 0) {
+			struct file * f = filp_open(tmp, flags, mode);
+			error = PTR_ERR(f);
+			if (IS_ERR(f))
+				goto out_error;
+			fd_install(fd, f);
+		}
 out:
-	unlock_kernel();
+		unlock_kernel();
+		putname(tmp);
+	}
 	return fd;
 
-out_fail:
+out_error:
 	put_unused_fd(fd);
 	fd = error;
 	goto out;
diff -u --recursive --new-file v2.1.132/linux/fs/read_write.c linux/fs/read_write.c
--- v2.1.132/linux/fs/read_write.c	Thu Nov 19 09:56:29 1998
+++ linux/fs/read_write.c	Sun Dec 27 10:52:09 1998
@@ -215,7 +215,8 @@
 		tot_len += iov[i].iov_len;
 
 	inode = file->f_dentry->d_inode;
-	ret = locks_verify_area((type == VERIFY_READ
+	/* VERIFY_WRITE actually means a read, as we write to user space */
+	ret = locks_verify_area((type == VERIFY_WRITE
 				 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
 				inode, file, file->f_pos, tot_len);
 	if (ret) goto out;
diff -u --recursive --new-file v2.1.132/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.1.132/linux/fs/smbfs/inode.c	Mon Apr  6 17:41:01 1998
+++ linux/fs/smbfs/inode.c	Wed Dec 23 09:44:42 1998
@@ -260,7 +260,7 @@
 	/*
 	 * Check whether we've recently refreshed the inode.
 	 */
-	if (jiffies < inode->u.smbfs_i.oldmtime + HZ/10)
+	if (time_before(jiffies, inode->u.smbfs_i.oldmtime + HZ/10))
 	{
 #ifdef SMBFS_DEBUG_VERBOSE
 printk("smb_revalidate_inode: up-to-date, jiffies=%lu, oldtime=%lu\n",
diff -u --recursive --new-file v2.1.132/linux/include/asm-alpha/atomic.h linux/include/asm-alpha/atomic.h
--- v2.1.132/linux/include/asm-alpha/atomic.h	Tue May 13 22:41:15 1997
+++ linux/include/asm-alpha/atomic.h	Sun Dec 27 15:21:50 1998
@@ -15,7 +15,7 @@
 typedef struct { int counter; } atomic_t;
 #endif
 
-#define ATOMIC_INIT(i)	{ (i) }
+#define ATOMIC_INIT(i)	( (atomic_t) { (i) } )
 
 #define atomic_read(v)		((v)->counter)
 #define atomic_set(v,i)		((v)->counter = (i))
diff -u --recursive --new-file v2.1.132/linux/include/asm-alpha/core_apecs.h linux/include/asm-alpha/core_apecs.h
--- v2.1.132/linux/include/asm-alpha/core_apecs.h	Tue Aug 18 22:02:06 1998
+++ linux/include/asm-alpha/core_apecs.h	Sun Dec 27 15:21:50 1998
@@ -458,7 +458,7 @@
 
 __EXTERN_INLINE void apecs_outb(unsigned char b, unsigned long addr)
 {
-	unsigned int w;
+	unsigned long w;
 
 	w = __kernel_insbl(b, addr & 3);
 	*(vuip) ((addr << 5) + APECS_IO + 0x00) = w;
@@ -473,7 +473,7 @@
 
 __EXTERN_INLINE void apecs_outw(unsigned short b, unsigned long addr)
 {
-	unsigned int w;
+	unsigned long w;
 
 	w = __kernel_inswl(b, addr & 3);
 	*(vuip) ((addr << 5) + APECS_IO + 0x08) = w;
diff -u --recursive --new-file v2.1.132/linux/include/asm-alpha/core_cia.h linux/include/asm-alpha/core_cia.h
--- v2.1.132/linux/include/asm-alpha/core_cia.h	Tue Aug 18 22:02:06 1998
+++ linux/include/asm-alpha/core_cia.h	Sun Dec 27 15:21:50 1998
@@ -326,7 +326,7 @@
 
 __EXTERN_INLINE void cia_outb(unsigned char b, unsigned long addr)
 {
-	unsigned int w = __kernel_insbl(b, addr & 3);
+	unsigned long w = __kernel_insbl(b, addr & 3);
 	*(vuip) ((addr << 5) + CIA_IO + 0x00) = w;
 	wmb();
 }
@@ -340,7 +340,7 @@
 
 __EXTERN_INLINE void cia_outw(unsigned short b, unsigned long addr)
 {
-	unsigned int w = __kernel_inswl(b, addr & 3);
+	unsigned long w = __kernel_inswl(b, addr & 3);
 	*(vuip) ((addr << 5) + CIA_IO + 0x08) = w;
 	wmb();
 }
diff -u --recursive --new-file v2.1.132/linux/include/asm-alpha/core_lca.h linux/include/asm-alpha/core_lca.h
--- v2.1.132/linux/include/asm-alpha/core_lca.h	Tue Aug 18 22:02:06 1998
+++ linux/include/asm-alpha/core_lca.h	Sun Dec 27 15:21:50 1998
@@ -262,7 +262,7 @@
 
 __EXTERN_INLINE void lca_outb(unsigned char b, unsigned long addr)
 {
-	unsigned int w;
+	unsigned long w;
 
 	w = __kernel_insbl(b, addr & 3);
 	*(vuip) ((addr << 5) + LCA_IO + 0x00) = w;
@@ -277,7 +277,7 @@
 
 __EXTERN_INLINE void lca_outw(unsigned short b, unsigned long addr)
 {
-	unsigned int w;
+	unsigned long w;
 
 	w = __kernel_inswl(b, addr & 3);
 	*(vuip) ((addr << 5) + LCA_IO + 0x08) = w;
@@ -340,7 +340,7 @@
 __EXTERN_INLINE void lca_writeb(unsigned char b, unsigned long addr)
 {
 	unsigned long msb;
-	unsigned int w;
+	unsigned long w;
 
 	if (addr >= (1UL << 24)) {
 		msb = addr & 0xf8000000;
@@ -354,7 +354,7 @@
 __EXTERN_INLINE void lca_writew(unsigned short b, unsigned long addr)
 {
 	unsigned long msb;
-	unsigned int w;
+	unsigned long w;
 
 	if (addr >= (1UL << 24)) {
 		msb = addr & 0xf8000000;
diff -u --recursive --new-file v2.1.132/linux/include/asm-alpha/core_mcpcia.h linux/include/asm-alpha/core_mcpcia.h
--- v2.1.132/linux/include/asm-alpha/core_mcpcia.h	Wed Sep  9 14:51:09 1998
+++ linux/include/asm-alpha/core_mcpcia.h	Sun Dec 27 15:21:50 1998
@@ -264,7 +264,7 @@
 {
 	unsigned long addr = in_addr & 0xffffffffUL;
 	unsigned long hose = (in_addr >> 32) & 3;
-	unsigned int w;
+	unsigned long w;
 
 	w = __kernel_insbl(b, addr & 3);
 	*(vuip) ((addr << 5) + MCPCIA_IO(hose) + 0x00) = w;
@@ -283,7 +283,7 @@
 {
 	unsigned long addr = in_addr & 0xffffffffUL;
 	unsigned long hose = (in_addr >> 32) & 3;
-	unsigned int w;
+	unsigned long w;
 
 	w = __kernel_inswl(b, addr & 3);
 	*(vuip) ((addr << 5) + MCPCIA_IO(hose) + 0x08) = w;
diff -u --recursive --new-file v2.1.132/linux/include/asm-alpha/core_pyxis.h linux/include/asm-alpha/core_pyxis.h
--- v2.1.132/linux/include/asm-alpha/core_pyxis.h	Wed Sep  9 14:51:09 1998
+++ linux/include/asm-alpha/core_pyxis.h	Sun Dec 27 15:21:50 1998
@@ -326,7 +326,7 @@
 
 __EXTERN_INLINE void pyxis_outb(unsigned char b, unsigned long addr)
 {
-	unsigned int w;
+	unsigned long w;
 
 	w = __kernel_insbl(b, addr & 3);
 	*(vuip) ((addr << 5) + PYXIS_IO + 0x00) = w;
@@ -341,7 +341,7 @@
 
 __EXTERN_INLINE void pyxis_outw(unsigned short b, unsigned long addr)
 {
-	unsigned int w;
+	unsigned long w;
 
 	w = __kernel_inswl(b, addr & 3);
 	*(vuip) ((addr << 5) + PYXIS_IO + 0x08) = w;
diff -u --recursive --new-file v2.1.132/linux/include/asm-alpha/core_t2.h linux/include/asm-alpha/core_t2.h
--- v2.1.132/linux/include/asm-alpha/core_t2.h	Tue Aug 18 22:02:06 1998
+++ linux/include/asm-alpha/core_t2.h	Sun Dec 27 15:21:50 1998
@@ -378,7 +378,7 @@
 
 __EXTERN_INLINE void t2_outw(unsigned short b, unsigned long addr)
 {
-	unsigned int w;
+	unsigned long w;
 
 	w = __kernel_inswl(b, addr & 3);
 	*(vuip) ((addr << 5) + T2_IO + 0x08) = w;
diff -u --recursive --new-file v2.1.132/linux/include/asm-alpha/io.h linux/include/asm-alpha/io.h
--- v2.1.132/linux/include/asm-alpha/io.h	Fri Oct 23 22:01:22 1998
+++ linux/include/asm-alpha/io.h	Sun Dec 27 15:21:50 1998
@@ -3,7 +3,6 @@
 
 #include <linux/config.h>
 #include <asm/system.h>
-#include <asm/machvec.h>
 
 /* We don't use IO slowdowns on the Alpha, but.. */
 #define __SLOW_DOWN_IO	do { } while (0)
@@ -19,6 +18,7 @@
 #endif
 
 #ifdef __KERNEL__
+#include <asm/machvec.h>
 
 /*
  * We try to avoid hae updates (thus the cache), but when we
@@ -78,6 +78,7 @@
  * There are different chipsets to interface the Alpha CPUs to the world.
  */
 
+#ifdef __KERNEL__
 #ifdef CONFIG_ALPHA_GENERIC
 
 /* In a generic kernel, we always go through the machine vector.  */
@@ -147,6 +148,7 @@
 #undef __WANT_IO_DEF
 
 #endif /* GENERIC */
+#endif /* __KERNEL__ */
 
 /*
  * The convention used for inb/outb etc. is that names starting with
@@ -172,6 +174,7 @@
 extern void		_writel(unsigned int b, unsigned long addr);
 extern void		_writeq(unsigned long b, unsigned long addr);
 
+#ifdef __KERNEL__
 /*
  * The platform header files may define some of these macros to use
  * the inlined versions where appropriate.  These macros may also be
@@ -216,6 +219,27 @@
 # define outl_p		outl
 #endif
 
+#else 
+
+/* Userspace declarations.  */
+
+extern unsigned int	inb (unsigned long port);
+extern unsigned int	inw (unsigned long port);
+extern unsigned int	inl (unsigned long port);
+extern void		outb (unsigned char b,unsigned long port);
+extern void		outw (unsigned short w,unsigned long port);
+extern void		outl (unsigned int l,unsigned long port);
+extern unsigned long	readb(unsigned long addr);
+extern unsigned long	readw(unsigned long addr);
+extern unsigned long	readl(unsigned long addr);
+extern void		writeb(unsigned char b, unsigned long addr);
+extern void		writew(unsigned short b, unsigned long addr);
+extern void		writel(unsigned int b, unsigned long addr);
+
+#endif /* __KERNEL__ */
+
+#ifdef __KERNEL__
+
 /*
  * The "address" in IO memory space is not clearly either an integer or a
  * pointer. We will accept both, thus the casts.
@@ -256,8 +280,6 @@
 #ifndef writeq
 # define writeq(v,a)	_writeq((v),(unsigned long)(a))
 #endif
-
-#ifdef __KERNEL__
 
 /*
  * String version of IO memory access ops:
diff -u --recursive --new-file v2.1.132/linux/include/asm-alpha/machvec.h linux/include/asm-alpha/machvec.h
--- v2.1.132/linux/include/asm-alpha/machvec.h	Fri Oct 23 22:01:22 1998
+++ linux/include/asm-alpha/machvec.h	Sun Dec 27 10:52:10 1998
@@ -4,6 +4,12 @@
 #include <linux/config.h>
 #include <linux/types.h>
 
+/*
+ *	This file gets pulled in by asm/io.h from user space. We don't
+ *	want most of this escaping.
+ */
+ 
+#ifdef __KERNEL__
 
 /* The following structure vectors all of the I/O and IRQ manipulation
    from the generic kernel to the hardware specific backend.  */
@@ -122,4 +128,5 @@
 #endif
 #endif /* GENERIC */
 
+#endif
 #endif /* __ALPHA_MACHVEC_H */
diff -u --recursive --new-file v2.1.132/linux/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- v2.1.132/linux/include/asm-alpha/pgtable.h	Wed Sep  9 14:51:10 1998
+++ linux/include/asm-alpha/pgtable.h	Sun Dec 27 10:52:10 1998
@@ -14,6 +14,7 @@
 #include <asm/processor.h>	/* For TASK_SIZE */
 #include <asm/mmu_context.h>
 #include <asm/machvec.h>
+#include <asm/spinlock.h>	/* For the task lock */
 
 
 /* Caches aren't brain-dead on the Alpha. */
diff -u --recursive --new-file v2.1.132/linux/include/asm-alpha/softirq.h linux/include/asm-alpha/softirq.h
--- v2.1.132/linux/include/asm-alpha/softirq.h	Wed Sep  9 14:51:10 1998
+++ linux/include/asm-alpha/softirq.h	Sun Dec 27 15:20:32 1998
@@ -27,7 +27,7 @@
 extern inline void init_bh(int nr, void (*routine)(void))
 {
 	bh_base[nr] = routine;
-	bh_mask_count[nr] = 0;
+	atomic_set(&bh_mask_count[nr], 0);
 	bh_mask |= 1 << nr;
 }
 
@@ -116,12 +116,13 @@
 extern inline void disable_bh(int nr)
 {
 	bh_mask &= ~(1 << nr);
-	bh_mask_count[nr]++;
+	atomic_inc(&bh_mask_count[nr]);
+	synchronize_bh();
 }
 
 extern inline void enable_bh(int nr)
 {
-	if (!--bh_mask_count[nr])
+	if (atomic_dec_and_test(&bh_mask_count[nr]))
 		bh_mask |= 1 << nr;
 }
 
diff -u --recursive --new-file v2.1.132/linux/include/asm-alpha/spinlock.h linux/include/asm-alpha/spinlock.h
--- v2.1.132/linux/include/asm-alpha/spinlock.h	Thu Nov 12 16:21:24 1998
+++ linux/include/asm-alpha/spinlock.h	Sun Dec 27 10:52:10 1998
@@ -88,12 +88,12 @@
 } spinlock_t;
 
 #if DEBUG_SPINLOCK
-#define SPIN_LOCK_UNLOCKED {0, 1, 0, 0, 0, 0}
+#define SPIN_LOCK_UNLOCKED (spinlock_t) {0, 1, 0, 0, 0, 0}
 #define spin_lock_init(x)						\
 	((x)->lock = 0, (x)->target_ipl = 0, (x)->debug_state = 1,	\
 	 (x)->previous = 0, (x)->task = 0)
 #else
-#define SPIN_LOCK_UNLOCKED	{ 0 }
+#define SPIN_LOCK_UNLOCKED	(spinlock_t) { 0 }
 #define spin_lock_init(x)	((x)->lock = 0)
 #endif
 
@@ -163,7 +163,7 @@
 
 typedef struct { volatile int write_lock:1, read_counter:31; } rwlock_t;
 
-#define RW_LOCK_UNLOCKED { 0, 0 }
+#define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
 
 #if DEBUG_RWLOCK
 extern void write_lock(rwlock_t * lock);
diff -u --recursive --new-file v2.1.132/linux/include/asm-i386/bitops.h linux/include/asm-i386/bitops.h
--- v2.1.132/linux/include/asm-i386/bitops.h	Tue Jul 21 00:15:32 1998
+++ linux/include/asm-i386/bitops.h	Mon Dec 28 14:09:28 1998
@@ -127,6 +127,7 @@
  */
 extern __inline__ int find_first_zero_bit(void * addr, unsigned size)
 {
+	int d0, d1, d2;
 	int res;
 
 	if (!size)
@@ -142,9 +143,8 @@
 		"1:\tsubl %%ebx,%%edi\n\t"
 		"shll $3,%%edi\n\t"
 		"addl %%edi,%%edx"
-		:"=d" (res)
-		:"c" ((size + 31) >> 5), "D" (addr), "b" (addr)
-		:"ax", "cx", "di");
+		:"=d" (res), "=&c" (d0), "=&D" (d1), "=&a" (d2)
+		:"1" ((size + 31) >> 5), "2" (addr), "b" (addr));
 	return res;
 }
 
diff -u --recursive --new-file v2.1.132/linux/include/asm-i386/checksum.h linux/include/asm-i386/checksum.h
--- v2.1.132/linux/include/asm-i386/checksum.h	Thu Sep 17 17:53:38 1998
+++ linux/include/asm-i386/checksum.h	Sun Dec 27 10:39:50 1998
@@ -14,7 +14,7 @@
  *
  * it's best to have buff aligned on a 32-bit boundary
  */
-unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+asmlinkage unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
 
 /*
  * the same as csum_partial, but copies from src while it
@@ -24,8 +24,8 @@
  * better 64-bit) boundary
  */
 
-unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
-					int *src_err_ptr, int *dst_err_ptr);
+asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
+						   int *src_err_ptr, int *dst_err_ptr);
 
 /*
  *	Note: when you get a NULL pointer exception here this means someone
diff -u --recursive --new-file v2.1.132/linux/include/asm-i386/init.h linux/include/asm-i386/init.h
--- v2.1.132/linux/include/asm-i386/init.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-i386/init.h	Sun Dec 27 22:45:13 1998
@@ -11,4 +11,7 @@
 #define __FINIT	.previous
 #define __INITDATA	.section	".data.init",#alloc,#write
 
+#define __cacheline_aligned __attribute__ \
+			 ((__section__ (".data.cacheline_aligned")))
+
 #endif
diff -u --recursive --new-file v2.1.132/linux/include/asm-i386/posix_types.h linux/include/asm-i386/posix_types.h
--- v2.1.132/linux/include/asm-i386/posix_types.h	Sun Jun  7 11:16:36 1998
+++ linux/include/asm-i386/posix_types.h	Sun Dec 27 10:39:50 1998
@@ -59,10 +59,14 @@
 
 #undef	__FD_ZERO
 #define __FD_ZERO(fdsetp) \
-		__asm__ __volatile__("cld ; rep ; stosl" \
-			:"=m" (*(__kernel_fd_set *) (fdsetp)) \
-			:"a" (0), "c" (__FDSET_LONGS), \
-			"D" ((__kernel_fd_set *) (fdsetp)) :"cx","di")
+do { \
+	int __d0, __d1; \
+	__asm__ __volatile__("cld ; rep ; stosl" \
+			:"=m" (*(__kernel_fd_set *) (fdsetp)), \
+			  "=&c" (__d0), "=&D" (__d1) \
+			:"a" (0), "1" (__FDSET_LONGS), \
+			"2" ((__kernel_fd_set *) (fdsetp)) : "memory"); \
+} while (0)
 
 #endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
 
diff -u --recursive --new-file v2.1.132/linux/include/asm-i386/smp.h linux/include/asm-i386/smp.h
--- v2.1.132/linux/include/asm-i386/smp.h	Tue Dec 22 14:16:58 1998
+++ linux/include/asm-i386/smp.h	Mon Dec 28 14:11:18 1998
@@ -185,10 +185,6 @@
 extern void smp_callin(void);
 extern void smp_boot_cpus(void);
 extern void smp_store_cpu_info(int id);		/* Store per CPU info (like the initial udelay numbers */
-extern void smp_message_pass(int target, int msg, unsigned long data, int wait);
-
-extern volatile unsigned long smp_proc_in_lock[NR_CPUS]; /* for computing process time */
-extern volatile int smp_process_available;
 
 /*
  *	APIC handlers: Note according to the Intel specification update
@@ -237,9 +233,7 @@
  *	processes are run.
  */
  
-#define PROC_CHANGE_PENALTY	10		/* Schedule penalty */
+#define PROC_CHANGE_PENALTY	15		/* Schedule penalty */
 
-#define SMP_FROM_INT		1
-#define SMP_FROM_SYSCALL	2
 #endif
 #endif
diff -u --recursive --new-file v2.1.132/linux/include/asm-i386/smplock.h linux/include/asm-i386/smplock.h
--- v2.1.132/linux/include/asm-i386/smplock.h	Mon Aug  3 17:48:28 1998
+++ linux/include/asm-i386/smplock.h	Mon Dec 28 14:11:20 1998
@@ -51,7 +51,7 @@
 {
 	__asm__ __volatile__(
 		"decl %1\n\t"
-		"jns 9f\n"
+		"jns 9f\n\t"
 		spin_unlock_string
 		"\n9:"
 		:"=m" (__dummy_lock(&kernel_flag)),
diff -u --recursive --new-file v2.1.132/linux/include/asm-i386/system.h linux/include/asm-i386/system.h
--- v2.1.132/linux/include/asm-i386/system.h	Sun Nov  8 14:03:08 1998
+++ linux/include/asm-i386/system.h	Mon Dec 28 14:09:28 1998
@@ -35,30 +35,30 @@
 		      "a" (prev), "d" (next)); 				\
 } while (0)
 
-#define _set_base(addr,base) \
-__asm__("movw %%dx,%0\n\t" \
+#define _set_base(addr,base) do { unsigned long __pr; \
+__asm__ __volatile__ ("movw %%dx,%1\n\t" \
 	"rorl $16,%%edx\n\t" \
-	"movb %%dl,%1\n\t" \
-	"movb %%dh,%2" \
-	: /* no output */ \
+	"movb %%dl,%2\n\t" \
+	"movb %%dh,%3" \
+	:"=&d" (__pr) \
 	:"m" (*((addr)+2)), \
 	 "m" (*((addr)+4)), \
 	 "m" (*((addr)+7)), \
-	 "d" (base) \
-	:"dx")
+         "0" (base) \
+        ); } while(0)
 
-#define _set_limit(addr,limit) \
-__asm__("movw %%dx,%0\n\t" \
+#define _set_limit(addr,limit) do { unsigned long __lr; \
+__asm__ __volatile__ ("movw %%dx,%1\n\t" \
 	"rorl $16,%%edx\n\t" \
-	"movb %1,%%dh\n\t" \
+	"movb %2,%%dh\n\t" \
 	"andb $0xf0,%%dh\n\t" \
 	"orb %%dh,%%dl\n\t" \
-	"movb %%dl,%1" \
-	: /* no output */ \
+	"movb %%dl,%2" \
+	:"=&d" (__lr) \
 	:"m" (*(addr)), \
 	 "m" (*((addr)+6)), \
-	 "d" (limit) \
-	:"dx")
+	 "0" (limit) \
+        ); } while(0)
 
 #define set_base(ldt,base) _set_base( ((char *)&(ldt)) , (base) )
 #define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , ((limit)-1)>>12 )
@@ -165,8 +165,19 @@
  * Force strict CPU ordering.
  * And yes, this is required on UP too when we're talking
  * to devices.
+ *
+ * For now, "wmb()" doesn't actually do anything, as all
+ * Intel CPU's follow what Intel calls a *Processor Order*,
+ * in which all writes are seen in the program order even
+ * outside the CPU.
+ *
+ * I expect future Intel CPU's to have a weaker ordering,
+ * but I'd also expect them to finally get their act together
+ * and add some real memory barriers if so.
  */
 #define mb() 	__asm__ __volatile__ ("lock; addl $0,0(%%esp)": : :"memory")
+#define rmb()	mb()
+#define wmb()	__asm__ __volatile__ ("": : :"memory")
 
 /* interrupt control.. */
 #define __sti() __asm__ __volatile__ ("sti": : :"memory")
diff -u --recursive --new-file v2.1.132/linux/include/asm-i386/timex.h linux/include/asm-i386/timex.h
--- v2.1.132/linux/include/asm-i386/timex.h	Fri May  8 23:14:54 1998
+++ linux/include/asm-i386/timex.h	Mon Dec 28 11:41:06 1998
@@ -12,4 +12,34 @@
 	(1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
 		<< (SHIFT_SCALE-SHIFT_HZ)) / HZ)
 
+/*
+ * Standard way to access the cycle counter on i586+ CPUs.
+ * Currently only used on SMP.
+ *
+ * If you really have a SMP machine with i486 chips or older,
+ * compile for that, and this will just always return zero.
+ * That's ok, it just means that the nicer scheduling heuristics
+ * won't work for you.
+ *
+ * We only use the low 32 bits, and we'd simply better make sure
+ * that we reschedule before that wraps. Scheduling at least every
+ * four billion cycles just basically sounds like a good idea,
+ * regardless of how fast the machine is. 
+ */
+typedef unsigned long cycles_t;
+
+extern cycles_t cacheflush_time;
+
+static inline cycles_t get_cycles (void)
+{
+#if CPU < 586
+	return 0;
+#else
+	unsigned long eax, edx;
+
+	__asm__("rdtsc":"=a" (eax), "=d" (edx));
+	return eax;
+#endif
+}
+
 #endif
diff -u --recursive --new-file v2.1.132/linux/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h
--- v2.1.132/linux/include/asm-i386/uaccess.h	Wed Aug 26 11:37:44 1998
+++ linux/include/asm-i386/uaccess.h	Mon Dec 28 14:11:22 1998
@@ -250,13 +250,15 @@
 
 /* Generic arbitrary sized copy.  */
 #define __copy_user(to,from,size)					\
+do {									\
+	int __d0, __d1;							\
 	__asm__ __volatile__(						\
 		"0:	rep; movsl\n"					\
-		"	movl %1,%0\n"					\
+		"	movl %3,%0\n"					\
 		"1:	rep; movsb\n"					\
 		"2:\n"							\
 		".section .fixup,\"ax\"\n"				\
-		"3:	lea 0(%1,%0,4),%0\n"				\
+		"3:	lea 0(%3,%0,4),%0\n"				\
 		"	jmp 2b\n"					\
 		".previous\n"						\
 		".section __ex_table,\"a\"\n"				\
@@ -264,18 +266,21 @@
 		"	.long 0b,3b\n"					\
 		"	.long 1b,2b\n"					\
 		".previous"						\
-		: "=&c"(size)						\
-		: "r"(size & 3), "0"(size / 4), "D"(to), "S"(from)	\
-		: "di", "si", "memory")
+		: "=&c"(size), "=&D" (__d0), "=&S" (__d1)		\
+		: "r"(size & 3), "0"(size / 4), "1"(to), "2"(from)	\
+		: "memory");						\
+} while (0)
 
 #define __copy_user_zeroing(to,from,size)				\
+do {									\
+	int __d0, __d1;							\
 	__asm__ __volatile__(						\
 		"0:	rep; movsl\n"					\
-		"	movl %1,%0\n"					\
+		"	movl %3,%0\n"					\
 		"1:	rep; movsb\n"					\
 		"2:\n"							\
 		".section .fixup,\"ax\"\n"				\
-		"3:	lea 0(%1,%0,4),%0\n"				\
+		"3:	lea 0(%3,%0,4),%0\n"				\
 		"4:	pushl %0\n"					\
 		"	pushl %%eax\n"					\
 		"	xorl %%eax,%%eax\n"				\
@@ -289,9 +294,10 @@
 		"	.long 0b,3b\n"					\
 		"	.long 1b,4b\n"					\
 		".previous"						\
-		: "=&c"(size)						\
-		: "r"(size & 3), "0"(size / 4), "D"(to), "S"(from)	\
-		: "di", "si", "memory");
+		: "=&c"(size), "=&D" (__d0), "=&S" (__d1)		\
+		: "r"(size & 3), "0"(size / 4), "1"(to), "2"(from)	\
+		: "memory");						\
+} while (0)
 
 /* We let the __ versions of copy_from/to_user inline, because they're often
  * used in fast paths and have only a small space overhead.
@@ -314,6 +320,7 @@
 /* Optimize just a little bit when we know the size of the move. */
 #define __constant_copy_user(to, from, size)			\
 do {								\
+	int __d0, __d1;						\
 	switch (size & 3) {					\
 	default:						\
 		__asm__ __volatile__(				\
@@ -327,9 +334,9 @@
 			"	.align 4\n"			\
 			"	.long 0b,2b\n"			\
 			".previous"				\
-			: "=c"(size)				\
-			: "S"(from), "D"(to), "0"(size/4)	\
-			: "di", "si", "memory");		\
+			: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
+			: "1"(from), "2"(to), "0"(size/4)	\
+			: "memory");				\
 		break;						\
 	case 1:							\
 		__asm__ __volatile__(				\
@@ -346,9 +353,9 @@
 			"	.long 0b,3b\n"			\
 			"	.long 1b,4b\n"			\
 			".previous"				\
-			: "=c"(size)				\
-			: "S"(from), "D"(to), "0"(size/4)	\
-			: "di", "si", "memory");		\
+			: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
+			: "1"(from), "2"(to), "0"(size/4)	\
+			: "memory");				\
 		break;						\
 	case 2:							\
 		__asm__ __volatile__(				\
@@ -365,9 +372,9 @@
 			"	.long 0b,3b\n"			\
 			"	.long 1b,4b\n"			\
 			".previous"				\
-			: "=c"(size)				\
-			: "S"(from), "D"(to), "0"(size/4)	\
-			: "di", "si", "memory");		\
+			: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
+			: "1"(from), "2"(to), "0"(size/4)	\
+			: "memory");				\
 		break;						\
 	case 3:							\
 		__asm__ __volatile__(				\
@@ -387,9 +394,9 @@
 			"	.long 1b,5b\n"			\
 			"	.long 2b,6b\n"			\
 			".previous"				\
-			: "=c"(size)				\
-			: "S"(from), "D"(to), "0"(size/4)	\
-			: "di", "si", "memory");		\
+			: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
+			: "1"(from), "2"(to), "0"(size/4)	\
+			: "memory");				\
 		break;						\
 	}							\
 } while (0)
@@ -397,6 +404,7 @@
 /* Optimize just a little bit when we know the size of the move. */
 #define __constant_copy_user_zeroing(to, from, size)		\
 do {								\
+	int __d0, __d1;						\
 	switch (size & 3) {					\
 	default:						\
 		__asm__ __volatile__(				\
@@ -416,9 +424,9 @@
 			"	.align 4\n"			\
 			"	.long 0b,2b\n"			\
 			".previous"				\
-			: "=c"(size)				\
-			: "S"(from), "D"(to), "0"(size/4)	\
-			: "di", "si", "memory");		\
+			: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
+			: "1"(from), "2"(to), "0"(size/4)	\
+			: "memory");				\
 		break;						\
 	case 1:							\
 		__asm__ __volatile__(				\
@@ -448,9 +456,9 @@
 			"	.long 0b,3b\n"			\
 			"	.long 1b,4b\n"			\
 			".previous"				\
-			: "=c"(size)				\
-			: "S"(from), "D"(to), "0"(size/4)	\
-			: "di", "si", "memory");		\
+			: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
+			: "1"(from), "2"(to), "0"(size/4)	\
+			: "memory");				\
 		break;						\
 	case 2:							\
 		__asm__ __volatile__(				\
@@ -480,9 +488,9 @@
 			"	.long 0b,3b\n"			\
 			"	.long 1b,4b\n"			\
 			".previous"				\
-			: "=c"(size)				\
-			: "S"(from), "D"(to), "0"(size/4)	\
-			: "di", "si", "memory");		\
+			: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
+			: "1"(from), "2"(to), "0"(size/4)	\
+			: "memory");				\
 		break;						\
 	case 3:							\
 		__asm__ __volatile__(				\
@@ -522,9 +530,9 @@
 			"	.long 1b,5b\n"			\
 			"	.long 2b,6b\n"			\
 			".previous"				\
-			: "=c"(size)				\
-			: "S"(from), "D"(to), "0"(size/4)	\
-			: "di", "si", "memory");		\
+			: "=c"(size), "=&S" (__d0), "=&D" (__d1)\
+			: "1"(from), "2"(to), "0"(size/4)	\
+			: "memory");				\
 		break;						\
 	}							\
 } while (0)
diff -u --recursive --new-file v2.1.132/linux/include/asm-ppc/softirq.h linux/include/asm-ppc/softirq.h
--- v2.1.132/linux/include/asm-ppc/softirq.h	Mon Oct  5 13:13:43 1998
+++ linux/include/asm-ppc/softirq.h	Wed Dec 23 07:20:09 1998
@@ -12,7 +12,7 @@
 extern inline void init_bh(int nr, void (*routine)(void))
 {
 	bh_base[nr] = routine;
-	bh_mask_count[nr] = 0;
+	atomic_set(&bh_mask_count[nr], 0);
 	bh_mask |= 1 << nr;
 }
 
@@ -96,13 +96,13 @@
 extern inline void disable_bh(int nr)
 {
 	bh_mask &= ~(1 << nr);
-	bh_mask_count[nr]++;
+	atomic_inc(&bh_mask_count[nr]);
 	synchronize_bh();
 }
 
 extern inline void enable_bh(int nr)
 {
-	if (!--bh_mask_count[nr])
+	if (atomic_dec_and_test(&bh_mask_count[nr]))
 		bh_mask |= 1 << nr;
 }
 
diff -u --recursive --new-file v2.1.132/linux/include/linux/atalk.h linux/include/linux/atalk.h
--- v2.1.132/linux/include/linux/atalk.h	Fri Jul 31 17:07:27 1998
+++ linux/include/linux/atalk.h	Mon Dec 28 14:09:31 1998
@@ -10,7 +10,7 @@
 
 #define ATPORT_FIRST	1
 #define ATPORT_RESERVED	128
-#define ATPORT_LAST	255
+#define ATPORT_LAST	254 /* 254 is only legal on localtalk */ 
 #define ATADDR_ANYNET	(__u16)0
 #define ATADDR_ANYNODE	(__u8)0
 #define ATADDR_ANYPORT  (__u8)0
diff -u --recursive --new-file v2.1.132/linux/include/linux/file.h linux/include/linux/file.h
--- v2.1.132/linux/include/linux/file.h	Wed Aug 26 11:37:44 1998
+++ linux/include/linux/file.h	Wed Dec 23 11:57:17 1998
@@ -6,7 +6,6 @@
 #define __LINUX_FILE_H
 
 extern void __fput(struct file *);
-extern void insert_file_free(struct file *file);
 
 /*
  * Check whether the specified task has the fd open. Since the task
@@ -50,34 +49,23 @@
 	current->files->fd[fd] = file;
 }
 
-/* It does not matter which list it is on. */
-extern inline void remove_filp(struct file *file)
-{
-	if(file->f_next)
-		file->f_next->f_pprev = file->f_pprev;
-	*file->f_pprev = file->f_next;
-}
-
-extern inline void fput(struct file *file)
-{
-	int count = file->f_count-1;
-
-	if (!count) {
-		locks_remove_flock(file);
-		__fput(file);
-		file->f_count = 0;
-		remove_filp(file);
-		insert_file_free(file);
-	} else
-		file->f_count = count;
-}
-
-extern inline void put_filp(struct file *file)
-{
-	if(--file->f_count == 0) {
-		remove_filp(file);
-		insert_file_free(file);
-	}
-}
+/*
+ * 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>: 
+ * 
+ * Since those functions where calling other functions, it was compleatly 
+ * bogous to make them all "extern inline".
+ *
+ * The removal of this pseudo optimization saved me scandaleous:
+ *
+ * 		3756 (i386 arch) 
+ *
+ * precious bytes from my kernel, even without counting all the code compiled
+ * as module!
+ *
+ * I suspect there are many other similiar "optimizations" across the
+ * kernel...
+ */
+extern void fput(struct file *file); 
+extern void put_filp(struct file *file);
 
 #endif
diff -u --recursive --new-file v2.1.132/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.132/linux/include/linux/fs.h	Tue Dec 22 14:16:58 1998
+++ linux/include/linux/fs.h	Mon Dec 28 14:11:18 1998
@@ -466,7 +466,7 @@
 	} fl_u;
 };
 
-extern struct file_lock		*file_lock_table;
+extern struct file_lock			*file_lock_table;
 
 #include <linux/fcntl.h>
 
@@ -692,7 +692,8 @@
 extern struct file *filp_open(const char *, int, int);
 
 extern char * getname(const char * filename);
-extern void putname(char * name);
+#define __getname()	((char *) __get_free_page(GFP_KERNEL))
+#define putname(name)	free_page((unsigned long)(name))
 
 extern void kill_fasync(struct fasync_struct *fa, int sig);
 extern int register_blkdev(unsigned int, const char *, struct file_operations *);
@@ -702,11 +703,16 @@
 extern struct file_operations def_blk_fops;
 extern struct inode_operations blkdev_inode_operations;
 
+/* fs/devices.c */
 extern int register_chrdev(unsigned int, const char *, struct file_operations *);
 extern int unregister_chrdev(unsigned int major, const char * name);
 extern int chrdev_open(struct inode * inode, struct file * filp);
 extern struct file_operations def_chr_fops;
 extern struct inode_operations chrdev_inode_operations;
+extern char * bdevname(kdev_t dev);
+extern char * cdevname(kdev_t dev);
+extern char * kdevname(kdev_t dev);
+
 
 extern void init_fifo(struct inode * inode);
 extern struct inode_operations fifo_inode_operations;
@@ -815,8 +821,6 @@
 extern struct buffer_head * getblk(kdev_t, int, int);
 extern struct buffer_head * find_buffer(kdev_t dev, int block, int size);
 extern void ll_rw_block(int, int, struct buffer_head * bh[]);
-extern void ll_rw_page(int, kdev_t, unsigned long, char *);
-extern void ll_rw_swap_file(int, kdev_t, unsigned int *, int, char *);
 extern int is_read_only(kdev_t);
 extern void __brelse(struct buffer_head *);
 extern inline void brelse(struct buffer_head *buf)
diff -u --recursive --new-file v2.1.132/linux/include/linux/genhd.h linux/include/linux/genhd.h
--- v2.1.132/linux/include/linux/genhd.h	Fri Oct 23 22:01:26 1998
+++ linux/include/linux/genhd.h	Mon Dec 28 14:09:28 1998
@@ -108,12 +108,21 @@
 #ifdef CONFIG_BSD_DISKLABEL
 /*
  * BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il>
+ * updated by Marc Espie <Marc.Espie@openbsd.org>
  */
+#define FREEBSD_PARTITION	0xa5    /* FreeBSD Partition ID */
+#define OPENBSD_PARTITION	0xa6    /* OpenBSD Partition ID */
+#define NETBSD_PARTITION	0xa9    /* NetBSD Partition ID */
+#define BSDI_PARTITION		0xb7    /* BSDI Partition ID */
 
-#define BSD_PARTITION		0xa5	/* Partition ID */
+/* Ours is not to wonder why.. */
+#define BSD_PARTITION		FREEBSD_PARTITION
+
+/* check against BSD src/sys/sys/disklabel.h for consistency */
 
 #define BSD_DISKMAGIC	(0x82564557UL)	/* The disk magic number */
 #define BSD_MAXPARTITIONS	8
+#define OPENBSD_MAXPARTITIONS	16
 #define BSD_FS_UNUSED		0	/* disklabel unused partition entry ID */
 struct bsd_disklabel {
 	__u32	d_magic;		/* the magic number */
@@ -159,6 +168,62 @@
 };
 
 #endif	/* CONFIG_BSD_DISKLABEL */
+
+#ifdef CONFIG_UNIXWARE_DISKLABEL
+/*
+ * Unixware slices support by Andrzej Krzysztofowicz <ankry@mif.pg.gda.pl>
+ * and Krzysztof G. Baranowski <kgb@knm.org.pl>
+ */
+
+#define UNIXWARE_PARTITION     0x63		/* Partition ID, same as */
+						/* GNU_HURD and SCO Unix */
+#define UNIXWARE_DISKMAGIC     (0xCA5E600DUL)	/* The disk magic number */
+#define UNIXWARE_DISKMAGIC2    (0x600DDEEEUL)	/* The slice table magic nr */
+#define UNIXWARE_NUMSLICE      16
+#define UNIXWARE_FS_UNUSED     0		/* Unused slice entry ID */
+
+struct unixware_slice {
+	__u16   s_label;	/* label */
+	__u16   s_flags;	/* permission flags */
+	__u32   start_sect;	/* starting sector */
+	__u32   nr_sects;	/* number of sectors in slice */
+};
+
+struct unixware_disklabel {
+	__u32   d_type;               	/* drive type */
+	__u32   d_magic;                /* the magic number */
+	__u32   d_version;              /* version number */
+	char    d_serial[12];           /* serial number of the device */
+	__u32   d_ncylinders;           /* # of data cylinders per device */
+	__u32   d_ntracks;              /* # of tracks per cylinder */
+	__u32   d_nsectors;             /* # of data sectors per track */
+	__u32   d_secsize;              /* # of bytes per sector */
+	__u32   d_part_start;           /* # of first sector of this partition */
+	__u32   d_unknown1[12];         /* ? */
+ 	__u32	d_alt_tbl;              /* byte offset of alternate table */
+ 	__u32	d_alt_len;              /* byte length of alternate table */
+ 	__u32	d_phys_cyl;             /* # of physical cylinders per device */
+ 	__u32	d_phys_trk;             /* # of physical tracks per cylinder */
+ 	__u32	d_phys_sec;             /* # of physical sectors per track */
+ 	__u32	d_phys_bytes;           /* # of physical bytes per sector */
+ 	__u32	d_unknown2;             /* ? */
+	__u32   d_unknown3;             /* ? */
+	__u32	d_pad[8];               /* pad */
+
+	struct unixware_vtoc {
+		__u32	v_magic;		/* the magic number */
+		__u32	v_version;		/* version number */
+		char	v_name[8];		/* volume name */
+		__u16	v_nslices;		/* # of slices */
+		__u16	v_unknown1;		/* ? */
+		__u32	v_reserved[10];		/* reserved */
+		struct unixware_slice
+			v_slice[UNIXWARE_NUMSLICE];	/* slice headers */
+	} vtoc;
+
+};  /* 408 */
+
+#endif /* CONFIG_UNIXWARE_DISKLABEL */
 
 extern struct gendisk *gendisk_head;	/* linked list of disks */
 
diff -u --recursive --new-file v2.1.132/linux/include/linux/hfs_fs_i.h linux/include/linux/hfs_fs_i.h
--- v2.1.132/linux/include/linux/hfs_fs_i.h	Tue Mar 17 22:18:15 1998
+++ linux/include/linux/hfs_fs_i.h	Wed Dec 23 14:10:36 1998
@@ -33,6 +33,9 @@
 	const struct hfs_hdr_layout	*default_layout;
 	struct hfs_hdr_layout		*layout;
 
+	/* to deal with localtime ugliness */
+	int                             tz_secondswest;
+
         /* for dentry cleanup */
         void (*d_drop_op)(struct dentry *, const ino_t);
 };
diff -u --recursive --new-file v2.1.132/linux/include/linux/ipc.h linux/include/linux/ipc.h
--- v2.1.132/linux/include/linux/ipc.h	Fri Jul 31 17:05:52 1998
+++ linux/include/linux/ipc.h	Sun Dec 27 22:18:28 1998
@@ -21,6 +21,11 @@
 #define IPC_EXCL   00002000   /* fail if key exists */
 #define IPC_NOWAIT 00004000   /* return error on wait */
 
+/* these fields are used by the DIPC package so the kernel as standard
+   should avoid using them if possible */
+   
+#define IPC_DIPC 00010000  /* make it distributed */
+#define IPC_OWN  00020000  /* this machine is the DIPC owner */
 
 /* 
  * Control commands used with semctl, msgctl and shmctl 
diff -u --recursive --new-file v2.1.132/linux/include/linux/ipx.h linux/include/linux/ipx.h
--- v2.1.132/linux/include/linux/ipx.h	Fri Jul 31 17:07:27 1998
+++ linux/include/linux/ipx.h	Mon Dec 28 14:11:23 1998
@@ -76,6 +76,7 @@
 #define SIOCAIPXITFCRT		(SIOCPROTOPRIVATE)
 #define SIOCAIPXPRISLT		(SIOCPROTOPRIVATE+1)
 #define SIOCIPXCFGDATA		(SIOCPROTOPRIVATE+2)
+#define SIOCIPXNCPCONN		(SIOCPROTOPRIVATE+3)
 
 #ifdef __KERNEL__
 #include <linux/skbuff.h>
diff -u --recursive --new-file v2.1.132/linux/include/linux/module.h linux/include/linux/module.h
--- v2.1.132/linux/include/linux/module.h	Fri Jul 31 17:05:53 1998
+++ linux/include/linux/module.h	Mon Dec 28 14:09:29 1998
@@ -20,6 +20,7 @@
 # endif
 #endif /* __GENKSYMS__ */
 
+#include <asm/atomic.h>
 
 /* Don't need to bring in all of uaccess.h just for this decl.  */
 struct exception_table_entry;
@@ -54,7 +55,12 @@
 	const char *name;
 	unsigned long size;
 
-	long usecount;
+	union
+	{
+		atomic_t usecount;
+		long pad;
+	} uc;				/* Needs to keep its size - so says rth */
+
 	unsigned long flags;		/* AUTOCLEAN et al */
 
 	unsigned nsyms;
@@ -80,10 +86,10 @@
 
 struct module_info
 {
-  unsigned long addr;
-  unsigned long size;
-  unsigned long flags;
-	   long usecount;
+	unsigned long addr;
+	unsigned long size;
+	unsigned long flags;
+	long usecount;
 };
 
 /* Bits of module.flags.  */
@@ -114,17 +120,17 @@
 
 /* Backwards compatibility definition.  */
 
-#define GET_USE_COUNT(module)	((module)->usecount)
+#define GET_USE_COUNT(module)	(atomic_read(&(module)->uc.usecount))
 
 /* Poke the use count of a module.  */
 
 #define __MOD_INC_USE_COUNT(mod)					\
-	((mod)->usecount++, (mod)->flags |= MOD_VISITED|MOD_USED_ONCE)
+	(atomic_inc(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED|MOD_USED_ONCE)
 #define __MOD_DEC_USE_COUNT(mod)					\
-	((mod)->usecount--, (mod)->flags |= MOD_VISITED)
+	(atomic_dec(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED)
 #define __MOD_IN_USE(mod)						\
 	(mod_member_present((mod), can_unload) && (mod)->can_unload	\
-	 ? (mod)->can_unload() : (mod)->usecount)
+	 ? (mod)->can_unload() : atomic_read(&(mod)->uc.usecount))
 
 /* Indirect stringification.  */
 
diff -u --recursive --new-file v2.1.132/linux/include/linux/msdos_fs_sb.h linux/include/linux/msdos_fs_sb.h
--- v2.1.132/linux/include/linux/msdos_fs_sb.h	Thu Jan  8 14:02:41 1998
+++ linux/include/linux/msdos_fs_sb.h	Sun Dec 27 10:47:18 1998
@@ -35,9 +35,11 @@
 struct msdos_sb_info {
 	unsigned short cluster_size; /* sectors/cluster */
 	unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */
-	unsigned short fat_start,fat_length; /* FAT start & length (sec.) */
-	unsigned short dir_start,dir_entries; /* root dir start & entries */
-	unsigned short data_start;   /* first data sector */
+	unsigned short fat_start;
+	unsigned long fat_length;    /* FAT start & length (sec.) */
+	unsigned long dir_start;
+	unsigned short dir_entries;  /* root dir start & entries */
+	unsigned long data_start;    /* first data sector */
 	unsigned long clusters;      /* number of clusters */
 	unsigned long root_cluster;  /* first cluster of the root directory */
 	unsigned long fsinfo_offset; /* FAT32 fsinfo offset from start of disk */
diff -u --recursive --new-file v2.1.132/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.132/linux/include/linux/sched.h	Thu Nov 12 16:21:24 1998
+++ linux/include/linux/sched.h	Mon Dec 28 14:11:20 1998
@@ -11,6 +11,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/times.h>
+#include <linux/timex.h>
 
 #include <asm/system.h>
 #include <asm/semaphore.h>
@@ -219,6 +220,7 @@
 /* various fields */
 	long counter;
 	long priority;
+	cycles_t avg_slice;
 /* SMP and runqueue state */
 	int has_cpu;
 	int processor;
@@ -336,7 +338,7 @@
  */
 #define INIT_TASK \
 /* state etc */	{ 0,0,0,KERNEL_DS,&default_exec_domain,0, \
-/* counter */	DEF_PRIORITY,DEF_PRIORITY, \
+/* counter */	DEF_PRIORITY,DEF_PRIORITY,0, \
 /* SMP */	0,0,0,-1, \
 /* schedlink */	&init_task,&init_task, &init_task, &init_task, \
 /* binfmt */	NULL, \
diff -u --recursive --new-file v2.1.132/linux/include/linux/sem.h linux/include/linux/sem.h
--- v2.1.132/linux/include/linux/sem.h	Fri Jul 31 17:05:53 1998
+++ linux/include/linux/sem.h	Sun Dec 27 22:18:29 1998
@@ -92,6 +92,7 @@
 	struct semid_ds *	sma;	 /* semaphore array for operations */
 	struct sembuf *		sops;	 /* array of pending operations */
 	int			nsops;	 /* number of operations */
+	int			alter;	 /* operation will alter semaphore */
 };
 
 /* Each task has a list of undo requests. They are executed automatically
diff -u --recursive --new-file v2.1.132/linux/include/linux/smp.h linux/include/linux/smp.h
--- v2.1.132/linux/include/linux/smp.h	Thu Aug  6 14:06:34 1998
+++ linux/include/linux/smp.h	Mon Dec 28 14:11:19 1998
@@ -11,12 +11,22 @@
 #include <asm/smp.h>
 
 /*
- * main IPI interface, handles INIT, TLB flush, STOP, etc. (defined in asm header):
- *
- * extern void smp_message_pass(int target, int msg, unsigned long data, int wait);
+ * main cross-CPU interfaces, handles INIT, TLB flush, STOP, etc.
+ * (defined in asm header):
  */ 
 
 /*
+ * stops all CPUs but the current one:
+ */
+extern void smp_send_stop(void);
+
+/*
+ * sends a 'reschedule' event to another CPU:
+ */
+extern void FASTCALL(smp_send_reschedule(int cpu));
+
+
+/*
  * Boot processor call to load the other CPU's
  */
 extern void smp_boot_cpus(void);
@@ -61,7 +71,6 @@
 #define smp_num_cpus			1
 #define smp_processor_id()		0
 #define hard_smp_processor_id()		0
-#define smp_message_pass(t,m,d,w)	
 #define smp_threads_ready		1
 #define kernel_lock()
 #define cpu_logical_map(cpu)		0
diff -u --recursive --new-file v2.1.132/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.1.132/linux/include/linux/swap.h	Tue Dec 22 14:16:58 1998
+++ linux/include/linux/swap.h	Mon Dec 28 14:09:30 1998
@@ -87,6 +87,7 @@
 /* linux/mm/page_io.c */
 extern void rw_swap_page(int, unsigned long, char *, int);
 extern void rw_swap_page_nocache(int, unsigned long, char *);
+extern void rw_swap_page_nolock(int, unsigned long, char *, int);
 extern void swap_after_unlock_page (unsigned long entry);
 
 /* linux/mm/page_alloc.c */
diff -u --recursive --new-file v2.1.132/linux/include/linux/videodev.h linux/include/linux/videodev.h
--- v2.1.132/linux/include/linux/videodev.h	Tue Dec 22 14:16:58 1998
+++ linux/include/linux/videodev.h	Sun Dec 27 10:49:06 1998
@@ -261,6 +261,8 @@
 #define VID_HARDWARE_PERMEDIA2	14	/* Reserved for Permedia2 */
 #define VID_HARDWARE_RIVA128	15	/* Reserved for RIVA 128 */
 #define VID_HARDWARE_PLANB	16	/* PowerMac motherboard video-in */
+#define VID_HARDWARE_BROADWAY	17	/* Broadway project */
+#define VID_HARDWARE_GEMTEK	18
 
 /*
  *	Initialiser list
diff -u --recursive --new-file v2.1.132/linux/include/net/sock.h linux/include/net/sock.h
--- v2.1.132/linux/include/net/sock.h	Sun Nov  8 14:03:12 1998
+++ linux/include/net/sock.h	Mon Dec 28 14:11:23 1998
@@ -128,6 +128,11 @@
 	unsigned char           node[IPX_NODE_LEN];
 #endif
 	unsigned short		type;
+/* 
+ * To handle special ncp connection-handling sockets for mars_nwe,
+ * the connection number must be stored in the socket.
+ */
+	unsigned short		ipx_ncp_conn;
 };
 #endif
 
diff -u --recursive --new-file v2.1.132/linux/include/video/fbcon.h linux/include/video/fbcon.h
--- v2.1.132/linux/include/video/fbcon.h	Tue Dec 22 14:16:59 1998
+++ linux/include/video/fbcon.h	Sun Dec 27 10:50:12 1998
@@ -441,6 +441,7 @@
 
 static __inline__ void fast_memmove(void *d, const void *s, size_t count)
 {
+  int d0, d1, d2, d3;
     if (d < s) {
 __asm__ __volatile__ (
 	"cld\n\t"
@@ -452,9 +453,9 @@
 	"movsw\n"
 	"2:\trep\n\t"
 	"movsl"
-	: /* no output */
-	:"c"(count),"D"((long)d),"S"((long)s)
-	:"cx","di","si","memory");
+	: "=&c" (d0), "=&D" (d1), "=&S" (d2)
+	:"0"(count),"1"((long)d),"2"((long)s)
+	:"memory");
     } else {
 __asm__ __volatile__ (
 	"std\n\t"
@@ -475,9 +476,9 @@
 	"2:\trep\n\t"
 	"movsl\n\t"
 	"cld"
-	: /* no output */
-	:"c"(count),"D"(count-4+(long)d),"S"(count-4+(long)s)
-	:"ax","cx","di","si","memory");
+	: "=&c" (d0), "=&D" (d1), "=&S" (d2), "=&a" (d3)
+	:"0"(count),"1"(count-4+(long)d),"2"(count-4+(long)s)
+	:"memory");
     }
 }
 
diff -u --recursive --new-file v2.1.132/linux/init/main.c linux/init/main.c
--- v2.1.132/linux/init/main.c	Tue Dec 22 14:16:59 1998
+++ linux/init/main.c	Sun Dec 27 22:45:13 1998
@@ -1177,6 +1177,7 @@
 	 */
 	smp_init();
 	kernel_thread(init, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	current->need_resched = 1;
  	cpu_idle(NULL);
 }
 
diff -u --recursive --new-file v2.1.132/linux/ipc/sem.c linux/ipc/sem.c
--- v2.1.132/linux/ipc/sem.c	Fri Nov 27 13:09:29 1998
+++ linux/ipc/sem.c	Sun Dec 27 10:53:45 1998
@@ -29,6 +29,25 @@
  *   see a clean way to get the old behavior with the new design.
  *   The POSIX standard and SVID should be consulted to determine
  *   what behavior is mandated.
+ *
+ * Further notes on refinement (Christoph Rohland, December 1998):
+ * - The POSIX standard says, that the undo adjustments simply should
+ *   redo. So the current implementation is o.K.
+ * - The previous code had two flaws:
+ *   1) It actively gave the semaphore to the next waiting process
+ *      sleeping on the semaphore. Since this process did not have the
+ *      cpu this led to many unnecessary context switches and bad
+ *      performance. Now we only check which process should be able to
+ *      get the semaphore and if this process wants to reduce some
+ *      semaphore value we simply wake it up without doing the
+ *      operation. So it has to try to get it later. Thus e.g. the
+ *      running process may reaquire the semaphore during the current
+ *      time slice. If it only waits for zero or increases the semaphore,
+ *      we do the operation in advance and wake it up.
+ *   2) It did not wake up all zero waiting processes. We try to do
+ *      better but only get the semops right which only wait for zero or
+ *      increase. If there are decrement operations in the operations
+ *      array we do the same as before.
  */
 
 #include <linux/malloc.h>
@@ -158,12 +177,26 @@
 /* Manage the doubly linked list sma->sem_pending as a FIFO:
  * insert new queue elements at the tail sma->sem_pending_last.
  */
-static inline void insert_into_queue (struct semid_ds * sma, struct sem_queue * q)
+static inline void append_to_queue (struct semid_ds * sma,
+                                    struct sem_queue * q)
 {
 	*(q->prev = sma->sem_pending_last) = q;
 	*(sma->sem_pending_last = &q->next) = NULL;
 }
-static inline void remove_from_queue (struct semid_ds * sma, struct sem_queue * q)
+
+static inline void prepend_to_queue (struct semid_ds * sma,
+                                     struct sem_queue * q)
+{
+        q->next = sma->sem_pending;
+        *(q->prev = &sma->sem_pending) = q;
+        if (q->next)
+                q->next->prev = &q->next;
+        else /* sma->sem_pending_last == &sma->sem_pending */
+                sma->sem_pending_last = &q->next;
+}
+
+static inline void remove_from_queue (struct semid_ds * sma,
+                                      struct sem_queue * q)
 {
 	*(q->prev) = q->next;
 	if (q->next)
@@ -173,112 +206,100 @@
 	q->prev = NULL; /* mark as removed */
 }
 
-/* Determine whether a sequence of semaphore operations would succeed
+/*
+ * Determine whether a sequence of semaphore operations would succeed
  * all at once. Return 0 if yes, 1 if need to sleep, else return error code.
  */
-static int try_semop (struct semid_ds * sma, struct sembuf * sops, int nsops)
-{
-	int result = 0;
-	int i = 0;
 
-	while (i < nsops) {
-		struct sembuf * sop = &sops[i];
-		struct sem * curr = &sma->sem_base[sop->sem_num];
-		if (sop->sem_op + curr->semval > SEMVMX) {
-			result = -ERANGE;
-			break;
-		}
-		if (!sop->sem_op && curr->semval) {
-			if (sop->sem_flg & IPC_NOWAIT)
-				result = -EAGAIN;
-			else
-				result = 1;
-			break;
-		}
-		i++;
-		curr->semval += sop->sem_op;
-		if (curr->semval < 0) {
-			if (sop->sem_flg & IPC_NOWAIT)
-				result = -EAGAIN;
-			else
-				result = 1;
-			break;
-		}
-	}
-	while (--i >= 0) {
-		struct sembuf * sop = &sops[i];
-		struct sem * curr = &sma->sem_base[sop->sem_num];
-		curr->semval -= sop->sem_op;
-	}
-	return result;
-}
+static int try_atomic_semop (struct semid_ds * sma, struct sembuf * sops,
+                             int nsops, struct sem_undo *un, int pid,
+                             int do_undo)
+{
+	int result, sem_op;
+	struct sembuf *sop;
+	struct sem * curr;
+
+	for (sop = sops; sop < sops + nsops; sop++) {
+		curr = sma->sem_base + sop->sem_num;
+		sem_op = sop->sem_op;
 
-/* Actually perform a sequence of semaphore operations. Atomically. */
-/* This assumes that try_semop() already returned 0. */
-static int do_semop (struct semid_ds * sma, struct sembuf * sops, int nsops,
-		     struct sem_undo * un, int pid)
-{
-	int i;
+		if (!sem_op && curr->semval)
+			goto would_block;
 
-	for (i = 0; i < nsops; i++) {
-		struct sembuf * sop = &sops[i];
-		struct sem * curr = &sma->sem_base[sop->sem_num];
-		if (sop->sem_op + curr->semval > SEMVMX) {
-			printk("do_semop: race\n");
-			break;
-		}
-		if (!sop->sem_op) {
-			if (curr->semval) {
-				printk("do_semop: race\n");
-				break;
-			}
-		} else {
-			curr->semval += sop->sem_op;
-			if (curr->semval < 0) {
-				printk("do_semop: race\n");
-				break;
-			}
-			if (sop->sem_flg & SEM_UNDO)
-				un->semadj[sop->sem_num] -= sop->sem_op;
-		}
-		curr->sempid = pid;
+		curr->sempid = (curr->sempid << 16) | pid;
+		curr->semval += sem_op;
+		if (sop->sem_flg & SEM_UNDO)
+			un->semadj[sop->sem_num] -= sem_op;
+
+		if (curr->semval < 0)
+			goto would_block;
+		if (curr->semval > SEMVMX)
+			goto out_of_range;
 	}
-	sma->sem_otime = CURRENT_TIME;
 
-	/* Previous implementation returned the last semaphore's semval.
-	 * This is wrong because we may not have checked read permission,
-	 * only write permission.
-	 */
+        if (do_undo)
+        {
+                sop--;
+                result = 0;
+                goto undo;
+        }
+
+	sma->sem_otime = CURRENT_TIME;
 	return 0;
+
+out_of_range:
+	result = -ERANGE;
+	goto undo;
+
+would_block:
+	if (sop->sem_flg & IPC_NOWAIT)
+		result = -EAGAIN;
+	else
+		result = 1;
+
+undo:
+        while (sop >= sops) {
+		curr = sma->sem_base + sop->sem_num;
+		curr->semval -= sop->sem_op;
+		curr->sempid >>= 16;
+
+		if (sop->sem_flg & SEM_UNDO)
+			un->semadj[sop->sem_num] += sop->sem_op;
+		sop--;
+	}
+
+	return result;
 }
 
 /* Go through the pending queue for the indicated semaphore
- * looking for tasks that can be completed. Keep cycling through
- * the queue until a pass is made in which no process is woken up.
+ * looking for tasks that can be completed.
  */
 static void update_queue (struct semid_ds * sma)
 {
-	int wokeup, error;
+	int error;
 	struct sem_queue * q;
 
-	do {
-		wokeup = 0;
-		for (q = sma->sem_pending; q; q = q->next) {
-			error = try_semop(sma, q->sops, q->nsops);
-			/* Does q->sleeper still need to sleep? */
-			if (error > 0)
-				continue;
-			/* Perform the operations the sleeper was waiting for */
-			if (!error)
-				error = do_semop(sma, q->sops, q->nsops, q->undo, q->pid);
-			q->status = error;
-			/* Remove it from the queue */
-			remove_from_queue(sma,q);
-			/* Wake it up */
-			wake_up_interruptible(&q->sleeper); /* doesn't sleep! */
-			wokeup++;
-		}
-	} while (wokeup);
+        for (q = sma->sem_pending; q; q = q->next) {
+                        
+                if (q->status == 1)
+                        return; /* wait for other process */
+
+                error = try_atomic_semop(sma, q->sops, q->nsops,
+                                         q->undo, q->pid, q->alter);
+
+                /* Does q->sleeper still need to sleep? */
+                if (error <= 0) {
+                                /* Found one, wake it up */
+                        wake_up_interruptible(&q->sleeper);
+                        if (error == 0 && q->alter) {
+                                /* if q-> alter let it self try */
+                                q->status = 1;
+                                return;
+                        }
+                        q->status = error;
+                        remove_from_queue(sma,q);
+                }
+        }
 }
 
 /* The following counts are associated to each semaphore:
@@ -460,7 +481,7 @@
 			goto out;
 		switch (cmd) {
 		case GETVAL : err = curr->semval; goto out;
-		case GETPID : err = curr->sempid; goto out;
+		case GETPID : err = curr->sempid & 0xffff; goto out;
 		case GETNCNT: err = count_semncnt(sma,semnum); goto out;
 		case GETZCNT: err = count_semzcnt(sma,semnum); goto out;
 		case GETALL:
@@ -582,11 +603,12 @@
 
 asmlinkage int sys_semop (int semid, struct sembuf *tsops, unsigned nsops)
 {
-	int i, id, size, error = -EINVAL;
+	int id, size, error = -EINVAL;
 	struct semid_ds *sma;
 	struct sembuf sops[SEMOPM], *sop;
 	struct sem_undo *un;
-	int undos = 0, alter = 0;
+	int undos = 0, decrease = 0, alter = 0;
+	struct sem_queue queue;
 
 	lock_kernel();
 	if (nsops < 1 || semid < 0)
@@ -595,8 +617,6 @@
 	if (nsops > SEMOPM)
 		goto out;
 	error = -EFAULT;
-	if (!tsops)
-		goto out;
 	if (copy_from_user (sops, tsops, nsops * sizeof(*tsops)))
 		goto out;
 	id = (unsigned int) semid % SEMMNI;
@@ -606,22 +626,23 @@
 	error = -EIDRM;
 	if (sma->sem_perm.seq != (unsigned int) semid / SEMMNI)
 		goto out;
-	for (i = 0; i < nsops; i++) {
-		sop = &sops[i];
+
 		error = -EFBIG;
+	for (sop = sops; sop < sops + nsops; sop++) {
 		if (sop->sem_num >= sma->sem_nsems)
 			goto out;
 		if (sop->sem_flg & SEM_UNDO)
 			undos++;
-		if (sop->sem_op)
-			alter++;
+		if (sop->sem_op < 0)
+			decrease = 1;
+                if (sop->sem_op > 0)
+                        alter = 1;
 	}
+        alter |= decrease;
+
 	error = -EACCES;
 	if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO))
 		goto out;
-	error = try_semop(sma, sops, nsops);
-	if (error < 0)
-		goto out;
 	if (undos) {
 		/* Make sure we have an undo structure
 		 * for this process and this semaphore set.
@@ -646,40 +667,59 @@
 		}
 	} else
 		un = NULL;
-	if (error == 0) {
-		/* the operations go through immediately */
-		error = do_semop(sma, sops, nsops, un, current->pid);
-		/* maybe some queued-up processes were waiting for this */
-		update_queue(sma);
-		goto out;
-	} else {
-		/* We need to sleep on this operation, so we put the current
-		 * task into the pending queue and go to sleep.
-		 */
-		struct sem_queue queue;
 
-		queue.sma = sma;
-		queue.sops = sops;
-		queue.nsops = nsops;
-		queue.undo = un;
-		queue.pid = current->pid;
-		queue.status = 0;
-		insert_into_queue(sma,&queue);
-		queue.sleeper = NULL;
-		current->semsleeping = &queue;
-		interruptible_sleep_on(&queue.sleeper);
-		current->semsleeping = NULL;
-		/* When we wake up, either the operation is finished,
-		 * or some kind of error happened.
-		 */
-		if (!queue.prev) {
-			/* operation is finished, update_queue() removed us */
-			error = queue.status;
-		} else {
-			remove_from_queue(sma,&queue);
-			error = -EINTR;
-		}
-	}
+	error = try_atomic_semop (sma, sops, nsops, un, current->pid, 0);
+	if (error <= 0)
+                goto update;
+
+        /* We need to sleep on this operation, so we put the current
+         * task into the pending queue and go to sleep.
+         */
+                
+        queue.sma = sma;
+        queue.sops = sops;
+        queue.nsops = nsops;
+        queue.undo = un;
+        queue.pid = current->pid;
+        queue.alter = decrease;
+        current->semsleeping = &queue;
+        if (alter)
+                append_to_queue(sma ,&queue);
+        else
+                prepend_to_queue(sma ,&queue);
+
+        for (;;) {
+                queue.status = -EINTR;
+                queue.sleeper = NULL;
+                interruptible_sleep_on(&queue.sleeper);
+
+                /*
+                 * If queue.status == 1 we where woken up and
+                 * have to retry else we simply return.
+                 * If an interrupt occured we have to clean up the
+                 * queue
+                 *
+                 */
+                if (queue.status == 1)
+                {
+                        error = try_atomic_semop (sma, sops, nsops, un,
+                                                  current->pid,0);
+                        if (error <= 0) 
+                                break;
+                } else {
+                        error = queue.status;;
+                        if (queue.prev) /* got Interrupt */
+                                break;
+                        /* Everything done by update_queue */
+                        current->semsleeping = NULL;
+                        goto out;
+                }
+        }
+        current->semsleeping = NULL;
+        remove_from_queue(sma,&queue);
+update:
+        if (alter)
+                update_queue (sma);
 out:
 	unlock_kernel();
 	return error;
diff -u --recursive --new-file v2.1.132/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.132/linux/kernel/ksyms.c	Tue Dec 22 14:16:59 1998
+++ linux/kernel/ksyms.c	Wed Dec 23 12:53:23 1998
@@ -109,7 +109,6 @@
 EXPORT_SYMBOL(update_atime);
 EXPORT_SYMBOL(get_super);
 EXPORT_SYMBOL(getname);
-EXPORT_SYMBOL(putname);
 EXPORT_SYMBOL(__fput);
 EXPORT_SYMBOL(iget);
 EXPORT_SYMBOL(iput);
@@ -129,7 +128,7 @@
 EXPORT_SYMBOL(__mark_inode_dirty);
 EXPORT_SYMBOL(get_empty_filp);
 EXPORT_SYMBOL(init_private_file);
-EXPORT_SYMBOL(insert_file_free);
+EXPORT_SYMBOL(fput);
 EXPORT_SYMBOL(check_disk_change);
 EXPORT_SYMBOL(invalidate_buffers);
 EXPORT_SYMBOL(invalidate_inodes);
@@ -161,7 +160,6 @@
 EXPORT_SYMBOL(posix_test_lock);
 EXPORT_SYMBOL(posix_block_lock);
 EXPORT_SYMBOL(posix_unblock_lock);
-EXPORT_SYMBOL(locks_remove_flock);
 EXPORT_SYMBOL(dput);
 EXPORT_SYMBOL(get_cached_page);
 EXPORT_SYMBOL(put_cached_page);
diff -u --recursive --new-file v2.1.132/linux/kernel/module.c linux/kernel/module.c
--- v2.1.132/linux/kernel/module.c	Fri Nov 27 13:09:30 1998
+++ linux/kernel/module.c	Sun Dec 27 10:41:41 1998
@@ -5,6 +5,7 @@
 #include <linux/vmalloc.h>
 #include <linux/smp_lock.h>
 #include <asm/pgtable.h>
+#include <linux/init.h>
 
 /*
  * Originally by Anonymous (as far as I know...)
@@ -30,7 +31,7 @@
 	NULL,			/* next */
 	"",			/* name */
 	0,			/* size */
-	1,			/* usecount */
+	{ATOMIC_INIT(1)},	/* usecount */
 	MOD_RUNNING,		/* flags */
 	0,			/* nsyms -- to filled in in init_modules */
 	0,			/* ndeps */
@@ -56,7 +57,7 @@
  * Called at boot time
  */
 
-void init_modules(void)
+__initfunc(void init_modules(void))
 {
 	kernel_module.nsyms = __stop___ksymtab - __start___ksymtab;
 
@@ -328,13 +329,13 @@
 	put_mod_name(name);
 
 	/* Initialize the module.  */
-	mod->usecount = 1;
+	atomic_set(&mod->uc.usecount,1);
 	if (mod->init && mod->init() != 0) {
-		mod->usecount = 0;
+		atomic_set(&mod->uc.usecount,0);
 		error = -EBUSY;
 		goto err0;
 	}
-	mod->usecount--;
+	atomic_dec(&mod->uc.usecount);
 
 	/* And set it running.  */
 	mod->flags |= MOD_RUNNING;
@@ -614,7 +615,7 @@
 		info.size = mod->size;
 		info.flags = mod->flags;
 		info.usecount = (mod_member_present(mod, can_unload)
-				 && mod->can_unload ? -1 : mod->usecount);
+				 && mod->can_unload ? -1 : atomic_read(&mod->uc.usecount));
 
 		if (copy_to_user(buf, &info, sizeof(struct module_info)))
 			return -EFAULT;
@@ -853,7 +854,7 @@
 			len = sprintf(tmpstr, "%4ld",
 				      (mod_member_present(mod, can_unload)
 				       && mod->can_unload
-				       ? -1 : mod->usecount));
+				       ? -1L : (long)atomic_read(&mod->uc.usecount)));
 			safe_copy_str(tmpstr, len);
 		}
 
diff -u --recursive --new-file v2.1.132/linux/kernel/panic.c linux/kernel/panic.c
--- v2.1.132/linux/kernel/panic.c	Fri Nov 27 13:09:30 1998
+++ linux/kernel/panic.c	Sun Dec 27 22:45:13 1998
@@ -50,7 +50,7 @@
 	unblank_console();
 
 #ifdef __SMP__
-	smp_message_pass(MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0);
+	smp_send_stop();
 #endif
 	if (panic_timeout > 0)
 	{
diff -u --recursive --new-file v2.1.132/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.132/linux/kernel/sched.c	Fri Nov 27 13:09:30 1998
+++ linux/kernel/sched.c	Mon Dec 28 10:54:09 1998
@@ -7,6 +7,12 @@
  *  1996-12-23  Modified by Dave Grothe to fix bugs in semaphores and
  *              make semaphores SMP safe
  *  1997-01-28  Modified by Finn Arne Gangstad to make timers scale better.
+ *  1998-11-19	Implemented schedule_timeout() and related stuff
+ *		by Andrea Arcangeli
+ *  1998-12-24	Fixed a xtime SMP race (we need the xtime_lock rw spinlock to
+ *		serialize accesses to xtime/lost_ticks).
+ *				Copyright (C) 1998  Andrea Arcangeli
+ *  1998-12-28  Implemented better SMP scheduling by Ingo Molnar
  */
 
 /*
@@ -91,47 +97,111 @@
 
 void scheduling_functions_start_here(void) { }
 
-static inline void reschedule_idle(struct task_struct * p)
+#ifdef __SMP__
+static void reschedule_idle_slow(struct task_struct * p)
 {
+/*
+ * (see reschedule_idle() for an explanation first ...)
+ *
+ * Pass #2
+ *
+ * We try to find another (idle) CPU for this woken-up process.
+ *
+ * On SMP, we mostly try to see if the CPU the task used
+ * to run on is idle.. but we will use another idle CPU too,
+ * at this point we already know that this CPU is not
+ * willing to reschedule in the near future.
+ *
+ * An idle CPU is definitely wasted, especially if this CPU is
+ * running long-timeslice processes. The following algorithm is
+ * pretty good at finding the best idle CPU to send this process
+ * to.
+ *
+ * [We can try to preempt low-priority processes on other CPUs in
+ * 2.3. Also we can try to use the avg_slice value to predict
+ * 'likely reschedule' events even on other CPUs.]
+ */
+	int best_cpu = p->processor, this_cpu = smp_processor_id();
+	struct task_struct **idle = task, *tsk, *target_tsk;
+	int i = smp_num_cpus;
+
+	target_tsk = NULL;
+	do {
+		tsk = *idle;
+		idle++;
+		if (tsk->has_cpu) {
+			if (tsk->processor == this_cpu)
+				continue;
+			target_tsk = tsk;
+			if (tsk->processor == best_cpu) {
+				/*
+				 * bingo, we couldnt get a better
+				 * CPU, activate it.
+				 */
+				goto send; /* this one helps GCC ... */
+			}
+		}
+	} while (--i > 0);
 
 	/*
-	 * For SMP, we try to see if the CPU the task used
-	 * to run on is idle..
+	 * found any idle CPU?
 	 */
-#if 0
+	if (target_tsk) {
+send:
+		target_tsk->need_resched = 1;
+		smp_send_reschedule(target_tsk->processor);
+		return;
+	}
+}
+#endif /* __SMP__ */
+
+static inline void reschedule_idle(struct task_struct * p)
+{
+
+	if (p->policy != SCHED_OTHER || p->counter > current->counter + 3) {
+		current->need_resched = 1;
+		return;
+	}
+
+#ifdef __SMP__
 	/*
-	 * Disable this for now. Ingo has some interesting
-	 * code that looks too complex, and I have some ideas,
-	 * but in the meantime.. One problem is that "wakeup()"
-	 * can be (and is) called before we've even initialized
-	 * SMP completely, so..
+	 * ("wakeup()" should not be called before we've initialized
+	 * SMP completely.
+	 * Basically a not-yet initialized SMP subsystem can be
+	 * considered as a not-yet working scheduler, simply dont use
+	 * it before it's up and running ...)
+	 *
+	 * SMP rescheduling is done in 2 passes:
+	 *  - pass #1: faster: 'quick decisions'
+	 *  - pass #2: slower: 'lets try and find another CPU'
 	 */
-#ifdef __SMP__
-	int want_cpu = p->processor;
 
 	/*
-	 * Don't even try to find another CPU for us if the task
-	 * ran on this one before..
+	 * Pass #1
+	 *
+	 * There are two metrics here:
+	 *
+	 * first, a 'cutoff' interval, currently 0-200 usecs on
+	 * x86 CPUs, depending on the size of the 'SMP-local cache'.
+	 * If the current process has longer average timeslices than
+	 * this, then we utilize the idle CPU.
+	 *
+	 * second, if the wakeup comes from a process context,
+	 * then the two processes are 'related'. (they form a
+	 * 'gang')
+	 *
+	 * An idle CPU is almost always a bad thing, thus we skip
+	 * the idle-CPU utilization only if both these conditions
+	 * are true. (ie. a 'process-gang' rescheduling with rather
+	 * high frequency should stay on the same CPU).
+	 *
+	 * [We can switch to something more finegrained in 2.3.]
 	 */
-	if (want_cpu != smp_processor_id()) {
-		struct task_struct **idle = task;
-		int i = smp_num_cpus;
-
-		do {
-			struct task_struct *tsk = *idle;
-			idle++;
-			/* Something like this.. */
-			if (tsk->has_cpu && tsk->processor == want_cpu) {
-				tsk->need_resched = 1;
-				smp_send_reschedule(want_cpu);
-				return;
-			}
-		} while (--i > 0);
-	}
-#endif
-#endif
-	if (p->policy != SCHED_OTHER || p->counter > current->counter + 3)
-		current->need_resched = 1;	
+	if ((current->avg_slice < cacheflush_time) && !in_interrupt())
+		return;
+
+	reschedule_idle_slow(p);
+#endif /* __SMP__ */
 }
 
 /*
@@ -149,6 +219,7 @@
 	init_task.next_run = p;
 	p->next_run = next;
 	next->prev_run = p;
+	nr_running++;
 }
 
 static inline void del_from_runqueue(struct task_struct * p)
@@ -227,7 +298,6 @@
 	if (!p->next_run) {
 		add_to_runqueue(p);
 		reschedule_idle(p);
-		nr_running++;
 	}
 	spin_unlock_irqrestore(&runqueue_lock, flags);
 }
@@ -437,23 +507,6 @@
 	struct timer_list timer;
 	unsigned long expire;
 
-	/*
-	 * PARANOID.
-	 */
-	if (current->state == TASK_UNINTERRUPTIBLE)
-	{
-		printk(KERN_WARNING "schedule_timeout: task not interrutible "
-		       "from %p\n", __builtin_return_address(0));
-		/*
-		 * We don' t want to interrupt a not interruptible task
-		 * risking to cause corruption. Better a a deadlock ;-).
-		 */
-		timeout = MAX_SCHEDULE_TIMEOUT;
-	}
-
-	/*
-	 * Here we start for real.
-	 */
 	switch (timeout)
 	{
 	case MAX_SCHEDULE_TIMEOUT:
@@ -501,6 +554,63 @@
 }
 
 /*
+ * This one aligns per-CPU data on cacheline boundaries.
+ */
+static union {
+	struct schedule_data {
+		struct task_struct * prev;
+		long prevstate;
+		cycles_t last_schedule;
+	} schedule_data;
+	char __pad [L1_CACHE_BYTES];
+} aligned_data [NR_CPUS] __cacheline_aligned = { {{&init_task,0}}};
+
+
+static inline void __schedule_tail (void)
+{
+#ifdef __SMP__
+	struct schedule_data * sched_data;
+
+	/*
+	 * We might have switched CPUs:
+	 */
+	sched_data = & aligned_data[smp_processor_id()].schedule_data;
+
+	/*
+	 * Subtle. In the rare event that we got a wakeup to 'prev' just
+	 * during the reschedule (this is possible, the scheduler is pretty
+	 * parallel), we should do another reschedule in the next task's
+	 * context. schedule() will do the right thing next time around.
+	 * this is equivalent to 'delaying' the wakeup until the reschedule
+	 * has finished.
+	 */
+	if (sched_data->prev->state != sched_data->prevstate)
+		current->need_resched = 1;
+
+	/*
+	 * Release the previous process ...
+	 *
+	 * We have dropped all locks, and we must make sure that we
+	 * only mark the previous process as no longer having a CPU
+	 * after all other state has been seen by other CPU's. Thus
+	 * the write memory barrier!
+	 */
+	wmb();
+	sched_data->prev->has_cpu = 0;
+#endif /* __SMP__ */
+}
+
+/*
+ * schedule_tail() is getting called from the fork return path. This
+ * cleans up all remaining scheduler things, without impacting the
+ * common case.
+ */
+void schedule_tail (void)
+{
+	__schedule_tail();
+}
+
+/*
  *  'schedule()' is the scheduler function. It's a very simple and nice
  * scheduler: it's not perfect, but certainly works for most things.
  *
@@ -512,11 +622,18 @@
  */
 asmlinkage void schedule(void)
 {
+	struct schedule_data * sched_data;
 	struct task_struct * prev, * next;
 	int this_cpu;
 
 	prev = current;
 	this_cpu = prev->processor;
+	/*
+	 * 'sched_data' is protected by the fact that we can run
+	 * only one process per CPU.
+	 */
+	sched_data = & aligned_data[this_cpu].schedule_data;
+
 	if (in_interrupt())
 		goto scheduling_in_interrupt;
 	release_kernel_lock(prev, this_cpu);
@@ -531,6 +648,7 @@
 
 	/* move an exhausted RR process to be last.. */
 	prev->need_resched = 0;
+
 	if (!prev->counter && prev->policy == SCHED_RR) {
 		prev->counter = prev->priority;
 		move_last_runqueue(prev);
@@ -546,6 +664,9 @@
 			del_from_runqueue(prev);
 		case TASK_RUNNING:
 	}
+
+	sched_data->prevstate = prev->state;
+
 	{
 		struct task_struct * p = init_task.next_run;
 		/*
@@ -592,25 +713,49 @@
 		}
 	}
 
+ 	/*
+ 	 * maintain the per-process 'average timeslice' value.
+ 	 * (this has to be recalculated even if we reschedule to
+ 	 * the same process) Currently this is only used on SMP:
+ 	 */
 #ifdef __SMP__
-	next->has_cpu = 1;
-	next->processor = this_cpu;
-#endif
+	{
+		cycles_t t, this_slice;
 
-	if (prev != next) {
-		kstat.context_swtch++;
-		get_mmu_context(next);
-		switch_to(prev,next);
-	}
+		t = get_cycles();
+		this_slice = t - sched_data->last_schedule;
+		sched_data->last_schedule = t;
 
-	spin_unlock(&scheduler_lock);
+		/*
+		 * Simple, exponentially fading average calculation:
+		 */
+		prev->avg_slice = this_slice + prev->avg_slice;
+		prev->avg_slice >>= 1;
+	}
 
 	/*
-	 * At this point "prev" is "current", as we just
-	 * switched into it (from an even more "previous"
-	 * prev)
+	 * We drop the scheduler lock early (it's a global spinlock),
+	 * thus we have to lock the previous process from getting
+	 * rescheduled during switch_to().
 	 */
-	reacquire_kernel_lock(prev);
+	prev->has_cpu = 1;
+
+ 	next->has_cpu = 1;
+ 	next->processor = this_cpu;
+	spin_unlock(&scheduler_lock);
+#endif /* __SMP__ */
+ 	if (prev != next) {
+#ifdef __SMP__
+		sched_data->prev = prev;
+#endif
+	 	kstat.context_swtch++;
+		get_mmu_context(next);
+		switch_to(prev,next);
+
+		__schedule_tail();
+	}
+  
+	reacquire_kernel_lock(current);
 	return;
 
 scheduling_in_interrupt:
@@ -618,7 +763,6 @@
 	*(int *)0 = 0;
 }
 
-
 rwlock_t waitqueue_lock = RW_LOCK_UNLOCKED;
 
 /*
@@ -1189,13 +1333,21 @@
 volatile unsigned long lost_ticks = 0;
 static unsigned long lost_ticks_system = 0;
 
+/*
+ * This spinlock protect us from races in SMP while playing with xtime. -arca
+ */
+rwlock_t xtime_lock = RW_LOCK_UNLOCKED;
+
 static inline void update_times(void)
 {
 	unsigned long ticks;
-	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	/*
+	 * update_times() is run from the raw timer_bh handler so we
+	 * just know that the irqs are locally enabled and so we don't
+	 * need to save/restore the flags of the local CPU here. -arca
+	 */
+	write_lock_irq(&xtime_lock);
 
 	ticks = lost_ticks;
 	lost_ticks = 0;
@@ -1206,12 +1358,12 @@
 
 		calc_load(ticks);
 		update_wall_time(ticks);
-		restore_flags(flags);
+		write_unlock_irq(&xtime_lock);
 		
 		update_process_times(ticks, system);
 
 	} else
-		restore_flags(flags);
+		write_unlock_irq(&xtime_lock);
 }
 
 static void timer_bh(void)
diff -u --recursive --new-file v2.1.132/linux/mm/page_io.c linux/mm/page_io.c
--- v2.1.132/linux/mm/page_io.c	Tue Dec 22 14:16:59 1998
+++ linux/mm/page_io.c	Mon Dec 28 13:56:29 1998
@@ -7,6 +7,7 @@
  *  Asynchronous swapping added 30.12.95. Stephen Tweedie
  *  Removed race in async swapping. 14.4.1996. Bruno Haible
  *  Add swap of shared pages through the page cache. 20.2.1998. Stephen Tweedie
+ *  Always use brw_page, life becomes simpler. 12 May 1998 Eric Biederman
  */
 
 #include <linux/mm.h>
@@ -15,8 +16,6 @@
 #include <linux/locks.h>
 #include <linux/swapctl.h>
 
-#include <asm/dma.h>
-#include <asm/uaccess.h> /* for copy_to/from_user */
 #include <asm/pgtable.h>
 
 static struct wait_queue * lock_queue = NULL;
@@ -24,8 +23,6 @@
 /*
  * Reads or writes a swap page.
  * wait=1: start I/O and wait for completion. wait=0: start asynchronous I/O.
- * All IO to swap files (as opposed to swap partitions) is done
- * synchronously.
  *
  * Important prevention of race condition: the caller *must* atomically 
  * create a unique swap cache entry for this swap page before calling
@@ -38,21 +35,22 @@
  * that shared pages stay shared while being swapped.
  */
 
-void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
+static void rw_swap_page_base(int rw, unsigned long entry, struct page *page, int wait)
 {
 	unsigned long type, offset;
 	struct swap_info_struct * p;
-	struct page *page = mem_map + MAP_NR(buf);
+	int zones[PAGE_SIZE/512];
+	int zones_used;
+	kdev_t dev = 0;
+	int block_size;
 
 #ifdef DEBUG_SWAP
 	printk ("DebugVM: %s_swap_page entry %08lx, page %p (count %d), %s\n",
 		(rw == READ) ? "read" : "write", 
-		entry, buf, atomic_read(&page->count),
+		entry, (char *) page_address(page), atomic_read(&page->count),
 		wait ? "wait" : "nowait");
 #endif
 
-	if (page->inode && page->inode != &swapper_inode)
-		panic ("Tried to swap a non-swapper page");
 	type = SWP_TYPE(entry);
 	if (type >= nr_swapfiles) {
 		printk("Internal error: bad swap-device\n");
@@ -85,13 +83,27 @@
 		printk(KERN_ERR "VM: swap page is unlocked\n");
 		return;
 	}
-	
-	/* Make sure we are the only process doing I/O with this swap page. */
-	while (test_and_set_bit(offset,p->swap_lockmap)) {
-		run_task_queue(&tq_disk);
-		sleep_on(&lock_queue);
+
+	if (PageSwapCache(page)) {
+		/* Make sure we are the only process doing I/O with this swap page. */
+		while (test_and_set_bit(offset,p->swap_lockmap)) {
+			run_task_queue(&tq_disk);
+			sleep_on(&lock_queue);
+		}
+
+		/* 
+		 * Make sure that we have a swap cache association for this
+		 * page.  We need this to find which swap page to unlock once
+		 * the swap IO has completed to the physical page.  If the page
+		 * is not already in the cache, just overload the offset entry
+		 * as if it were: we are not allowed to manipulate the inode
+		 * hashing for locked pages.
+		 */
+		if (page->offset != entry) {
+			printk ("swap entry mismatch");
+			return;
+		}
 	}
-	
 	if (rw == READ) {
 		clear_bit(PG_uptodate, &page->flags);
 		kstat.pswpin++;
@@ -99,54 +111,25 @@
 		kstat.pswpout++;
 
 	atomic_inc(&page->count);
-	/* 
-	 * Make sure that we have a swap cache association for this
-	 * page.  We need this to find which swap page to unlock once
-	 * the swap IO has completed to the physical page.  If the page
-	 * is not already in the cache, just overload the offset entry
-	 * as if it were: we are not allowed to manipulate the inode
-	 * hashing for locked pages.
-	 */
-	if (!PageSwapCache(page)) {
-		printk(KERN_ERR "VM: swap page is not in swap cache\n");
-		return;
-	}
-	if (page->offset != entry) {
-		printk (KERN_ERR "VM: swap entry mismatch\n");
-		return;
-	}
-
 	if (p->swap_device) {
-		if (!wait) {
-			set_bit(PG_free_after, &page->flags);
-			set_bit(PG_decr_after, &page->flags);
-			set_bit(PG_swap_unlock_after, &page->flags);
-			atomic_inc(&nr_async_pages);
-		}
-		ll_rw_page(rw,p->swap_device,offset,buf);
-		/*
-		 * NOTE! We don't decrement the page count if we
-		 * don't wait - that will happen asynchronously
-		 * when the IO completes.
-		 */
-		if (!wait)
-			return;
-		wait_on_page(page);
+		zones[0] = offset;
+		zones_used = 1;
+		dev = p->swap_device;
+		block_size = PAGE_SIZE;
 	} else if (p->swap_file) {
 		struct inode *swapf = p->swap_file->d_inode;
-		unsigned int zones[PAGE_SIZE/512];
 		int i;
 		if (swapf->i_op->bmap == NULL
 			&& swapf->i_op->smap != NULL){
 			/*
-				With MS-DOS, we use msdos_smap which return
+				With MS-DOS, we use msdos_smap which returns
 				a sector number (not a cluster or block number).
 				It is a patch to enable the UMSDOS project.
 				Other people are working on better solution.
 
 				It sounds like ll_rw_swap_file defined
-				it operation size (sector size) based on
-				PAGE_SIZE and the number of block to read.
+				its operation size (sector size) based on
+				PAGE_SIZE and the number of blocks to read.
 				So using bmap or smap should work even if
 				smap will require more blocks.
 			*/
@@ -159,39 +142,72 @@
 					return;
 				}
 			}
+			block_size = 512;
 		}else{
 			int j;
 			unsigned int block = offset
 				<< (PAGE_SHIFT - swapf->i_sb->s_blocksize_bits);
 
-			for (i=0, j=0; j< PAGE_SIZE ; i++, j +=swapf->i_sb->s_blocksize)
+			block_size = swapf->i_sb->s_blocksize;
+			for (i=0, j=0; j< PAGE_SIZE ; i++, j += block_size)
 				if (!(zones[i] = bmap(swapf,block++))) {
 					printk("rw_swap_page: bad swap file\n");
 					return;
 				}
+			zones_used = i;
+			dev = swapf->i_dev;
 		}
-		ll_rw_swap_file(rw,swapf->i_dev, zones, i,buf);
-		/* Unlike ll_rw_page, ll_rw_swap_file won't unlock the
-		   page for us. */
-		clear_bit(PG_locked, &page->flags);
-		wake_up(&page->wait);
-	} else
+	} else {
 		printk(KERN_ERR "rw_swap_page: no swap file or device\n");
-
+		/* Do some cleaning up so if this ever happens we can hopefully
+		 * trigger controlled shutdown.
+		 */
+		if (PageSwapCache(page)) {
+			if (!test_and_clear_bit(offset,p->swap_lockmap))
+				printk("swap_after_unlock_page: lock already cleared\n");
+			wake_up(&lock_queue);
+		}
+		atomic_dec(&page->count);
+		return;
+	}
+ 	if (!wait) {
+ 		set_bit(PG_decr_after, &page->flags);
+ 		atomic_inc(&nr_async_pages);
+ 	}
+ 	if (PageSwapCache(page)) {
+ 		/* only lock/unlock swap cache pages! */
+ 		set_bit(PG_swap_unlock_after, &page->flags);
+ 	}
+ 	set_bit(PG_free_after, &page->flags);
+
+ 	/* block_size == PAGE_SIZE/zones_used */
+ 	brw_page(rw, page, dev, zones, block_size, 0);
+ 
+ 	/* Note! For consistency we do all of the logic,
+ 	 * decrementing the page count, and unlocking the page in the
+ 	 * swap lock map - in the IO completion handler.
+ 	 */
+ 	if (!wait) 
+ 		return;
+ 	wait_on_page(page);
 	/* This shouldn't happen, but check to be sure. */
-	if (atomic_read(&page->count) == 1)
+	if (atomic_read(&page->count) == 0)
 		printk(KERN_ERR "rw_swap_page: page unused while waiting!\n");
-	atomic_dec(&page->count);
-	if (offset && !test_and_clear_bit(offset,p->swap_lockmap))
-		printk(KERN_ERR "rw_swap_page: lock already cleared\n");
-	wake_up(&lock_queue);
+
 #ifdef DEBUG_SWAP
 	printk ("DebugVM: %s_swap_page finished on page %p (count %d)\n",
 		(rw == READ) ? "read" : "write", 
-		buf, atomic_read(&page->count));
+		(char *) page_adddress(page), 
+		atomic_read(&page->count));
 #endif
 }
 
+/* Note: We could remove this totally asynchronous function,
+ * and improve swap performance, and remove the need for the swap lock map,
+ * by not removing pages from the swap cache until after I/O has been
+ * processed and letting remove_from_page_cache decrement the swap count
+ * just before it removes the page from the page cache.
+ */
 /* This is run when asynchronous page I/O has completed. */
 void swap_after_unlock_page (unsigned long entry)
 {
@@ -214,6 +230,35 @@
 	wake_up(&lock_queue);
 }
 
+/* A simple wrapper so the base function doesn't need to enforce
+ * that all swap pages go through the swap cache!
+ */
+void rw_swap_page(int rw, unsigned long entry, char *buf, int wait)
+{
+	struct page *page = mem_map + MAP_NR(buf);
+
+	if (page->inode && page->inode != &swapper_inode)
+		panic ("Tried to swap a non-swapper page");
+
+	/*
+	 * Make sure that we have a swap cache association for this
+	 * page.  We need this to find which swap page to unlock once
+	 * the swap IO has completed to the physical page.  If the page
+	 * is not already in the cache, just overload the offset entry
+	 * as if it were: we are not allowed to manipulate the inode
+	 * hashing for locked pages.
+	 */
+	if (!PageSwapCache(page)) {
+		printk("VM: swap page is not in swap cache\n");
+		return;
+	}
+	if (page->offset != entry) {
+		printk ("swap entry mismatch");
+		return;
+	}
+	rw_swap_page_base(rw, entry, page, wait);
+}
+
 /*
  * Setting up a new swap file needs a simple wrapper just to read the 
  * swap signature.  SysV shared memory also needs a simple wrapper.
@@ -242,33 +287,23 @@
 	clear_bit(PG_swap_cache, &page->flags);
 }
 
-
-
 /*
- * Swap partitions are now read via brw_page.  ll_rw_page is an
- * asynchronous function now --- we must call wait_on_page afterwards
- * if synchronous IO is required.  
+ * shmfs needs a version that doesn't put the page in the page cache!
+ * The swap lock map insists that pages be in the page cache!
+ * Therefore we can't use it.  Later when we can remove the need for the
+ * lock map and we can reduce the number of functions exported.
  */
-void ll_rw_page(int rw, kdev_t dev, unsigned long offset, char * buffer)
+void rw_swap_page_nolock(int rw, unsigned long entry, char *buffer, int wait)
 {
-	int block = offset;
-	struct page *page;
-
-	switch (rw) {
-		case READ:
-			break;
-		case WRITE:
-			if (is_read_only(dev)) {
-				printk("Can't page to read-only device %s\n",
-					kdevname(dev));
-				return;
-			}
-			break;
-		default:
-			panic("ll_rw_page: bad block dev cmd, must be R/W");
-	}
-	page = mem_map + MAP_NR(buffer);
-	if (!PageLocked(page))
-		panic ("ll_rw_page: page not already locked");
-	brw_page(rw, page, dev, &block, PAGE_SIZE, 0);
+	struct page *page = mem_map + MAP_NR((unsigned long) buffer);
+	
+	if (!PageLocked(page)) {
+		printk("VM: rw_swap_page_nolock: page not locked!\n");
+		return;
+	}
+	if (PageSwapCache(page)) {
+		printk ("VM: rw_swap_page_nolock: page in swap cache!\n");
+		return;
+	}
+	rw_swap_page_base(rw, entry, page, wait);
 }
diff -u --recursive --new-file v2.1.132/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c
--- v2.1.132/linux/net/appletalk/aarp.c	Thu Nov 19 09:56:29 1998
+++ linux/net/appletalk/aarp.c	Wed Dec 23 09:44:42 1998
@@ -294,7 +294,7 @@
 	while((*n)!=NULL)
 	{
 		/* Expired ? */
-		if((*n)->expires_at < jiffies)
+		if(time_after(jiffies, (*n)->expires_at))
 		{
 			t= *n;
 			*n=(*n)->next;
diff -u --recursive --new-file v2.1.132/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.1.132/linux/net/appletalk/ddp.c	Tue Dec 22 14:16:59 1998
+++ linux/net/appletalk/ddp.c	Wed Dec 23 14:10:36 1998
@@ -31,12 +31,19 @@
  *						AppleTalk drivers, cleaned it.
  *		Rob Newberry		:	Added proxy AARP and AARP proc fs, 
  *						moved probing to AARP module.
+ *              Adrian Sun/ 
+ *              Michael Zuelsdorff      :       fix for net.0 packets. don't 
+ *                                              allow illegal ether/tokentalk
+ *                                              port assignment. we lose a 
+ *                                              valid localtalk port as a 
+ *                                              result.
+ *              
  *
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
- *
+ * 
  */
 
 #include <linux/config.h>
@@ -141,7 +148,7 @@
 			continue;
 	   	}
 
-	    	if(to->sat_addr.s_net == 0
+	    	if(to->sat_addr.s_net == ATADDR_ANYNET
 			&& to->sat_addr.s_node == ATADDR_BCAST
 			&& s->protinfo.af_at.src_net == atif->address.s_net)
 		{
@@ -156,7 +163,14 @@
 			break;
 	   	}
 
-	    	/* XXXX.0 */
+	    	/* XXXX.0 -- we got a request for this router. make sure
+		 * that the node is appropriately set. */
+		if (to->sat_addr.s_node == ATADDR_ANYNODE &&
+		    to->sat_addr.s_net != ATADDR_ANYNET &&
+		    atif->address.s_node == s->protinfo.af_at.src_node) {
+			to->sat_addr.s_node = atif->address.s_node;
+			break; 
+		}
 	}
 
 	return (s);
@@ -502,6 +516,12 @@
 			&& iface->address.s_net==net 
 			&& !(iface->status & ATIF_PROBE))
 			return (iface);
+
+		/* XXXX.0 -- net.0 returns the iface associated with net */
+		if ((node==ATADDR_ANYNODE) && (net != ATADDR_ANYNET) &&
+		    (ntohs(iface->nets.nr_firstnet) <= ntohs(net)) &&
+		    (ntohs(net) <= ntohs(iface->nets.nr_lastnet)))
+		        return (iface);
 	}
 
 	return (NULL);
diff -u --recursive --new-file v2.1.132/linux/net/bridge/br.c linux/net/bridge/br.c
--- v2.1.132/linux/net/bridge/br.c	Tue Dec 22 14:16:59 1998
+++ linux/net/bridge/br.c	Wed Dec 23 09:44:42 1998
@@ -1539,7 +1539,7 @@
 		f->mcast_timer = jiffies;
 	else {
 		if(f->mcast_count > max_mcast_per_period) {
-			if(jiffies > (f->mcast_timer + mcast_hold_time))
+			if(time_after(jiffies, f->mcast_timer + mcast_hold_time))
 				f->mcast_count = 0;
 			else	return 1;
 		}
diff -u --recursive --new-file v2.1.132/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.1.132/linux/net/ipv6/af_inet6.c	Mon Oct  5 13:13:49 1998
+++ linux/net/ipv6/af_inet6.c	Sun Dec 27 10:44:45 1998
@@ -477,7 +477,7 @@
 {
 	if (!unloadable) return 1;
 	/* We keep internally 3 raw sockets */
-	return __this_module.usecount - 3;
+	return atomic_read(&(__this_module.uc.usecount)) - 3;
 }
 #endif
 
diff -u --recursive --new-file v2.1.132/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.1.132/linux/net/ipx/af_ipx.c	Thu Nov 19 09:56:29 1998
+++ linux/net/ipx/af_ipx.c	Mon Dec 28 11:06:44 1998
@@ -50,6 +50,9 @@
  *	Revision 0.39:  SPX interfaces
  *	Revision 0.40:  Tiny SIOCGSTAMP fix (chris@cybernet.co.nz)
  *      Revision 0.41:  802.2TR removed (p.norton@computer.org)
+ *			Fixed connecting to primary net,
+ *			Automatic binding on send & receive,
+ *			Martijn van Oosterhout <kleptogimp@geocities.com>
  *
  *	Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT
  *	pair. Also, now usage count is managed this way
@@ -450,7 +453,57 @@
 	struct sock *sock1 = NULL, *sock2 = NULL;
 	struct sk_buff *skb1 = NULL, *skb2 = NULL;
 
-	sock1 = ipxitf_find_socket(intrfc, ipx->ipx_dest.sock);
+	if (intrfc == ipx_primary_net && ntohs(ipx->ipx_dest.sock) == 0x451) 
+	{
+		/* 
+	 	 * The packet's target is a NCP connection handler. We want to
+	 	 * hand it to the correct socket directly within the kernel,
+	 	 * so that the mars_nwe packet distribution process
+	 	 * does not have to do it. Here we only care about NCP and
+	 	 * BURST packets.
+	 	 * You might call this a hack, but believe me, you do not
+	 	 * want a complete NCP layer in the kernel, and this is
+	 	 * VERY fast as well.
+	 	 */
+	 	int connection = 0;
+
+	 	if (*((char*)(ipx+1)) == 0x22 &&  *((char*)(ipx+1)+1) == 0x22) 
+		{
+	  		/*
+			 * The packet is a NCP request
+			 */
+			connection = ( ((int) *((char*)(ipx+1)+5)) << 8 )
+		 	       | (int) *((char*)(ipx+1)+3);
+		} 
+		else if (*((char*)(ipx+1))== 0x77 &&  *((char*)(ipx+1)+1) == 0x77) 
+		{
+			/*
+			 * The packet is a BURST packet
+			 */
+			connection = ( ((int) *((char*)(ipx+1)+9)) << 8 )
+		 	       | (int) *((char*)(ipx+1)+8);
+		}
+
+        	if (connection) 
+		{
+			/*
+			 * Now we have to look for a special NCP connection handling
+			 * socket. Only these sockets have ipx_ncp_conn != 0, set
+			 * by SIOCIPXNCPCONN.
+			 */
+			for (sock1=intrfc->if_sklist;
+				(sock1 != NULL) &&
+				(sock1->protinfo.af_ipx.ipx_ncp_conn != connection);
+					sock1=sock1->next);
+		}
+        }
+        if (sock1 == NULL) 
+	{
+		/* No special socket found, forward the packet the
+		 * normal way.
+		 */
+		sock1 = ipxitf_find_socket(intrfc, ipx->ipx_dest.sock);
+	}
 
 	/*
 	 * We need to check if there is a primary net and if
@@ -1822,7 +1875,7 @@
 	}
 
 	/* protect IPX system stuff like routing/sap */
-	if(ntohs(addr->sipx_port) < IPX_MIN_EPHEMERAL_SOCKET && !suser())
+	if(ntohs(addr->sipx_port) < IPX_MIN_EPHEMERAL_SOCKET && !capable(CAP_NET_ADMIN))
 		return (-EACCES);
 
 	sk->protinfo.af_ipx.port = addr->sipx_port;
@@ -1930,7 +1983,8 @@
 			return (ret);
 	}
 
-	if(ipxrtr_lookup(addr->sipx_network) == NULL)
+        /* We can either connect to primary network or somewhere we can route to */
+	if( !(addr->sipx_network == 0 && ipx_primary_net != NULL) && ipxrtr_lookup(addr->sipx_network) == NULL)
 		return (-ENETUNREACH);
 
 	sk->protinfo.af_ipx.dest_addr.net  = addr->sipx_network;
@@ -2061,8 +2115,9 @@
 	int retval;
 	int flags = msg->msg_flags;
 
-	if(sk->zapped)
-		return (-EIO);	/* Socket not bound */
+	/* Socket gets bound below anyway */
+/*	if(sk->zapped)
+		return (-EIO); */	/* Socket not bound */
 	if(flags & ~MSG_DONTWAIT)
 		return (-EINVAL);
 
@@ -2120,6 +2175,26 @@
 	struct sk_buff *skb;
 	int copied, err;
 
+	/* put the autobinding in */
+	if(sk->protinfo.af_ipx.port == 0)
+	{
+		struct sockaddr_ipx uaddr;
+		int ret;
+
+		uaddr.sipx_port		= 0;
+		uaddr.sipx_network 	= 0;
+
+#ifdef CONFIG_IPX_INTERN
+		memcpy(uaddr.sipx_node, sk->protinfo.af_ipx.intrfc->if_node,
+		       IPX_NODE_LEN);
+#endif	/* CONFIG_IPX_INTERN */
+
+		ret = ipx_bind(sock, (struct sockaddr *)&uaddr,
+				sizeof(struct sockaddr_ipx));
+		if(ret != 0)
+			return (ret);
+	}
+	
 	if(sk->zapped)
 		return (-ENOTCONN);
 
@@ -2191,14 +2266,14 @@
 
 		case SIOCADDRT:
 		case SIOCDELRT:
-			if(!suser())
+			if(!capable(CAP_NET_ADMIN))
 				return (-EPERM);
 			return (ipxrtr_ioctl(cmd,(void *)arg));
 
 		case SIOCSIFADDR:
 		case SIOCAIPXITFCRT:
 		case SIOCAIPXPRISLT:
-			if(!suser())
+			if(!capable(CAP_NET_ADMIN))
 				return (-EPERM);
 
 		case SIOCGIFADDR:
@@ -2206,6 +2281,17 @@
 
 		case SIOCIPXCFGDATA:
 			return (ipxcfg_get_config_data((void *)arg));
+
+		case SIOCIPXNCPCONN:
+                {
+			/*
+			 * This socket wants to take care of the NCP connection
+			 * handed to us in arg.
+			 */
+                	if (!capable(CAP_NET_ADMIN))
+                		return(-EPERM);
+			return get_user(sk->protinfo.af_ipx.ipx_ncp_conn, (const unsigned short *)(arg));
+                }
 
 		case SIOCGSTAMP:
 		{
diff -u --recursive --new-file v2.1.132/linux/net/netrom/nr_dev.c linux/net/netrom/nr_dev.c
--- v2.1.132/linux/net/netrom/nr_dev.c	Thu Feb 12 20:56:15 1998
+++ linux/net/netrom/nr_dev.c	Mon Dec 28 11:06:44 1998
@@ -52,6 +52,8 @@
 #include <net/ax25.h>
 #include <net/netrom.h>
 
+#ifdef CONFIG_INET
+
 /*
  *	Only allow IP over NET/ROM frames through if the netrom device is up.
  */
@@ -81,37 +83,6 @@
 	return 1;
 }
 
-static int nr_header(struct sk_buff *skb, struct device *dev, unsigned short type,
-	void *daddr, void *saddr, unsigned len)
-{
-	unsigned char *buff = skb_push(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
-
-	memcpy(buff, (saddr != NULL) ? saddr : dev->dev_addr, dev->addr_len);
-	buff[6] &= ~AX25_CBIT;
-	buff[6] &= ~AX25_EBIT;
-	buff[6] |= AX25_SSSID_SPARE;
-	buff    += AX25_ADDR_LEN;
-
-	if (daddr != NULL)
-		memcpy(buff, daddr, dev->addr_len);
-	buff[6] &= ~AX25_CBIT;
-	buff[6] |= AX25_EBIT;
-	buff[6] |= AX25_SSSID_SPARE;
-	buff    += AX25_ADDR_LEN;
-
-	*buff++ = sysctl_netrom_network_ttl_initialiser;
-
-	*buff++ = NR_PROTO_IP;
-	*buff++ = NR_PROTO_IP;
-	*buff++ = 0;
-	*buff++ = 0;
-	*buff++ = NR_PROTOEXT;
-
-	if (daddr != NULL)
-		return 37;
-
-	return -37;
-}
 
 static int nr_rebuild_header(struct sk_buff *skb)
 {
@@ -121,10 +92,6 @@
 	unsigned char *bp = skb->data;
 
 	if (arp_find(bp + 7, skb)) {
-#if 0
-		/* BUGGGG! If arp_find returned 1, skb does not exist. --ANK*/
-		kfree_skb(skb);
-#endif
 		return 1;
 	}
 
@@ -156,6 +123,47 @@
 	stats->tx_bytes += skbn->len;
 
 	return 1;
+}
+
+#else
+
+static int nr_rebuild_header(struct sk_buff *skb)
+{
+	return 1;
+}
+
+#endif
+
+static int nr_header(struct sk_buff *skb, struct device *dev, unsigned short type,
+	void *daddr, void *saddr, unsigned len)
+{
+	unsigned char *buff = skb_push(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);
+
+	memcpy(buff, (saddr != NULL) ? saddr : dev->dev_addr, dev->addr_len);
+	buff[6] &= ~AX25_CBIT;
+	buff[6] &= ~AX25_EBIT;
+	buff[6] |= AX25_SSSID_SPARE;
+	buff    += AX25_ADDR_LEN;
+
+	if (daddr != NULL)
+		memcpy(buff, daddr, dev->addr_len);
+	buff[6] &= ~AX25_CBIT;
+	buff[6] |= AX25_EBIT;
+	buff[6] |= AX25_SSSID_SPARE;
+	buff    += AX25_ADDR_LEN;
+
+	*buff++ = sysctl_netrom_network_ttl_initialiser;
+
+	*buff++ = NR_PROTO_IP;
+	*buff++ = NR_PROTO_IP;
+	*buff++ = 0;
+	*buff++ = 0;
+	*buff++ = NR_PROTOEXT;
+
+	if (daddr != NULL)
+		return 37;
+
+	return -37;
 }
 
 static int nr_set_mac_address(struct device *dev, void *addr)
diff -u --recursive --new-file v2.1.132/linux/net/sched/sch_api.c linux/net/sched/sch_api.c
--- v2.1.132/linux/net/sched/sch_api.c	Sat Sep  5 16:46:42 1998
+++ linux/net/sched/sch_api.c	Wed Dec 23 09:44:42 1998
@@ -898,7 +898,7 @@
 	stop = jiffies + HZ/10;
 	PSCHED_GET_TIME(stamp);
 	do_gettimeofday(&tv);
-	while (jiffies < stop)
+	while (time_before(jiffies, stop))
 		barrier();
 	PSCHED_GET_TIME(stamp1);
 	do_gettimeofday(&tv1);
diff -u --recursive --new-file v2.1.132/linux/net/sunrpc/auth.c linux/net/sunrpc/auth.c
--- v2.1.132/linux/net/sunrpc/auth.c	Mon Apr  7 11:35:33 1997
+++ linux/net/sunrpc/auth.c	Wed Dec 23 09:44:42 1998
@@ -117,7 +117,7 @@
 				printk("RPC: rpcauth_gc_credcache looping!\n");
 				break;
 			}
-			if (!cred->cr_count && cred->cr_expire < jiffies) {
+			if (!cred->cr_count && time_after(jiffies, cred->cr_expire)) {
 				*q = cred->cr_next;
 				cred->cr_next = free;
 				free = cred;
@@ -160,7 +160,7 @@
 
 	nr = RPC_DO_ROOTOVERRIDE(task)? 0 : (current->uid % RPC_CREDCACHE_NR);
 
-	if (auth->au_nextgc < jiffies)
+	if (time_after(jiffies, auth->au_nextgc))
 		rpcauth_gc_credcache(auth);
 
 	q = &auth->au_credcache[nr];
diff -u --recursive --new-file v2.1.132/linux/net/sunrpc/xprt.c linux/net/sunrpc/xprt.c
--- v2.1.132/linux/net/sunrpc/xprt.c	Mon Oct  5 13:13:49 1998
+++ linux/net/sunrpc/xprt.c	Wed Dec 23 09:44:42 1998
@@ -293,7 +293,7 @@
 	if (xprt->nocong)
 		return;
 	if (result >= 0) {
-		if (xprt->cong < cwnd || jiffies < xprt->congtime)
+		if (xprt->cong < cwnd || time_before(jiffies, xprt->congtime))
 			return;
 		/* The (cwnd >> 1) term makes sure
 		 * the result gets rounded properly. */
@@ -543,7 +543,7 @@
 		pkt_cnt++;
 		pkt_len += req->rq_slen + copied;
 		pkt_rtt += jiffies - req->rq_xtime;
-		if (nextstat < jiffies) {
+		if (time_after(jiffies, nextstat)) {
 			printk("RPC: %lu %ld cwnd\n", jiffies, xprt->cwnd);
 			printk("RPC: %ld %ld %ld %ld stat\n",
 					jiffies, pkt_cnt, pkt_len, pkt_rtt);
diff -u --recursive --new-file v2.1.132/linux/net/wanrouter/wanmain.c linux/net/wanrouter/wanmain.c
--- v2.1.132/linux/net/wanrouter/wanmain.c	Tue Dec 22 14:16:59 1998
+++ linux/net/wanrouter/wanmain.c	Mon Dec 28 11:07:13 1998
@@ -27,6 +27,9 @@
 * May 17, 1998  K. Baranowski	Fixed SNAP encapsulation in wan_encapsulate
 * Dec 15, 1998  Arnaldo Melo    support for firmwares of up to 128000 bytes
 *                               check wandev->setup return value
+* Dec 22, 1998  Arnaldo Melo    vmalloc/vfree used in device_setup to allocate
+*                               kernel memory and copy configuration data to
+*                               kernel space (for big firmwares)
 *****************************************************************************/
 
 #include <linux/stddef.h>	/* offsetof(), etc. */
@@ -36,6 +39,7 @@
 #include <linux/malloc.h>	/* kmalloc(), kfree() */
 #include <linux/mm.h>		/* verify_area(), etc. */
 #include <linux/string.h>	/* inline mem*, str* functions */
+#include <linux/vmalloc.h>	/* vmalloc, vfree */
 #include <asm/segment.h>	/* kernel <-> user copy */
 #include <asm/byteorder.h>	/* htons(), etc. */
 #include <asm/uaccess.h>	/* copy_to/from_user */
@@ -100,7 +104,30 @@
 static unsigned char oui_802_2[] = { 0x00, 0x80, 0xC2 };
 #endif
 
-#ifdef MODULE
+#ifndef MODULE
+
+int wanrouter_init(void)
+{
+	int err;
+	extern void wanpipe_init(void);
+
+	printk(KERN_INFO "%s v%u.%u %s\n",
+		fullname, ROUTER_VERSION, ROUTER_RELEASE, copyright);
+	err = wanrouter_proc_init();
+	if (err)
+		printk(KERN_ERR "%s: can't create entry in proc filesystem!\n", modname);		
+
+	/*
+	 *	Initialise compiled in boards
+	 */		
+	 
+#ifdef CONFIG_VENDOR_SANGOMA
+	wanpipe_init();
+#endif	
+	return err;
+}
+
+#else
 
 /*
  *	Kernel Loadable Module Entry Points
@@ -139,14 +166,6 @@
 	wanrouter_proc_cleanup();
 }
 
-#else
-
-__initfunc(void wanrouter_init(void))
-{
-	int err = wanrouter_proc_init();
-	if (err) printk(KERN_ERR
-		"%s: can't create entry in proc filesystem!\n", modname);
-}
 #endif
 
 /*
@@ -440,7 +459,7 @@
 static int device_setup (wan_device_t* wandev, wandev_conf_t* u_conf)
 {
 	void* data;
-	wandev_conf_t* conf;
+	wandev_conf_t *conf;
 	int err= -EINVAL;
 
 	if (wandev->setup == NULL)	/* Nothing to do ? */
@@ -464,7 +483,7 @@
 		if(conf->data_size > 128000 || conf->data_size < 0){
 			goto bail;
 		}
-		data = kmalloc(conf->data_size, GFP_KERNEL);
+		data = vmalloc(conf->data_size);
 		if (data)
 		{
 			if(!copy_from_user(data, conf->data, conf->data_size))
@@ -473,10 +492,13 @@
 				err = wandev->setup(wandev,conf);
 			}
 			else 
-				err = -ENOBUFS;
+				err = -EFAULT;
 		}
+		else
+			err = -ENOBUFS;
+			
 		if (data)
-			kfree(data);
+			vfree(data);
 	}
 bail:
 	kfree(conf);
diff -u --recursive --new-file v2.1.132/linux/scripts/Menuconfig linux/scripts/Menuconfig
--- v2.1.132/linux/scripts/Menuconfig	Thu May  7 22:51:56 1998
+++ linux/scripts/Menuconfig	Wed Dec 23 07:26:32 1998
@@ -47,6 +47,16 @@
 #
 # 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
 # texts.
+#
+# 12 Dec 1998, Michael Elizabeth Chastain (mec@shout.net)
+# Remove a /tmp security hole in get_def (also makes it faster).
+# Give uninitialized variables canonical values rather than null value.
+# Change a lot of places to call set_x_info uniformly.
+# Take out message about preparing version (old sound driver cruft).
+#
+# 13 Dec 1998, Riley H Williams (rhw@bigfoot.com)
+# When an error occurs, actually display the error message as well as
+# our comments thereon.
 
 
 #
@@ -65,20 +75,24 @@
 #
 set -h +o posix
 
-#
-# Converts "# xxx is not..." to xxx=n
-#
-parse_config () {
-	sed -e 's/# \(.*\) is not.*/\1=n/'
-}
 
-#
-# Parses the defconfig file to set the default for a new parameter.
-#
-function get_def () {
-	parse_config < arch/$ARCH/defconfig | grep "^$1=" > /tmp/conf.$$
-	. /tmp/conf.$$
-	rm /tmp/conf.$$
+
+# Given a configuration variable, set the global variable $x to its value,
+# and the global variable $info to the string " (NEW)" if this is a new
+# variable.
+#
+# This function looks for: (1) the current value, or (2) the default value
+# from the arch-dependent defconfig file, or (3) a default passed by the caller.
+
+function set_x_info () {
+    eval x=\$$1
+    if [ -z "$x" ]; then
+	eval `sed -n -e 's/# \(.*\) is not set.*/\1=n/' -e "/^$1=/p" arch/$ARCH/defconfig`
+	eval x=\${$1:-"$2"}
+	eval $1=$x
+	eval INFO_$1="' (NEW)'"
+    fi
+    eval info="\$INFO_$1"
 }
 
 #
@@ -93,19 +107,6 @@
 load_functions () {
 
 #
-# Macro for setting the x and info varibles. get's default from defconfig
-# file if it's a new parameter.
-#
-function set_x () {
-	eval x=\$$1
-	if [ -z "$x" ]; then
-		get_def "$1"
-		eval x=\${$1:-'n'} INFO_$1="' (NEW)'"
-	fi
-	eval info="\$INFO_$1"
-}
-
-#
 # Additional comments
 #
 function comment () {
@@ -125,7 +126,7 @@
 # which calls our local bool function.
 #
 function bool () {
-	set_x "$2"
+	set_x_info "$2" "n"
 
 	case $x in
 	y|m)	flag="*" ;;
@@ -148,7 +149,7 @@
 	then
 		bool "$1" "$2"
 	else
-		set_x "$2"
+		set_x_info "$2" "n"
 	
 		case $x in
 		y) flag="*" ;;
@@ -193,9 +194,9 @@
 # Add a menu item which will call our local int function.
 # 
 function int () {
-	eval $2=\${$2:-"$3"} x=\$$2
+	set_x_info "$2" "$3"
 
-	echo -ne "'$2' '($x) $1' " >>MCmenu
+	echo -ne "'$2' '($x) $1$info' " >>MCmenu
 
 	echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' ;}" >>MCradiolists
 }
@@ -204,9 +205,10 @@
 # Add a menu item which will call our local hex function.
 # 
 function hex () {
-	eval $2=\${$2:-"$3"} x=\${$2##*[x,X]}
+	set_x_info "$2" "$3"
+	x=${x##*[x,X]}
 
-	echo -ne "'$2' '($x) $1' " >>MCmenu
+	echo -ne "'$2' '($x) $1$info' " >>MCmenu
 
 	echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' ;}" >>MCradiolists
 }
@@ -215,9 +217,9 @@
 # Add a menu item which will call our local string function.
 # 
 function string () {
-	eval $2=\${$2:-"$3"} x=\$$2
+	set_x_info "$2" "$3"
 
-	echo -ne "'$2' '     $1: \"$x\"' " >>MCmenu
+	echo -ne "'$2' '     $1: \"$x\"$info' " >>MCmenu
 
 	echo -e "function $2 () { l_string '$1' '$2' '$3' '$x' ;}" >>MCradiolists
 }
@@ -370,7 +372,7 @@
 # Same as bool() except options are (Module/No)
 #
 function mod_bool () {
-	set_x "$2"
+	set_x_info "$2" "n"
 
 	case $x in
 	y|m) flag='M' ;;
@@ -722,14 +724,20 @@
 	do
 		comment_ctr=0		#So comment lines get unique tags
 
-		$1 "$default"		#Create the lxdialog menu & functions
+		$1 "$default" 2> MCerror #Create the lxdialog menu & functions
 
 		if [ "$?" != "0" ]
 		then
 			clear
 			cat <<EOM
+
 Menuconfig has encountered a possible error in one of the kernel's
-configuration files and is unable to continue.
+configuration files and is unable to continue.  Here is the error
+report:
+
+EOM
+			sed 's/^/ Q> /' MCerror
+			cat <<EOM
 
 Please report this to the maintainer <mec@shout.net>.  You may also
 send a problem report to <linux-kernel@vger.rutgers.edu>.
@@ -741,6 +749,7 @@
 			cleanup
 			exit 1
 		fi
+		rm -f MCerror
 
 		. ./MCradiolists		#Source the menu's functions
 
@@ -778,6 +787,7 @@
 			stty sane
 			clear
 			cat <<EOM
+
 There seems to be a problem with the lxdialog companion utility which is
 built prior to running Menuconfig.  Usually this is an indicator that you
 have upgraded/downgraded your ncurses libraries and did not remove the 
@@ -954,61 +964,41 @@
 	echo -n "Saving your kernel configuration."
 
 	#
-	# Macro for setting the newval varible. get's default from defconfig
-	# file if it's a new parameter and it has not been shown yet.
-	#
-	function set_newval () {
-		eval newval=\$$1
-		if [ -z "$newval" ]; then
-			get_def "$1"
-			eval newval=\${$1:-'n'}
-		fi
-	}
-
-	#
 	# Now, let's redefine the configuration functions for final
 	# output to the config files.
 	#
 	# Nested function definitions, YIPEE!
 	#
 	function bool () {
-		set_newval "$2"
-		eval define_bool "$2" "$newval"
+		set_x_info "$2" "n"
+		eval define_bool "$2" "$x"
 	}
 
 	function tristate () {
-		set_newval "$2"
-		eval define_bool "$2" "$newval"
+		set_x_info "$2" "n"
+		eval define_bool "$2" "$x"
 	}
 
 	function dep_tristate () {
-		set_newval "$2"
-
-		if eval [ "_$3" = "_m" ]
-		then
-			if [ "$newval" = "y" ]
-			then
-				newval="m"
-			fi
-		fi
-
-		define_bool "$2" "$newval"
+		set_x_info "$2" "n"
+		if [ "$3" = "m" -a "$x" = "y" ]; then x="m"; fi
+		define_bool "$2" "$x"
 	}
 
 	function int () {
-		eval x=\${$2:-"$3"}
+		set_x_info "$2" "$3"
 		echo "$2=$x" 		>>$CONFIG
 		echo "#define $2 ($x)"	>>$CONFIG_H
 	}
 
 	function hex () {
-		eval x=\${$2:-"$3"}
+		set_x_info "$2" "$3"
 		echo "$2=$x" 			 >>$CONFIG
 		echo "#define $2 0x${x##*[x,X]}" >>$CONFIG_H
 	}
 
 	function string () {
-		eval x=\${$2:-"$3"}
+		set_x_info "$2" "$3"
 		echo "$2=\"$x\"" 			 >>$CONFIG
 		echo "#define $2 \"$x\""	>>$CONFIG_H
 	}
@@ -1250,10 +1240,8 @@
 # Fresh new log.
 >.menuconfig.log
 
-echo -n "Preparing configuration scripts: version" 
-
 # Load the functions used by the config.in files.
-echo -n ", functions"
+echo -n "Preparing scripts: functions" 
 load_functions
 
 if [ ! -e $CONFIG_IN ]
