diff -u --recursive --new-file v2.1.42/linux/CREDITS linux/CREDITS
--- v2.1.42/linux/CREDITS	Mon May 19 12:57:38 1997
+++ linux/CREDITS	Sun Jun 15 11:00:19 1997
@@ -508,6 +508,13 @@
 S: Toronto, Ontario, M5S 3A6 
 S: Canada
 
+N: Richard Günther
+E: richard.guenther@student.uni-tuebingen.de
+D: binfmt_misc
+S: Fichtenweg 3/511
+S: 72076 Tübingen
+S: Germany
+
 N: Danny ter Haar
 E: dth@cistron.nl
 D: /proc/procinfo, reboot on panic , kernel pre-patch tester ;)
@@ -1387,7 +1394,7 @@
 S: Spain
 
 N: Linus Torvalds
-E: Linus.Torvalds@Helsinki.FI
+E: torvalds@transmeta.com
 W: http://www.cs.helsinki.fi/~torvalds/
 P: 1024/A86B35C5 96 54 50 29 EC 11 44 7A  BE 67 3C 24 03 13 62 C8
 D: Original kernel hacker
@@ -1556,6 +1563,11 @@
 S: 820 4th St. N.
 S: Fargo, North Dakota  58122
 S: USA
+
+N: Steven Whitehouse
+E: SteveW@ACM.org
+D: Linux DECnet project: http://eeshack3.swan.ac.uk/~gw7rrm/DECnet/index.html
+D: Minor debugging of other networking protocols.
 
 N: Hans-Joachim Widmaier
 E: hjw@zvw.de
diff -u --recursive --new-file v2.1.42/linux/Documentation/00-INDEX linux/Documentation/00-INDEX
--- v2.1.42/linux/Documentation/00-INDEX	Tue May 13 22:40:59 1997
+++ linux/Documentation/00-INDEX	Thu Jun 12 16:22:04 1997
@@ -18,6 +18,8 @@
 	- how to access I/O mapped memory from within device drivers.
 SMP.txt
 	- notes, and "To Fix" list for multi-processor Linux. (see smp.tex)
+binfmt_misc.txt
+	- info on the kernel support for extra binary formats.
 cdrom/
 	- directory with information on the CD-ROM drivers that Linux has.
 devices.tex
diff -u --recursive --new-file v2.1.42/linux/Documentation/Changes linux/Documentation/Changes
--- v2.1.42/linux/Documentation/Changes	Tue May 13 22:40:59 1997
+++ linux/Documentation/Changes	Thu Jun 12 16:22:04 1997
@@ -29,28 +29,30 @@
    Also, don't forget http://www.linuxhq.com/ for all your Linux kernel
 needs.
 
-Last updated: May 12, 1997.
+Last updated: May 31, 1997.
 Current Author: Chris Ricker (gt1355b@prism.gatech.edu).
 
 Current Minimal Requirements
 ****************************
 
    Upgrade to at *least* these software revisions before thinking you've
-encountered a bug!
+encountered a bug!  If you're unsure what version you're currently
+running, the suggested command should tell you.
 
-- Kernel modules	 modutils-2.1.34
-- Gnu C 		 2.7.2.1
-- Binutils		 2.8.0.3
-- Linux C Library	 5.4.23
-- Dynamic Linker (ld.so) 1.8.5
-- Linux C++ Library	 2.7.2.1
-- Procps		 1.01
-- Mount                  2.6g
-- Net-tools              1.41
+- Kernel modules	 modutils-2.1.34         ; insmod -v
+- Gnu C 		 2.7.2.1                 ; gcc --version
+- Binutils		 2.8.1.0.1               ; ld -v
+- Linux C Library	 5.4.23                  ; ls -l /lib/libc.so.*
+- Dynamic Linker (ld.so) 1.8.5                   ; ldd -v
+- Linux C++ Library	 2.7.2.1                 ; ls -l /usr/lib/libg++.so.*
+- Procps		 1.01                    ; ps --version
+- Procinfo               0.11                    ; procinfo -v
+- Mount                  2.6g                    ; mount --version
+- Net-tools              1.41                    ; hostname -V
 - Loadlin                1.6a
-- Sh-utils               1.16
-- Autofs                 0.3.0
-- NFS                    0.4.21
+- Sh-utils               1.16                    ; expr --v
+- Autofs                 0.3.3                   ; automount --version
+- NFS                    0.4.21                  ; showmount --version
 
 Upgrade notes
 *************
@@ -86,6 +88,9 @@
 later than 1.8.5, avoid 1.8.10 as it introduces a few bugs that are
 fixed in later releases.
 
+   If you upgrade to libc-5.4.x, you may also need to upgrade ypbind if
+you're using NIS.
+
 Modules
 =======
 
@@ -134,6 +139,15 @@
    For support for new features like IPv6, upgrade to the latest
 net-tools.
 
+Memory
+======
+
+   As of 2.1.41, the format of /proc/meminfo has changed.  This broke
+many memory utils, which have to be upgraded.  Get the new procinfo and
+procps (which, AFAIK, is not yet available) to fix this.  Until you
+upgrade, programs which read /proc/meminfo will seg-fault or give an
+error.
+
 Mount and network file systems
 ==============================
 
@@ -178,37 +192,18 @@
 /dev/lp0 with the new Plug-and-Play driver.  If printing breaks with
 the new driver, try checking your lpd configuration.
 
-How to know the version of the installed programs
-*************************************************
-
-   There are some simple methods useful to know the version of the
-installed programs and libraries.
-
-Binutils: ld -v
-Gnu C: gcc -v or gcc --version
-Kbd: dumpkeys -h
-Ld.so: ldd -v
-Libc: ls -l /lib/libc.so.*
-Libc++: ls -l /usr/lib/libg++.so.*
-Modutils: insmod -V
-Mount: mount --version
-Net-tools:  hostname -V
-Procps: ps --version
-RPM:  rpm --version
-Sh-utils:  expr --v
-
 Where to get the files
 **********************
 
 Binutils
 ========
 
-The 2.8.0.3 release:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.0.3.bin.tar.gz
-ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.0.3.bin.tar.gz
+The 2.8.1.0.1 release:
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/binutils-2.8.1.0.1.bin.tar.gz
+ftp://sunsite.unc.edu/pub/Linux/GCC/binutils-2.8.1.0.1.bin.tar.gz
 Installation notes:
-ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.0.3
-ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.0.3
+ftp://tsx-11.mit.edu/pub/linux/packages/GCC/release.binutils-2.8.1.0.1
+ftp://sunsite.unc.edu/pub/Linux/GCC/release.binutils-2.8.1.0.1
 
 Gnu C
 =====
@@ -258,9 +253,15 @@
 ================
 
 The 1.01 release:
-ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.01.tgz
+ftp://tsx-11.mit.edu/pub/linux/sources/usr.bin/procps-1.01.tar.gz
 ftp://sunsite.unc.edu/pub/Linux/system/status/ps/procps-1.01.tgz
 
+Procinfo utilities
+==================
+
+The 0.11 release:
+ftp://ftp.cistron.nl/pub/people/svm/procinfo-0.11.tar.gz
+
 RPM utilities
 =============
 
@@ -304,8 +305,8 @@
 Autofs
 ======
 
-The 0.3.0 release:
-ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-0.3.0.tar.gz
+The 0.3.3 release:
+ftp://ftp.kernel.org/pub/linux/daemons/autofs/autofs-0.3.3.tar.gz
 
 NFS
 ===
@@ -320,6 +321,12 @@
 The 0.41 release:
 ftp://ftp.london.uk.eu.org/pub/ipv6/net-tools-1.41.tar.gz
 ftp://ftp.cs-ipv6.lancs.ac.uk/pub/Code/Linux/Net_Tools/net-tools-1.41.tar.gz
+
+Ypbind
+======
+
+The 3.2 release:
+ftp://ftp.uni-paderborn.de/pub/linux/local/yp/ypbind-3.2.tar.gz
 
 Other Info
 ==========
diff -u --recursive --new-file v2.1.42/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- v2.1.42/linux/Documentation/Configure.help	Thu May 29 21:53:03 1997
+++ linux/Documentation/Configure.help	Sun Jun 15 14:05:27 1997
@@ -795,6 +795,20 @@
   will be called binfmt_java.o. If you don't know what to answer at
   this point then answer Y.
 
+Kernel support for MISC binaries
+CONFIG_BINFMT_MISC
+  This enables the possibility to plug wrapper-driven binary formats
+  into the kernel. You will like this especially when you use programs
+  that need an interpreter to run like Java, Python or Emacs-Lisp. And
+  you don't need CONFIG_BINFMT_JAVA or CONFIG_BINFMT_EM86, as this is
+  a more general feature.
+  You can do other nice things, too. Read Documentation/binfmt_misc.txt
+  to learn how to use this feature.
+  You must enable CONFIG_PROC_FS to use this part of the kernel.
+  You may answer M for module support and later load the module when
+  you have use for it.
+  If you don't know what to answer at this point, say Y.
+
 Processor type
 CONFIG_M386
   This is the processor type of your CPU. This information is used for
@@ -2371,7 +2385,8 @@
   compatible cards. If you have a dual mode card (i.e. a WSS cards
   with a SoundBlaster emulation) you should say N here and Y to
   "Soundcard modem support for WSS and Crystal cards", below, because
-  this usually results in better performance.
+  this usually results in better performance. This option also supports
+  SB16/32/64 in full duplex mode.
 
 Soundcard modem support for WSS and Crystal cards
 CONFIG_SOUNDMODEM_WSS
@@ -2389,26 +2404,27 @@
   compatible to popular modems using TCM3105 or AM7911. The demodulator
   requires about 12% of the CPU power of a Pentium 75 CPU per channel.
 
-Soundmodem 1200 baud AFSK using floating point
-CONFIG_SOUNDMODEM_AFSK1200_FP
-  This option enables floating point calculations to be used for the
-  AFSK1200 baud modem. The Intel Pentium is a perverted chip because
-  integer multiplications are, although easier to implement in silicon,
-  an order of magnitude slower than floating point calculations.
-  Enabling this option uses a highly optimized assembler routine for
-  correlations, modeled after the one published by Phil Karn, KA9Q.
-  This reduces the computing power needed on Intel Pentium chips to
-  about 50%. On the other hand, Pentium clones with faster integer
-  multiply and slower floating point multiply will probably take
-  longer with this option turned on. As a rule of thumb, enable it for
-  Intel Pentium and Pentium Pro processors, and disable it for
-  anything else.
-  I (sailer@ife.ee.ethz.ch) am very interested in figures. If you are
-  willing to give me a feedback, please compile the driver once with
-  this option enabled and once with it disabled, and send me the cycle
-  counter numbers obtained with both compilations, and your exact
-  chip. The cycle counter numbers can be obtained with a recent
-  sethdlc utility.
+Soundcard modem support for 2400 baud AFSK modulation (7.3728MHz crystal)
+CONFIG_SOUNDMODEM_AFSK2400_7
+  This option enables the soundmodem driver 2400 baud AFSK modem,
+  compatible to TCM3105 modems (over-)clocked with a 7.3728MHz crystal.
+  Note that the availability of this driver does _not_ imply that I
+  recommend building such links. It is only here since users especially
+  in eastern europe have asked me to do so. In fact this modulation scheme
+  has many disadvantages, mainly its incompatibility with many transceiver
+  designs and the fact that the TCM3105 (if used) is operated widely outside
+  its specifications.
+
+Soundcard modem support for 2400 baud AFSK modulation (8MHz crystal)
+CONFIG_SOUNDMODEM_AFSK2400_8
+  This option enables the soundmodem driver 2400 baud AFSK modem,
+  compatible to TCM3105 modems (over-)clocked with an 8MHz crystal.
+  Note that the availability of this driver does _not_ imply that I
+  recommend building such links. It is only here since users especially
+  in eastern europe have asked me to do so. In fact this modulation scheme
+  has many disadvantages, mainly its incompatibility with many transceiver
+  designs and the fact that the TCM3105 (if used) is operated widely outside
+  its specifications.
 
 Soundcard modem support for 4800 baud HAPN-1 modulation
 CONFIG_SOUNDMODEM_HAPN4800
@@ -2426,27 +2442,6 @@
   can only use one protocol at a time, depending on what the other end
   can understand).
 
-Soundcard modem support using floating point arithmetic
-CONFIG_SOUNDMODEM_FLOAT
-  This option enables floating point calculations to be used for the
-  AFSK1200 baud modem. The Intel Pentium is a perverted chip because
-  integer multiplications are, although easier to implement in silicon,
-  an order of a magnitude slower than floating point calculations.
-  Enabling this option uses a highly optimized assembler routine for
-  correlations, modeled after the one published by Phil Karn, KA9Q.
-  This reduces the computing power needed on Intel Pentium chips to
-  about 50%. On the other hand, Pentium clones with faster integer
-  multiply and slower floating point multiply will probably take
-  longer with this option turned on. As a rule of thumb, enable it for
-  Intel Pentium and Pentium Pro processors, and disable it for
-  anything else.
-  I (sailer@ife.ee.ethz.ch) am very interested in figures. If you are
-  willing to give me a feedback, please compile the driver once with
-  this option enabled and once with it disabled, and send me the cycle
-  counter numbers obtained with both compilations, and your exact
-  chip. The cycle counter numbers can be obtained by a recent sethdlc
-  utility.
-
 Serial port KISS driver for AX.25
 CONFIG_MKISS
   KISS is the protocol used to send IP traffic over AX.25 radio
@@ -3617,6 +3612,14 @@
   be called isp16.o. If you want to compile it as a module, say M here
   and read Documentation/modules.txt.
 
+Preload dcache
+CONFIG_DCACHE_PRELOAD
+  Preloading will create dcache entries when a directory is scanned
+  (e.g. with ls) the *first* time. This should speed up successive
+  inode lookups, but also can consume large amounts of memory.
+  Please report speedups (or slowdowns due to the memory usage if they
+  occur) to schoebel@informatik.uni-stuttgart.de .
+
 Quota support
 CONFIG_QUOTA
   If you say Y here, you will be able to set per user limits for disk
@@ -3627,6 +3630,138 @@
   quota support is only useful for multi user systems. If unsure, say
   N.
 
+Online mirror support
+CONFIG_OMIRR
+  omirr is a package for _symmetric_ mirroring of files over the
+  internet. In contrast to rdist, the online mirror daemon (omirrd)
+  is running all the time and transfers any changes on the file system
+  as soon as possible to all other servers. Symmetric means that all
+  servers have equal rights in changing a file: the last changer of a
+  file will win. This is the same behaviour as multiple processes
+  operating on a global file system. In effect, omirr can do the same
+  as nfs mounts, but will have better performance since the data is
+  stored on local disks. In contrast to a cache filesystem which has a
+  dedicated master copy, broken connections and/or servers are no problem
+  for continuing work on the remaining ones, because there is no master
+  copy. You must say Y if you want to use omirrd, but you should (but
+  need not) say N if you don't (for performance reasons).
+
+Filename translation support
+CONFIG_TRANS_NAMES
+  Normally used only when you want diskless clients to mount the root
+  filesystem of the server. If unsure, or if you don't have clients, select N.
+  When selected, filenames, directory names etc become context-sensitive.
+  If you have a file named "/etc/config#host=banana#", it will appear
+  (by default) as hardlinked to "/etc/config" on host "banana", while on host
+  "mango" another file "/etc/config#host=mango#" will appear as been
+  hardlinked to "/etc/config". The default behaviour can be changed
+  by setting the _first_ environment variable NAMETRANS to a colon-separated
+  list of suffixes which are tried in the specified order. For example,
+  in 'env - NAMETRANS=#host=mango#:#ktype=diskless# "`env`" command ...' the
+  command will see the same files as if it had been executed on host "mango"
+  with a diskless kernel. Using NAMETRANS supersedes _all_ default
+  translations. Thus translations can be generally switched off by an
+  empty list, e.g. 'env - NAMETRANS= "`env`" command ...'.
+  Note that some system utililies like tar, dump, restore should
+  be used with translation switched off, in order to avoid doubled
+  space in archive files and when extracting from them. Also, make sure
+  that nfsd, mountd (and similar ones like samba daemons) run without
+  translation, in order to avoid doubled (or even wrong) translation
+  at the server and at the client. You can automatically force the creation
+  of context-dependent filenames if there exists a template filename like
+  "/etc/mtab#host=CREATE#". As soon as a process running on "mango" tries
+  to create a file "/etc/mtab", the version "/etc/mtab#host=mango#" is
+  created instead (which appears in turn as hardlinked to "/etc/mtab").
+  Note that if you want to make "/etc/fstab" context-dependend, you should
+  execute "touch /etc/mtab#host=CREATE#" and
+  "touch /etc/mtab.tmp#host=CREATE#", because mount, umount and others
+  running on different hosts would otherwise try to create one shared
+  /etc/mtab which would result in a clash. Also one should execute
+  "touch /etc/nologin#host=CREATE#" to prevent global side effects from
+  shutdown resp. runlevel.
+
+Restrict translation to gid
+CONFIG_TRANS_RESTRICT
+  When selected, default translations are carried out only if the parent
+  directory of the context-sensitive file belongs to a specific group id
+  (gid). Trying to translate names everywhere will decrease performance of
+  file openings. Normally translations are used only in system configuration
+  files but not in ordinary user filespace. So you should change the gid of
+  directories containing context-dependent files to some special group like
+  "adm" (group id 4) and enable this option. As a result, users will not
+  notice any performance degradation resulting from filename translation.
+  Note that translations resulting from the first environment variable
+  "NAMETRANS=..." are always carried out regardless of the gid of directories.
+  Beware, before turning on this option make sure all directories containing
+  context-dependent files belong to the special group, or system
+  initialization may fail. In unsure, select N.
+
+Group id (gid) for translation restriction
+CONFIG_TRANS_GID
+  Default name translations will be carried out only inside directories
+  belonging to the group id (gid) you can specify here.
+  Default is 4 (group "adm").
+
+Nodename (hostname) translation
+CONFIG_TR_NODENAME
+  Enables translation of name suffixes like in "/etc/config#host=banana#".
+  The syntax is <filename>#host=<hostname>#. The hostname can be queried
+  with the command "uname -n". Normally this option is used heavily when
+  translation is enabled. If unsure, say Y.
+
+Kernelname translation
+CONFIG_TR_KERNNAME
+  Enables translation of name suffixes like in "/etc/config#kname=default#".
+  The string is hard compiled into the kernel by the following option.
+  Useful if your kernel does not know the hostname at boot time, and there
+  is no way to tell the hostname by lilo or bootp. Please avoid using this
+  option and prefer CONFIG_TR_NODENAME wherever possible. When mounting
+  the root over nfs, the own hostname must be known at boot time anyway;
+  this option is just for special use.
+  Note that the default translations are tried in the order as occuring
+  in the configuration, that is 1) host 2) kname 3) ktype 4) machine
+  5) system. If unsure, say Y.
+
+String for kernelname translation
+CONFIG_KERNNAME
+  Enter the string you want to compile into the kernel. The string
+  will be used as context in context-depenant file like
+  "/etc/config#kname=<hostname>#".
+
+Kerneltype translation
+CONFIG_TR_KERNTYPE
+  Enables translation of name suffixes like in "/etc/config#ktype=default#".
+  The syntax is <filename>#ktype=<string>#. The string is hard compiled
+  in the kernel by the following option. Use if you want to create
+  different kernels with different behaviour. For example, use the string
+  "default" on your server, and use "diskless" on all your diskless clients
+  (and perhaps "dataless" on dataless clients). This way you can avoid
+  dozens of "config#host=<something># with same contents and you have no
+  effort when new machines are added. If unsure, say Y.
+
+String for kerneltype translation
+CONFIG_KERNTYPE
+  Enter the string you want to compile into the kernel. The string
+  will be used as context in context-depenant file like
+  "/etc/config#ktype=default#". If your kernel is to be used on a server,
+  you probably can use "default" here. If your kernel is intended for
+  a diskless client, you probably should enter "diskless" here.
+
+Machine type translation
+CONFIG_TR_MACHINE
+  Enables translation of name suffixes like in "/etc/config#machine=i486#".
+  The syntax is <filename>#machine=<id>#. The machine types can be queried
+  with the command "uname -m". Normally used only on multi-architecture
+  installations. If unsure, say Y.
+
+System name translation
+CONFIG_TR_SYSNAME
+  Enables translation of name suffixes like in "/etc/config#system=Linux#".
+  The syntax is <filename>#system=<id>#. The system name can be queried
+  with the command "uname -s". Currently only supportet by Linux, but
+  hopefully other operating systems will pick up the idea of context-dependent
+  translations. If unsure, say Y.
+
 Minix fs support
 CONFIG_MINIX_FS
   Minix is a simple operating system used in many classes about
@@ -4702,6 +4837,17 @@
   said Y to "Kernel profiling support", you must be a kernel hacker and
   hence you know what this is about :-)
 
+Magic System Request Key support
+CONFIG_MAGIC_SYSRQ
+  This is for kernel hackers who want to have some control over the
+  system even if the system crashes during kernel debugging (e.g., to
+  flush the disks, reboot the system immediately or dump some status
+  information). This is accomplished by pressing various keys while
+  holding SysRq (Alt+PrintScreen). As you are expected to be a kernel
+  hacker to use this, the simple rule about learning what do the keys
+  mean is "Use the source, Luke!" -- read drivers/char/sysrq.c.
+  Don't say Y unless you really know what does this hack do.
+ 
 ISDN subsystem
 CONFIG_ISDN
   ISDN ("Integrated Services Digital Networks", called RNIS in France)
diff -u --recursive --new-file v2.1.42/linux/Documentation/binfmt_misc.txt linux/Documentation/binfmt_misc.txt
--- v2.1.42/linux/Documentation/binfmt_misc.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/binfmt_misc.txt	Thu Jun 12 16:22:04 1997
@@ -0,0 +1,83 @@
+	Kernel Support for miscellaneous (your favourite) Binary Formats v1.1
+	====================================================================
+
+This Kernel feature allows to invoke almost (for restrictions see below) every
+program by simply typing it's name in the shell.
+This includes for example compiled Java(TM), Python or Emacs programs.
+
+To achieve this you must tell binfmt_misc which interpreter has to be invoked with
+which binary. Binfmt_misc recognises the binary-type by matching some bytes at the
+beginning of the file with a magic byte sequence (masking out specified bits) you
+have supplied. Binfmt_misc can also recognise a filename extension (aka .com) and
+optionally strip it off.
+
+To actually register a new binary type, you have to set up a string looking like
+:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon your
+needs) and echo it to /proc/sys/fs/binfmt_misc/register.
+Here is what the fields mean:
+ - 'name' is an identifier string. A new /proc file will be created with this
+   this name below /proc/sys/fs/binfmt_misc
+ - 'type' is the type of recognition. Give 'M' for magic and 'E' for extension.
+   Give the corresponding lowercase letter to let binfmt_misc strip of the
+   filename extension.
+ - 'offset' is the offset of the magic/mask in the file counted in bytes. This
+   defaults to 0 if you omit it (i.e. you write ':name:type::magic...')
+ - 'magic' is the byte sequence binfmt_misc is matching for. The magic string
+   may contain hex-encoded characters like \x0a or \xA4. In a shell environment
+   you will have to write \\x0a to prevent the shell from eating your \.
+   If you chose filename extension matching, this is the extension to be
+   recognised (the \x0a specials are not allowed). Extension matching is case
+   sensitive!
+ - 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some bits
+   from matching by supplying a string like magic and as long as magic. The
+   mask is anded with the byte sequence of the file.
+ - 'interpreter' is the program that should be invoked with the binary as first
+   argument (specify the full path)
+There are some restrictions:
+ - the whole register string may not exceed 255 characters
+ - the magic must resist in the first 128 bytes of the file, i.e. offset+size(magic)
+   has to be less than 128
+ - the interpreter string may not exceed 127 characters
+You may want to add the binary formats in one of your /etc/rc scripts during boot-up.
+Read the manual of your init program to figure out how to do this right.
+
+
+A few examples (assumed you are in /proc/sys/fs/binfmt_misc):
+
+- enable Java(TM)-support (like binfmt_java):
+  echo ":Java:M::\xca\xfe\xba\xbe::/usr/local/bin/java:" > register
+  echo :Applet:M::\<\!--applet::/usr/local/bin/appletviewer: > register
+- enable support for em86 (like binfmt_em86, for Alpha AXP only):
+  echo ":i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
+  echo ":i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register
+- enable support for packed DOS applications (pre-configured dosemu hdimages):
+  echo ":DEXE:M::\x0eDEX::/usr/bin/dosexec:" > register
+- enable support for DOS/Windows executables (using mzloader and dosemu/wine):
+  echo ":DOSWin:M::MZ::/usr/sbin/mzloader:" > register
+  echo ":DOS:E::com::/usr/sbin/mzloader:" > register
+
+
+You can enable/disable binfmt_misc or one binary type by echoing 0 (to disable)
+or 1 (to enable) to /proc/sys/fs/binfmt_misc/status or /proc/.../the_name.
+Catting the file tells you the current status of binfmt_misc/the entry.
+
+You can remove one entry or all entries by echoing -1 to /proc/.../the_name
+or /proc/sys/fs/binfmt_misc/status.
+
+
+HINTS:
+======
+
+If your interpreter does not look at the PATH to determine the full name of the
+program, you need to invoke a wrapper-script (like the following for java) first:
+
+#!/bin/sh
+FOO=`which $1` || exit 1
+shift
+/usr/local/bin/java $FOO ${1+$@}
+
+
+There is a web page about binfmt_misc at
+http://www.anatom.uni-tuebingen.de/~richi/linux/binfmt_misc.html
+
+Richard Günther, richard.guenther@student.uni-tuebingen.de
diff -u --recursive --new-file v2.1.42/linux/Documentation/transname.txt linux/Documentation/transname.txt
--- v2.1.42/linux/Documentation/transname.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/transname.txt	Thu Jun 12 16:22:04 1997
@@ -0,0 +1,264 @@
+Transname version 1.9 (C) 1997 Thomas Schoebel-Theuer
+
+transname enables diskless clients, X-terminals etc to mount the
+*root filesystem* of the server. This make administration of
+large pools a lot easier.
+
+Wherefore is linux-2.0.21-transname.patch?
+
+Currently different diskless clients must have their root / on different
+directories on the server, beause each client has _some_ different
+configuration files. However, most files (typically about 99%) have the same
+contents on the clients and on the server, but have to be replicated
+(and maintained separately) just because of the 1% differences.
+This duplication causes very large efforts in practise, since at least
+the /etc directory has to be duplicated for every client. Even in /etc
+many files are identical, for example sendmail.cf, initrc scripts and
+others. Maintaining a large pool means to ensure coherence amoung the
+duplicates. Classical methods like symlinks are unconvenient
+for this task because they have to be valid in the view of mounted
+filesystems at all clients, not at the server.
+
+Linux transname overcomes this problem by allowing filenames
+to be context-dependend. For example, if you have a file /etc/config
+that should differ on the hosts "myserver" and "myclient", you just
+create two different files named /etc/config#host=myserver# and
+/etc/config#host=myclient# . On host "myserver", the file
+/etc/config#host=myserver# will appear as if it were hardlinked to
+file /etc/config (without the #...=...# suffix). On host "myclient",
+the corresponding other file will appear as /etc/config. So you
+can access the right file contents under the _same_ name, depending
+on which host you are working.
+
+A similar concept can be found in elder HP-UX versions, but with
+so-called "hidden directories" which don't allow contemporary viewing
+all versions by default. In contrast, transname shows all context-dependent
+files in the dir listing and they can be edited using the
+fully qualified name.
+
+Transname was developped for and is used at our Linux pool at the
+University of Stuttgart with good results. Maintainance of the pool is
+at a minimum, and adding new clients is a child's play. No worry with
+keeping up mail configurations, newly installed tools, changed /etc/services,
+/etc/shells, /etc/resolv.conf and many, many others. In contrast to a
+sophisticated symlink solution, adding a new file to the /etc directory
+is seen immediately by all clients.
+
+An example for the use of linux-2.0-transname.patch:
+
+For example, you can make your /etc/fstab context-dependend. If you want
+to do that, you should create an /etc/fstab#ktype=default# for the
+server and an /etc/fstab#ktype=diskless# for all clients. This is because
+your clients may not yet know their own hostname when they attempt to mount
+the root filesystem. You can compile in the kerneltypes "default" and
+"diskless" into different kernels for servers and clients. Of course,
+if your clients boot via bootp and know their names when mounting the root,
+you can use /etc/fstab#host=myclient# instead. But at least servers
+booting from disk normally dont know their hostname at root mount time,
+so you can mix methods and use /etc/fstab#ktype=default# for the server,
+/etc/fstab#ktype=diskless# for the majority of the clients and
+/etc/fstab#host=myclient# for some specific client, because translation
+of #host=...# is given precedence over #ktype=...# by default.
+
+This sort of name translation works with any underlying file system
+and with any inode type (i.e. with directories, symlinks, devices etc),
+because it is implemented in the VFS layer of the kernel. Currently,
+five types of default translations are supported:
+
+ * <name>#host=<hostname>#  depends on the hostname, see "uname -n"
+ * <name>#kname=<string>#   works with a hard compiled-in string
+ * <name>#ktype=<string>#   works with a hard compiled-in string
+ * <name>#machine=<id>#     depends on architecture, see "uname -m"
+ * <name>#system=<id>#      currently only supported by Linux, see "uname -s"
+
+Others may be added in future.
+
+The current translation are displayed at boot time in the kernel messages
+for easier debugging, and can be retrieved by reading
+/proc/sys/kernel/nametrans which is a special file containing the currently
+valid translations.
+
+The default translations change whenever the hostname(1) is set or changed.
+Thus, the hostname is not set (or set to the name "(none)") at boot time
+before init(8) sets it. So, if you want to use the hostname before that
+moment, there are three ways:
+
+ a) set the hostname before via bootp or similar.
+ b) use the compiled-in translations kname and ktype solely.
+ c) set all translations by lilo (or on the boot command line) with
+    kernel parameter   nametrans=#host=banana#:#ktype=diskless# ,
+    thus overriding and hiding the default (built-in) translations.
+
+Note that by supplying the colon-separated list of at most 16 suffixes, you
+can also use other translation types that are not defined in the default
+translations. However, you must ensure that the syntax #...=...# is correct.
+The specified contexts will be tried in the specified order *instead* of the
+default translations. 
+
+You can override the default (or parameter-supplied) translations at runtime
+by executing
+echo "#host=$HOST#:#ktype=diskless#:#myconfig=something#" > /proc/sys/kernel/nametrans
+However, after doing this (or setting as kernel parameter) the built-in
+default translations have no effect any more, thus changing the hostname
+will not be reflected in the overridden translations. You can switch
+back to the default translations by executing
+echo "" > /proc/sys/kernel/nametrans
+
+Another drawback is that administration tools currently are not aware of
+context-dependend files, so you cannot switch between contexts inside
+one tool session. However, you can simulate administration sessions
+on the server as if they were running on some client. To do this,
+you have to set an environment variable NAMETRANS which has to be the
+*first* environment variable in the list. For example, you can execute
+'env - NAMETRANS=#host=mango#:#ktype=diskless# "`env`" command ...'
+where the command will see the same files as if it had been executed on host
+"mango" with a "diskless" kernel. To switch off translations entirely, use
+an empty list, e.g. 'env - NAMETRANS= "`env`" command ...'.
+
+Hopefully the creators of administration tools and maintainers of Linux 
+distributions will support changing environments in future, so that
+maintaining different views will be very easy.
+
+Some hints:
+
+Archivers like tar, dump, restore should be used with translation
+switched off, in order to avoid doubled space in archive files and when
+extracting from them. Also, make sure that nfsd, mountd (and similar ones
+like samba daemons) run without translation, in order to avoid doubled
+(or even wrong) translation at the server and at the client. You can
+automatically force the creation of context-dependent filenames if there
+exists a template filename like /etc/mtab#host=CREATE#. As soon as a
+process running on "mango" tries to create a file /etc/mtab, the version
+/etc/mtab#host=mango# is created instead (which appears in turn as
+hardlinked to /etc/mtab). Note that if you want to make /etc/fstab
+context-dependend, you should execute "touch /etc/mtab#host=CREATE#" and
+"touch /etc/mtab.tmp#host=CREATE#", because mount, umount and others
+running on different hosts would otherwise try to create one shared
+/etc/mtab which would result in a clash. Also one should execute
+"touch /etc/nologin#host=CREATE#" to prevent global side effects from
+shutdown resp. runlevel.
+
+Which files you have to make context-dependent will differ for different
+needs and different applications. Hopefully some day a standard will
+cover the most common cases and the mist common Linux distributions.
+A HOWTO on this subject is in preparation.
+
+How to install linux-2.0.21-transname.patch?
+
+First of all, keep a backup of your kernel on your disk. Second, keep a
+floppy with a miniroot handy, so you can boot from the floppy, mount
+your harddisk root filesystem and change the names of your configuration
+files back to their old names in case of emergency.
+
+Then, make a kernel with transname support enabled. With "make config"
+or "make xconfig", just go to the section "filesystems". Take a look at
+the help texts that are associated with the transname options, they tell
+you further hints not mentioned in this README. Then build your kernel as
+usual, install it with a *new* kernel-filename, add a *new* entry to
+/etc/lilo.conf and run lilo. **DONT CHANGE** any configuration files for the
+first reboot!
+
+Just reboot the new kernel and play a little bit around with
+creating context-dependend filenames in your home directory.
+Try all modes including setting NAMETRANS to different values.
+
+As an example for the changes necessary on our LST-1.8-based Linux pool,
+here is the output of the command
+find / /tmp -xdev -name "*#*#" -print | sort -u | xargs ls -ld
+
+-r--r--r--   1 root     root         1725 Dec 21  1995 /etc/X11R6/xdm/xdm-config#host=eiche#
+-r--r--r--   3 root     root         9509 Feb 15 17:35 /etc/XF86Config#host=balsa#
+-r--r--r--   1 root     root         9401 Feb 15 17:34 /etc/XF86Config#host=eiche#
+-rw-r--r--   1 root     root         9820 Feb 21 17:00 /etc/XF86Config#host=fichte#
+-rw-r--r--   1 root     root         9822 Feb 14 15:45 /etc/XF86Config#host=laerche#
+-r--r--r--   3 root     root         9509 Feb 15 17:35 /etc/XF86Config#host=mahagoni#
+-r--r--r--   3 root     root         9509 Feb 15 17:35 /etc/XF86Config#host=palisander#
+-r--r--r--   2 root     root         9509 Feb 15 17:41 /etc/XF86Config#host=pcbs10#
+-r--r--r--   2 root     root         9509 Feb 15 17:41 /etc/XF86Config#host=pcbs11#
+-rw-r--r--   1 root     root          586 Jun 11 23:13 /etc/fstab#ktype=default#
+-rw-r--r--   1 root     root          242 May 29 17:35 /etc/fstab#ktype=diskless#
+-rw-------   1 root     root          338 Jun 14 16:37 /etc/lilo.conf#host=eiche#
+-rw-------   1 root     root         5236 Dec 16  1995 /etc/lst.cnf#host=balsa#
+-rw-------   1 root     root         5254 Dec 16  1995 /etc/lst.cnf#host=eiche#
+-rw-------   1 root     root         5236 Dec 19  1995 /etc/lst.cnf#host=fichte#
+-rw-------   1 root     root         5236 Jan 11 13:47 /etc/lst.cnf#host=laerche#
+-rw-------   1 root     root         5236 Feb 14 16:57 /etc/lst.cnf#host=mahagoni#
+-rw-------   1 root     root         5236 Jan  4  1996 /etc/lst.cnf#host=palisander#
+-rw-------   1 root     root         5236 Feb 15 13:57 /etc/lst.cnf#host=pcbs10#
+-rw-------   1 root     root         5236 Feb 14 17:06 /etc/lst.cnf#host=pcbs11#
+-rw-r--r--   1 root     root            0 Dec 18  1995 /etc/mtab#host=CREATE#
+-rw-r--r--   1 root     root          157 Jun 23 21:16 /etc/mtab#host=balsa#
+-rw-r--r--   1 root     root          466 Jul  1 16:15 /etc/mtab#host=eiche#
+-rw-r--r--   1 root     root          239 Jul  4 11:10 /etc/mtab#host=fichte#
+-rw-r--r--   1 root     root          239 Jun 18 14:17 /etc/mtab#host=laerche#
+-rw-r--r--   1 root     root          239 May 23 10:50 /etc/mtab#host=mahagoni#
+-rw-r--r--   1 root     root          239 Jul  3 10:36 /etc/mtab#host=palisander#
+-rw-r--r--   1 root     root           47 Feb 15 14:57 /etc/mtab#host=pcbs10#
+-rw-r--r--   1 root     root           47 Feb 14 20:04 /etc/mtab#host=pcbs11#
+-rw-r--r--   1 root     root            0 Dec 18  1995 /etc/mtab.tmp#host=CREATE#
+-rw-r--r--   1 root     root            0 Dec 19  1995 /etc/nologin#host=CREATE#
+----------   1 root     root          115 Feb 15 14:57 /etc/nologin#host=pcbs10#
+----------   1 root     root          115 Feb 14 20:04 /etc/nologin#host=pcbs11#
+-rw-r--r--   1 root     root         4818 Dec 16  1995 /etc/system.cnf#host=balsa#
+lrwxrwxrwx   1 root     root           25 Dec 22  1995 /etc/system.cnf#host=eiche# -> system.cnf#ktype=default#
+-rw-r--r--   1 root     root         4821 Dec 19  1995 /etc/system.cnf#host=fichte#
+-rw-r--r--   1 root     root         4824 Jan 11 13:47 /etc/system.cnf#host=laerche#
+-rw-r--r--   1 root     root         4827 Feb 14 16:57 /etc/system.cnf#host=mahagoni#
+-rw-r--r--   1 root     root         4833 Jan  4  1996 /etc/system.cnf#host=palisander#
+-rw-r--r--   1 root     root         4840 Feb 15 14:10 /etc/system.cnf#host=pcbs10#
+-rw-r--r--   1 root     root         4846 Feb 14 18:23 /etc/system.cnf#host=pcbs11#
+-rw-r--r--   1 root     root         4818 Dec 13  1995 /etc/system.cnf#ktype=default#
+drwxrwxrwt  16 root     root         3072 Jul  4 14:29 /tmp#ktype=default#
+lrwxrwxrwx   1 root     root           26 Jul  4 14:22 /tmp#ktype=diskless# -> /tmp#ktype=default#/client
+-rw-rw-rw-   1 root     root            0 Feb 15 14:57 /tmp/client#host=CREATE#
+drwxrwxrwx   4 root     root         1024 Jun 28 12:15 /tmp/client#host=balsa#
+drwxrwxrwx   3 root     root         1024 Jul  4 11:10 /tmp/client#host=fichte#
+drwxrwxrwx   3 root     root         1024 Jun 18 14:18 /tmp/client#host=laerche#
+drwxrwxrwx   3 root     root         1024 May 24 13:06 /tmp/client#host=mahagoni#
+drwxrwxrwx   3 root     root         1024 Jul  3 10:37 /tmp/client#host=palisander#
+drwxrwxrwx   4 root     root         1024 Feb 15 14:57 /tmp/client#host=pcbs10#
+drwxrwxrwx   3 root     root         1024 Feb 20 06:43 /tmp/client#host=pcbs11#
+lrwxrwxrwx   1 root     root            9 Feb 15 13:58 /usr/X11R6/bin/X#host=pcbs10# -> XF86_SVGA
+lrwxrwxrwx   1 root     root            9 Feb 14 17:37 /usr/X11R6/bin/X#host=pcbs11# -> XF86_SVGA
+lrwxrwxrwx   1 root     root            7 Feb 14 17:15 /usr/X11R6/bin/X#ktype=diskless# -> XF86_S3
+drwxr-xr-x  22 root     root         1024 Dec 13  1995 /var#host=balsa#
+drwxr-xr-x  23 root     root         1024 Jan 12 14:22 /var#host=eiche#
+drwxr-xr-x  22 root     root         1024 Dec 13  1995 /var#host=fichte#
+drwxr-xr-x  22 root     root         1024 Dec 13  1995 /var#host=laerche#
+drwxr-xr-x  22 root     root         1024 Dec 13  1995 /var#host=mahagoni#
+drwxr-xr-x  22 root     root         1024 Dec 13  1995 /var#host=palisander#
+drwxr-xr-x  22 root     root         1024 Dec 13  1995 /var#host=pcbs10#
+drwxr-xr-x  22 root     root         1024 Dec 13  1995 /var#host=pcbs11#
+
+Notes: The /tmp directory has an own filesystem on server "eiche",
+in order to prevent users from filling the whole filestore (we dont use
+quotas). Each client needs a different /tmp because of possible name clashes.
+Also, the whole /var hierarchy is kept differently to prevent any risk, but
+that could be optimized perhaps. Note that nfsd and mountd have been
+replaced by a script which switches off translations, in the style
+
+-rwxr-xr-x   2 root     root           70 Mar 22 12:54 /usr/sbin/rpc.mountd
+-rwxr-xr-x   1 root     root        32772 Jun 11  1995 /usr/sbin/rpc.mountd.notrans
+-rwxr-xr-x   2 root     root           70 Mar 22 12:54 /usr/sbin/rpc.nfsd
+-rwxr-xr-x   1 root     root        45060 Jun 11  1995 /usr/sbin/rpc.nfsd.notrans
+
+where /usr/sbin/rpc.mountd has the contents
+
+#!/bin/sh
+exec /usr/bin/env - NAMETRANS= "`/usr/bin/env`" $0.notrans $*
+
+Of course, that could be improved, but is a quick hack to get things work.
+
+Enjoy,
+
+-- Thomas
+
+
+The author can be contacted under
+   schoebel@informatik.uni-stuttgart.de
+or snailmail
+   Thomas Schoebel-Theuer
+   Institut fuer Informatik
+   Breitwiesenstr. 20-22
+   D-70565 Stuttgart
+
diff -u --recursive --new-file v2.1.42/linux/MAINTAINERS linux/MAINTAINERS
--- v2.1.42/linux/MAINTAINERS	Sat May 24 09:10:22 1997
+++ linux/MAINTAINERS	Thu Jun 12 16:22:05 1997
@@ -125,6 +125,12 @@
 L:	netatalk@umich.edu
 S:	Maintained
 
+DECnet NETWORK LAYER
+P:	Steven Whitehouse
+M:	SteveW@ACM.org
+L:	netdev@roxanne.nuclecu.unam.mx
+S:	Maintained
+
 AX.25 NETWORK LAYER
 P:	Jon Naylor
 M:	jsn@cs.nott.ac.uk
diff -u --recursive --new-file v2.1.42/linux/Makefile linux/Makefile
--- v2.1.42/linux/Makefile	Thu May 29 21:53:03 1997
+++ linux/Makefile	Thu Jun 12 16:22:05 1997
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 42
+SUBLEVEL = 43
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
diff -u --recursive --new-file v2.1.42/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- v2.1.42/linux/arch/alpha/config.in	Wed Apr 16 14:14:59 1997
+++ linux/arch/alpha/config.in	Thu Jun 12 16:22:05 1997
@@ -94,10 +94,11 @@
 bool 'Sysctl support' CONFIG_SYSCTL
 tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
-tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
   tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
 fi
+tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
 tristate 'Parallel port support' CONFIG_PNP_PARPORT
 endmenu
 
@@ -172,4 +173,5 @@
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
diff -u --recursive --new-file v2.1.42/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c
--- v2.1.42/linux/arch/alpha/kernel/osf_sys.c	Wed Apr 23 19:01:14 1997
+++ linux/arch/alpha/kernel/osf_sys.c	Thu Jun 12 16:22:05 1997
@@ -295,7 +295,7 @@
 	retval = verify_area(VERIFY_WRITE, buffer, bufsiz);
 	if (retval)
 		goto out;
-	retval = namei(path, &inode);
+	retval = namei(NAM_FOLLOW_LINK, path, &inode);
 	if (retval)
 		goto out;
 	retval = -ENOSYS;
@@ -376,7 +376,7 @@
 	struct file_operations *fops;
 	int retval;
 
-	retval = namei(name, &inode);
+	retval = namei(NAM_FOLLOW_LINK, name, &inode);
 	if (retval)
 		return retval;
 	if (!S_ISBLK(inode->i_mode)) {
@@ -845,14 +845,12 @@
 					unsigned long nbytes,
 					int *start, void *arg)
 {
-	extern unsigned long rdfpcr(void);
 	unsigned long w;
 
 	switch (op) {
 	case GSI_IEEE_FP_CONTROL:
-		/* build and return current fp control word: */
-		w = current->tss.flags & IEEE_TRAP_ENABLE_MASK;
-		w |= ((rdfpcr() >> 52) << 17) & IEEE_STATUS_MASK;
+		/* Return current software fp control & status bits.  */
+		w = current->tss.flags & IEEE_SW_MASK;
 		if (put_user(w, (unsigned long *) buffer))
 			return -EFAULT;
 		return 0;
@@ -883,16 +881,32 @@
 					unsigned long nbytes,
 					int *start, void *arg)
 {
-	unsigned long v, w, i;
-
 	switch (op) {
-	case SSI_IEEE_FP_CONTROL:
-		/* update trap enable bits: */
-		if (get_user(w, (unsigned long *) buffer))
+	case SSI_IEEE_FP_CONTROL: {
+		unsigned long swcr, fpcr;
+
+		/* 
+		 * Alpha Architecture Handbook 4.7.7.3:
+		 * To be fully IEEE compiant, we must track the current IEEE
+		 * exception state in software, because spurrious bits can be
+		 * set in the trap shadow of a software-complete insn.
+		 */
+
+		/* Update softare trap enable bits.  */
+		if (get_user(swcr, (unsigned long *)buffer))
 			return -EFAULT;
-		current->tss.flags &= ~IEEE_TRAP_ENABLE_MASK;
-		current->tss.flags |= (w & IEEE_TRAP_ENABLE_MASK);
+		current->tss.flags &= ~IEEE_SW_MASK;
+		current->tss.flags |= swcr & IEEE_SW_MASK;
+
+		/* Update the real fpcr.  For exceptions that are disabled in
+		   software but have not been seen, enable the exception in
+		   hardware so that we can update our software status mask.  */
+		fpcr = rdfpcr() & (~FPCR_MASK | FPCR_DYN_MASK);
+		fpcr = ieee_swcr_to_fpcr(swcr | (~swcr & IEEE_STATUS_MASK)>>16);
+		wrfpcr(fpcr);
+		   
 		return 0;
+	}
 
 	case SSI_IEEE_STATE_AT_SIGNAL:
 	case SSI_IEEE_IGNORE_STATE_AT_SIGNAL:
@@ -903,7 +917,9 @@
 		 */
 		break;
 
- 	case SSI_NVPAIRS:
+ 	case SSI_NVPAIRS: {
+		unsigned long v, w, i;
+		
  		for (i = 0; i < nbytes; ++i) {
  			if (get_user(v, 2*i + (unsigned int *)buffer))
  				return -EFAULT;
@@ -922,6 +938,7 @@
  			}
  		}
  		return 0;
+	}
  
 	default:
 		break;
diff -u --recursive --new-file v2.1.42/linux/arch/alpha/math-emu/fp-emul.c linux/arch/alpha/math-emu/fp-emul.c
--- v2.1.42/linux/arch/alpha/math-emu/fp-emul.c	Tue Oct 29 04:02:04 1996
+++ linux/arch/alpha/math-emu/fp-emul.c	Thu Jun 12 16:22:05 1997
@@ -13,9 +13,9 @@
 #define OPC_INTL	0x11
 #define OPC_INTS	0x12
 #define OPC_INTM	0x13
-#define OPC_FLTV	0x14
-#define OPC_FLTI	0x15
-#define OPC_FLTL	0x16
+#define OPC_FLTV	0x15
+#define OPC_FLTI	0x16
+#define OPC_FLTL	0x17
 
 #define OPC_MISC	0x18
 
@@ -298,19 +298,26 @@
 	 *
 	 *	- Set the appropriate bits in the FPCR
 	 *	- If the specified exception is enabled in the FPCR,
-	 *	  return.  The caller (mxr_signal_handler) will dispatch
+	 *	  return.  The caller (entArith) will dispatch
 	 *	  the appropriate signal to the translated program.
+	 *
+	 * In addition, properly track the exception state in software
+	 * as described in the Alpha Architectre Handbook section 4.7.7.3.
 	 */
 	if (res) {
-		fpcr |= FPCR_SUM | res;
+		/* Record exceptions in software control word.  */
+		current->tss.flags = fpcw |= res >> 35;
+
+		/* Update hardware control register */
+		fpcr &= (~FPCR_MASK | FPCR_DYN_MASK);
+		fpcr |= ieee_swcr_to_fpcr(fpcw | (~fpcw&IEEE_STATUS_MASK)>>16);
 		wrfpcr(fpcr);
-		if (((res & FPCR_INV) && (fpcw & IEEE_TRAP_ENABLE_INV)) ||
-		    ((res & FPCR_DZE) && (fpcw & IEEE_TRAP_ENABLE_DZE)) ||
-		    ((res & FPCR_OVF) && (fpcw & IEEE_TRAP_ENABLE_OVF)) ||
-		    ((res & FPCR_UNF) && (fpcw & IEEE_TRAP_ENABLE_UNF)) ||
-		    ((res & FPCR_INE) && (fpcw & IEEE_TRAP_ENABLE_INE)))
+
+		/* Do we generate a signal?  */
+		if (res >> 51 & fpcw & IEEE_TRAP_ENABLE_MASK)
 			return 0;
 	}
+
 	/*
 	 * Whoo-kay... we got this far, and we're not generating a signal
 	 * to the translated program.  All that remains is to write the
@@ -326,6 +333,7 @@
 {
 	unsigned long trigger_pc = regs->pc - 4;
 	unsigned long insn, opcode, rc;
+
 	/*
 	 * Turn off the bits corresponding to registers that are the
 	 * target of instructions that set bits in the exception
diff -u --recursive --new-file v2.1.42/linux/arch/i386/config.in linux/arch/i386/config.in
--- v2.1.42/linux/arch/i386/config.in	Sun Apr 13 10:18:20 1997
+++ linux/arch/i386/config.in	Thu Jun 12 16:22:05 1997
@@ -34,6 +34,7 @@
 bool 'Sysctl support' CONFIG_SYSCTL
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
+tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
 fi
@@ -117,4 +118,5 @@
 if [ "$CONFIG_PROFILE" = "y" ]; then
   int ' Profile shift count' CONFIG_PROFILE_SHIFT 2
 fi
+bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ
 endmenu
diff -u --recursive --new-file v2.1.42/linux/arch/i386/defconfig linux/arch/i386/defconfig
--- v2.1.42/linux/arch/i386/defconfig	Tue May 13 22:41:00 1997
+++ linux/arch/i386/defconfig	Thu Jun 12 16:22:05 1997
@@ -25,6 +25,7 @@
 CONFIG_SYSCTL=y
 CONFIG_BINFMT_AOUT=y
 CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
 # CONFIG_M386 is not set
 # CONFIG_M486 is not set
 # CONFIG_M586 is not set
@@ -190,6 +191,9 @@
 # Filesystems
 #
 # CONFIG_QUOTA is not set
+# CONFIG_DCACHE_PRELOAD is not set
+# CONFIG_OMIRR is not set
+# CONFIG_TRANS_NAMES is not set
 CONFIG_MINIX_FS=y
 CONFIG_EXT2_FS=y
 CONFIG_FAT_FS=y
@@ -241,3 +245,4 @@
 # Kernel hacking
 #
 # CONFIG_PROFILE is not set
+# CONFIG_MAGIC_SYSRQ is not set
diff -u --recursive --new-file v2.1.42/linux/arch/i386/kernel/head.S linux/arch/i386/kernel/head.S
--- v2.1.42/linux/arch/i386/kernel/head.S	Tue May 13 22:41:00 1997
+++ linux/arch/i386/kernel/head.S	Thu Jun 12 16:22:05 1997
@@ -532,8 +532,8 @@
 	.quad 0x0000000000000000	/* not used */
 	.quad 0x00cf9a000000ffff	/* 0x10 kernel 4GB code at 0x00000000 */
 	.quad 0x00cf92000000ffff	/* 0x18 kernel 4GB data at 0x00000000 */
-	.quad 0x00cbfa000000ffff	/* 0x23 user   3GB code at 0x00000000 */
-	.quad 0x00cbf2000000ffff	/* 0x2b user   3GB data at 0x00000000 */
+	.quad 0x00cffa000000ffff	/* 0x23 user   4GB code at 0x00000000 */
+	.quad 0x00cff2000000ffff	/* 0x2b user   4GB data at 0x00000000 */
 	.quad 0x0000000000000000	/* not used */
 	.quad 0x0000000000000000	/* not used */
 	.fill 2*NR_TASKS,8,0		/* space for LDT's and TSS's etc */
diff -u --recursive --new-file v2.1.42/linux/arch/i386/kernel/irq.c linux/arch/i386/kernel/irq.c
--- v2.1.42/linux/arch/i386/kernel/irq.c	Tue May 13 22:41:01 1997
+++ linux/arch/i386/kernel/irq.c	Thu Jun 12 16:22:05 1997
@@ -142,21 +142,6 @@
  * the operations that are needed to keep the AT interrupt-controller
  * happy. They are also written to be fast - and to disable interrupts
  * as little as humanly possible.
- *
- * NOTE! These macros expand to three different handlers for each line: one
- * complete handler that does all the fancy stuff (including signal handling),
- * and one fast handler that is meant for simple IRQ's that want to be
- * atomic. The specific handler is chosen depending on the SA_INTERRUPT
- * flag when installing a handler. Finally, one "bad interrupt" handler, that
- * is used when no handler is present.
- *
- * The timer interrupt is handled specially to insure that the jiffies
- * variable is updated at all times.  Specifically, the timer interrupt is
- * just like the complete handlers except that it is invoked with interrupts
- * disabled and should never re-enable them.  If other interrupts were
- * allowed to be processed while the timer interrupt is active, then the
- * other interrupts would have to avoid using the jiffies variable for delay
- * and interval timing operations to avoid hanging the system.
  */
 
 #if NR_IRQS != 16
@@ -539,6 +524,9 @@
 	status = 0;
 	action = *(irq + irq_action);
 	if (action) {
+		if (!(action->flags & SA_INTERRUPT))
+			__sti();
+
 		do {
 			status |= action->flags;
 			action->handler(irq, action->dev_id, &regs);
@@ -546,7 +534,6 @@
 		} while (action);
 		if (status & SA_SAMPLE_RANDOM)
 			add_interrupt_randomness(irq);
-
 		__cli();
 		spin_lock(&irq_controller_lock);
 		unmask_irq(irq);
diff -u --recursive --new-file v2.1.42/linux/arch/i386/kernel/irq.h linux/arch/i386/kernel/irq.h
--- v2.1.42/linux/arch/i386/kernel/irq.h	Mon May 19 12:57:38 1997
+++ linux/arch/i386/kernel/irq.h	Thu Jun 12 16:22:05 1997
@@ -9,24 +9,10 @@
 
 #ifdef __SMP__
 
-#undef INIT_STUCK
-#define INIT_STUCK 200000000
-
-#undef STUCK
-#define STUCK \
-if (!--stuck) {printk("irq_enter stuck (irq=%d, cpu=%d, global=%d)\n",irq,cpu,global_irq_holder); stuck = INIT_STUCK;}
-
 static inline void irq_enter(int cpu, int irq)
 {
-	int stuck = INIT_STUCK;
-
 	hardirq_enter(cpu);
 	while (test_bit(0,&global_irq_lock)) {
-		if ((unsigned char) cpu == global_irq_holder) {
-			printk("BAD! Local interrupts enabled, global disabled\n");
-			break;
-		}
-		STUCK;
 		/* nothing */;
 	}
 }
diff -u --recursive --new-file v2.1.42/linux/arch/i386/kernel/smp.c linux/arch/i386/kernel/smp.c
--- v2.1.42/linux/arch/i386/kernel/smp.c	Tue May 13 22:41:01 1997
+++ linux/arch/i386/kernel/smp.c	Thu Jun 12 16:22:05 1997
@@ -870,6 +870,8 @@
 	*((volatile unsigned long *)phys_to_virt(8192)) = 0;
 }
 
+unsigned int prof_multiplier[NR_CPUS];
+unsigned int prof_counter[NR_CPUS];
 
 /*
  *	Cycle through the processors sending APIC IPI's to boot each.
@@ -912,8 +914,15 @@
 	 *	of here now!
 	 */
 
-	if (!smp_found_config)
+	if (!smp_found_config) {
+		/*
+		 * For SMP-simulation on one CPU to work, we must initialize these 
+		 * values for the single CPU here:
+                 */
+	        prof_counter[0] = prof_multiplier[0] = 1;
+
 		return;
+        }
 
 	/*
 	 *	Map the local APIC into kernel space
@@ -1301,9 +1310,6 @@
  * multiplier is 1 and it can be changed by writing the new multiplier
  * value into /proc/profile.
  */
-
-unsigned int prof_multiplier[NR_CPUS];
-unsigned int prof_counter[NR_CPUS];
 
 void smp_local_timer_interrupt(struct pt_regs * regs)
 {
diff -u --recursive --new-file v2.1.42/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
--- v2.1.42/linux/arch/i386/kernel/time.c	Tue May 13 22:41:01 1997
+++ linux/arch/i386/kernel/time.c	Thu Jun 12 16:22:05 1997
@@ -515,7 +515,7 @@
 	return mktime(year, mon, day, hour, min, sec);
 }
 
-static struct irqaction irq0  = { timer_interrupt, 0, 0, "timer", NULL, NULL};
+static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};
 
 
 __initfunc(void time_init(void))
diff -u --recursive --new-file v2.1.42/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- v2.1.42/linux/arch/i386/kernel/traps.c	Tue May 13 22:41:01 1997
+++ linux/arch/i386/kernel/traps.c	Thu Jun 12 16:22:05 1997
@@ -191,8 +191,6 @@
 	spin_lock_irq(&die_lock);
 	printk("%s: %04lx\n", str, err & 0xffff);
 	show_registers(regs);
-do { int i=2000000000; while (i) i--; } while (0);
-do { int i=2000000000; while (i) i--; } while (0);
 	spin_unlock_irq(&die_lock);
 	do_exit(SIGSEGV);
 }
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/amiga/amifb.c linux/arch/m68k/amiga/amifb.c
--- v2.1.42/linux/arch/m68k/amiga/amifb.c	Tue May 13 22:41:01 1997
+++ linux/arch/m68k/amiga/amifb.c	Thu Jun 12 16:22:05 1997
@@ -1307,6 +1307,7 @@
 	 */
 
 extern unsigned short ami_intena_vals[];
+extern void amiga_init_sound(void);
 
 	/*
 	 * Support for Graphics Boards
@@ -1808,6 +1809,11 @@
 {
 	int err, tag, i;
 	u_long chipptr;
+
+	/*
+	 * Our beloved beeper
+	 */
+	amiga_init_sound();
 
 	/*
 	 * Check for a Graphics Board
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/amiga/amikeyb.c linux/arch/m68k/amiga/amikeyb.c
--- v2.1.42/linux/arch/m68k/amiga/amikeyb.c	Tue May 13 22:41:01 1997
+++ linux/arch/m68k/amiga/amikeyb.c	Thu Jun 12 16:22:05 1997
@@ -23,18 +23,17 @@
 #include <linux/random.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/kbd_ll.h>
 
 #include <asm/amigaints.h>
 #include <asm/amigahw.h>
 #include <asm/irq.h>
 
-extern void handle_scancode(unsigned char);
-
 #define AMIKEY_CAPS	(0x62)
 #define BREAK_MASK	(0x80)
 #define RESET_WARNING	(0xf0)	/* before rotation */
 
-static u_short amiplain_map[NR_KEYS] = {
+static u_short amiplain_map[NR_KEYS] __initdata = {
 	0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037,
 	0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf05c, 0xf200, 0xf300,
 	0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
@@ -178,15 +177,13 @@
 static void amikeyb_rep(unsigned long ignore);
 static struct timer_list amikeyb_rep_timer = {NULL, NULL, 0, 0, amikeyb_rep};
 
-extern struct pt_regs *pt_regs;
-
 static void amikeyb_rep(unsigned long ignore)
 {
     unsigned long flags;
     save_flags(flags);
     cli();
 
-    pt_regs = NULL;
+    kbd_pt_regs = NULL;
 
     amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
     amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
@@ -202,7 +199,7 @@
     static int reset_warning = 0;
 
     /* save frame for register dump */
-    pt_regs = (struct pt_regs *)fp;
+    kbd_pt_regs = fp;
 
     /* get and invert scancode (keyboard is active low) */
     scancode = ~ciaa.sdr;
@@ -302,14 +299,13 @@
         return -EIO;
 
     /* setup key map */
-    key_maps[0]  = amiplain_map;
+    memcpy(plain_map, amiplain_map, sizeof(plain_map));
     key_maps[1]  = amishift_map;
     key_maps[2]  = amialtgr_map;
     key_maps[4]  = amictrl_map;
     key_maps[5]  = amishift_ctrl_map;
     key_maps[8]  = amialt_map;
     key_maps[12] = amictrl_alt_map;
-    memcpy(plain_map, amiplain_map, sizeof(plain_map));
 
     /*
      * Initialize serial data direction.
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/amiga/amisound.c linux/arch/m68k/amiga/amisound.c
--- v2.1.42/linux/arch/m68k/amiga/amisound.c	Tue May 13 22:41:01 1997
+++ linux/arch/m68k/amiga/amisound.c	Thu Jun 12 16:22:05 1997
@@ -40,7 +40,7 @@
 
 static u_long clock_constant;
 
-__initfunc(static void init_sound(void))
+__initfunc(void amiga_init_sound(void))
 {
 	snd_data = amiga_chip_alloc(sizeof(sine_data));
 	if (!snd_data) {
@@ -58,13 +58,7 @@
 
 void amiga_mksound( unsigned int hz, unsigned int ticks )
 {
-	static int inited = 0;
 	unsigned long flags;
-
-	if (!inited) {
-		init_sound();
-		inited = 1;
-	}
 
 	if (!snd_data)
 		return;
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c
--- v2.1.42/linux/arch/m68k/amiga/config.c	Thu May 29 21:53:04 1997
+++ linux/arch/m68k/amiga/config.c	Thu Jun 12 16:22:05 1997
@@ -78,6 +78,7 @@
 extern struct consw fb_con;
 extern struct fb_info *amiga_fb_init(long *);
 extern void zorro_init(void);
+extern void amiga_init_sound(void);
 static void amiga_savekmsg_init(void);
 static void amiga_mem_console_write(const char *b, unsigned int count);
 static void amiga_serial_console_write(const char *s, unsigned int count);
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/atari/ataints.c linux/arch/m68k/atari/ataints.c
--- v2.1.42/linux/arch/m68k/atari/ataints.c	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/atari/ataints.c	Thu Jun 12 16:22:05 1997
@@ -48,6 +48,7 @@
 #include <asm/atariints.h>
 #include <asm/atari_stdma.h>
 #include <asm/irq.h>
+#include <asm/entry.h>
 
 
 /*
@@ -161,22 +162,6 @@
 
 #define IRQ_NAME(nr) atari_slow_irq_##nr##_handler(void)
 
-#define	MFP_MK_BASE	"0xfa13"
-
-/* This must agree with entry.S.  */
-#define ORIG_DO "0x24"
-#define FORMATVEC "0x32"
-#define SR "0x2C"
-#define SAVE_ALL				\
-	"clrl	%%sp@-;"    /* stk_adj */	\
-	"pea	-1:w;"	    /* orig d0 = -1 */	\
-	"movel	%%d0,%%sp@-;" /* d0 */		\
-	"moveml	%%d1-%%d5/%%a0-%%a2,%%sp@-"
-#define GET_CURRENT(tmp) \
-	"movel	%%sp,"#tmp";" \
-	"andw	#-8192,"#tmp";" \
-	"movel	"#tmp",%%a2"
-
 #define	BUILD_SLOW_IRQ(n)						   \
 asmlinkage void IRQ_NAME(n);						   \
 /* Dummy function to allow asm with operands.  */			   \
@@ -184,29 +169,31 @@
 __asm__ (ALIGN_STR "\n"							   \
 SYMBOL_NAME_STR(atari_slow_irq_) #n "_handler:\t"			   \
 "	addql	#1,"SYMBOL_NAME_STR(local_irq_count)"\n"		   \
-	SAVE_ALL "\n"							   \
+	SAVE_ALL_INT "\n"						   \
 	GET_CURRENT(%%d0) "\n"						   \
-"	andb	#~(1<<(" #n "&7)),"	/* mask this interrupt */	   \
-	"("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n"	   \
-"	bfextu	%%sp@("SR"){#5,#3},%%d0\n" /* get old IPL from stack frame */ \
+"	andb	#~(1<<(%c3&7)),%a4:w\n"	/* mask this interrupt */	   \
+	/* get old IPL from stack frame */				   \
+"	bfextu	%%sp@(%c2){#5,#3},%%d0\n"				   \
 "	movew	%%sr,%%d1\n"						   \
 "	bfins	%%d0,%%d1{#21,#3}\n"					   \
 "	movew	%%d1,%%sr\n"		/* set IPL = previous value */	   \
 "	addql	#1,%a0\n"						   \
-"	lea	"SYMBOL_NAME_STR(irq_handler)"+("#n"+8)*8,%%a0\n"	   \
+"	lea	%a1,%%a0\n"						   \
 "	pea 	%%sp@\n"		/* push addr of frame */	   \
 "	movel	%%a0@(4),%%sp@-\n"	/* push handler data */		   \
-"	pea 	(" #n "+8)\n"		/* push int number */		   \
+"	pea 	(%c3+8)\n"		/* push int number */		   \
 "	movel	%%a0@,%%a0\n"						   \
 "	jbsr	%%a0@\n"		/* call the handler */		   \
 "	addql	#8,%%sp\n"						   \
 "	addql	#4,%%sp\n"						   \
 "	orw	#0x0600,%%sr\n"						   \
 "	andw	#0xfeff,%%sr\n"		/* set IPL = 6 again */		   \
-"	orb 	#(1<<(" #n "&7)),"	/* now unmask the int again */	   \
-	    "("MFP_MK_BASE"+(((" #n "&8)^8)>>2)+((" #n "&16)<<3)):w\n"	   \
+"	orb 	#(1<<(%c3&7)),%a4:w\n"	/* now unmask the int again */	   \
 "	jbra	"SYMBOL_NAME_STR(ret_from_interrupt)"\n"		   \
-	 : : "i" (&kstat.interrupts[n+8])				   \
+	 : : "i" (&kstat.interrupts[n+8]), "i" (&irq_handler[n+8]),	   \
+	     "n" (PT_OFF_SR), "n" (n),					   \
+	     "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a)	   \
+		        : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b))	   \
 );									   \
 }
 
@@ -288,10 +275,10 @@
 	orw 	#0x700,%%sr		/* disable all interrupts */
 "SYMBOL_NAME_STR(atari_prio_irq_handler) ":\t
 	addql	#1,"SYMBOL_NAME_STR(local_irq_count)"\n"
-	SAVE_ALL "\n"
+	SAVE_ALL_INT "\n"
 	GET_CURRENT(%%d0) "
 	/* get vector number from stack frame and convert to source */
-	bfextu	%%sp@(" FORMATVEC "){#4,#10},%%d0
+	bfextu	%%sp@(%c1){#4,#10},%%d0
 	subw	#(0x40-8),%%d0
 	jpl 	1f
 	addw	#(0x40-8-0x18),%%d0
@@ -307,7 +294,7 @@
 	addql	#8,%%sp
 	addql	#4,%%sp
 	jbra	"SYMBOL_NAME_STR(ret_from_interrupt)
-	 : : "i" (&kstat.interrupts)
+	 : : "i" (&kstat.interrupts), "n" (PT_OFF_FORMATVEC)
 );
 }
 
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/atari/atakeyb.c linux/arch/m68k/atari/atakeyb.c
--- v2.1.42/linux/arch/m68k/atari/atakeyb.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/atari/atakeyb.c	Thu Jun 12 16:22:05 1997
@@ -23,6 +23,7 @@
 #include <linux/kd.h>
 #include <linux/random.h>
 #include <linux/init.h>
+#include <linux/kbd_ll.h>
 
 #include <asm/atariints.h>
 #include <asm/atarihw.h>
@@ -31,7 +32,6 @@
 #include <asm/atari_joystick.h>
 #include <asm/irq.h>
 
-extern void handle_scancode(unsigned char);
 extern int ovsc_switchmode;
 extern unsigned char mach_keyboard_type;
 static void atakeyb_rep( unsigned long ignore );
@@ -99,7 +99,7 @@
  *  - Keypad Left/Right Parenthesis mapped to new K_PPAREN[LR]
  */
 
-static u_short ataplain_map[NR_KEYS] = {
+static u_short ataplain_map[NR_KEYS] __initdata = {
 	0xf200, 0xf01b, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036,
 	0xf037, 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf008, 0xf009,
 	0xfb71, 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69,
@@ -139,7 +139,7 @@
 
 static u_short atactrl_map[NR_KEYS] = {
 	0xf200, 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e,
-	0xf01f, 0xf07f, 0xf200, 0xf200, 0xf07f, 0xf200, 0xf008, 0xf200,
+	0xf01f, 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
 	0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
 	0xf00f, 0xf010, 0xf01b, 0xf01d, 0xf201, 0xf702, 0xf001, 0xf013,
 	0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
@@ -158,18 +158,18 @@
 
 static u_short atashift_ctrl_map[NR_KEYS] = {
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf008, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf201, 0xf702, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf700, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200,
-	0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf117,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf008, 0xf200,
+	0xf011, 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009,
+	0xf00f, 0xf010, 0xf200, 0xf200, 0xf201, 0xf702, 0xf001, 0xf013,
+	0xf004, 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200,
+	0xf200, 0xf200, 0xf700, 0xf200, 0xf01a, 0xf018, 0xf003, 0xf016,
+	0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf07f, 0xf700, 0xf200,
+	0xf703, 0xf200, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf117,
 	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
-	0xf600, 0xf200, 0xf115, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+	0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
 	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
 	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -207,7 +207,7 @@
 	0xf118, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
 	0xf119, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+	0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
 	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
 	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -215,7 +215,7 @@
 
 static u_short atactrl_alt_map[NR_KEYS] = {
 	0xf200, 0xf200, 0xf200, 0xf800, 0xf81b, 0xf81c, 0xf81d, 0xf81e,
-	0xf81f, 0xf87f, 0xf200, 0xf200, 0xf87f, 0xf200, 0xf808, 0xf200,
+	0xf81f, 0xf87f, 0xf200, 0xf200, 0xf81f, 0xf200, 0xf808, 0xf200,
 	0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
 	0xf80f, 0xf810, 0xf81b, 0xf81d, 0xf201, 0xf702, 0xf801, 0xf813,
 	0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
@@ -224,7 +224,7 @@
 	0xf703, 0xf800, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
 	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf114,
 	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
-	0xf600, 0xf200, 0xf115, 0xf07f, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf600, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf1ff, 0xf202, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
 	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
@@ -234,18 +234,18 @@
 
 static u_short atashift_ctrl_alt_map[NR_KEYS] = {
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf808, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf201, 0xf702, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf700, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200,
-	0xf703, 0xf200, 0xf207, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf117,
+	0xf200, 0xf200, 0xf200, 0xf200, 0xf81f, 0xf200, 0xf808, 0xf200,
+	0xf811, 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809,
+	0xf80f, 0xf810, 0xf200, 0xf200, 0xf201, 0xf702, 0xf801, 0xf813,
+	0xf804, 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200,
+	0xf200, 0xf200, 0xf700, 0xf200, 0xf81a, 0xf818, 0xf803, 0xf816,
+	0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf87f, 0xf700, 0xf200,
+	0xf703, 0xf200, 0xf207, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104,
+	0xf105, 0xf106, 0xf107, 0xf108, 0xf109, 0xf200, 0xf200, 0xf117,
 	0xf603, 0xf200, 0xf30b, 0xf601, 0xf200, 0xf602, 0xf30a, 0xf200,
-	0xf600, 0xf200, 0xf115, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
+	0xf600, 0xf200, 0xf115, 0xf87f, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
-	0xf200, 0xf200, 0xf200, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
+	0xf200, 0xf1ff, 0xf11b, 0xf312, 0xf313, 0xf30d, 0xf30c, 0xf307,
 	0xf308, 0xf309, 0xf304, 0xf305, 0xf306, 0xf301, 0xf302, 0xf303,
 	0xf300, 0xf310, 0xf30e, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200,
 	0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200
@@ -277,12 +277,10 @@
 static unsigned char rep_scancode;
 static struct timer_list atakeyb_rep_timer = { NULL, NULL, 0, 0, atakeyb_rep };
 
-extern struct pt_regs *pt_regs;
-
 static void atakeyb_rep( unsigned long ignore )
 
 {
-	pt_regs = NULL;
+	kbd_pt_regs = NULL;
 
 	/* Disable keyboard for the time we call handle_scancode(), else a race
 	 * in the keyboard tty queue may happen */
@@ -327,7 +325,7 @@
   int break_flag;
 
   /* save frame for register dump */
-  pt_regs = (struct pt_regs *)fp;
+  kbd_pt_regs = fp;
 
  repeat:
   if (acia.mid_ctrl & ACIA_IRQ)
@@ -420,14 +418,14 @@
 		     * make codes instead. Therefore, simply ignore
 		     * break_flag...
 		     * */
-		    int keyval = ataplain_map[scancode], keytyp;
-		    
+		    int keyval = plain_map[scancode], keytyp;
+
 		    set_bit( scancode, broken_keys );
 		    self_test_last_rcv = jiffies;
-		    keyval = ataplain_map[scancode];
+		    keyval = plain_map[scancode];
 		    keytyp = KTYP(keyval) - 0xf0;
 		    keyval = KVAL(keyval);
-		    
+
 		    printk( KERN_WARNING "Key with scancode %d ", scancode );
 		    if (keytyp == KT_LATIN || keytyp == KT_LETTER) {
 			if (keyval < ' ')
@@ -440,7 +438,7 @@
 		}
 		else if (test_bit( scancode, broken_keys ))
 		    break;
-		
+
 		if (break_flag) {
 		    del_timer( &atakeyb_rep_timer );
 		    rep_scancode = 0;
@@ -808,7 +806,7 @@
 __initfunc(int atari_keyb_init(void))
 {
     /* setup key map */
-    key_maps[0]  = ataplain_map;
+    memcpy (plain_map, ataplain_map, sizeof(plain_map));
     key_maps[1]  = atashift_map;
     key_maps[2]  = 0; /* ataaltgr_map */
     key_maps[4]  = atactrl_map;
@@ -817,7 +815,6 @@
     key_maps[9]  = atashift_alt_map;
     key_maps[12] = atactrl_alt_map;
     key_maps[13] = atashift_ctrl_alt_map;
-    memcpy (plain_map, ataplain_map, sizeof(plain_map));
     keymap_count = 8;
 
     /* say that we don't have an AltGr key */
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/console/fbcon.c linux/arch/m68k/console/fbcon.c
--- v2.1.42/linux/arch/m68k/console/fbcon.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/console/fbcon.c	Thu Jun 12 16:22:05 1997
@@ -69,8 +69,8 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
-#include "../../../drivers/char/vt_kern.h"   /* vt_cons and vc_resize_con() */
-#include "../../../drivers/char/console_struct.h"
+#include <linux/vt_kern.h>
+#include <linux/console_struct.h>
 
 /* Import console_blanked from console.c */
 
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/fpsp040/skeleton.S linux/arch/m68k/fpsp040/skeleton.S
--- v2.1.42/linux/arch/m68k/fpsp040/skeleton.S	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/fpsp040/skeleton.S	Thu Jun 12 16:22:05 1997
@@ -39,6 +39,7 @@
 |
 
 #include <linux/linkage.h>
+#include <asm/entry.h>
 
 |SKELETON	idnt    2,1 | Motorola 040 Floating Point Software Package
 
@@ -51,24 +52,6 @@
  
 	.include "fpsp.h"
 
-/*
- * This has to match entry.S
- */
-LOFF_ORIG_D0	= 0x24
-
-#define curptr a2
-
-#define SAVE_ALL				\
-	clrl	%sp@-;     /* stk_adj */	\
-	movel	%d0,%sp@-; /* orig d0 */	\
-	movel	%d0,%sp@-; /* d0 */		\
-	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-;
-
-#define GET_CURRENT(tmp) \
-	movel	%sp,tmp; \
-	andw	&-8192,tmp; \
-	movel	tmp,%curptr;
-
 	|xref	b1238_fix
 
 |
@@ -86,11 +69,7 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL
-	moveq	#-1,%d0
-	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
-					| signifies that the stack frame
-					| is NOT for syscall
+	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
@@ -181,11 +160,7 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL
-	moveq	#-1,%d0
-	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
-					| signifies that the stack frame
-					| is NOT for syscall
+	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
@@ -211,11 +186,7 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL
-	moveq	#-1,%d0
-	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
-					| signifies that the stack frame
-					| is NOT for syscall
+	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
@@ -241,11 +212,7 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL
-	moveq	#-1,%d0
-	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
-					| signifies that the stack frame
-					| is NOT for syscall
+	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
@@ -267,11 +234,7 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL
-	moveq	#-1,%d0
-	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
-					| signifies that the stack frame
-					| is NOT for syscall
+	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
@@ -293,11 +256,7 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL
-	moveq	#-1,%d0
-	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
-					| signifies that the stack frame
-					| is NOT for syscall
+	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
@@ -325,11 +284,7 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL
-	moveq	#-1,%d0
-	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
-					| signifies that the stack frame
-					| is NOT for syscall
+	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
@@ -350,11 +305,7 @@
 	jmp	fpsp_fline
 real_fline:
 
-	SAVE_ALL
-	moveq	#-1,%d0
-	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
-					| signifies that the stack frame
-					| is NOT for syscall
+	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
@@ -376,11 +327,7 @@
 	frestore	(%sp)+
 	unlk		%a6
 
-	SAVE_ALL
-	moveq	#-1,%d0
-	movel	%d0,%sp@(LOFF_ORIG_D0)    | a -1 in the ORIG_D0 field
-					| signifies that the stack frame
-					| is NOT for syscall
+	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
@@ -435,9 +382,7 @@
 	bne	Lmustsched
 	rte
 Lmustsched:
-	SAVE_ALL
-	moveq	#-1,%d0
-	movel	%d0,%sp@(LOFF_ORIG_D0)    | indicate stack frame not for syscall
+	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	bral	SYMBOL_NAME(ret_from_exception)	| deliver signals, reschedule etc..
 
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/kernel/console.c linux/arch/m68k/kernel/console.c
--- v2.1.42/linux/arch/m68k/kernel/console.c	Wed Apr 23 19:01:15 1997
+++ linux/arch/m68k/kernel/console.c	Thu Jun 12 16:22:05 1997
@@ -109,7 +109,6 @@
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-#include <linux/console.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/errno.h>
@@ -119,17 +118,18 @@
 #include <linux/major.h>
 #include <linux/mm.h>
 #include <linux/ioport.h>
+#include <linux/init.h>
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
 
-#include "../../../drivers/char/kbd_kern.h"
-#include "../../../drivers/char/vt_kern.h"
-#include "../../../drivers/char/consolemap.h"
-#include "../../../drivers/char/selection.h"
-#include "../../../drivers/char/console_struct.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 
 
 #ifndef MIN
@@ -159,6 +159,8 @@
 extern void vesa_blank(void);
 extern void vesa_unblank(void);
 extern void compute_shiftstate(void);
+extern void reset_palette(int currcons);
+extern void set_palette(void);
 void poke_blanked_console(void);
 void do_blank_screen(int);
 
@@ -257,6 +259,7 @@
 #define	ulcolor		(vc_cons[currcons].d->vc_ulcolor)
 #define	halfcolor	(vc_cons[currcons].d->vc_halfcolor)
 #define tab_stop	(vc_cons[currcons].d->vc_tab_stop)
+#define palette		(vc_cons[currcons].d->vc_palette)
 #define bell_pitch	(vc_cons[currcons].d->vc_bell_pitch)
 #define bell_duration	(vc_cons[currcons].d->vc_bell_duration)
 #define sw		(vc_cons[currcons].d->vc_sw)
@@ -539,6 +542,14 @@
 static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7,
 				       8,12,10,14, 9,13,11,15 };
 
+/* the default colour table, for VGA+ colour systems */
+int default_red[] = {0x00,0xaa,0x00,0xaa,0x00,0xaa,0x00,0xaa,
+    0x55,0xff,0x55,0xff,0x55,0xff,0x55,0xff};
+int default_grn[] = {0x00,0x00,0xaa,0x55,0x00,0x00,0xaa,0xaa,
+    0x55,0x55,0xff,0xff,0x55,0x55,0xff,0xff};
+int default_blu[] = {0x00,0x00,0x00,0x00,0xaa,0xaa,0xaa,0xaa,
+    0x55,0x55,0x55,0x55,0xff,0xff,0xff,0xff};
+
 /*
  * gotoxy() must verify all boundaries, because the arguments
  * might also be negative. If the given position is out of
@@ -1655,7 +1666,7 @@
 				if (nextx == cols) {
 					sw->con_putc(vc_cons[currcons].d,
 						     *putcs_buf, y, x);
-					((unsigned short *)pos)--;
+					pos--;
 					need_wrap = decawm;
 					continue;
 				}
@@ -1837,9 +1848,7 @@
 			    vc_state = ESpalette;
 			    continue;
 			} else if (c=='R') {   /* reset palette */
-#if 0
 			    reset_palette (currcons);
-#endif
 			    vc_state = ESnormal;
 			} else
 			    vc_state = ESnormal;
@@ -1848,7 +1857,6 @@
 			if ( (c>='0'&&c<='9') || (c>='A'&&c<='F') || (c>='a'&&c<='f') ) {
 			    par[npar++] = (c>'9' ? (c&0xDF)-'A'+10 : c-'0') ;
 			    if (npar==7) {
-#if 0
 				int i = par[0]*3, j = 1;
 				palette[i] = 16*par[j++];
 				palette[i++] += par[j++];
@@ -1857,7 +1865,6 @@
 				palette[i] = 16*par[j++];
 				palette[i] += par[j];
 				set_palette() ;
-#endif
 				vc_state = ESnormal;
 			    }
 			} else
@@ -2283,7 +2290,7 @@
  * Reads the information preserved by setup.s to determine the current display
  * type and sets everything accordingly.
  */
-unsigned long con_init(unsigned long kmem_start)
+__initfunc(unsigned long con_init(unsigned long kmem_start))
 {
 	const char *display_desc = "????";
 	unsigned int currcons = 0;
@@ -2617,22 +2624,61 @@
  * map, 3 bytes per colour, 16 colours, range from 0 to 255.
  */
 
+static int set_get_cmap(unsigned char *arg, int set)
+{
+	int i, j, k;
+
+	for (i = 0; i < 16; i++)
+		if (set) {
+			get_user(default_red[i], arg++);
+			get_user(default_grn[i], arg++);
+			get_user(default_blu[i], arg++);
+		} else {
+			put_user(default_red[i], arg++);
+			put_user(default_grn[i], arg++);
+			put_user(default_blu[i], arg++);
+		}
+	if (set) {
+		for (i = 0; i < MAX_NR_CONSOLES; i++)
+			if (vc_cons_allocated(i))
+				for (j = k = 0; j < 16; j++) {
+					vc_cons[i].d->vc_palette[k++] =
+						default_red[j];
+					vc_cons[i].d->vc_palette[k++] =
+						default_grn[j];
+					vc_cons[i].d->vc_palette[k++] =
+						default_blu[j];
+				}
+		set_palette();
+	}
+	return 0;
+}
+
 int con_set_cmap (unsigned char *arg)
 {
-	return -EINVAL;
+	return set_get_cmap (arg, 1);
 }
 
 int con_get_cmap (unsigned char *arg)
 {
-	return -EINVAL;
+	return set_get_cmap (arg, 0);
 }
 
 void reset_palette(int currcons)
 {
+	int j, k;
+	for (j = k = 0; j < 16; j++) {
+		palette[k++] = default_red[j];
+		palette[k++] = default_grn[j];
+		palette[k++] = default_blu[j];
+	}
+	set_palette() ;
 }
 
 void set_palette(void)
 {
+	if (vt_cons[fg_console]->vc_mode != KD_GRAPHICS)
+		conswitchp->con_set_palette(vc_cons[fg_console].d, color_table);
 }
 
 /*
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- v2.1.42/linux/arch/m68k/kernel/entry.S	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/kernel/entry.S	Thu Jun 12 16:22:05 1997
@@ -22,24 +22,6 @@
  * NOTE: This code handles signal-recognition, which happens every time
  * after a timer-interrupt and after each system call.
  *
- * Stack layout in 'ret_from_exception':
- *
- *	This allows access to the syscall arguments in registers d1-d5
- *
- *	 0(sp) - d1
- *	 4(sp) - d2
- *	 8(sp) - d3
- *	 C(sp) - d4
- *	10(sp) - d5
- *	14(sp) - a0
- *	18(sp) - a1
- *	1C(sp) - a2
- *	20(sp) - d0
- *	24(sp) - orig_d0
- *	28(sp) - stack adjustment
- *	2C(sp) - sr
- *	2E(sp) - pc
- *	32(sp) - format & vector
  */
 
 /*
@@ -48,94 +30,12 @@
  *               number 0 in the 'current_set' list.
  */
 
-/*
- * 97/05/14 Andreas: Register %a2 is now set to the current task throughout
- *		     the whole kernel.
- */
-
 #include <linux/sys.h>
 #include <linux/config.h>
 #include <linux/linkage.h>
+#include <asm/entry.h>
 #include <asm/setup.h>
 #include <asm/segment.h>
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-.globl SYMBOL_NAME(kgdb_registers)
-#endif
-
-#define curptr a2
-
-LENOSYS = 38
-
-/*
- * these are offsets into the task-struct
- */
-LTASK_STATE	=  0
-LTASK_COUNTER	=  4
-LTASK_PRIORITY	=  8
-LTASK_SIGNAL	= 12
-LTASK_BLOCKED	= 16
-LTASK_FLAGS	= 20
-
-/* the following macro is used when enabling interrupts */
-#if defined(MACH_ATARI_ONLY)
-	/* block out HSYNC on the atari */
-#define ALLOWINT 0xfbff
-#define	MAX_NOINT_IPL	3
-#else
-	/* portable version */
-#define ALLOWINT 0xf8ff
-#define	MAX_NOINT_IPL	0
-#endif /* machine compilation types */ 
-
-LD0		= 0x20
-LORIG_D0	= 0x24
-LSR		= 0x2C
-LFORMATVEC	= 0x32
-
-/*
- * This defines the normal kernel pt-regs layout.
- *
- * regs a3-a6 and d6-d7 are preserved by C code
- * the kernel doesn't mess with usp unless it needs to
- */
-#ifndef CONFIG_KGDB
-#define SAVE_ALL			\
-	clrl	%sp@-;    /* stk_adj */	\
-	movel	%d0,%sp@-; /* orig d0 */	\
-	movel	%d0,%sp@-; /* d0 */	\
-	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-;
-#else
-/* Need to save the "missing" registers for kgdb...
- */
-#define SAVE_ALL						\
-	clrl	%sp@-;    /* stk_adj */				\
-	movel	%d0,%sp@-; /* orig d0 */			\
-	movel	%d0,%sp@-; /* d0 */				\
-	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-;			\
-	moveml	%d6-%d7,SYMBOL_NAME(kgdb_registers)+GDBOFFA_D6;	\
-	moveml	%a3-%a6,SYMBOL_NAME(kgdb_registers)+GDBOFFA_A3;
-#endif
-
-#define RESTORE_ALL			\
-	moveml	%sp@+,%a0-%a1/%curptr/%d1-%d5;	\
-	movel	%sp@+,%d0;		\
-	addql	#4,%sp;	 /* orig d0 */	\
-	addl	%sp@+,%sp; /* stk adj */	\
-	rte
-
-#define SWITCH_STACK_SIZE (6*4+4)	/* includes return address */
-
-#define SAVE_SWITCH_STACK \
-	moveml	%a3-%a6/%d6-%d7,%sp@-
-
-#define RESTORE_SWITCH_STACK \
-	moveml	%sp@+,%a3-%a6/%d6-%d7
-
-#define GET_CURRENT(tmp) \
-	movel	%sp,tmp; \
-	andw	&-8192,tmp; \
-	movel	tmp,%curptr;
 
 .globl SYMBOL_NAME(system_call), SYMBOL_NAME(buserr), SYMBOL_NAME(trap)
 .globl SYMBOL_NAME(resume), SYMBOL_NAME(ret_from_exception)
@@ -146,12 +46,7 @@
 
 .text
 ENTRY(buserr)
-	SAVE_ALL
-	moveq	#-1,%d0
-	movel	%d0,%sp@(LORIG_D0)	| a -1 in the ORIG_D0 field
-					| signifies that the stack frame
-					| is NOT for syscall
-
+	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(buserr_c)
@@ -159,11 +54,7 @@
 	jra	SYMBOL_NAME(ret_from_exception)
 
 ENTRY(trap)
-	SAVE_ALL
-	moveq	#-1,%d0
-	movel	%d0,%sp@(LORIG_D0)	| a -1 in the ORIG_D0 field
-					| signifies that the stack frame
-					| is NOT for syscall
+	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	movel	%sp,%sp@- 		| stack frame pointer argument
 	bsrl	SYMBOL_NAME(trap_c)
@@ -180,18 +71,18 @@
 	jmp	SYMBOL_NAME(schedule)
 
 badsys:
-	movel	#-LENOSYS,LD0(%sp)
+	movel	#-LENOSYS,LPT_OFF_D0(%sp)
 	jra	SYMBOL_NAME(ret_from_exception)
 
 do_trace:
-	movel	#-LENOSYS,LD0(%sp)	| needed for strace
+	movel	#-LENOSYS,LPT_OFF_D0(%sp)	| needed for strace
 	subql	#4,%sp
 	SAVE_SWITCH_STACK
 	jbsr	SYMBOL_NAME(syscall_trace)
 	RESTORE_SWITCH_STACK
 	addql	#4,%sp
 	jbsr	@(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0)
-	movel	%d0,%sp@(LD0)		| save the return value
+	movel	%d0,%sp@(LPT_OFF_D0)	| save the return value
 	subql	#4,%sp			| dummy return address
 	SAVE_SWITCH_STACK
 	jbsr	SYMBOL_NAME(syscall_trace)
@@ -202,7 +93,7 @@
 	jra	SYMBOL_NAME(ret_from_exception)
 
 ENTRY(system_call)
-	SAVE_ALL
+	SAVE_ALL_SYS
 	movel	%d0,%d2
 
 	GET_CURRENT(%d0)
@@ -213,19 +104,20 @@
 
 	cmpl	#NR_syscalls,%d2
 	jcc	badsys
-	btst	#5,%curptr@(LTASK_FLAGS+3)	| PF_TRACESYS
+	btst	#LPF_TRACESYS_BIT,%curptr@(LTASK_FLAGS+LPF_TRACESYS_OFF)
 	jne	do_trace
 	jbsr	@(SYMBOL_NAME(sys_call_table),%d2:l:4)@(0)
-	movel	%d0,%sp@(LD0)		| save the return value
+	movel	%d0,%sp@(LPT_OFF_D0)	| save the return value
 
 SYMBOL_NAME_LABEL(ret_from_exception)
-	btst	#5,%sp@(LSR)		| check if returning to kernel
+	btst	#5,%sp@(LPT_OFF_SR)	| check if returning to kernel
 	bnes	2f			| if so, skip resched, signals
 	tstl	SYMBOL_NAME(need_resched)
 	jne	SYMBOL_NAME(reschedule)
 	cmpl	#SYMBOL_NAME(task),%curptr	| task[0] cannot have signals
 	jeq	2f
-	bclr	#5,%curptr@(LTASK_FLAGS+1)	| check for delayed trace
+					| check for delayed trace
+	bclr	#LPF_DTRACE_BIT,%curptr@(LTASK_FLAGS+LPF_DTRACE_OFF)
 	jne	do_delayed_trace
 5:
 	tstl	%curptr@(LTASK_STATE)	| state
@@ -236,7 +128,7 @@
 	movel	%curptr@(LTASK_BLOCKED),%d0
 	movel	%d0,%d1			| save blocked in d1 for sig handling
 	notl	%d0
-	btst	#4,%curptr@(LTASK_FLAGS+3)	| PF_PTRACED
+	btst	#LPF_PTRACED_BIT,%curptr@(LTASK_FLAGS+LPF_PTRACED_OFF)
 	jeq	1f
 	moveq	#-1,%d0			| let the debugger see all signals
 1:	andl	%curptr@(LTASK_SIGNAL),%d0
@@ -255,10 +147,10 @@
 	RESTORE_ALL
 
 do_delayed_trace:
-	bclr	#7,%sp@(LSR)		| clear trace bit in SR
+	bclr	#7,%sp@(LPT_OFF_SR)	| clear trace bit in SR
 	pea	1			| send SIGTRAP
-	movel	%a0,%sp@-
-	pea	5
+	movel	%curptr,%sp@-
+	pea	LSIGTRAP
 	jbsr	SYMBOL_NAME(send_sig)
 	addql	#8,%sp
 	addql	#4,%sp
@@ -268,15 +160,11 @@
 ** This is the main interrupt handler, responsible for calling process_int()
 */
 SYMBOL_NAME_LABEL(inthandler)
-	SAVE_ALL
-	moveq	#-1,%d0
-	movel	%d0,%sp@(LORIG_D0)	| a -1 in the ORIG_D0 field
-					| signifies that the stack frame
-					| is NOT for syscall
+	SAVE_ALL_INT
 	GET_CURRENT(%d0)
 	addql	#1,SYMBOL_NAME(local_irq_count)
 					|  put exception # in d0
-	bfextu %sp@(LFORMATVEC){#4,#10},%d0
+	bfextu %sp@(LPT_OFF_FORMATVEC){#4,#10},%d0
 
 	movel	%sp,%sp@-
 	movel	%d0,%sp@- 		|  put vector # on stack
@@ -290,7 +178,7 @@
 	RESTORE_ALL
 1:
 #if 1
-	bfextu  %sp@(LSR){#5,#3},%d0    | Check for nested interrupt.
+	bfextu  %sp@(LPT_OFF_SR){#5,#3},%d0	| Check for nested interrupt.
 #if MAX_NOINT_IPL > 0
 	cmpiw	#MAX_NOINT_IPL,%d0
 #endif
@@ -347,14 +235,6 @@
 	RESTORE_SWITCH_STACK
 	rts
 
-LFLUSH_I_AND_D = 0x00000808
-LTSS_KSP	= 0
-LTSS_USP	= 4
-LTSS_SR		= 8
-LTSS_FS		= 10
-LTSS_CRP	= 12
-LTSS_FPCTXT	= 24
-
 SYMBOL_NAME_LABEL(resume)
 	/*
 	 * Beware - when entering resume, offset of tss is in d1,
@@ -460,8 +340,10 @@
 
 #if defined (CONFIG_M68060)
 	/* is it a '060 ? */
+#if !defined(CPU_M68060_ONLY)
 	btst	#3,SYMBOL_NAME(m68k_cputype)+3
 	beqs	2f
+#endif
 	/* clear user entries in the branch cache */
 	movec	%cacr,%d0
 	orl	#0x00200000,%d0
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- v2.1.42/linux/arch/m68k/kernel/setup.c	Tue May 13 22:41:02 1997
+++ linux/arch/m68k/kernel/setup.c	Thu Jun 12 16:22:05 1997
@@ -142,8 +142,8 @@
     }
 }
 
- __initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
-		unsigned long * memory_end_p))
+__initfunc(void setup_arch(char **cmdline_p, unsigned long * memory_start_p,
+			   unsigned long * memory_end_p))
 {
 	unsigned long memory_start, memory_end;
 	extern int _etext, _edata, _end;
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/kernel/traps.c linux/arch/m68k/kernel/traps.c
--- v2.1.42/linux/arch/m68k/kernel/traps.c	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/kernel/traps.c	Thu Jun 12 16:22:05 1997
@@ -201,7 +201,7 @@
 		if ((!(fslw & MMU060_ERR_BITS)) && !(fslw & MMU060_SEE))
 			return;
 	}
-	
+
 	if (fslw & (MMU060_DESC_ERR | MMU060_WP)) {
 		unsigned long errorcode;
 		unsigned long addr = fp->un.fmt4.effaddr;
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- v2.1.42/linux/arch/m68k/mm/init.c	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/mm/init.c	Thu Jun 12 16:22:05 1997
@@ -296,7 +296,8 @@
  * The parameters are pointers to where to stick the starting and ending
  * addresses  of available kernel virtual memory.
  */
-__initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_mem))
+__initfunc(unsigned long paging_init(unsigned long start_mem,
+				     unsigned long end_mem))
 {
 	int chunk;
 	unsigned long mem_avail = 0;
diff -u --recursive --new-file v2.1.42/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- v2.1.42/linux/arch/m68k/mm/memory.c	Sat May 24 09:10:22 1997
+++ linux/arch/m68k/mm/memory.c	Thu Jun 12 16:22:05 1997
@@ -552,39 +552,26 @@
 void cache_clear (unsigned long paddr, int len)
 {
     if (CPU_IS_040_OR_060) {
+	int tmp;
+
 	/*
 	 * cwe need special treatment for the first page, in case it
 	 * is not page-aligned.
 	 */
-	if (paddr & (PAGE_SIZE - 1)){
+	if ((tmp = -paddr & (PAGE_SIZE - 1))) {
 	    pushcl040(paddr);
-	    if (len <= PAGE_SIZE){
-		if (((paddr + len - 1) ^ paddr) & PAGE_MASK) {
-		    pushcl040(paddr + len - 1);
-		}
+	    if ((len -= tmp) <= 0)
 		return;
-	    }else{
-		len -=PAGE_SIZE;
-		paddr += PAGE_SIZE;
-	    }
+	    paddr += tmp;
 	}
-		
-	while (len > PAGE_SIZE) {
-#if 0
-	    pushcl040(paddr);
-#else
+	tmp = PAGE_SIZE;
+	while ((len -= tmp) >= 0) {
 	    clear040(paddr);
-#endif
-	    len -= PAGE_SIZE;
-	    paddr += PAGE_SIZE;
+	    paddr += tmp;
 	}
-	if (len > 0) {
+	if ((len += tmp))
+	    /* a page boundary gets crossed at the end */
 	    pushcl040(paddr);
-	    if (((paddr + len - 1) ^ paddr) & PAGE_MASK) {
-		/* a page boundary gets crossed at the end */
-		pushcl040(paddr + len - 1);
-	    }
-	}
     }
     else /* 68030 or 68020 */
 	asm volatile ("movec %/cacr,%/d0\n\t"
@@ -605,26 +592,19 @@
 void cache_push (unsigned long paddr, int len)
 {
     if (CPU_IS_040_OR_060) {
+	int tmp = PAGE_SIZE;
+
 	/*
          * on 68040 or 68060, push cache lines for pages in the range;
 	 * on the '040 this also invalidates the pushed lines, but not on
 	 * the '060!
 	 */
-	while (len > PAGE_SIZE) {
+	len += paddr & (PAGE_SIZE - 1);
+	do {
 	    pushcli040(paddr);
-	    len -= PAGE_SIZE;
-	    paddr += PAGE_SIZE;
-	    }
-	if (len > 0) {
-	    pushcli040(paddr);
-	    if (((paddr + len - 1) ^ paddr) & PAGE_MASK) {
-		/* a page boundary gets crossed at the end */
-		pushcli040(paddr + len - 1);
-		}
-	    }
-	}
-    
-    
+	    paddr += tmp;
+	} while ((len -= tmp) > 0);
+    }
     /*
      * 68030/68020 have no writeback cache. On the other hand,
      * cache_push is actually a superset of cache_clear (the lines
@@ -654,34 +634,24 @@
 void cache_push_v (unsigned long vaddr, int len)
 {
     if (CPU_IS_040) {
+	int tmp = PAGE_SIZE;
+
 	/* on 68040, push cache lines for pages in the range */
-	while (len > PAGE_SIZE) {
+	len += vaddr & (PAGE_SIZE - 1);
+	do {
 	    pushv040(vaddr);
-	    len -= PAGE_SIZE;
-	    vaddr += PAGE_SIZE;
-	    }
-	if (len > 0) {
-	    pushv040(vaddr);
-	    if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) {
-		/* a page boundary gets crossed at the end */
-		pushv040(vaddr + len - 1);
-		}
-	    }
-	}
+	    vaddr += tmp;
+	} while ((len -= tmp) > 0);
+    }
     else if (CPU_IS_060) {
+	int tmp = PAGE_SIZE;
+
 	/* on 68040, push cache lines for pages in the range */
-	while (len > PAGE_SIZE) {
+	len += vaddr & (PAGE_SIZE - 1);
+	do {
 	    pushv060(vaddr);
-	    len -= PAGE_SIZE;
-	    vaddr += PAGE_SIZE;
-	}
-	if (len > 0) {
-	    pushv060(vaddr);
-	    if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) {
-		/* a page boundary gets crossed at the end */
-		pushv060(vaddr + len - 1);
-	    }
-	}
+	    vaddr += tmp;
+	} while ((len -= tmp) > 0);
     }
     /* 68030/68020 have no writeback cache; still need to clear icache. */
     else /* 68030 or 68020 */
diff -u --recursive --new-file v2.1.42/linux/arch/sparc/config.in linux/arch/sparc/config.in
--- v2.1.42/linux/arch/sparc/config.in	Mon Apr 14 16:28:06 1997
+++ linux/arch/sparc/config.in	Thu Jun 12 16:22:05 1997
@@ -54,6 +54,7 @@
 tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
   tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
 fi
 endmenu
diff -u --recursive --new-file v2.1.42/linux/arch/sparc/defconfig linux/arch/sparc/defconfig
--- v2.1.42/linux/arch/sparc/defconfig	Wed Apr 23 19:01:16 1997
+++ linux/arch/sparc/defconfig	Thu Jun 12 16:22:05 1997
@@ -42,6 +42,7 @@
 SUN_FB_BWTWO=y
 SUN_FB_LEO=y
 TADPOLE_FB_WEITEK=y
+SUN_FB_CREATOR=y
 
 #
 # Misc Linux/SPARC drivers
@@ -177,6 +178,9 @@
 # Filesystems
 #
 CONFIG_QUOTA=y
+# CONFIG_DCACHE_PRELOAD is not set
+# CONFIG_OMIRR is not set
+# CONFIG_TRANS_NAMES is not set
 CONFIG_MINIX_FS=m
 CONFIG_EXT2_FS=y
 CONFIG_FAT_FS=m
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/config.in linux/arch/sparc64/config.in
--- v2.1.42/linux/arch/sparc64/config.in	Wed Apr 23 19:01:16 1997
+++ linux/arch/sparc64/config.in	Thu Jun 12 16:22:05 1997
@@ -59,6 +59,9 @@
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
   tristate 'Kernel support for JAVA binaries' CONFIG_BINFMT_JAVA
 fi
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
+fi
 endmenu
 
 mainmenu_option next_comment
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S
--- v2.1.42/linux/arch/sparc64/kernel/entry.S	Thu May 29 21:53:04 1997
+++ linux/arch/sparc64/kernel/entry.S	Thu Jun 12 16:22:05 1997
@@ -1,4 +1,4 @@
-/* $Id: entry.S,v 1.27 1997/05/27 19:30:11 jj Exp $
+/* $Id: entry.S,v 1.31 1997/06/02 06:33:25 davem Exp $
  * arch/sparc64/kernel/entry.S:  Sparc64 trap low-level entry points.
  *
  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -18,7 +18,7 @@
 #include <asm/signal.h>
 #include <asm/pgtable.h>
 
-/* define SYSCALL_TRACING */
+/* #define SYSCALL_TRACING */
 
 #define curptr      g6
 
@@ -39,82 +39,84 @@
 	 * it will not get updated properly.
 	 */
 sparc64_dtlb_prot_catch:
-	wr	%g0, ASI_DMMU, %asi
-	rdpr	%pstate, %g1
-	wrpr	%g1, PSTATE_AG|PSTATE_MG, %pstate
-	rdpr	%tl, %g2
-	ldxa	[%g0 + TLB_TAG_ACCESS] %asi, %g5
-	ldxa	[%g0 + TLB_SFSR] %asi, %g4
-	cmp	%g2, 1
-	stxa	%g0, [%g0 + TLB_SFSR] %asi
-	bgu,a	%icc, winfix_trampoline
-	 rdpr	%tpc, %g5
-	ba,pt	%xcc, etrap
-	 rd	%pc, %g7
-	b,a,pt	%xcc, 1f
+	wr		%g0, ASI_DMMU, %asi
+	rdpr		%pstate, %g1
+	wrpr		%g1, PSTATE_AG|PSTATE_MG, %pstate
+	rdpr		%tl, %g3
+	ldxa		[%g0 + TLB_TAG_ACCESS] %asi, %g5
+	ldxa		[%g0 + TLB_SFSR] %asi, %g4
+	cmp		%g3, 1
+	stxa		%g0, [%g0 + TLB_SFSR] %asi
+	bgu,a,pn	%icc, winfix_trampoline
+	 rdpr		%tpc, %g3
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
+	b,a,pt		%xcc, 1f
 
 sparc64_dtlb_refbit_catch:
-	srlx	%g5, 9, %g4
-	and	%g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
-	cmp	%g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
-	be,a,pt	%xcc, 2f
-	 mov	1, %g4
-	wr	%g0, ASI_DMMU, %asi
-	rdpr	%pstate, %g1
-	wrpr	%g1, PSTATE_AG|PSTATE_MG, %pstate
-	rdpr	%tl, %g2
-	ldxa	[%g0 + TLB_TAG_ACCESS] %asi, %g5
-	cmp	%g2, 1
-	clr	%g4				! sfsr not updated for tlb misses
-	bgu,a	%icc, winfix_trampoline
-	 rdpr	%tpc, %g5
-	ba,pt	%xcc, etrap
-	 rd	%pc, %g7
+	srlx		%g5, 9, %g4
+	and		%g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
+	cmp		%g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
+	be,a,pt		%xcc, 2f
+	 mov		1, %g4
+	wr		%g0, ASI_DMMU, %asi
+	rdpr		%pstate, %g1
+	wrpr		%g1, PSTATE_AG|PSTATE_MG, %pstate
+	rdpr		%tl, %g3
+	ldxa		[%g0 + TLB_TAG_ACCESS] %asi, %g5
+	cmp		%g3, 1
+	clr		%g4			! sfsr not updated for tlb misses
+	bgu,a,pn	%icc, winfix_trampoline
+	 rdpr		%tpc, %g3
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
 1:
-	mov	%l5, %o4				! raw tag access
-	mov	%l4, %o5				! raw sfsr
-	srlx	%l5, PAGE_SHIFT, %o3
-	clr	%o1					! text_fault == 0
-	sllx	%o3, PAGE_SHIFT, %o3			! address
-	and	%l4, 0x4, %o2				! write == sfsr.W
-	call	do_sparc64_fault
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0	! pt_regs ptr
-	ba,a,pt	%xcc, rtrap
+	mov		%l5, %o4		! raw tag access
+	mov		%l4, %o5		! raw sfsr
+	srlx		%l5, PAGE_SHIFT, %o3
+	clr		%o1			! text_fault == 0
+	sllx		%o3, PAGE_SHIFT, %o3	! address
+	and		%l4, 0x4, %o2		! write == sfsr.W
+	call		do_sparc64_fault
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0	! pt_regs ptr
+	ba,pt		%xcc, rtrap
+	 clr		%l6
 
 sparc64_itlb_refbit_catch:
-	srlx	%g5, 9, %g4
-	and	%g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
-	cmp	%g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
-	be,a,pt	%xcc, 3f
-	 mov	1, %g4
-	rdpr	%pstate, %g1
-	wrpr	%g1, PSTATE_AG|PSTATE_MG, %pstate
-	ba,pt	%xcc, etrap
-	 rd	%pc, %g7
-
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3
-	mov	1, %o1					! text_fault == 1
-	clr	%o2					! write == 0
-	clr	%o4					! tag access (N/A)
-	clr	%o5					! raw sfsr (N/A)
-	call	do_sparc64_fault
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0	! pt_regs ptr
-	ba,a,pt	%xcc, rtrap
+	srlx		%g5, 9, %g4
+	and		%g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9), %g4
+	cmp		%g4, ((_PAGE_PRESENT | _PAGE_READ) >> 9)
+	be,a,pt		%xcc, 3f
+	 mov		1, %g4
+	rdpr		%pstate, %g1
+	wrpr		%g1, PSTATE_AG|PSTATE_MG, %pstate
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
+
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %o3
+	mov		1, %o1					! text_fault == 1
+	clr		%o2					! write == 0
+	clr		%o4					! tag access (N/A)
+	clr		%o5					! raw sfsr (N/A)
+	call		do_sparc64_fault
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0	! pt_regs ptr
+	ba,pt		%xcc, rtrap
+	 clr		%l6
 
 2:
-	sllx	%g4, 63, %g4				! _PAGE_VALID
-	or	%g5, _PAGE_ACCESSED, %g5
-	or	%g5, %g4, %g5
-	stxa	%g5, [%g3 + %g1] ASI_PHYS_USE_EC	! store new PTE
-	stxa	%g5, [%g0] ASI_DTLB_DATA_IN		! TLB load
+	sllx		%g4, 63, %g4				! _PAGE_VALID
+	or		%g5, _PAGE_ACCESSED, %g5
+	or		%g5, %g4, %g5
+	stxa		%g5, [%g3 + %g1] ASI_PHYS_USE_EC	! store new PTE
+	stxa		%g5, [%g0] ASI_DTLB_DATA_IN		! TLB load
 	retry
 
 3:
-	sllx	%g4, 63, %g4				! _PAGE_VALID
-	or	%g5, _PAGE_ACCESSED, %g5
-	or	%g5, %g4, %g5
-	stxa	%g5, [%g3 + %g1] ASI_PHYS_USE_EC	! store new PTE
-	stxa	%g5, [%g0] ASI_ITLB_DATA_IN		! TLB load
+	sllx		%g4, 63, %g4				! _PAGE_VALID
+	or		%g5, _PAGE_ACCESSED, %g5
+	or		%g5, %g4, %g5
+	stxa		%g5, [%g3 + %g1] ASI_PHYS_USE_EC	! store new PTE
+	stxa		%g5, [%g0] ASI_ITLB_DATA_IN		! TLB load
 	retry
 
 	/* Note check out head.h, this code isn't even used for UP,
@@ -131,268 +133,285 @@
 	.align	4
 	.globl	do_ivec
 do_ivec:
-	ldxa	[%g0] ASI_INTR_RECEIVE, %g1
-	andcc	%g1, 0x20, %g0
-	be,pn	%xcc, do_ivec_return
-	 mov	0x40, %g2
+	ldxa		[%g0] ASI_INTR_RECEIVE, %g1
+	andcc		%g1, 0x20, %g0
+	be,pn		%xcc, do_ivec_return
+	 mov		0x40, %g2
 
 	/* Load up Interrupt Vector Data 0 register. */
-	sethi	%uhi(ivector_to_mask), %g4
-	ldxa	[%g2] ASI_UDB_INTR_R, %g3
-	or	%g4, %ulo(ivector_to_mask), %g4
-	and	%g3, 0x7ff, %g3
-	sllx	%g4, 32, %g4
-	sethi	%hi(ivector_to_mask), %g5
-	sllx	%g3, 3, %g3
-	or	%g5, %lo(ivector_to_mask), %g5
-	add	%g5, %g4, %g4
-	ldx	[%g4 + %g3], %g2
-	brz,pn	%g2, do_ivec_spurious
+	sethi		%uhi(ivector_to_mask), %g4
+	ldxa		[%g2] ASI_UDB_INTR_R, %g3
+	or		%g4, %ulo(ivector_to_mask), %g4
+	and		%g3, 0x7ff, %g3
+	sllx		%g4, 32, %g4
+	sethi		%hi(ivector_to_mask), %g5
+	sllx		%g3, 3, %g3
+	or		%g5, %lo(ivector_to_mask), %g5
+	add		%g5, %g4, %g4
+	ldx		[%g4 + %g3], %g2
+	brz,pn		%g2, do_ivec_spurious
 	 nop
 
 	/* No branches, worse case we don't know about this interrupt
 	 * yet, so we would just write a zero into the softint register
 	 * which is completely harmless.
 	 */
-	wr	%g2, 0x0, %set_softint
+	wr		%g2, 0x0, %set_softint
 
 do_ivec_return:
 	/* Acknowledge the UPA */
-	stxa	%g0, [%g0] ASI_INTR_RECEIVE
-	membar	#Sync
+	stxa		%g0, [%g0] ASI_INTR_RECEIVE
+	membar		#Sync
 	retry
 
 do_ivec_spurious:
-	stxa	%g0, [%g0] ASI_INTR_RECEIVE
-	rdpr	%pstate, %g1
-	wrpr	%g1, PSTATE_IG | PSTATE_AG, %pstate
-	ba,pt	%xcc, etrap
-	 rd	%pc, %g7
-	call	report_spurious_ivec
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
-	ba,pt	%xcc, rtrap
-	 nop
+	stxa		%g0, [%g0] ASI_INTR_RECEIVE
+	rdpr		%pstate, %g1
+	wrpr		%g1, PSTATE_IG | PSTATE_AG, %pstate
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
+	call		report_spurious_ivec
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+
+	.globl	do_mna
+do_mna:
+	rdpr		%tl, %g3
+	cmp		%g3, 1
+	bgu,a,pn	%icc, winfix_mna
+	 rdpr		%tpc, %g3
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
+	call		mem_address_unaligned
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,pt		%xcc, rtrap
+	 clr		%l6
 
-breakpoint_t:
-	.asciz	"Breakpoint Trap %lx\n"
-	.align	4
 	.globl	breakpoint_trap
 breakpoint_trap:
-	mov	%o0, %o1
-	sethi	%hi(breakpoint_t), %o0
-	or	%o0, %lo(breakpoint_t), %o0
-	call	prom_printf
-	 add	%o0, %g4, %o0
-	call	prom_cmdline
+	call		sparc_breakpoint
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,pt		%xcc, rtrap
 	 nop
-	ba,a,pt	%xcc, rtrap
 
 	.globl	sys_pipe, sys_execve, sys_sigpause, sys_nis_syscall
 	.globl	sys_sigsuspend, sys_sigreturn
 	.globl	sys32_execve, sys_ptrace
 
 sys_pipe:
-	sethi	%hi(sparc_pipe), %g1
-	add	%g1, %g4, %g1
-	jmpl	%g1 + %lo(sparc_pipe), %g0
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+	sethi		%hi(sparc_pipe), %g1
+	add		%g1, %g4, %g1
+	jmpl		%g1 + %lo(sparc_pipe), %g0
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 
 sys_nis_syscall:
-	sethi	%hi(c_sys_nis_syscall), %g1
-	add	%g1, %g4, %g1
-	jmpl	%g1 + %lo(c_sys_nis_syscall), %g0
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+	sethi		%hi(c_sys_nis_syscall), %g1
+	add		%g1, %g4, %g1
+	jmpl		%g1 + %lo(c_sys_nis_syscall), %g0
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 
 sys_execve:
-	sethi	%hi(sparc_execve), %g1
-	add	%g1, %g4, %g1
-	jmpl	%g1 + %lo(sparc_execve), %g0
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+	sethi		%hi(sparc_execve), %g1
+	add		%g1, %g4, %g1
+	jmpl		%g1 + %lo(sparc_execve), %g0
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 
 sys32_execve:
-	sethi	%hi(sparc32_execve), %g1
-	add	%g1, %g4, %g1
-	jmpl	%g1 + %lo(sparc32_execve), %g0
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+	sethi		%hi(sparc32_execve), %g1
+	add		%g1, %g4, %g1
+	jmpl		%g1 + %lo(sparc32_execve), %g0
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 
 sys_sigpause:
 	/* NOTE: %o0 has a correct value already */
-	call	do_sigpause
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o1
+	call		do_sigpause
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
 	
-	ld	[%curptr + AOFF_task_flags], %l5
-	andcc	%l5, 0x20, %g0
-	be,pt	%icc, rtrap
+	ld		[%curptr + AOFF_task_flags], %l5
+	andcc		%l5, 0x20, %g0
+	be,pt		%icc, rtrap
+	 clr		%l6
+	call		syscall_trace
 	 nop
-	call	syscall_trace
-	 nop
-	ba,a,pt	%xcc, rtrap
+	ba,pt		%xcc, rtrap
+	 clr		%l6
 
 sys_sigsuspend:
-	call	do_sigsuspend
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+	call		do_sigsuspend
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 	
-	ld	[%curptr + AOFF_task_flags], %l5
-	andcc	%l5, 0x20, %g0
-	be,pt	%icc, rtrap
-	 nop
-	call	syscall_trace
+	ld		[%curptr + AOFF_task_flags], %l5
+	andcc		%l5, 0x20, %g0
+	be,pt		%icc, rtrap
+	 clr		%l6
+	call		syscall_trace
 	 nop
-	ba,a,pt	%xcc, rtrap
+	ba,pt		%xcc, rtrap
+	 clr		%l6
 	
 sys_sigreturn:
-	call	do_sigreturn
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+	call		do_sigreturn
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 	
-	ld	[%curptr + AOFF_task_flags], %l5
-	andcc	%l5, 0x20, %g0
-	be,pt	%icc, rtrap
+	ld		[%curptr + AOFF_task_flags], %l5
+	andcc		%l5, 0x20, %g0
+	be,pt		%icc, rtrap
+	 clr		%l6
+	call		syscall_trace
 	 nop
-	call	syscall_trace
-	 nop
-	ba,a,pt	%xcc, rtrap
+	ba,pt		%xcc, rtrap
+	 clr		%l6
 
 sys_ptrace:
-	call	do_ptrace
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+	call		do_ptrace
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
 	
-	ld	[%curptr + AOFF_task_flags], %l5
-	andcc	%l5, 0x20, %g0
-	be,pt	%icc, rtrap
-	 nop
-	call	syscall_trace
+	ld		[%curptr + AOFF_task_flags], %l5
+	andcc		%l5, 0x20, %g0
+	be,pt		%icc, rtrap
+	 clr		%l6
+	call		syscall_trace
 	 nop
-	ba,a,pt	%xcc, rtrap
+	ba,pt		%xcc, rtrap
+	 clr		%l6
 	
-	/* This is how fork() was meant to be done, 10 instruction entry. -DaveM */
+	/* This is how fork() was meant to be done, 12 instruction entry. -DaveM */
 	.globl	sys_fork, sys_vfork, sys_clone
 sys_fork:
 sys_vfork:
-	mov	SIGCHLD, %o0
-	clr	%o1
+	mov		SIGCHLD, %o0
+	clr		%o1
 sys_clone:
-	mov	%o7, %l5
+	mov		%o7, %l5
+	save		%sp, -REGWIN_SZ, %sp
 	flushw
-	rdpr	%cwp, %o4
-	add	%sp, STACK_BIAS + REGWIN_SZ, %o2
-	movrz	%o1, %fp, %o1
+	restore		%g0, %g0, %g0
+	rdpr		%cwp, %o4
+	add		%sp, STACK_BIAS + REGWIN_SZ, %o2
+	movrz		%o1, %fp, %o1
 
 	/* Don't try this at home. */
-	stx	%o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0]
-	call	do_fork
-	 mov	%l5, %o7
+	stx		%o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0]
+	call		do_fork
+	 mov		%l5, %o7
 
 linux_sparc_ni_syscall:
-	sethi	%hi(sys_ni_syscall), %l7
-	or	%l7, %lo(sys_ni_syscall), %l7
-	ba,pt	%xcc,syscall_is_too_hard
-	 add	%l7, %g4, %l7
+	sethi		%hi(sys_ni_syscall), %l7
+	or		%l7, %lo(sys_ni_syscall), %l7
+	ba,pt		%xcc,syscall_is_too_hard
+	 add		%l7, %g4, %l7
 
 linux_fast_syscall:
-	andn	%l7, 3, %l7
-	mov	%i0, %o0
-	mov	%i1, %o1
-	mov 	%i2, %o2
-	jmpl	%l7 + %g0, %g0
-	 mov	%i3, %o3
+	andn		%l7, 3, %l7
+	mov		%i0, %o0
+	mov		%i1, %o1
+	mov		%i2, %o2
+	jmpl		%l7 + %g0, %g0
+	 mov		%i3, %o3
 
 linux_syscall_trace:
-	call	syscall_trace
+	call		syscall_trace
 	 nop
-	mov	%i0, %o0
-	mov	%i1, %o1
-	mov	%i2, %o2
-	mov	%i3, %o3
-	ba,pt	%xcc, 2f
-	 mov	%i4, %o4
+	mov		%i0, %o0
+	mov		%i1, %o1
+	mov		%i2, %o2
+	mov		%i3, %o3
+	ba,pt		%xcc, 2f
+	 mov		%i4, %o4
 
 	.globl	ret_from_syscall
 ret_from_syscall:
-	ba,pt	%xcc, ret_sys_call
-	 ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
+	ba,pt		%xcc, ret_sys_call
+	 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
 
 	/* Linux native and SunOS system calls enter here... */
 	.align	4
 	.globl	linux_sparc_syscall
 linux_sparc_syscall:
 	/* Direct access to user regs, must faster. */
-	cmp	%g1, NR_SYSCALLS
-	add	%l7, %g4, %l7
-	bgeu,pn	%xcc, linux_sparc_ni_syscall
-	 sll	%g1, 3, %l4
-	ldx	[%l7 + %l4], %l7
-	andcc	%l7, 1, %g0
-	bne,pn	%icc, linux_fast_syscall
+	cmp		%g1, NR_SYSCALLS
+	add		%l7, %g4, %l7
+	bgeu,pn		%xcc, linux_sparc_ni_syscall
+	 sll		%g1, 3, %l4
+	ldx		[%l7 + %l4], %l7
+	andcc		%l7, 1, %g0
+	bne,pn		%icc, linux_fast_syscall
 	 /* Just do the next insn in the delay slot */
 
 	.globl	syscall_is_too_hard
 syscall_is_too_hard:
 #ifdef SYSCALL_TRACING	/* Debugging... */
-	mov	%g1, %o0				! o0=scall, o1=ptregs
-	call	syscall_trace_entry
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o1
+	mov		%g1, %o0				! o0=scall, o1=ptregs
+	call		syscall_trace_entry
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
 #endif
-	mov	%i0, %o0
-	mov	%i1, %o1
-	mov	%i2, %o2
-
-	ldx	[%curptr + AOFF_task_flags], %l5
-	mov	%i3, %o3
-	mov	%i4, %o4
-	andcc	%l5, 0x20, %g0
-	bne,pn	%icc, linux_syscall_trace
-	 mov	%i0, %l5
+	mov		%i0, %o0
+	mov		%i1, %o1
+	mov		%i2, %o2
+
+	ldx		[%curptr + AOFF_task_flags], %l5
+	mov		%i3, %o3
+	mov		%i4, %o4
+	andcc		%l5, 0x20, %g0
+	bne,pn		%icc, linux_syscall_trace
+	 mov		%i0, %l5
 2:
-	call	%l7
-	 mov	%i5, %o5
+	call		%l7
+	 mov		%i5, %o5
 
 #ifdef SYSCALL_TRACING	/* Debugging... */
-	call	syscall_trace_exit			! o0=sysret, o1=ptregs
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o1
+	call		syscall_trace_exit			! o0=sysret, o1=ptregs
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o1
 #endif
-	stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
 
 	.globl	ret_sys_call
 ret_sys_call:
-	ldx	[%curptr + AOFF_task_flags], %l6
-	mov	%ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
-	cmp	%o0, -ENOIOCTLCMD
-	sllx	%g2, 32, %g2
-	bgeu,pn	%xcc, 1f
-	 andcc	%l6, 0x20, %l6	
+	ldx		[%curptr + AOFF_task_flags], %l6
+	ldx		[%curptr + AOFF_task_tss + AOFF_thread_flags], %l2
+	mov		%ulo(TSTATE_XCARRY | TSTATE_ICARRY), %g2
+	and		%l2, SPARC_FLAG_32BIT, %l2
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %g3
+	brnz,a,pn	%l2, 1f
+	 sra		%o0, 0, %o0
+1:
+	cmp		%o0, -ENOIOCTLCMD
+	sllx		%g2, 32, %g2
+	bgeu,pn		%xcc, 1f
+	 andcc		%l6, 0x20, %l6	
 
 	/* System call success, clear Carry condition code. */
-	andn	%g3, %g2, %g3
-	clr	%l6
-	stx	%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]	
-	bne,pn	%icc, linux_syscall_trace2
-	 ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */
-	add	%l1, 0x4, %l2				      /* npc = npc+4 */
-	stx	%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
-	ba,pt	%xcc, rtrap
-	 stx	%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+	andn		%g3, %g2, %g3
+	clr		%l6
+	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]	
+	bne,pn		%icc, linux_syscall_trace2
+	 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
+	add		%l1, 0x4, %l2				         !npc = npc+4
+	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+	ba,pt		%xcc, rtrap
+	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
 1:
 	/* System call failure, set Carry condition code.
 	 * Also, get abs(errno) to return to the process.
 	 */
-	sub	%g0, %o0, %o0
-	or	%g3, %g2, %g3
-	stx	%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
-	mov	1, %l6
-	stx	%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
-	bne,pn	%icc, linux_syscall_trace2
-	 ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 /* pc = npc */
-	add	%l1, 0x4, %l2				      /* npc = npc+4 */
-	stx	%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
-	ba,pt	%xcc, rtrap
-	 stx	%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+	sub		%g0, %o0, %o0
+	or		%g3, %g2, %g3
+	stx		%o0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
+	mov		1, %l6
+	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE]
+	bne,pn		%icc, linux_syscall_trace2
+	 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1 ! pc = npc
+	add		%l1, 0x4, %l2				         !npc = npc+4
+	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+	ba,pt		%xcc, rtrap
+	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
 
 linux_syscall_trace2:
-	call	syscall_trace
-	 add	%l1, 0x4, %l2			/* npc = npc+4 */
-	stx	%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
-	ba,pt	%xcc, rtrap
-	 stx	%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
+	call		syscall_trace
+	 add		%l1, 0x4, %l2			/* npc = npc+4 */
+	stx		%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC]
+	ba,pt		%xcc, rtrap
+	 stx		%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC]
 
 /* End of entry.S */
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/etrap.S linux/arch/sparc64/kernel/etrap.S
--- v2.1.42/linux/arch/sparc64/kernel/etrap.S	Thu May 29 21:53:04 1997
+++ linux/arch/sparc64/kernel/etrap.S	Thu Jun 12 16:22:05 1997
@@ -1,4 +1,4 @@
-/* $Id: etrap.S,v 1.18 1997/05/19 05:58:51 davem Exp $
+/* $Id: etrap.S,v 1.21 1997/06/02 06:33:28 davem Exp $
  * etrap.S: Preparing for entry into the kernel on Sparc V9.
  *
  * Copyright (C) 1996, 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -22,7 +22,7 @@
 
 	.text
 	.align	32
-	.globl	etrap, etrap_irq
+	.globl	etrap, etrap_irq, etraptl1
 etrap:
 	rdpr		%pil, %g2
 etrap_irq:
@@ -45,13 +45,14 @@
 
 	stx		%g3, [%g2 + REGWIN_SZ + PT_V9_TNPC]
 	stx		%g1, [%g2 + REGWIN_SZ + PT_V9_Y]
-	rdpr		%pstate, %g1
-	save		%g2, -STACK_BIAS, %sp
-	bne,pn		%xcc, 1f
+	save		%g2, -STACK_BIAS, %sp	! The ordering of these two instructions
+	rdpr		%pstate, %g1		! is critical, see winfixup.S for details
+	bne,pn		%xcc, 2f
 	 rdpr		%canrestore, %g3
 	rdpr		%wstate, %g6
-	wrpr		%g0, 0, %canrestore
+	wrpr		%g0, 7, %cleanwin
 
+	wrpr		%g0, 0, %canrestore
 	sll		%g6, 3, %g6
 	wrpr		%g3, 0, %otherwin
 	wrpr		%g6, %wstate
@@ -59,17 +60,17 @@
 	sllx		%g3, 32, %g3
 	mov		PRIMARY_CONTEXT, %g2
 	stxa		%g0, [%g2] ASI_DMMU
+
 	flush		%g3
-1:
-	wrpr		%g0, 0x0, %tl
+2:	wrpr		%g0, 0x0, %tl
 	mov		%g1, %l1
 	mov		%g4, %l4
 	mov		%g5, %l5
 	mov		%g7, %l2
 	wrpr		%l1, PSTATE_AG, %pstate
 	stx		%g1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1]
-	stx		%g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]
 
+	stx		%g2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2]
 	stx		%g3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3]
 	stx		%g4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4]
 	stx		%g5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5]
@@ -77,8 +78,8 @@
 	stx		%g7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7]
 	stx		%i0, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0]
 	stx		%i1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1]
-	stx		%i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]
 
+	stx		%i2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2]
 	stx		%i3, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3]
 	stx		%i4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4]
 	stx		%i5, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5]
@@ -86,16 +87,13 @@
 	stx		%i7, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7]
 	wrpr		%l1, (PSTATE_IE | PSTATE_AG), %pstate
 	sethi		%uhi(KERNBASE), %g4
-	rd		%pic, %g6
 
+	rd		%pic, %g6
 	jmpl		%l2 + 0x4, %g0
 	 sllx		%g4, 32, %g4
-
-	.globl	etraptl1
 etraptl1:
 	rdpr	%tstate, %g1
+	sub	%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
 	ba,pt	%xcc, 1b
-	 sub	%sp, REGWIN_SZ + TRACEREG_SZ - STACK_BIAS, %g2
-	nop
-	nop
+	 andcc	%g1, TSTATE_PRIV, %g0
 	nop
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/hack.S linux/arch/sparc64/kernel/hack.S
--- v2.1.42/linux/arch/sparc64/kernel/hack.S	Thu May 29 21:53:04 1997
+++ linux/arch/sparc64/kernel/hack.S	Thu Jun 12 16:22:05 1997
@@ -24,16 +24,12 @@
 do_iae_tl1:	retl;nop
 	.globl	do_ill_tl1
 do_ill_tl1:	retl;nop
-	.globl	do_irq
-do_irq:	retl;nop
 	.globl	do_irq_tl1
 do_irq_tl1:	retl;nop
 	.globl	do_lddfmna
 do_lddfmna:	retl;nop
 	.globl	do_lddfmna_tl1
 do_lddfmna_tl1:	retl;nop
-	.globl	do_mna_tl1
-do_mna_tl1:	retl;nop
 	.globl	do_paw
 do_paw:	retl;nop
 	.globl	do_paw_tl1
@@ -51,7 +47,7 @@
 	.globl	floppy_hardint
 floppy_hardint:	retl;nop
 	.globl	get_cpuid
-get_cpuid:	retl;nop
+get_cpuid:	retl;mov 0, %o0
 	.globl	getcc
 getcc:	retl;nop
 	.globl	halt
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/head.S linux/arch/sparc64/kernel/head.S
--- v2.1.42/linux/arch/sparc64/kernel/head.S	Sat May 24 09:10:23 1997
+++ linux/arch/sparc64/kernel/head.S	Thu Jun 12 16:22:05 1997
@@ -1,4 +1,4 @@
-/* $Id: head.S,v 1.30 1997/05/18 22:52:12 davem Exp $
+/* $Id: head.S,v 1.31 1997/05/30 22:35:28 davem Exp $
  * head.S: Initial boot code for the Sparc64 port of Linux.
  *
  * Copyright (C) 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -55,7 +55,7 @@
         .word   0
 ramdisk_size:
         .word   0
-        .word   reboot_command
+        .xword   reboot_command
 
 	/* We must be careful, 32-bit OpenBOOT will get confused if it
 	 * tries to save away a register window to a 64-bit kernel
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c
--- v2.1.42/linux/arch/sparc64/kernel/ioctl32.c	Thu May 29 21:53:04 1997
+++ linux/arch/sparc64/kernel/ioctl32.c	Thu Jun 12 16:22:05 1997
@@ -1,4 +1,4 @@
-/* $Id: ioctl32.c,v 1.3 1997/05/27 19:30:13 jj Exp $
+/* $Id: ioctl32.c,v 1.8 1997/06/04 13:05:15 jj Exp $
  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -7,22 +7,369 @@
  * ioctls.
  */
 
+#include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/ioctl.h>
+#include <linux/if.h>
+#include <linux/malloc.h>
+#include <linux/hdreg.h>
+#include <linux/md.h>
+#include <linux/kd.h>
+#include <linux/route.h>
+#include <linux/netlink.h>
 
 #include <asm/types.h>
 #include <asm/uaccess.h>
 
-/* As gcc will warn about casting u32 to some ptr, we have to cast it to unsigned long first, and that's what is A() for.
- * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x) or instead of just (void *)x, which will
- * produce warnings */
+/* As gcc will warn about casting u32 to some ptr, we have to cast it to
+ * unsigned long first, and that's what is A() for.
+ * You just do (void *)A(x), instead of having to type (void *)((unsigned long)x)
+ * or instead of just (void *)x, which will produce warnings.
+ */
 #define A(x) ((unsigned long)x)
 
 extern asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
+static int w_long(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	unsigned long old_fs = get_fs();
+	int err;
+	unsigned long val;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, cmd, (unsigned long)&val);
+	set_fs (old_fs);
+	if (!err && put_user(val, (u32 *)A(arg)))
+		return -EFAULT;
+	return err;
+}
  
+struct ifmap32 {
+	u32 mem_start;
+	u32 mem_end;
+	unsigned short base_addr;
+	unsigned char irq;
+	unsigned char dma;
+	unsigned char port;
+};
+
+struct ifreq32 {
+#define IFHWADDRLEN     6
+#define IFNAMSIZ        16
+        union {
+                char    ifrn_name[IFNAMSIZ];            /* if name, e.g. "en0" */
+        } ifr_ifrn;
+        union {
+                struct  sockaddr ifru_addr;
+                struct  sockaddr ifru_dstaddr;
+                struct  sockaddr ifru_broadaddr;
+                struct  sockaddr ifru_netmask;
+                struct  sockaddr ifru_hwaddr;
+                short   ifru_flags;
+                int     ifru_ivalue;
+                int     ifru_mtu;
+                struct  ifmap32 ifru_map;
+                char    ifru_slave[IFNAMSIZ];   /* Just fits the size */
+                __kernel_caddr_t32 ifru_data;
+        } ifr_ifru;
+};
+
+struct ifconf32 {
+        int     ifc_len;                        /* size of buffer       */
+        __kernel_caddr_t32  ifcbuf;
+};
+
+static inline int dev_ifconf(unsigned int fd, u32 arg)
+{
+	struct ifconf32 ifc32;
+	struct ifconf ifc;
+	struct ifreq32 *ifr32;
+	struct ifreq *ifr;
+	unsigned long old_fs;
+	unsigned int i, j;
+	int err;
+
+	if (copy_from_user(&ifc32, (struct ifconf32 *)A(arg), sizeof(struct ifconf32)))
+		return -EFAULT;
+	ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * sizeof (struct ifreq);
+	ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL);
+	if (!ifc.ifc_buf) return -ENOMEM;
+	ifr = ifc.ifc_req;
+	ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);
+	for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) {
+		if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) {
+			kfree (ifc.ifc_buf);
+			return -EFAULT;
+		}
+	}
+	old_fs = get_fs(); set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc);	
+	set_fs (old_fs);
+	if (!err) {
+		ifr = ifc.ifc_req;
+		ifr32 = (struct ifreq32 *)A(ifc32.ifcbuf);
+		for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len;
+		     i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) {
+			if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) {
+				err = -EFAULT;
+				break;
+			}
+		}
+		if (!err) {
+			if (i <= ifc32.ifc_len)
+				ifc32.ifc_len = i;
+			else
+				ifc32.ifc_len = i - sizeof (struct ifreq32);
+			if (copy_to_user((struct ifconf32 *)A(arg), &ifc32, sizeof(struct ifconf32)))
+				err = -EFAULT;
+		}
+	}
+	kfree (ifc.ifc_buf);
+	return err;
+}
+
+static inline int dev_ifsioc(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	struct ifreq ifr;
+	unsigned long old_fs;
+	int err;
+	
+	if (cmd == SIOCSIFMAP) {
+		if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(ifr.ifr_name)) ||
+		    __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) ||
+		    __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) ||
+		    __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.base_addr)) ||
+		    __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.irq)) ||
+		    __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) ||
+		    __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port)))
+			return -EFAULT;
+	} else {
+		if (copy_from_user(&ifr, (struct ifreq32 *)A(arg), sizeof(struct ifreq32)))
+			return -EFAULT;
+	}
+	old_fs = get_fs();
+	set_fs (KERNEL_DS);
+	err = sys_ioctl (fd, cmd, (unsigned long)&ifr);
+	set_fs (old_fs);
+	if (!err) {
+		switch (cmd) {
+		case SIOCGIFFLAGS:
+		case SIOCGIFMETRIC:
+		case SIOCGIFMTU:
+		case SIOCGIFMEM:
+		case SIOCGIFHWADDR:
+		case SIOGIFINDEX:
+		case SIOCGIFADDR:
+		case SIOCGIFBRDADDR:
+		case SIOCGIFDSTADDR:
+		case SIOCGIFNETMASK:
+			if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(struct ifreq32)))
+				return -EFAULT;
+			break;
+		case SIOCGIFMAP:
+			if (copy_to_user((struct ifreq32 *)A(arg), &ifr, sizeof(ifr.ifr_name)) ||
+			    __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_start)) ||
+			    __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.mem_end)) ||
+			    __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.base_addr)) ||
+			    __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.irq)) ||
+			    __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.dma)) ||
+			    __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)A(arg))->ifr_ifru.ifru_map.port)))
+				return -EFAULT;
+			break;
+		}
+	}
+	return err;
+}
+
+struct rtentry32 {
+        u32   		rt_pad1;
+        struct sockaddr rt_dst;         /* target address               */
+        struct sockaddr rt_gateway;     /* gateway addr (RTF_GATEWAY)   */
+        struct sockaddr rt_genmask;     /* target network mask (IP)     */
+        unsigned short  rt_flags;
+        short           rt_pad2;
+        u32   		rt_pad3;
+        unsigned char   rt_tos;
+        unsigned char   rt_class;
+        short           rt_pad4;
+        short           rt_metric;      /* +1 for binary compatibility! */
+        /* char * */ u32 rt_dev;        /* forcing the device at add    */
+        u32   		rt_mtu;         /* per route MTU/Window         */
+        u32   		rt_window;      /* Window clamping              */
+        unsigned short  rt_irtt;        /* Initial RTT                  */
+
+};
+
+static inline int routing_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
+{
+	struct rtentry r;
+	char devname[16];
+	u32 rtdev;
+	int ret;
+	unsigned long old_fs = get_fs();
+	
+	if (get_user (r.rt_pad1, &(((struct rtentry32 *)A(arg))->rt_pad1)) ||
+	    copy_from_user (&r.rt_dst, &(((struct rtentry32 *)A(arg))->rt_dst), 3 * sizeof(struct sockaddr)) ||
+	    __get_user (r.rt_flags, &(((struct rtentry32 *)A(arg))->rt_flags)) ||
+	    __get_user (r.rt_pad2, &(((struct rtentry32 *)A(arg))->rt_pad2)) ||
+	    __get_user (r.rt_pad3, &(((struct rtentry32 *)A(arg))->rt_pad3)) ||
+	    __get_user (r.rt_tos, &(((struct rtentry32 *)A(arg))->rt_tos)) ||
+	    __get_user (r.rt_class, &(((struct rtentry32 *)A(arg))->rt_class)) ||
+	    __get_user (r.rt_pad4, &(((struct rtentry32 *)A(arg))->rt_pad4)) ||
+	    __get_user (r.rt_metric, &(((struct rtentry32 *)A(arg))->rt_metric)) ||
+	    __get_user (r.rt_mtu, &(((struct rtentry32 *)A(arg))->rt_mtu)) ||
+	    __get_user (r.rt_window, &(((struct rtentry32 *)A(arg))->rt_window)) ||
+	    __get_user (r.rt_irtt, &(((struct rtentry32 *)A(arg))->rt_irtt)) ||
+	    __get_user (rtdev, &(((struct rtentry32 *)A(arg))->rt_dev)) ||
+	    (rtdev && copy_from_user (devname, (char *)A(rtdev), 15)))
+		return -EFAULT;
+	if (rtdev) {
+		r.rt_dev = devname; devname[15] = 0;
+	} else
+		r.rt_dev = 0;
+	set_fs (KERNEL_DS);
+	ret = sys_ioctl (fd, cmd, (long)&r);
+	set_fs (old_fs);
+	return ret;
+}
+
+struct nlmsghdr32 {
+        u32   		nlmsg_len;      /* Length of message including header */
+        u32   		nlmsg_type;     /* Message type */
+        u32   		nlmsg_seq;      /* Sequence number */
+        u32   		nlmsg_pid;      /* Sending process PID */
+        unsigned char   nlmsg_data[0];
+};
+
+struct in_rtmsg32 {
+        struct in_addr  rtmsg_prefix;
+        struct in_addr  rtmsg_gateway;
+        unsigned        rtmsg_flags;
+        u32   		rtmsg_mtu;
+        u32   		rtmsg_window;
+        unsigned short  rtmsg_rtt;
+        short           rtmsg_metric;
+        unsigned char   rtmsg_tos;
+        unsigned char   rtmsg_class;
+        unsigned char   rtmsg_prefixlen;
+        unsigned char   rtmsg_reserved;
+        int             rtmsg_ifindex;
+};
+
+struct in_ifmsg32 {
+        struct sockaddr ifmsg_lladdr;
+        struct in_addr  ifmsg_prefix;
+        struct in_addr  ifmsg_brd;
+        unsigned        ifmsg_flags;
+        u32   		ifmsg_mtu;
+        short           ifmsg_metric;
+        unsigned char   ifmsg_prefixlen;
+        unsigned char   ifmsg_reserved;
+        int             ifmsg_index;
+        char            ifmsg_name[16];
+};
+
+static inline int rtmsg_ioctl(unsigned int fd, u32 arg)
+{
+	struct {
+		struct nlmsghdr n;
+		union {
+			struct in_rtmsg rt;
+			struct in_ifmsg iff;
+			struct in_rtctlmsg ctl;
+			struct in_rtrulemsg rule;
+		} u;
+	} nn;
+	char *p;
+	int ret;
+	unsigned long old_fs = get_fs();
+	
+	if (get_user (nn.n.nlmsg_len, &(((struct nlmsghdr32 *)A(arg))->nlmsg_len)) ||
+	    __get_user (nn.n.nlmsg_type, &(((struct nlmsghdr32 *)A(arg))->nlmsg_type)) ||
+	    __get_user (nn.n.nlmsg_seq, &(((struct nlmsghdr32 *)A(arg))->nlmsg_seq)) ||
+	    __get_user (nn.n.nlmsg_pid, &(((struct nlmsghdr32 *)A(arg))->nlmsg_pid)) ||
+	    __get_user (nn.n.nlmsg_data[0], &(((struct nlmsghdr32 *)A(arg))->nlmsg_data[0])))
+		return -EFAULT;
+	p = ((char *)(&nn.n)) + sizeof(struct nlmsghdr);
+	arg += sizeof(struct nlmsghdr32);
+	switch (nn.n.nlmsg_type) {
+	case RTMSG_NEWRULE:
+	case RTMSG_DELRULE:
+		if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtrulemsg)
+		    - sizeof(struct in_rtmsg) + sizeof(struct in_rtmsg32))
+			return -EINVAL;
+		if (copy_from_user (p, (struct in_rtrulemsg *)A(arg), sizeof(struct in_rtrulemsg) - sizeof(struct in_rtmsg)))
+			return -EFAULT;
+		nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtrulemsg);
+		p += sizeof (struct in_rtrulemsg) - sizeof(struct in_rtmsg);
+		arg += sizeof (struct in_rtrulemsg) - sizeof(struct in_rtmsg);
+		goto newroute;
+	case RTMSG_NEWROUTE:
+	case RTMSG_DELROUTE:
+		if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtmsg))
+			return -EINVAL;
+		nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtmsg);
+newroute:
+		if (copy_from_user (p, (struct in_rtmsg32 *)A(arg), 2*sizeof(struct in_addr) + sizeof(unsigned)) ||
+	    	    __get_user (((struct in_rtmsg *)p)->rtmsg_mtu, &((struct in_rtmsg32 *)A(arg))->rtmsg_mtu) ||
+	    	    __get_user (((struct in_rtmsg *)p)->rtmsg_window, &((struct in_rtmsg32 *)A(arg))->rtmsg_window) ||
+		    copy_from_user (&(((struct in_rtmsg *)p)->rtmsg_rtt), &((struct in_rtmsg32 *)A(arg))->rtmsg_rtt, 
+			2 * sizeof(short) + 4 + sizeof(int)))
+			return -EFAULT;
+		break;
+	case RTMSG_NEWDEVICE:
+	case RTMSG_DELDEVICE:
+		if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_ifmsg))
+			return -EINVAL;
+		nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_ifmsg);
+		if (copy_from_user (p, (struct in_ifmsg32 *)A(arg), 
+			sizeof(struct sockaddr) + 2*sizeof(struct in_addr) + sizeof(unsigned)) ||
+	    	    __get_user (((struct in_ifmsg *)p)->ifmsg_mtu, &((struct in_ifmsg32 *)A(arg))->ifmsg_mtu) ||
+		    copy_from_user (&(((struct in_ifmsg *)p)->ifmsg_metric), &((struct in_ifmsg32 *)A(arg))->ifmsg_metric, 
+			sizeof(short) + 2 + sizeof(int) + 16))
+			return -EFAULT;
+		break;
+	case RTMSG_CONTROL:
+		if (nn.n.nlmsg_len < sizeof(struct nlmsghdr32) + sizeof(struct in_rtctlmsg))
+			return -EINVAL;
+		nn.n.nlmsg_len = sizeof(struct nlmsghdr) + sizeof(struct in_rtctlmsg);
+		if (copy_from_user (p, (struct in_rtctlmsg *)A(arg), sizeof(struct in_rtctlmsg)))
+			return -EFAULT;
+		break;
+	}
+	set_fs (KERNEL_DS);
+	ret = sys_ioctl (fd, SIOCRTMSG, (long)&(nn.n));
+	set_fs (old_fs);
+	return ret;
+}
+
+struct hd_geometry32 {
+	unsigned char heads;
+	unsigned char sectors;
+	unsigned short cylinders;
+	u32 start;
+};
+                        
+static inline int hdio_getgeo(unsigned int fd, u32 arg)
+{
+	unsigned long old_fs = get_fs();
+	struct hd_geometry geo;
+	int err;
+	
+	set_fs (KERNEL_DS);
+	err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo);
+	set_fs (old_fs);
+	if (!err) {
+		if (copy_to_user ((struct hd_geometry32 *)A(arg), &geo, 4) ||
+		    __put_user (geo.start, &(((struct hd_geometry32 *)A(arg))->start)))
+			return -EFAULT;
+	}
+	return err;
+}
+
 asmlinkage int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg)
 {
 	struct file * filp;
@@ -35,16 +382,149 @@
 		error = sys_ioctl (fd, cmd, (unsigned long)arg);
 		goto out;
 	}
-	error = 0;
+	error = -EFAULT;
 	switch (cmd) {
-		default:
-			error = sys_ioctl (fd, cmd, (unsigned long)arg);
-			goto out;
+	case SIOCGIFCONF:
+		error = dev_ifconf(fd, arg);
+		goto out;
+		
+	case SIOCGIFFLAGS:
+	case SIOCSIFFLAGS:
+	case SIOCGIFMETRIC:
+	case SIOCSIFMETRIC:
+	case SIOCGIFMTU:
+	case SIOCSIFMTU:
+	case SIOCGIFMEM:
+	case SIOCSIFMEM:
+	case SIOCGIFHWADDR:
+	case SIOCSIFHWADDR:
+	case SIOCADDMULTI:
+	case SIOCDELMULTI:
+	case SIOGIFINDEX:
+	case SIOCGIFMAP:
+	case SIOCSIFMAP:
+	case SIOCGIFADDR:
+	case SIOCSIFADDR:
+	case SIOCGIFBRDADDR:
+	case SIOCSIFBRDADDR:
+	case SIOCGIFDSTADDR:
+	case SIOCSIFDSTADDR:
+	case SIOCGIFNETMASK:
+	case SIOCSIFNETMASK:
+		error = dev_ifsioc(fd, cmd, arg);
+		goto out;
+		
+	case SIOCADDRT:
+	case SIOCDELRT:
+		error = routing_ioctl(fd, cmd, arg);
+		goto out;
+
+	case SIOCRTMSG:
+		error = rtmsg_ioctl(fd, arg);
+		goto out;
+		
+	case HDIO_GETGEO:
+		error = hdio_getgeo(fd, arg);
+		goto out;
+		
+	case BLKRAGET:
+	case BLKGETSIZE:
+		error = w_long(fd, cmd, arg);
+		goto out;
+
+	/* List here exlicitly which ioctl's are known to have
+	 * compatable types passed or none at all...
+	 */
+
+	/* Bit T */
+	case TCGETA:
+	case TCSETA:
+	case TCSETAW:
+	case TCSETAF:
+	case TCSBRK:
+	case TCXONC:
+	case TCFLSH:
+	case TCGETS:
+	case TCSETS:
+	case TCSETSW:
+	case TCSETSF:
+	case TIOCLINUX:
+
+	/* Little t */
+	case TIOCGETD:
+	case TIOCSETD:
+	case TIOCEXCL:
+	case TIOCNXCL:
+	case TIOCCONS:
+	case TIOCGSOFTCAR:
+	case TIOCSSOFTCAR:
+	case TIOCSWINSZ:
+	case TIOCGWINSZ:
+	case TIOCMGET:
+	case TIOCMBIC:
+	case TIOCMBIS:
+	case TIOCMSET:
+	case TIOCPKT:
+	case TIOCNOTTY:
+	case TIOCSTI:
+	case TIOCOUTQ:
+	case TIOCSPGRP:
+	case TIOCGPGRP:
+	case TIOCSCTTY:
+
+	/* Little f */
+	case FIOCLEX:
+	case FIONCLEX:
+	case FIOASYNC:
+	case FIONBIO:
+	case FIONREAD: /* This is also TIOCINQ */
+	
+	/* 0x12 */
+	case BLKRRPART:
+	case BLKFLSBUF:
+	case BLKRASET:
+	
+	/* 0x09 */
+	case REGISTER_DEV:
+	case START_MD:
+	case STOP_MD:
+	
+	/* Big K */
+	case PIO_FONT:
+	case GIO_FONT:
+	case KDSIGACCEPT:
+	case KDGETKEYCODE:
+	case KDSETKEYCODE:
+
+	/* Socket level stuff */
+	case FIOSETOWN:
+	case SIOCSPGRP:
+	case FIOGETOWN:
+	case SIOCGPGRP:
+	case SIOCATMARK:
+	case SIOCGSTAMP:
+	case SIOCSIFLINK:
+	case SIOCSIFENCAP:
+	case SIOCGIFENCAP:
+	case SIOCSIFBR:
+	case SIOCGIFBR:
+	case SIOCSARP:
+	case SIOCGARP:
+	case SIOCDARP:
+	case SIOCADDDLCI:
+	case SIOCDELDLCI:
+		error = sys_ioctl (fd, cmd, (unsigned long)arg);
+		goto out;
+		break;
+
+	default:
+		printk("sys32_ioctl: Unknown cmd fd(%d) cmd(%08x) arg(%08x)\n",
+		       (int)fd, (unsigned int)cmd, (unsigned int)arg);
+		error = -EINVAL;
+		goto out;
+		break;
 	}
 out:
-	if (error == -EINVAL) {
-		printk ("sys32_ioctl on %016lx's %08x returns EINVAL\n", filp->f_op ? (long)filp->f_op->ioctl : 0UL, cmd);
-	}
 	unlock_kernel();
 	return error;
 }
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c
--- v2.1.42/linux/arch/sparc64/kernel/process.c	Thu May 29 21:53:04 1997
+++ linux/arch/sparc64/kernel/process.c	Thu Jun 12 16:22:05 1997
@@ -1,4 +1,4 @@
-/*  $Id: process.c,v 1.12 1997/05/23 09:35:43 jj Exp $
+/*  $Id: process.c,v 1.17 1997/06/02 06:33:32 davem Exp $
  *  arch/sparc64/kernel/process.c
  *
  *  Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -317,6 +317,13 @@
 #else
 	if(current->flags & PF_USEDFPU) {
 #endif
+		fprs_write(FPRS_FEF);
+		if(current->tss.flags & SPARC_FLAG_32BIT)
+			fpsave32((unsigned long *)&current->tss.float_regs[0],
+				 &current->tss.fsr);
+		else
+			fpsave((unsigned long *)&current->tss.float_regs[0],
+			       &current->tss.fsr);
 #ifndef __SMP__
 		last_task_used_math = NULL;
 #else
@@ -338,6 +345,13 @@
 #else
 	if(current->flags & PF_USEDFPU) {
 #endif
+		fprs_write(FPRS_FEF);
+		if(current->tss.flags & SPARC_FLAG_32BIT)
+			fpsave32((unsigned long *)&current->tss.float_regs[0],
+				 &current->tss.fsr);
+		else
+			fpsave((unsigned long *)&current->tss.float_regs[0],
+			       &current->tss.fsr);
 #ifndef __SMP__
 		last_task_used_math = NULL;
 #else
@@ -424,6 +438,8 @@
 	return sp;
 }
 
+/* #define DEBUG_WINFIXUPS */
+
 /* Standard stuff. */
 static inline void shift_window_buffer(int first_win, int last_win,
 				       struct thread_struct *tp)
@@ -440,12 +456,15 @@
 void synchronize_user_stack(void)
 {
 	struct thread_struct *tp = &current->tss;
-	unsigned long window = tp->w_saved;
+	unsigned long window;
 
 	flush_user_windows();
-	if(window) {
+	if((window = tp->w_saved) != 0) {
 		int winsize = REGWIN_SZ;
 
+#ifdef DEBUG_WINFIXUPS
+		printk("sus(%d", (int)window);
+#endif
 		if(tp->flags & SPARC_FLAG_32BIT)
 			winsize = REGWIN32_SZ;
 
@@ -459,18 +478,26 @@
 				tp->w_saved--;
 			}
 		} while(window--);
+#ifdef DEBUG_WINFIXUPS
+		printk(")");
+#endif
 	}
 }
 
 void fault_in_user_windows(struct pt_regs *regs)
 {
 	struct thread_struct *tp = &current->tss;
-	unsigned long window = tp->w_saved;
+	unsigned long window;
 	int winsize = REGWIN_SZ;
 
 	if(tp->flags & SPARC_FLAG_32BIT)
 		winsize = REGWIN32_SZ;
-	if(window) {
+	flush_user_windows();
+	window = tp->w_saved;
+#ifdef DEBUG_WINFIXUPS
+	printk("fiuw(%d", (int)window);
+#endif
+	if(window != 0) {
 		window -= 1;
 		do {
 			unsigned long sp = tp->rwbuf_stkptrs[window];
@@ -481,6 +508,9 @@
 		} while(window--);
 	}
 	current->tss.w_saved = 0;
+#ifdef DEBUG_WINFIXUPS
+	printk(")");
+#endif
 }
 
 /* Copy a Sparc thread.  The fork() return value conventions
@@ -504,19 +534,17 @@
 	struct reg_window *new_stack, *old_stack;
 	unsigned long stack_offset;
 
-#if 0
 #ifndef __SMP__
 	if(last_task_used_math == current) {
 #else
 	if(current->flags & PF_USEDFPU) {
 #endif
-		put_psr(get_psr() | PSR_EF);
-		fpsave(&p->tss.float_regs[0], &p->tss.fsr);
+		fprs_write(FPRS_FEF);
+		fpsave((unsigned long *)&p->tss.float_regs[0], &p->tss.fsr);
 #ifdef __SMP__
 		current->flags &= ~PF_USEDFPU;
 #endif
 	}
-#endif	
 
 	/* Calculate offset to stack_frame & pt_regs */
 	stack_offset = ((PAGE_SIZE<<1) - TRACEREG_SZ);
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/rtrap.S linux/arch/sparc64/kernel/rtrap.S
--- v2.1.42/linux/arch/sparc64/kernel/rtrap.S	Thu May 29 21:53:04 1997
+++ linux/arch/sparc64/kernel/rtrap.S	Thu Jun 12 16:22:05 1997
@@ -1,4 +1,4 @@
-/* $Id: rtrap.S,v 1.18 1997/05/27 06:28:05 davem Exp $
+/* $Id: rtrap.S,v 1.21 1997/06/02 07:26:54 davem Exp $
  * rtrap.S: Preparing for return from trap on Sparc V9.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -17,109 +17,114 @@
 
 	.text
 	.align	32
-	.globl	rtrap
-rtrap:
-	sethi	%hi(bh_active), %l2
-	or	%l2, %lo(bh_active), %l2
-	sethi	%hi(bh_mask), %l1
-	or	%l1, %lo(bh_mask), %l1
-	ldx	[%l2 + %g4], %l3
-	ldx	[%l1 + %g4], %l4
-	andcc	%l3, %l4, %g0
-	nop
+	.globl	rtrap_clr_l6, rtrap
+rtrap_clr_l6:
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+rtrap:	sethi		%hi(bh_active), %l2
+	or		%l2, %lo(bh_active), %l2
+	sethi		%hi(bh_mask), %l1
+	or		%l1, %lo(bh_mask), %l1
+	ldx		[%l2 + %g4], %l3
+	ldx		[%l1 + %g4], %l4
 
-	be,pt	%xcc, 2f
+	andcc		%l3, %l4, %g0
+	be,pt		%xcc, 2f
 	 nop
-	call	do_bottom_half
+	call		do_bottom_half
 	 nop
-2:	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %l1
-	sethi	%hi(0xf << 20), %l4
-	andcc	%l1, TSTATE_PRIV, %l3
-	and	%l1, %l4, %l4
-
-	rdpr	%pstate, %l7
-	andn	%l1, %l4, %l1
-	be,pt	%icc, to_user
-	 andn	%l7, PSTATE_IE, %l7
-3:	ldx	[%g6 + AOFF_task_tss + AOFF_thread_ctx], %l6
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1], %g1
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2], %g2
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3], %g3
-
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4], %g4
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5], %g5
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6], %g6
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7], %g7
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %i0
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1], %i1
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2], %i2
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3], %i3
-
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4], %i4
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5], %i5
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6], %i6
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7], %i7
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_Y], %o3
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %l2
-	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %o2
-	wr	%o3, %g0, %y
-
-	srl	%l4, 20, %l4
-	wrpr	%l7, %g0, %pstate
-	wrpr	%l4, 0x0, %pil
-	wrpr	%g0, 0x1, %tl
-	wrpr	%l1, %g0, %tstate
-	wrpr	%l2, %g0, %tpc
-	brnz,pn	%l3, 1f
-	 wrpr	%o2, %g0, %tnpc
-
-	mov	PRIMARY_CONTEXT, %l7
-	sethi	%uhi(KERNBASE), %l5
-	sllx	%l5, 32, %l5
-	stxa	%l6, [%l7] ASI_DMMU
-	flush	%l5
-	rdpr	%wstate, %l1
-	rdpr	%otherwin, %l2
-	srl	%l1, 3, %l1
-
-	wrpr	%l2, %g0, %canrestore
-	wrpr	%l1, %g0, %wstate
-	wrpr	%g0, %g0, %otherwin
-1:	restore
-	retry
+2:	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TSTATE], %l1
+	sethi		%hi(0xf << 20), %l4
+	andcc		%l1, TSTATE_PRIV, %l3
+
+	and		%l1, %l4, %l4
+	rdpr		%pstate, %l7
+	andn		%l1, %l4, %l1
+	be,pt		%icc, to_user
+	 andn		%l7, PSTATE_IE, %l7
+3:	ldx		[%g6 + AOFF_task_tss + AOFF_thread_ctx], %l0
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G1], %g1
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G2], %g2
+
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G3], %g3
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G4], %g4
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G5], %g5
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G6], %g6
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G7], %g7
+	wrpr		%l7, PSTATE_AG, %pstate
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %i0
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I1], %i1
+
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I2], %i2
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I3], %i3
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I4], %i4
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I5], %i5
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I6], %i6
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I7], %i7
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_Y], %o3
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC], %l2
+
+	ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %o2
+	wr		%o3, %g0, %y
+	srl		%l4, 20, %l4
+	wrpr		%l4, 0x0, %pil
+	wrpr		%g0, 0x1, %tl
+	wrpr		%l1, %g0, %tstate
+	wrpr		%l2, %g0, %tpc
+	mov		PRIMARY_CONTEXT, %l7
+
+	wrpr		%o2, %g0, %tnpc
+	brnz,a,pn	%l3, 1f
+	 restore
+	sethi		%uhi(KERNBASE), %l5
+	sllx		%l5, 32, %l5
+	stxa		%l0, [%l7] ASI_DMMU
+	flush		%l5
+	rdpr		%wstate, %l1
+
+	rdpr		%otherwin, %l2
+	srl		%l1, 3, %l1
+	wrpr		%l2, %g0, %canrestore
+	wrpr		%l1, %g0, %wstate
+	wrpr		%g0, %g0, %otherwin
+	restore
+	rdpr		%canrestore, %g1
+	wrpr		%g1, 0x0, %cleanwin
+
+1:	retry
 to_user:
 	sethi	%hi(need_resched), %l0
 	or	%l0, %lo(need_resched), %l0
 	ld	[%l0 + %g4], %l0
-
 	wrpr	%l7, PSTATE_IE, %pstate
 	brz,pt	%l0, check_signal
 	 ldx	[%g6 + AOFF_task_signal], %l0
+	nop
+
 	call	schedule
 	 nop
-	ldx	[%g6 + AOFF_task_signal], %l0
-	nop
+	ba,pt	%xcc, check_signal
+	 ldx	[%g6 + AOFF_task_signal], %l0
 check_signal:
 	ldx	[%g6 + AOFF_task_blocked], %o0
-
-	or	%l7, PSTATE_AG, %l7		! Will need this for setting back wstate
 	andncc	%l0, %o0, %g0
-	be,pt	%xcc, check_user_wins
-	 mov	%l5, %o2  
+	be,a,pt	%xcc, check_user_wins
+	 ldx	[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
+
+	mov	%l5, %o2  
 	mov	%l6, %o3
 	call	do_signal
 	 add	%sp, STACK_BIAS + REGWIN_SZ, %o1
-check_user_wins:
-#if 0
-	call	user_rtrap_report
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
-#endif
 	ldx	[%g6 + AOFF_task_tss + AOFF_thread_w_saved], %o2
-
+	clr	%l6
+check_user_wins:
 	brz,pt	%o2, 3b
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o1
+	 nop
+
 	call	fault_in_user_windows
-	 add	%o7, 3b-.-4, %o7
+	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,a,pt	%xcc, 3b
+	nop
 	nop
 	nop
 	nop
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c
--- v2.1.42/linux/arch/sparc64/kernel/signal.c	Thu May 29 21:53:04 1997
+++ linux/arch/sparc64/kernel/signal.c	Thu Jun 12 16:22:05 1997
@@ -1,4 +1,4 @@
-/*  $Id: signal.c,v 1.4 1997/05/27 06:28:05 davem Exp $
+/*  $Id: signal.c,v 1.6 1997/05/29 12:44:48 jj Exp $
  *  arch/sparc64/kernel/signal.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -193,13 +193,17 @@
 {
 #ifdef __SMP__
 	if (current->flags & PF_USEDFPU) {
-		fpsave(&current->tss.float_regs[0], &current->tss.fsr);
+		fprs_write(FPRS_FEF);
+		fpsave((unsigned long *)&current->tss.float_regs[0],
+		       &current->tss.fsr);
 		regs->tstate &= ~(TSTATE_PEF);
 		current->flags &= ~(PF_USEDFPU);
 	}
 #else
 	if (current == last_task_used_math) {
-		fpsave((unsigned long *)&current->tss.float_regs[0], &current->tss.fsr);
+		fprs_write(FPRS_FEF);
+		fpsave((unsigned long *)&current->tss.float_regs[0],
+		       &current->tss.fsr);
 		last_task_used_math = 0;
 		regs->tstate &= ~(TSTATE_PEF);
 	}
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c
--- v2.1.42/linux/arch/sparc64/kernel/signal32.c	Thu May 29 21:53:04 1997
+++ linux/arch/sparc64/kernel/signal32.c	Thu Jun 12 16:22:05 1997
@@ -1,4 +1,4 @@
-/*  $Id: signal32.c,v 1.10 1997/05/27 06:28:07 davem Exp $
+/*  $Id: signal32.c,v 1.13 1997/06/01 05:46:09 davem Exp $
  *  arch/sparc64/kernel/signal32.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
@@ -139,35 +139,51 @@
 void do_new_sigreturn32(struct pt_regs *regs)
 {
 	struct new_signal_frame32 *sf;
-	unsigned int psr, i;
+	unsigned int psr;
 	unsigned pc, npc, fpu_save, mask;
 	
 	sf = (struct new_signal_frame32 *) regs->u_regs [UREG_FP];
+
 	/* 1. Make sure we are not getting garbage from the user */
-	if (verify_area (VERIFY_READ, sf, sizeof (*sf))){
-		goto segv;
-	}
-	if (((unsigned long) sf) & 3){
+	if (verify_area (VERIFY_READ, sf, sizeof (*sf))	||
+	    (((unsigned long) sf) & 3))
 		goto segv;
-	}
+
 	get_user(pc, &sf->info.si_regs.pc);
 	__get_user(npc, &sf->info.si_regs.npc);
-	if ((pc | npc) & 3){
+
+	if ((pc | npc) & 3)
 		goto segv;
-	}
+
 	regs->tpc = pc;
 	regs->tnpc = npc;
 
 	/* 2. Restore the state */
 	__get_user(regs->y, &sf->info.si_regs.y);
 	__get_user(psr, &sf->info.si_regs.psr);
-	for (i = 0; i < 16; i++)
-		__get_user(regs->u_regs[i], &sf->info.si_regs.u_regs[i]);
+
+	__get_user(regs->u_regs[UREG_G1], &sf->info.si_regs.u_regs[UREG_G1]);
+	__get_user(regs->u_regs[UREG_G2], &sf->info.si_regs.u_regs[UREG_G2]);
+	__get_user(regs->u_regs[UREG_G3], &sf->info.si_regs.u_regs[UREG_G3]);
+	__get_user(regs->u_regs[UREG_G4], &sf->info.si_regs.u_regs[UREG_G4]);
+	__get_user(regs->u_regs[UREG_G5], &sf->info.si_regs.u_regs[UREG_G5]);
+	__get_user(regs->u_regs[UREG_G6], &sf->info.si_regs.u_regs[UREG_G6]);
+	__get_user(regs->u_regs[UREG_G7], &sf->info.si_regs.u_regs[UREG_G7]);
+	__get_user(regs->u_regs[UREG_I0], &sf->info.si_regs.u_regs[UREG_I0]);
+	__get_user(regs->u_regs[UREG_I1], &sf->info.si_regs.u_regs[UREG_I1]);
+	__get_user(regs->u_regs[UREG_I2], &sf->info.si_regs.u_regs[UREG_I2]);
+	__get_user(regs->u_regs[UREG_I3], &sf->info.si_regs.u_regs[UREG_I3]);
+	__get_user(regs->u_regs[UREG_I4], &sf->info.si_regs.u_regs[UREG_I4]);
+	__get_user(regs->u_regs[UREG_I5], &sf->info.si_regs.u_regs[UREG_I5]);
+	__get_user(regs->u_regs[UREG_I6], &sf->info.si_regs.u_regs[UREG_I6]);
+	__get_user(regs->u_regs[UREG_I7], &sf->info.si_regs.u_regs[UREG_I7]);
 
 	/* User can only change condition codes and FPU enabling in %tstate. */
 	regs->tstate &= ~(TSTATE_ICC | TSTATE_PEF);
 	regs->tstate |= psr_to_tstate_icc(psr);
-	if (psr & PSR_EF) regs->tstate |= TSTATE_PEF;
+
+	if (psr & PSR_EF)
+		regs->tstate |= TSTATE_PEF;
 
 	__get_user(fpu_save, &sf->fpu_save);
 	if (fpu_save)
@@ -193,11 +209,12 @@
 	scptr = (struct sigcontext32 *) regs->u_regs[UREG_I0];
 	/* Check sanity of the user arg. */
 	if(verify_area(VERIFY_READ, scptr, sizeof(struct sigcontext32)) ||
-	   (((unsigned long) scptr) & 3)) {
+	   (((unsigned long) scptr) & 3))
 		goto segv;
-	}
+
 	__get_user(pc, &scptr->sigc_pc);
 	__get_user(npc, &scptr->sigc_npc);
+
 	if((pc | npc) & 3)
 		goto segv; /* Nice try. */
 
@@ -241,7 +258,6 @@
 	int old_status = current->tss.sstk_info.cur_status;
 	unsigned psr;
 	int i;
-	u32 temp;
 
 	synchronize_user_stack();
 	sframep = (struct signal_sframe32 *) regs->u_regs[UREG_FP];
@@ -285,7 +301,10 @@
 		}
 	else
 #endif	
+		/* XXX Perhaps we need a copy_in_user()? -DaveM */
 		for (i = 0; i < 16; i++) {
+			u32 temp;
+
 			get_user (temp, (((u32 *)(regs->u_regs[UREG_FP]))+i));
 			put_user (temp, (((u32 *)sframep)+i));
 		}
@@ -315,13 +334,17 @@
 {
 #ifdef __SMP__
 	if (current->flags & PF_USEDFPU) {
-		fpsave32(&current->tss.float_regs[0], &current->tss.fsr);
+		fprs_write(FPRS_FEF);
+		fpsave32((unsigned long *)&current->tss.float_regs[0],
+			 &current->tss.fsr);
 		regs->tstate &= ~(TSTATE_PEF);
 		current->flags &= ~(PF_USEDFPU);
 	}
 #else
 	if (current == last_task_used_math) {
-		fpsave32((unsigned long *)&current->tss.float_regs[0], &current->tss.fsr);
+		fprs_write(FPRS_FEF);
+		fpsave32((unsigned long *)&current->tss.float_regs[0],
+			 &current->tss.fsr);
 		last_task_used_math = 0;
 		regs->tstate &= ~(TSTATE_PEF);
 	}
@@ -338,7 +361,7 @@
 {
 	struct new_signal_frame32 *sf;
 	int sigframe_size;
-	u32 psr, tmp;
+	u32 psr;
 	int i;
 
 	/* 1. Make sure everything is clean */
@@ -349,12 +372,12 @@
 
 	sf = (struct new_signal_frame32 *)(regs->u_regs[UREG_FP] - sigframe_size);
 	
-	if (invalid_frame_pointer (sf, sigframe_size)){
+	if (invalid_frame_pointer (sf, sigframe_size)) {
 		lock_kernel ();
 		do_exit(SIGILL);
 	}
 
-	if (current->tss.w_saved != 0){
+	if (current->tss.w_saved != 0) {
 		printk ("%s[%d]: Invalid user stack frame for "
 			"signal delivery.\n", current->comm, current->pid);
 		lock_kernel ();
@@ -378,7 +401,11 @@
 	}
 
 	__put_user(oldmask, &sf->info.si_mask);
+
+	/* XXX Perhaps we need a copy_in_user()? -DaveM */
 	for (i = 0; i < sizeof(struct reg_window32)/4; i++) {
+		u32 tmp;
+
 		__get_user(tmp, (((u32 *)regs->u_regs[UREG_FP])+i));
 		__put_user(tmp, (((u32 *)sf)+i));
 	}
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c
--- v2.1.42/linux/arch/sparc64/kernel/sys_sparc32.c	Thu May 29 21:53:04 1997
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Thu Jun 12 16:22:05 1997
@@ -1,7 +1,8 @@
-/* $Id: sys_sparc32.c,v 1.18 1997/05/27 06:28:08 davem Exp $
+/* $Id: sys_sparc32.c,v 1.26 1997/06/04 13:05:21 jj Exp $
  * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  *
  * These routines maintain argument size conversion between 32bit and 64bit
  * environment.
@@ -28,6 +29,7 @@
 #include <linux/smb_fs.h>
 #include <linux/ncp_fs.h>
 #include <linux/quota.h>
+#include <linux/file.h>
 
 #include <asm/types.h>
 #include <asm/poll.h>
@@ -42,112 +44,7 @@
  */
 #define A(x) ((unsigned long)x)
  
-extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
-extern asmlinkage unsigned long sys_brk(unsigned long brk);
-extern asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long off);
-extern asmlinkage int sys_bdflush(int func, long data);
-extern asmlinkage int sys_uselib(const char * library);
-extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
-extern asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev);
-extern asmlinkage int sys_mkdir(const char * pathname, int mode);
-extern asmlinkage int sys_rmdir(const char * pathname);
-extern asmlinkage int sys_unlink(const char * pathname);
-extern asmlinkage int sys_symlink(const char * oldname, const char * newname);
-extern asmlinkage int sys_link(const char * oldname, const char * newname);
-extern asmlinkage int sys_rename(const char * oldname, const char * newname);
-extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
-extern asmlinkage int sys_statfs(const char * path, struct statfs * buf);
-extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf);
-extern asmlinkage int sys_truncate(const char * path, unsigned long length);
-extern asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length);
-extern asmlinkage int sys_utime(char * filename, struct utimbuf * times);
-extern asmlinkage int sys_utimes(char * filename, struct timeval * utimes);
-extern asmlinkage int sys_access(const char * filename, int mode);
-extern asmlinkage int sys_chdir(const char * filename);
-extern asmlinkage int sys_chroot(const char * filename);
-extern asmlinkage int sys_chmod(const char * filename, mode_t mode);
-extern asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group);
-extern asmlinkage int sys_open(const char * filename,int flags,int mode);
-extern asmlinkage int sys_creat(const char * pathname, int mode);
-extern asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin);
-extern asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high, unsigned long offset_low, loff_t *result, unsigned int origin);
-extern asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count);
-extern asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count);
-extern asmlinkage long sys_readv(unsigned long fd, const struct iovec * vector, unsigned long count);
-extern asmlinkage long sys_writev(unsigned long fd, const struct iovec * vector, unsigned long count);
-extern asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp);
-extern asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout);
-extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf);
-extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf);
-extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf);
-extern asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz);
-extern asmlinkage int sys_sysfs(int option, ...);
-extern asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf);
-extern asmlinkage int sys_umount(char * name);
-extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, unsigned long new_flags, void *data);
-extern asmlinkage int sys_syslog(int type, char * bug, int count);
-extern asmlinkage int sys_personality(unsigned long personality);
-extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru);
-extern asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options);
-extern asmlinkage int sys_sysinfo(struct sysinfo *info);
-extern asmlinkage int sys_getitimer(int which, struct itimerval *value);
-extern asmlinkage int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue);
-extern asmlinkage int sys_sched_setscheduler(pid_t pid, int policy, struct sched_param *param);
-extern asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param);
-extern asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param);
-extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
-extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
-extern asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset);
-extern asmlinkage int sys_sigpending(sigset_t *set);
-extern asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler);
-extern asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg);
-extern asmlinkage int sys_acct(const char *name);
-extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
-extern asmlinkage long sys_times(struct tms * tbuf);
-extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist);
-extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist);
-extern asmlinkage int sys_newuname(struct new_utsname * name);
-extern asmlinkage int sys_olduname(struct oldold_utsname * name);
-extern asmlinkage int sys_sethostname(char *name, int len);
-extern asmlinkage int sys_gethostname(char *name, int len);
-extern asmlinkage int sys_setdomainname(char *name, int len);
-extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim);
-extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim);
-extern asmlinkage int sys_getrusage(int who, struct rusage *ru);
-extern asmlinkage int sys_time(int * tloc);
-extern asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz);
-extern asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz);
-extern asmlinkage int sys_adjtimex(struct timex *txc_p);
-extern asmlinkage int sys_msync(unsigned long start, size_t len, int flags);
-extern asmlinkage int sys_mlock(unsigned long start, size_t len);
-extern asmlinkage int sys_munlock(unsigned long start, size_t len);
-extern asmlinkage int sys_munmap(unsigned long addr, size_t len);
-extern asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot);
-extern asmlinkage unsigned long sys_mremap(unsigned long addr, unsigned long old_len, unsigned long new_len, unsigned long flags);
-extern asmlinkage int sys_swapoff(const char * specialfile);
-extern asmlinkage int sys_swapon(const char * specialfile, int swap_flags);
-extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
-extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen);
-extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
-extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
-extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len);
-extern asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags);
-extern asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags, struct sockaddr *addr, int addr_len);
-extern asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags);
-extern asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags, struct sockaddr *addr, int *addr_len); 
-extern asmlinkage int sys_setsockopt(int fd, int level, int optname, char *optval, int optlen);
-extern asmlinkage int sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen);
-extern asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned flags);
-extern asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags);
-extern asmlinkage int sys_socketcall(int call, unsigned long *args);
-extern asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp);
-extern asmlinkage int sys_listen(int fd, int backlog);
-extern asmlinkage int sys_socket(int family, int type, int protocol);
-extern asmlinkage int sys_socketpair(int family, int type, int protocol, int usockvec[2]);
-extern asmlinkage int sys_shutdown(int fd, int how);
-
-/*
- * In order to reduce some races, while at the same time doing additional
+/* 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..
  *
@@ -168,8 +65,7 @@
 	return retval;
 }
 
-/*
- * This is a single page for faster getname.
+/* This is a single page for faster getname.
  *   If the page is available when entering getname, use it.
  *   If the page is not available, call __get_free_page instead.
  * This works even though do_getname can block (think about it).
@@ -209,6 +105,8 @@
 	return retval;
 }
 
+extern asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
+
 asmlinkage int sys32_ioperm(u32 from, u32 num, int on)
 {
 	return sys_ioperm((unsigned long)from, (unsigned long)num, on);
@@ -571,22 +469,56 @@
 	return err;
 }
 
-asmlinkage unsigned long sys32_mmap(u32 addr, u32 len, u32 prot, u32 flags, u32 fd, u32 off)
+extern asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
+					 unsigned long prot, unsigned long flags,
+					 unsigned long fd, unsigned long off);
+
+asmlinkage unsigned long sys32_mmap(u32 addr, u32 len, u32 prot,
+				    u32 flags, u32 fd, u32 off)
 {
-	return sys_mmap((unsigned long)addr, (unsigned long)len, (unsigned long)prot, (unsigned long)flags, 
+	return sys_mmap((unsigned long)addr, (unsigned long)len,
+			(unsigned long)prot, (unsigned long)flags, 
 			(unsigned long)fd, (unsigned long)off);
 }
 
+extern asmlinkage int sys_bdflush(int func, long data);
+
 asmlinkage int sys32_bdflush(int func, s32 data)
 {
 	return sys_bdflush(func, (long)data);
 }
 
+extern asmlinkage int sys_uselib(const char * library);
+
 asmlinkage int sys32_uselib(u32 library)
 {
 	return sys_uselib((const char *)A(library));
 }
 
+static inline int get_flock(struct flock *kfl, struct flock32 *ufl)
+{
+	if(get_user(kfl->l_type, &ufl->l_type)		||
+	   __get_user(kfl->l_whence, &ufl->l_whence)	||
+	   __get_user(kfl->l_start, &ufl->l_start)	||
+	   __get_user(kfl->l_len, &ufl->l_len)		||
+	   __get_user(kfl->l_pid, &ufl->l_pid))
+		return -EFAULT;
+	return 0;
+}
+
+static inline int put_flock(struct flock *kfl, struct flock32 *ufl)
+{
+	if(__put_user(kfl->l_type, &ufl->l_type)	||
+	   __put_user(kfl->l_whence, &ufl->l_whence)	||
+	   __put_user(kfl->l_start, &ufl->l_start)	||
+	   __put_user(kfl->l_len, &ufl->l_len)		||
+	   __put_user(kfl->l_pid, &ufl->l_pid))
+		return -EFAULT;
+	return 0;
+}
+
+extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
+
 asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, u32 arg)
 {
 	switch (cmd) {
@@ -598,20 +530,12 @@
 			unsigned long old_fs;
 			long ret;
 			
-			if (get_user (f.l_type, &(((struct flock32 *)A(arg))->l_type)) ||
-			    __get_user (f.l_whence, &(((struct flock32 *)A(arg))->l_whence)) ||
-			    __get_user (f.l_start, &(((struct flock32 *)A(arg))->l_start)) ||
-			    __get_user (f.l_len, &(((struct flock32 *)A(arg))->l_len)) ||
-			    __get_user (f.l_pid, &(((struct flock32 *)A(arg))->l_pid)))
+			if(get_flock(&f, (struct flock32 *)A(arg)))
 				return -EFAULT;
 			old_fs = get_fs(); set_fs (KERNEL_DS);
 			ret = sys_fcntl(fd, cmd, (unsigned long)&f);
 			set_fs (old_fs);
-   			if (__put_user (f.l_type, &(((struct flock32 *)A(arg))->l_type)) ||
-			    __put_user (f.l_whence, &(((struct flock32 *)A(arg))->l_whence)) ||
-			    __put_user (f.l_start, &(((struct flock32 *)A(arg))->l_start)) ||
-			    __put_user (f.l_len, &(((struct flock32 *)A(arg))->l_len)) ||
-			    __put_user (f.l_pid, &(((struct flock32 *)A(arg))->l_pid)))
+			if(put_flock(&f, (struct flock32 *)A(arg)))
 				return -EFAULT;
 			return ret;
 		}
@@ -620,36 +544,50 @@
 	}
 }
 
+extern asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev);
+
 asmlinkage int sys32_mknod(u32 filename, int mode, __kernel_dev_t32 dev)
 {
 	return sys_mknod((const char *)A(filename), mode, dev);
 }
 
+extern asmlinkage int sys_mkdir(const char * pathname, int mode);
+
 asmlinkage int sys32_mkdir(u32 pathname, int mode)
 {
 	return sys_mkdir((const char *)A(pathname), mode);
 }
 
+extern asmlinkage int sys_rmdir(const char * pathname);
+
 asmlinkage int sys32_rmdir(u32 pathname)
 {
 	return sys_rmdir((const char *)A(pathname));
 }
 
+extern asmlinkage int sys_unlink(const char * pathname);
+
 asmlinkage int sys32_unlink(u32 pathname)
 {
 	return sys_unlink((const char *)A(pathname));
 }
 
+extern asmlinkage int sys_symlink(const char * oldname, const char * newname);
+
 asmlinkage int sys32_symlink(u32 oldname, u32 newname)
 {
 	return sys_symlink((const char *)A(oldname), (const char *)A(newname));
 }
 
+extern asmlinkage int sys_link(const char * oldname, const char * newname);
+
 asmlinkage int sys32_link(u32 oldname, u32 newname)
 {
 	return sys_link((const char *)A(oldname), (const char *)A(newname));
 }
 
+extern asmlinkage int sys_rename(const char * oldname, const char * newname);
+
 asmlinkage int sys32_rename(u32 oldname, u32 newname)
 {
 	return sys_rename((const char *)A(oldname), (const char *)A(newname));
@@ -666,12 +604,15 @@
     __kernel_time_t32 dqb_itime;
 };
                                 
+extern asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr);
+
 asmlinkage int sys32_quotactl(int cmd, u32 special, int id, u32 addr)
 {
 	int cmds = cmd >> SUBCMDSHIFT;
 	int err;
 	struct dqblk d;
 	unsigned long old_fs;
+	char *spec;
 	
 	switch (cmds) {
 	case Q_GETQUOTA:
@@ -679,57 +620,73 @@
 	case Q_SETQUOTA:
 	case Q_SETUSE:
 	case Q_SETQLIM:
-		if (copy_from_user (&d, (struct dqblk32 *)A(addr), sizeof (struct dqblk32)))
+		if (copy_from_user (&d, (struct dqblk32 *)A(addr),
+				    sizeof (struct dqblk32)))
 			return -EFAULT;
 		d.dqb_itime = ((struct dqblk32 *)&d)->dqb_itime;
 		d.dqb_btime = ((struct dqblk32 *)&d)->dqb_btime;
 		break;
 	default:
-		return sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+		return sys_quotactl(cmd, (const char *)A(special),
+				    id, (caddr_t)A(addr));
 	}
+	err = getname32 (special, &spec);
+	if (err) return err;
 	old_fs = get_fs ();
 	set_fs (KERNEL_DS);
-	err = sys_quotactl(cmd, (const char *)A(special), id, (caddr_t)A(addr));
+	err = sys_quotactl(cmd, (const char *)spec, id, (caddr_t)A(addr));
 	set_fs (old_fs);
+	putname32 (spec);
 	if (cmds == Q_GETQUOTA) {
 		__kernel_time_t b = d.dqb_btime, i = d.dqb_itime;
 		((struct dqblk32 *)&d)->dqb_itime = i;
 		((struct dqblk32 *)&d)->dqb_btime = b;
-		if (copy_to_user ((struct dqblk32 *)A(addr), &d, sizeof (struct dqblk32)))
+		if (copy_to_user ((struct dqblk32 *)A(addr), &d,
+				  sizeof (struct dqblk32)))
 			return -EFAULT;
 	}
 	return err;
 }
 
-static int put_statfs (u32 buf, struct statfs *s)
+static inline int put_statfs (struct statfs32 *ubuf, struct statfs *kbuf)
 {
-	if (put_user (s->f_type, &(((struct statfs32 *)A(buf))->f_type)) ||
-	    __put_user (s->f_bsize, &(((struct statfs32 *)A(buf))->f_bsize)) ||
-	    __put_user (s->f_blocks, &(((struct statfs32 *)A(buf))->f_blocks)) ||
-	    __put_user (s->f_bfree, &(((struct statfs32 *)A(buf))->f_bfree)) ||
-	    __put_user (s->f_bavail, &(((struct statfs32 *)A(buf))->f_bavail)) ||
-	    __put_user (s->f_files, &(((struct statfs32 *)A(buf))->f_files)) ||
-	    __put_user (s->f_ffree, &(((struct statfs32 *)A(buf))->f_ffree)) ||
-	    __put_user (s->f_namelen, &(((struct statfs32 *)A(buf))->f_namelen)) ||
-	    __put_user (s->f_fsid.val[0], &(((struct statfs32 *)A(buf))->f_fsid.val[0])) ||
-	    __put_user (s->f_fsid.val[1], &(((struct statfs32 *)A(buf))->f_fsid.val[1])))
+	if (put_user (kbuf->f_type, &ubuf->f_type)			||
+	    __put_user (kbuf->f_bsize, &ubuf->f_bsize)			||
+	    __put_user (kbuf->f_blocks, &ubuf->f_blocks)		||
+	    __put_user (kbuf->f_bfree, &ubuf->f_bfree)			||
+	    __put_user (kbuf->f_bavail, &ubuf->f_bavail)		||
+	    __put_user (kbuf->f_files, &ubuf->f_files)			||
+	    __put_user (kbuf->f_ffree, &ubuf->f_ffree)			||
+	    __put_user (kbuf->f_namelen, &ubuf->f_namelen)		||
+	    __put_user (kbuf->f_fsid.val[0], &ubuf->f_fsid.val[0])	||
+	    __put_user (kbuf->f_fsid.val[1], &ubuf->f_fsid.val[1]))
 		return -EFAULT;
 	return 0;
 }
 
+extern asmlinkage int sys_statfs(const char * path, struct statfs * buf);
+
 asmlinkage int sys32_statfs(u32 path, u32 buf)
 {
 	int ret;
 	struct statfs s;
 	unsigned long old_fs = get_fs();
+	char *pth;
 	
-	set_fs (KERNEL_DS);
-	ret = sys_statfs((const char *)A(path), &s);
-	set_fs (old_fs);
-	if (put_statfs(buf, &s)) return -EFAULT;
+	ret = getname32 (path, &pth);
+	if (!ret) {
+		set_fs (KERNEL_DS);
+		ret = sys_statfs((const char *)pth, &s);
+		set_fs (old_fs);
+		putname32 (pth);
+		if (put_statfs((struct statfs32 *)A(buf), &s))
+			return -EFAULT;
+	}
 	return ret;
 }
 
+extern asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf);
+
 asmlinkage int sys32_fstatfs(unsigned int fd, u32 buf)
 {
 	int ret;
@@ -739,20 +696,27 @@
 	set_fs (KERNEL_DS);
 	ret = sys_fstatfs(fd, &s);
 	set_fs (old_fs);
-	if (put_statfs(buf, &s)) return -EFAULT;
+	if (put_statfs((struct statfs32 *)A(buf), &s))
+		return -EFAULT;
 	return ret;
 }
 
+extern asmlinkage int sys_truncate(const char * path, unsigned long length);
+
 asmlinkage int sys32_truncate(u32 path, u32 length)
 {
 	return sys_truncate((const char *)A(path), (unsigned long)length);
 }
 
+extern asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length);
+
 asmlinkage int sys32_ftruncate(unsigned int fd, u32 length)
 {
 	return sys_ftruncate(fd, (unsigned long)length);
 }
 
+extern asmlinkage int sys_utime(char * filename, struct utimbuf * times);
+
 asmlinkage int sys32_utime(u32 filename, u32 times)
 {
 	struct utimbuf32 { __kernel_time_t32 actime, modtime; };
@@ -777,63 +741,91 @@
 	return ret;
 }
 
+extern asmlinkage int sys_utimes(char * filename, struct timeval * utimes);
+
 asmlinkage int sys32_utimes(u32 filename, u32 utimes)
 {
 	/* struct timeval is the same :)) */
 	return sys_utimes((char *)A(filename), (struct timeval *)A(utimes));
 }
 
+extern asmlinkage int sys_access(const char * filename, int mode);
+
 asmlinkage int sys32_access(u32 filename, int mode)
 {
 	return sys_access((const char *)A(filename), mode);
 }
 
+extern asmlinkage int sys_chdir(const char * filename);
+
 asmlinkage int sys32_chdir(u32 filename)
 {
 	return sys_chdir((const char *)A(filename));
 }
 
+extern asmlinkage int sys_chroot(const char * filename);
+
 asmlinkage int sys32_chroot(u32 filename)
 {
 	return sys_chroot((const char *)A(filename));
 }
 
+extern asmlinkage int sys_chmod(const char * filename, mode_t mode);
+
 asmlinkage int sys32_chmod(u32 filename, __kernel_mode_t32 mode)
 {
 	return sys_chmod((const char *)A(filename), mode);
 }
 
+extern asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group);
+
 asmlinkage int sys32_chown(u32 filename, __kernel_uid_t32 user, __kernel_gid_t32 group)
 {
 	return sys_chown((const char *)A(filename), user, group);
 }
 
+extern asmlinkage int sys_open(const char * filename,int flags,int mode);
+
 asmlinkage int sys32_open(u32 filename, int flags, int mode)
 {
 	return sys_open((const char *)A(filename), flags, mode);
 }
 
+extern asmlinkage int sys_creat(const char * pathname, int mode);
+
 asmlinkage int sys32_creat(u32 pathname, int mode)
 {
 	return sys_creat((const char *)A(pathname), mode);
 }
 
+extern asmlinkage long sys_lseek(unsigned int fd, off_t offset, unsigned int origin);
+
 asmlinkage long sys32_lseek(unsigned int fd, s32 offset, unsigned int origin)
 {
 	return sys_lseek(fd, (off_t)offset, origin);
 }
 
-asmlinkage int sys32_llseek(unsigned int fd, u32 offset_high, u32 offset_low, u32 result, unsigned int origin)
+extern asmlinkage int sys_llseek(unsigned int fd, unsigned long offset_high,
+				 unsigned long offset_low,
+				 loff_t *result, unsigned int origin);
+
+asmlinkage int sys32_llseek(unsigned int fd, u32 offset_high,
+			    u32 offset_low, u32 result, unsigned int origin)
 {
 	/* loff_t is the same :)) */
-	return sys_llseek(fd, (unsigned long)offset_high, (unsigned long)offset_low, (loff_t *)A(result), origin);
+	return sys_llseek(fd, (unsigned long)offset_high, (unsigned long)offset_low,
+			  (loff_t *)A(result), origin);
 }
 
+extern asmlinkage long sys_read(unsigned int fd, char * buf, unsigned long count);
+
 asmlinkage long sys32_read(unsigned int fd, u32 buf, u32 count)
 {
 	return sys_read(fd, (char *)A(buf), (unsigned long)count);
 }
 
+extern asmlinkage long sys_write(unsigned int fd, const char * buf, unsigned long count);
+
 asmlinkage long sys32_write(unsigned int fd, u32 buf, u32 count)
 {
 	return sys_write(fd, (const char *)A(buf), (unsigned long)count);
@@ -841,86 +833,146 @@
 
 struct iovec32 { u32 iov_base; __kernel_size_t32 iov_len; };
 
-asmlinkage long sys32_readv(u32 fd, u32 vector, u32 count)
+typedef long (*IO_fn_t)(struct inode *, struct file *, char *, unsigned long);
+
+static long do_readv_writev32(int type, struct inode *inode, struct file *file,
+			      const struct iovec32 *vector, u32 count)
 {
-	struct iovec *v;
-	struct iovec vf[UIO_FASTIOV];
-	u32 i;
-	long ret;
-	unsigned long old_fs;
-	
-	if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
-	if (count <= UIO_FASTIOV)
-		v = vf;
-	else {
-		lock_kernel ();
-		v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
-		if (!v) {
-			ret = -ENOMEM;
-			goto out;
-		}
+	unsigned long tot_len;
+	struct iovec iovstack[UIO_FASTIOV];
+	struct iovec *iov=iovstack, *ivp;
+	long retval, i;
+	IO_fn_t fn;
+
+	/* First get the "struct iovec" from user memory and
+	 * verify all the pointers
+	 */
+	if (!count)
+		return 0;
+	if(verify_area(VERIFY_READ, vector, sizeof(struct iovec32)*count))
+		return -EFAULT;
+	if (count > UIO_MAXIOV)
+		return -EINVAL;
+	if (count > UIO_FASTIOV) {
+		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
+		if (!iov)
+			return -ENOMEM;
 	}
-	for (i = 0; i < count; i++) {
-		if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
-		    __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
-		    	ret = -EFAULT;
-		    	goto out;
-		}
+
+	tot_len = 0;
+	i = count;
+	ivp = iov;
+	while(i > 0) {
+		u32 len;
+		u32 buf;
+
+		__get_user(len, &vector->iov_len);
+		__get_user(buf, &vector->iov_base);
+		tot_len += len;
+		ivp->iov_base = (void *)A(buf);
+		ivp->iov_len = (__kernel_size_t) len;
+		vector++;
+		ivp++;
+		i--;
+	}
+
+	retval = locks_verify_area((type == VERIFY_READ) ?
+				   FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE,
+				   inode, file, file->f_pos, tot_len);
+	if (retval) {
+		if (iov != iovstack)
+			kfree(iov);
+		return retval;
 	}
-	old_fs = get_fs();
-	set_fs (KERNEL_DS);
-	ret = sys_readv((unsigned long)fd, v, (unsigned long)count);
-	set_fs (old_fs);
-out:
-	if (count > UIO_FASTIOV) {
-		kfree (v);
-		unlock_kernel ();
+
+	/* Then do the actual IO.  Note that sockets need to be handled
+	 * specially as they have atomicity guarantees and can handle
+	 * iovec's natively
+	 */
+	if (inode->i_sock) {
+		int err;
+		err = sock_readv_writev(type, inode, file, iov, count, tot_len);
+		if (iov != iovstack)
+			kfree(iov);
+		return err;
 	}
-	return ret;
-}
 
-asmlinkage long sys32_writev(u32 fd, u32 vector, u32 count)
-{
-	struct iovec *v;
-	struct iovec vf[UIO_FASTIOV];
-	u32 i;
-	long ret;
-	unsigned long old_fs;
-	
-	if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
-	if (count <= UIO_FASTIOV)
-		v = vf;
-	else {
-		lock_kernel ();
-		v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
-		if (!v) {
-			ret = -ENOMEM;
-			goto out;
-		}
+	if (!file->f_op) {
+		if (iov != iovstack)
+			kfree(iov);
+		return -EINVAL;
 	}
-	for (i = 0; i < count; i++) {
-		if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
-		    __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
-			ret = -EFAULT;
-			goto out;
+	/* VERIFY_WRITE actually means a read, as we write to user space */
+	fn = file->f_op->read;
+	if (type == VERIFY_READ)
+		fn = (IO_fn_t) file->f_op->write;		
+	ivp = iov;
+	while (count > 0) {
+		void * base;
+		int len, nr;
+
+		base = ivp->iov_base;
+		len = ivp->iov_len;
+		ivp++;
+		count--;
+		nr = fn(inode, file, base, len);
+		if (nr < 0) {
+			if (retval)
+				break;
+			retval = nr;
+			break;
 		}
+		retval += nr;
+		if (nr != len)
+			break;
 	}
-	old_fs = get_fs();
-	set_fs (KERNEL_DS);
-	ret = sys_writev((unsigned long)fd, v, (unsigned long)count);
-	set_fs (old_fs);
-out:	
-	if (count > UIO_FASTIOV) {
-		kfree (v);
-		unlock_kernel ();
-	}
-	return ret;
+	if (iov != iovstack)
+		kfree(iov);
+	return retval;
+}
+
+asmlinkage long sys32_readv(int fd, u32 vector, u32 count)
+{
+	struct file *file;
+	struct inode *inode;
+	long err = -EBADF;
+
+	lock_kernel();
+	if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode))
+		goto out;
+	if (!(file->f_mode & 1))
+		goto out;
+	err = do_readv_writev32(VERIFY_WRITE, inode, file,
+				(struct iovec32 *)A(vector), count);
+out:
+	unlock_kernel();
+	return err;
+}
+
+asmlinkage long sys32_writev(int fd, u32 vector, u32 count)
+{
+	int error = -EBADF;
+	struct file *file;
+	struct inode *inode;
+
+	lock_kernel();
+	if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode))
+		goto out;
+	if (!(file->f_mode & 2))
+		goto out;
+	down(&inode->i_sem);
+	error = do_readv_writev32(VERIFY_READ, inode, file,
+				(struct iovec32 *)A(vector), count);
+	up(&inode->i_sem);
+out:
+	unlock_kernel();
+	return error;
 }
 
 /* readdir & getdents */
 
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
-#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
+#define ROUND_UP(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
 
 struct old_linux_dirent32 {
 	u32		d_ino;
@@ -934,7 +986,8 @@
 	int count;
 };
 
-static int fillonedir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
+static int fillonedir(void * __buf, const char * name, int namlen,
+		      off_t offset, ino_t ino)
 {
 	struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
 	struct old_linux_dirent32 * dirent;
@@ -963,7 +1016,8 @@
 	error = -ENOTDIR;
 	if (!file->f_op || !file->f_op->readdir)
 		goto out;
-	error = verify_area(VERIFY_WRITE, (void *)A(dirent), sizeof(struct old_linux_dirent32));
+	error = verify_area(VERIFY_WRITE, (void *)A(dirent),
+			    sizeof(struct old_linux_dirent32));
 	if (error)
 		goto out;
 	buf.count = 0;
@@ -1052,84 +1106,124 @@
 
 /* end of readdir & getdents */
 
+extern asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp,
+				 fd_set *exp, struct timeval *tvp);
+
 asmlinkage int sys32_select(int n, u32 inp, u32 outp, u32 exp, u32 tvp)
 {
 	struct timeval kern_tv, *ktvp;
 	unsigned long old_fs;
 	char *p;
-	u32 *q;
+	u32 *q, *Inp, *Outp, *Exp;
 	int i, ret = -EINVAL, nn;
-	u32 *Inp, *Outp, *Exp;
 	
-	if (n < 0 || n > PAGE_SIZE*2) return -EINVAL;
+	if (n < 0 || n > PAGE_SIZE*2)
+		return -EINVAL;
+
 	lock_kernel ();
 	p = (char *)__get_free_page (GFP_KERNEL);
-	if (!p) goto out;
+	if (!p)
+		goto out;
+
 	q = (u32 *)p;
-	nn = (n + 8 * sizeof(unsigned long) - 1) / (8 * sizeof (unsigned long));
-	Inp = (u32 *)A(inp); Outp = (u32 *)A(outp); Exp = (u32 *)A(exp);
+	Inp = (u32 *)A(inp);
+	Outp = (u32 *)A(outp);
+	Exp = (u32 *)A(exp);
+
 	ret = -EFAULT;
-	for (i = 0; i < ret; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
-		if (__get_user (q[1], Inp) ||
-		    __get_user (q[0], Inp+1) ||
-		    __get_user (q[1+PAGE_SIZE/4], Outp) ||
-		    __get_user (q[PAGE_SIZE/4], Outp+1) ||
-		    __get_user (q[1+PAGE_SIZE/2], Exp) ||
-		    __get_user (q[PAGE_SIZE/2], Exp+1))
+
+	nn = (n + (8 * sizeof(unsigned long)) - 1) / (8 * sizeof (unsigned long));
+	for (i = 0; i < nn; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
+		if(inp && (__get_user (q[1], Inp) || __get_user (q[0], Inp+1)))
+			goto out;
+		if(outp && (__get_user (q[1+(PAGE_SIZE/4/sizeof(u32))], Outp) ||
+			    __get_user (q[(PAGE_SIZE/4/sizeof(u32))], Outp+1)))
+			goto out;
+		if(exp && (__get_user (q[1+(PAGE_SIZE/2/sizeof(u32))], Exp) ||
+			   __get_user (q[(PAGE_SIZE/2/sizeof(u32))], Exp+1)))
 			goto out;
 	}
+
 	ktvp = NULL;
 	if(tvp) {
 		if(copy_from_user(&kern_tv, (struct timeval *)A(tvp), sizeof(*ktvp)))
 			goto out;
 		ktvp = &kern_tv;
 	}
+
 	old_fs = get_fs ();
 	set_fs (KERNEL_DS);
-	ret = sys_select(n, (fd_set *)p, (fd_set *)(p + PAGE_SIZE/4), (fd_set *)(p + PAGE_SIZE/2), ktvp);
+	q = (u32 *) p;
+	ret = sys_select(n,
+			 inp ? (fd_set *)&q[0] : (fd_set *)0,
+			 outp ? (fd_set *)&q[PAGE_SIZE/4/sizeof(u32)] : (fd_set *)0,
+			 exp ? (fd_set *)&q[PAGE_SIZE/2/sizeof(u32)] : (fd_set *)0,
+			 ktvp);
 	set_fs (old_fs);
+
+	if(tvp && !(current->personality & STICKY_TIMEOUTS))
+		copy_to_user((struct timeval *)A(tvp), &kern_tv, sizeof(*ktvp));
+
 	q = (u32 *)p;
-	Inp = (u32 *)A(inp); Outp = (u32 *)A(outp); Exp = (u32 *)A(exp);
-	for (i = 0; i < ret; i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
-		if (__put_user (q[1], Inp) ||
-		    __put_user (q[0], Inp+1) ||
-		    __put_user (q[1+PAGE_SIZE/4], Outp) ||
-		    __put_user (q[PAGE_SIZE/4], Outp+1) ||
-		    __put_user (q[1+PAGE_SIZE/2], Exp) ||
-		    __put_user (q[PAGE_SIZE/2], Exp+1)) {
+	Inp = (u32 *)A(inp);
+	Outp = (u32 *)A(outp);
+	Exp = (u32 *)A(exp);
+
+	if(ret < 0)
+		goto out;
+
+	for (i = 0;
+	     i < nn;
+	     i++, Inp += 2, Outp += 2, Exp += 2, q += 2) {
+		if(inp && (__put_user (q[1], Inp) || __put_user (q[0], Inp+1))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		if(outp && (__put_user (q[1+(PAGE_SIZE/4/sizeof(u32))], Outp) ||
+			    __put_user (q[(PAGE_SIZE/4/sizeof(u32))], Outp+1))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		if(exp && (__put_user (q[1+(PAGE_SIZE/2/sizeof(u32))], Exp) ||
+			   __put_user (q[(PAGE_SIZE/2/sizeof(u32))], Exp+1))) {
 		    	ret = -EFAULT;
 			goto out;
 		}
 	}
 out:
 	free_page ((unsigned long)p);
+	unlock_kernel();
 	return ret;
 }
 
+extern asmlinkage int sys_poll(struct pollfd * ufds, unsigned int nfds, int timeout);
+
 asmlinkage int sys32_poll(u32 ufds, unsigned int nfds, int timeout)
 {
 	return sys_poll((struct pollfd *)A(ufds), nfds, timeout);
 }
 
-static inline int putstat(u32 statbuf, struct stat *s)
+static inline int putstat(struct stat32 *ubuf, struct stat *kbuf)
 {
-	if (put_user (s->st_dev, &(((struct stat32 *)A(statbuf))->st_dev)) ||
-	    __put_user (s->st_ino, &(((struct stat32 *)A(statbuf))->st_ino)) ||
-	    __put_user (s->st_mode, &(((struct stat32 *)A(statbuf))->st_mode)) ||
-	    __put_user (s->st_nlink, &(((struct stat32 *)A(statbuf))->st_nlink)) ||
-	    __put_user (s->st_uid, &(((struct stat32 *)A(statbuf))->st_uid)) ||
-	    __put_user (s->st_gid, &(((struct stat32 *)A(statbuf))->st_gid)) ||
-	    __put_user (s->st_rdev, &(((struct stat32 *)A(statbuf))->st_rdev)) ||
-	    __put_user (s->st_size, &(((struct stat32 *)A(statbuf))->st_size)) ||
-	    __put_user (s->st_atime, &(((struct stat32 *)A(statbuf))->st_atime)) ||
-	    __put_user (s->st_mtime, &(((struct stat32 *)A(statbuf))->st_mtime)) ||
-	    __put_user (s->st_ctime, &(((struct stat32 *)A(statbuf))->st_ctime)) ||
-	    __put_user (s->st_blksize, &(((struct stat32 *)A(statbuf))->st_blksize)) ||
-	    __put_user (s->st_blocks, &(((struct stat32 *)A(statbuf))->st_blocks)))
+	if (put_user (kbuf->st_dev, &ubuf->st_dev)		||
+	    __put_user (kbuf->st_ino, &ubuf->st_ino)		||
+	    __put_user (kbuf->st_mode, &ubuf->st_mode)		||
+	    __put_user (kbuf->st_nlink, &ubuf->st_nlink)	||
+	    __put_user (kbuf->st_uid, &ubuf->st_uid)		||
+	    __put_user (kbuf->st_gid, &ubuf->st_gid)		||
+	    __put_user (kbuf->st_rdev, &ubuf->st_rdev)		||
+	    __put_user (kbuf->st_size, &ubuf->st_size)		||
+	    __put_user (kbuf->st_atime, &ubuf->st_atime)	||
+	    __put_user (kbuf->st_mtime, &ubuf->st_mtime)	||
+	    __put_user (kbuf->st_ctime, &ubuf->st_ctime)	||
+	    __put_user (kbuf->st_blksize, &ubuf->st_blksize)	||
+	    __put_user (kbuf->st_blocks, &ubuf->st_blocks))
 		return -EFAULT;
 	return 0;
 }
 
+extern asmlinkage int sys_newstat(char * filename, struct stat * statbuf);
+
 asmlinkage int sys32_newstat(u32 filename, u32 statbuf)
 {
 	int ret;
@@ -1143,11 +1237,14 @@
 		ret = sys_newstat(filenam, &s);
 		set_fs (old_fs);
 		putname32 (filenam);
-		if (putstat (statbuf, &s)) return -EFAULT;
+		if (putstat ((struct stat32 *)A(statbuf), &s))
+			return -EFAULT;
 	}
 	return ret;
 }
 
+extern asmlinkage int sys_newlstat(char * filename, struct stat * statbuf);
+
 asmlinkage int sys32_newlstat(u32 filename, u32 statbuf)
 {
 	int ret;
@@ -1161,11 +1258,14 @@
 		ret = sys_newlstat(filenam, &s);
 		set_fs (old_fs);
 		putname32 (filenam);
-		if (putstat (statbuf, &s)) return -EFAULT;
+		if (putstat ((struct stat32 *)A(statbuf), &s))
+			return -EFAULT;
 	}
 	return ret;
 }
 
+extern asmlinkage int sys_newfstat(unsigned int fd, struct stat * statbuf);
+
 asmlinkage int sys32_newfstat(unsigned int fd, u32 statbuf)
 {
 	int ret;
@@ -1175,15 +1275,20 @@
 	set_fs (KERNEL_DS);
 	ret = sys_newfstat(fd, &s);
 	set_fs (old_fs);
-	if (putstat (statbuf, &s)) return -EFAULT;
+	if (putstat ((struct stat32 *)A(statbuf), &s))
+		return -EFAULT;
 	return ret;
 }
 
+extern asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz);
+
 asmlinkage int sys32_readlink(u32 path, u32 buf, int bufsiz)
 {
 	return sys_readlink((const char *)A(path), (char *)A(buf), bufsiz);
 }
 
+extern asmlinkage int sys_sysfs(int option, ...);
+
 asmlinkage int sys32_sysfs(int option, ...)
 {
         va_list args;
@@ -1207,28 +1312,39 @@
 	return ret;
 }
 
+extern asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf);
+
 asmlinkage int sys32_ustat(dev_t dev, u32 ubuf)
 {
 	/* ustat is the same :)) */
 	return sys_ustat(dev, (struct ustat *)A(ubuf));
 }
 
+extern asmlinkage int sys_umount(char * name);
+
 asmlinkage int sys32_umount(u32 name)
 {
 	return sys_umount((char *)A(name));
 }
 
+extern asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
+				unsigned long new_flags, void *data);
+
 asmlinkage int sys32_mount(u32 dev_name, u32 dir_name, u32 type, u32 new_flags, u32 data)
 {
 	return sys_mount((char *)A(dev_name), (char *)A(dir_name), (char *)A(type), 
 			 (unsigned long)new_flags, (void *)A(data));
 }
 
+extern asmlinkage int sys_syslog(int type, char * bug, int count);
+
 asmlinkage int sys32_syslog(int type, u32 bug, int count)
 {
 	return sys_syslog(type, (char *)A(bug), count);
 }
 
+extern asmlinkage int sys_personality(unsigned long personality);
+
 asmlinkage int sys32_personality(u32 personality)
 {
 	return sys_personality((unsigned long)personality);
@@ -1277,6 +1393,9 @@
 	return 0;
 }
 
+extern asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr,
+				int options, struct rusage * ru);
+
 asmlinkage int sys32_wait4(__kernel_pid_t32 pid, u32 stat_addr, int options, u32 ru)
 {
 	if (!ru)
@@ -1284,16 +1403,21 @@
 	else {
 		struct rusage r;
 		int ret;
+		unsigned int status;
 		unsigned long old_fs = get_fs();
 		
 		set_fs (KERNEL_DS);
-		ret = sys_wait4(pid, (unsigned int *)A(stat_addr), options, &r);
+		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
 		set_fs (old_fs);
 		if (put_rusage (ru, &r)) return -EFAULT;
+		if (stat_addr && put_user (status, (unsigned int *)A(stat_addr)))
+			return -EFAULT;
 		return ret;
 	}
 }
 
+extern asmlinkage int sys_waitpid(pid_t pid,unsigned int * stat_addr, int options);
+
 asmlinkage int sys32_waitpid(__kernel_pid_t32 pid, u32 stat_addr, int options)
 {
 	return sys_waitpid(pid, (unsigned int *)A(stat_addr), options);
@@ -1312,6 +1436,8 @@
         char _f[22];
 };
 
+extern asmlinkage int sys_sysinfo(struct sysinfo *info);
+
 asmlinkage int sys32_sysinfo(u32 info)
 {
 	struct sysinfo s;
@@ -1336,28 +1462,41 @@
 	return ret;
 }
 
+extern asmlinkage int sys_getitimer(int which, struct itimerval *value);
+
 asmlinkage int sys32_getitimer(int which, u32 value)
 {
 	/* itimerval is the same :)) */
 	return sys_getitimer(which, (struct itimerval *)A(value));
 }
 
+extern asmlinkage int sys_setitimer(int which, struct itimerval *value,
+				    struct itimerval *ovalue);
+
 asmlinkage int sys32_setitimer(int which, u32 value, u32 ovalue)
 {
-	return sys_setitimer(which, (struct itimerval *)A(value), (struct itimerval *)A(ovalue));
+	return sys_setitimer(which, (struct itimerval *)A(value),
+			     (struct itimerval *)A(ovalue));
 }
 
+extern asmlinkage int sys_sched_setscheduler(pid_t pid, int policy,
+					     struct sched_param *param);
+
 asmlinkage int sys32_sched_setscheduler(__kernel_pid_t32 pid, int policy, u32 param)
 {
 	/* sched_param is the same :)) */
 	return sys_sched_setscheduler(pid, policy, (struct sched_param *)A(param));
 }
 
+extern asmlinkage int sys_sched_setparam(pid_t pid, struct sched_param *param);
+
 asmlinkage int sys32_sched_setparam(__kernel_pid_t32 pid, u32 param)
 {
 	return sys_sched_setparam(pid, (struct sched_param *)A(param));
 }
 
+extern asmlinkage int sys_sched_getparam(pid_t pid, struct sched_param *param);
+
 asmlinkage int sys32_sched_getparam(__kernel_pid_t32 pid, u32 param)
 {
 	return sys_sched_getparam(pid, (struct sched_param *)A(param));
@@ -1368,6 +1507,8 @@
 	s32    tv_nsec;
 };
                 
+extern asmlinkage int sys_sched_rr_get_interval(pid_t pid, struct timespec *interval);
+
 asmlinkage int sys32_sched_rr_get_interval(__kernel_pid_t32 pid, u32 interval)
 {
 	struct timespec t;
@@ -1383,6 +1524,8 @@
 	return ret;
 }
 
+extern asmlinkage int sys_nanosleep(struct timespec *rqtp, struct timespec *rmtp);
+
 asmlinkage int sys32_nanosleep(u32 rqtp, u32 rmtp)
 {
 	struct timespec t;
@@ -1403,6 +1546,8 @@
 	return ret;
 }
 
+extern asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset);
+
 asmlinkage int sys32_sigprocmask(int how, u32 set, u32 oset)
 {
 	sigset_t s;
@@ -1417,6 +1562,8 @@
 	return ret;
 }
 
+extern asmlinkage int sys_sigpending(sigset_t *set);
+
 asmlinkage int sys32_sigpending(u32 set)
 {
 	sigset_t s;
@@ -1430,21 +1577,29 @@
 	return ret;
 }
 
+extern asmlinkage unsigned long sys_signal(int signum, __sighandler_t handler);
+
 asmlinkage unsigned long sys32_signal(int signum, u32 handler)
 {
 	return sys_signal(signum, (__sighandler_t)A(handler));
 }
 
+extern asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg);
+
 asmlinkage int sys32_reboot(int magic1, int magic2, int cmd, u32 arg)
 {
 	return sys_reboot(magic1, magic2, cmd, (void *)A(arg));
 }
 
+extern asmlinkage int sys_acct(const char *name);
+
 asmlinkage int sys32_acct(u32 name)
 {
 	return sys_acct((const char *)A(name));
 }
 
+extern asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);
+
 asmlinkage int sys32_getresuid(u32 ruid, u32 euid, u32 suid)
 {
 	uid_t a, b, c;
@@ -1468,6 +1623,8 @@
 	__kernel_clock_t32 tms_cstime;
 };
                                 
+extern asmlinkage long sys_times(struct tms * tbuf);
+
 asmlinkage long sys32_times(u32 tbuf)
 {
 	struct tms t;
@@ -1486,6 +1643,8 @@
 	return ret;
 }
 
+extern asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist);
+
 asmlinkage int sys32_getgroups(int gidsetsize, u32 grouplist)
 {
 	gid_t gl[NGROUPS];
@@ -1502,6 +1661,8 @@
 	return ret;
 }
 
+extern asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist);
+
 asmlinkage int sys32_setgroups(int gidsetsize, u32 grouplist)
 {
 	gid_t gl[NGROUPS];
@@ -1519,27 +1680,37 @@
 	return ret;
 }
 
+extern asmlinkage int sys_newuname(struct new_utsname * name);
+
 asmlinkage int sys32_newuname(u32 name)
 {
 	/* utsname is the same :)) */
 	return sys_newuname((struct new_utsname *)A(name));
 }
 
+extern asmlinkage int sys_olduname(struct oldold_utsname * name);
+
 asmlinkage int sys32_olduname(u32 name)
 {
 	return sys_olduname((struct oldold_utsname *)A(name));
 }
 
+extern asmlinkage int sys_sethostname(char *name, int len);
+
 asmlinkage int sys32_sethostname(u32 name, int len)
 {
 	return sys_sethostname((char *)A(name), len);
 }
 
+extern asmlinkage int sys_gethostname(char *name, int len);
+
 asmlinkage int sys32_gethostname(u32 name, int len)
 {
 	return sys_gethostname((char *)A(name), len);
 }
 
+extern asmlinkage int sys_setdomainname(char *name, int len);
+
 asmlinkage int sys32_setdomainname(u32 name, int len)
 {
 	return sys_setdomainname((char *)A(name), len);
@@ -1550,6 +1721,8 @@
 	s32	rlim_max;
 };
 
+extern asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim);
+
 asmlinkage int sys32_getrlimit(unsigned int resource, u32 rlim)
 {
 	struct rlimit r;
@@ -1566,6 +1739,8 @@
 	return ret;
 }
 
+extern asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim);
+
 asmlinkage int sys32_setrlimit(unsigned int resource, u32 rlim)
 {
 	struct rlimit r;
@@ -1582,6 +1757,8 @@
 	return ret;
 }
 
+extern asmlinkage int sys_getrusage(int who, struct rusage *ru);
+
 asmlinkage int sys32_getrusage(int who, u32 ru)
 {
 	struct rusage r;
@@ -1595,17 +1772,23 @@
 	return ret;
 }
 
+extern asmlinkage int sys_time(int * tloc);
+
 asmlinkage int sys32_time(u32 tloc)
 {
 	return sys_time((int *)A(tloc));
 }
 
+extern asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz);
+
 asmlinkage int sys32_gettimeofday(u32 tv, u32 tz)
 {
 	/* both timeval and timezone are ok :)) */
 	return sys_gettimeofday((struct timeval *)A(tv), (struct timezone *)A(tz));
 }
 
+extern asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz);
+
 asmlinkage int sys32_settimeofday(u32 tv, u32 tz)
 {
 	return sys_settimeofday((struct timeval *)A(tv), (struct timezone *)A(tz));
@@ -1636,6 +1819,8 @@
 	int  :32; int  :32; int  :32; int  :32;
 };
 
+extern asmlinkage int sys_adjtimex(struct timex *txc_p);
+
 asmlinkage int sys32_adjtimex(u32 txc_p)
 {
 	struct timex t;
@@ -1680,98 +1865,154 @@
 	return ret;
 }
 
+extern asmlinkage int sys_msync(unsigned long start, size_t len, int flags);
+
 asmlinkage int sys32_msync(u32 start, __kernel_size_t32 len, int flags)
 {
 	return sys_msync((unsigned long)start, (size_t)len, flags);
 }
 
+extern asmlinkage int sys_mlock(unsigned long start, size_t len);
+
 asmlinkage int sys32_mlock(u32 start, __kernel_size_t32 len)
 {
 	return sys_mlock((unsigned long)start, (size_t)len);
 }
 
+extern asmlinkage int sys_munlock(unsigned long start, size_t len);
+
 asmlinkage int sys32_munlock(u32 start, __kernel_size_t32 len)
 {
 	return sys_munlock((unsigned long)start, (size_t)len);
 }
 
+extern asmlinkage unsigned long sys_brk(unsigned long brk);
+
 asmlinkage unsigned long sparc32_brk(u32 brk)
 {
 	return sys_brk((unsigned long)brk);
 }
 
+extern asmlinkage int sys_munmap(unsigned long addr, size_t len);
+
 asmlinkage int sys32_munmap(u32 addr, __kernel_size_t32 len)
 {
 	return sys_munmap((unsigned long)addr, (size_t)len);
 }
 
+extern asmlinkage int sys_mprotect(unsigned long start, size_t len, unsigned long prot);
+
 asmlinkage int sys32_mprotect(u32 start, __kernel_size_t32 len, u32 prot)
 {
 	return sys_mprotect((unsigned long)start, (size_t)len, (unsigned long)prot);
 }
 
+extern asmlinkage unsigned long sys_mremap(unsigned long addr, unsigned long old_len,
+					   unsigned long new_len, unsigned long flags);
+
 asmlinkage unsigned long sys32_mremap(u32 addr, u32 old_len, u32 new_len, u32 flags)
 {
-	return sys_mremap((unsigned long)addr, (unsigned long)old_len, (unsigned long)new_len, (unsigned long)flags);
+	return sys_mremap((unsigned long)addr, (unsigned long)old_len,
+			  (unsigned long)new_len, (unsigned long)flags);
 }
 
+extern asmlinkage int sys_swapoff(const char * specialfile);
+
 asmlinkage int sys32_swapoff(u32 specialfile)
 {
 	return sys_swapoff((const char *)A(specialfile));
 }
 
+extern asmlinkage int sys_swapon(const char * specialfile, int swap_flags);
+
 asmlinkage int sys32_swapon(u32 specialfile, int swap_flags)
 {
 	return sys_swapon((const char *)A(specialfile), swap_flags);
 }
 
-asmlinkage int sys32_bind(int fd, u32 umyaddr, int addrlen)
+extern asmlinkage int sys_bind(int fd, struct sockaddr *umyaddr, int addrlen);
+
+asmlinkage inline int sys32_bind(int fd, u32 umyaddr, int addrlen)
 {
 	/* sockaddr is the same :)) */
 	return sys_bind(fd, (struct sockaddr *)A(umyaddr), addrlen);
 }
 
-asmlinkage int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen)
+extern asmlinkage int sys_accept(int fd, struct sockaddr *upeer_sockaddr,
+				 int *upeer_addrlen);
+
+asmlinkage inline int sys32_accept(int fd, u32 upeer_sockaddr, u32 upeer_addrlen)
 {
-	return sys_accept(fd, (struct sockaddr *)A(upeer_sockaddr), (int *)A(upeer_addrlen));
+	return sys_accept(fd, (struct sockaddr *)A(upeer_sockaddr),
+			  (int *)A(upeer_addrlen));
 }
 
-asmlinkage int sys32_connect(int fd, u32 uservaddr, int addrlen)
+extern asmlinkage int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen);
+
+asmlinkage inline int sys32_connect(int fd, u32 uservaddr, int addrlen)
 {
 	return sys_connect(fd, (struct sockaddr *)A(uservaddr), addrlen);
 }
 
+extern asmlinkage int sys_getsockname(int fd, struct sockaddr *usockaddr,
+				      int *usockaddr_len);
+
 asmlinkage int sys32_getsockname(int fd, u32 usockaddr, u32 usockaddr_len)
 {
-	return sys_getsockname(fd, (struct sockaddr *)A(usockaddr), (int *)A(usockaddr_len));
+	return sys_getsockname(fd, (struct sockaddr *)A(usockaddr),
+			       (int *)A(usockaddr_len));
 }
 
+extern asmlinkage int sys_getpeername(int fd, struct sockaddr *usockaddr,
+				      int *usockaddr_len);
+
 asmlinkage int sys32_getpeername(int fd, u32 usockaddr, u32 usockaddr_len)
 {
-	return sys_getpeername(fd, (struct sockaddr *)A(usockaddr), (int *)A(usockaddr_len));
+	return sys_getpeername(fd, (struct sockaddr *)A(usockaddr),
+			       (int *)A(usockaddr_len));
 }
 
-asmlinkage int sys32_send(int fd, u32 buff, __kernel_size_t32 len, unsigned flags)
+extern asmlinkage int sys_send(int fd, void * buff, size_t len, unsigned flags);
+
+asmlinkage inline int sys32_send(int fd, u32 buff,
+				 __kernel_size_t32 len, unsigned flags)
 {
 	return sys_send(fd, (void *)A(buff), (size_t)len, flags);
 }
 
-asmlinkage int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len, unsigned flags, u32 addr, int addr_len)
+extern asmlinkage int sys_sendto(int fd, void * buff, size_t len, unsigned flags,
+				 struct sockaddr *addr, int addr_len);
+
+asmlinkage inline int sys32_sendto(int fd, u32 buff, __kernel_size_t32 len,
+				   unsigned flags, u32 addr, int addr_len)
 {
-	return sys_sendto(fd, (void *)A(buff), (size_t)len, flags, (struct sockaddr *)A(addr), addr_len);
+	return sys_sendto(fd, (void *)A(buff), (size_t)len, flags,
+			  (struct sockaddr *)A(addr), addr_len);
 }
 
-asmlinkage int sys32_recv(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags)
+extern asmlinkage int sys_recv(int fd, void * ubuf, size_t size, unsigned flags);
+
+asmlinkage inline int sys32_recv(int fd, u32 ubuf,
+				 __kernel_size_t32 size, unsigned flags)
 {
 	return sys_recv(fd, (void *)A(ubuf), (size_t)size, flags);
 }
 
-asmlinkage int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size, unsigned flags, u32 addr, u32 addr_len)
+extern asmlinkage int sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags,
+				   struct sockaddr *addr, int *addr_len); 
+
+asmlinkage inline int sys32_recvfrom(int fd, u32 ubuf, __kernel_size_t32 size,
+				     unsigned flags, u32 addr, u32 addr_len)
 {
-	return sys_recvfrom(fd, (void *)A(ubuf), (size_t)size, flags, (struct sockaddr *)A(addr), (int *)A(addr_len));
+	return sys_recvfrom(fd, (void *)A(ubuf), (size_t)size, flags,
+			    (struct sockaddr *)A(addr), (int *)A(addr_len));
 }
  
-asmlinkage int sys32_setsockopt(int fd, int level, int optname, u32 optval, int optlen)
+extern asmlinkage int sys_setsockopt(int fd, int level, int optname,
+				     char *optval, int optlen);
+
+asmlinkage inline int sys32_setsockopt(int fd, int level, int optname,
+				       u32 optval, int optlen)
 {
 	/* XXX handle ip_fw32->ip_fw conversion for IP firewalling and accounting.
 	       Do it using some macro in ip_sockglue.c
@@ -1779,11 +2020,54 @@
 	return sys_setsockopt(fd, level, optname, (char *)A(optval), optlen);
 }
 
-asmlinkage int sys32_getsockopt(int fd, int level, int optname, u32 optval, u32 optlen)
+extern asmlinkage int sys_getsockopt(int fd, int level, int optname,
+				     char *optval, int *optlen);
+
+asmlinkage inline int sys32_getsockopt(int fd, int level, int optname,
+				       u32 optval, u32 optlen)
 {
 	return sys_getsockopt(fd, level, optname, (char *)A(optval), (int *)A(optlen));
 }
 
+/* XXX This really belongs in some header file... -DaveM */
+#define MAX_SOCK_ADDR	128		/* 108 for Unix domain - 
+					   16 for IP, 16 for IPX,
+					   24 for IPv6,
+					   about 80 for AX.25 */
+
+/* XXX These as well... */
+extern __inline__ struct socket *socki_lookup(struct inode *inode)
+{
+	return &inode->u.socket_i;
+}
+
+extern __inline__ struct socket *sockfd_lookup(int fd, int *err)
+{
+	struct file *file;
+	struct inode *inode;
+
+	if (!(file = fget(fd)))
+	{
+		*err = -EBADF;
+		return NULL;
+	}
+
+	inode = file->f_inode;
+	if (!inode || !inode->i_sock || !socki_lookup(inode))
+	{
+		*err = -ENOTSOCK;
+		fput(file,inode);
+		return NULL;
+	}
+
+	return socki_lookup(inode);
+}
+
+extern __inline__ void sockfd_put(struct socket *sock)
+{
+	fput(sock->file,sock->inode);
+}
+
 struct msghdr32 {
         u32               msg_name;
         int               msg_namelen;
@@ -1801,207 +2085,270 @@
         unsigned char     cmsg_data[0];
 };
 
-asmlinkage int sys32_sendmsg(int fd, u32 msg, unsigned flags)
+static inline int iov_from_user32_to_kern(struct iovec *kiov,
+					  struct iovec32 *uiov32,
+					  int niov)
+{
+	int tot_len = 0;
+
+	while(niov > 0) {
+		u32 len, buf;
+
+		if(get_user(len, &uiov32->iov_len) ||
+		   get_user(buf, &uiov32->iov_base)) {
+			tot_len = -EFAULT;
+			break;
+		}
+		tot_len += len;
+		kiov->iov_base = (void *)A(buf);
+		kiov->iov_len = (__kernel_size_t) len;
+		uiov32++;
+		kiov++;
+		niov--;
+	}
+	return tot_len;
+}
+
+static inline int msghdr_from_user32_to_kern(struct msghdr *kmsg,
+					     struct msghdr32 *umsg)
 {
-	struct msghdr m;
-	int count;
-	struct iovec *v;
-	struct iovec vf[UIO_FASTIOV];
-	u32 i, vector;
-	long ret;
-	unsigned long old_fs;
-	
-	if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) ||
-	    __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) ||
-	    __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) ||
-	    __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) ||
-	    __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) ||
-	    __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) ||
-	    __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)))
+	u32 tmp1, tmp2, tmp3;
+
+	if(get_user(tmp1, &umsg->msg_name)	||
+	   get_user(tmp2, &umsg->msg_iov)	||
+	   get_user(tmp3, &umsg->msg_control))
 		return -EFAULT;
-	
-	count = m.msg_iovlen;
-	if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
-	if (count <= UIO_FASTIOV)
-		v = vf;
-	else {
-		lock_kernel ();
-		v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
-		if (!v) {
-			ret = -ENOMEM;
-			goto out;
+
+	kmsg->msg_name = (void *)A(tmp1);
+	kmsg->msg_iov = (struct iovec *)A(tmp2);
+	kmsg->msg_control = (void *)A(tmp3);
+
+	if(get_user(kmsg->msg_namelen, &umsg->msg_namelen)		||
+	   get_user(kmsg->msg_controllen, &umsg->msg_controllen)	||
+	   get_user(kmsg->msg_flags, &umsg->msg_flags))
+		return -EFAULT;
+
+	return 0;
+}
+
+/* I've named the args so it is easy to tell whose space the pointers are in. */
+static int verify_iovec32(struct msghdr *kern_msg, struct iovec *kern_iov,
+			  char *kern_address, int mode)
+{
+	int tot_len;
+
+	if(kern_msg->msg_namelen) {
+		if(mode==VERIFY_READ) {
+			int err = move_addr_to_kernel(kern_msg->msg_name,
+						      kern_msg->msg_namelen,
+						      kern_address);
+			if(err < 0)
+				return err;
 		}
+		kern_msg->msg_name = kern_address;
+	} else
+		kern_msg->msg_name = NULL;
+
+	if(kern_msg->msg_iovlen > UIO_FASTIOV) {
+		kern_iov = kmalloc(kern_msg->msg_iovlen * sizeof(struct iovec),
+				   GFP_KERNEL);
+		if(!kern_iov)
+			return -ENOMEM;
 	}
 
-	for (i = 0; i < count; i++) {
-		if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
-		    __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
-		    	ret = -EFAULT;
-		    	goto out;
+	tot_len = iov_from_user32_to_kern(kern_iov,
+					  (struct iovec32 *)kern_msg->msg_iov,
+					  kern_msg->msg_iovlen);
+	if(tot_len >= 0)
+		kern_msg->msg_iov = kern_iov;
+	else if(kern_msg->msg_iovlen > UIO_FASTIOV)
+		kfree(kern_iov);
+
+	return tot_len;
+}
+
+asmlinkage int sys32_sendmsg(int fd, u32 user_msg, unsigned user_flags)
+{
+	struct socket *sock;
+	char address[MAX_SOCK_ADDR];
+	struct iovec iov[UIO_FASTIOV];
+	unsigned char ctl[sizeof(struct cmsghdr) + 20];
+	struct msghdr kern_msg;
+	int err;
+	int total_len;
+	unsigned char *ctl_buf = ctl;
+
+	if(msghdr_from_user32_to_kern(&kern_msg, (struct msghdr32 *)A(user_msg)))
+		return -EFAULT;
+	if(kern_msg.msg_iovlen > UIO_MAXIOV)
+		return -EINVAL;
+	total_len = verify_iovec32(&kern_msg, iov, address, VERIFY_READ);
+	if(total_len < 0)
+		return total_len;
+	if(kern_msg.msg_controllen) {
+		struct cmsghdr32 *ucmsg = (struct cmsghdr32 *)kern_msg.msg_control;
+		unsigned long *kcmsg;
+		__kernel_size_t32 cmlen;
+
+		if(kern_msg.msg_controllen > sizeof(ctl) &&
+		   kern_msg.msg_controllen <= 256) {
+			ctl_buf = kmalloc(kern_msg.msg_controllen, GFP_KERNEL);
+			if(!ctl_buf) {
+				if(kern_msg.msg_iov != iov)
+					kfree(kern_msg.msg_iov);
+				return -ENOBUFS;
+			}
 		}
+		__get_user(cmlen, &ucmsg->cmsg_len);
+		kcmsg = (unsigned long *) ctl_buf;
+		*kcmsg++ = (unsigned long)cmlen;
+		if(copy_from_user(kcmsg, &ucmsg->cmsg_level,
+				  kern_msg.msg_controllen - sizeof(__kernel_size_t32))) {
+			if(ctl_buf != ctl)
+				kfree_s(ctl_buf, kern_msg.msg_controllen);
+			if(kern_msg.msg_iov != iov)
+				kfree(kern_msg.msg_iov);
+			return -EFAULT;
+		}
+		kern_msg.msg_control = ctl_buf;
 	}
-	
-	m.msg_iov = v;
+	kern_msg.msg_flags = user_flags;
 
-	if (m.msg_controllen) {
-		/* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */
-	}
-	old_fs = get_fs();
-	set_fs (KERNEL_DS);
-	ret = sys_sendmsg(fd, &m, flags);
-	set_fs (old_fs);
-out:
-	if (count > UIO_FASTIOV) {
-		kfree (v);
-		unlock_kernel ();
+	lock_kernel();
+	if(current->files->fd[fd]->f_flags & O_NONBLOCK)
+		kern_msg.msg_flags |= MSG_DONTWAIT;
+	if((sock = sockfd_lookup(fd, &err)) != NULL) {
+		err = sock_sendmsg(sock, &kern_msg, total_len);
+		sockfd_put(sock);
 	}
-	return ret;
+	unlock_kernel();
+
+	if(ctl_buf != ctl)
+		kfree_s(ctl_buf, kern_msg.msg_controllen);
+	if(kern_msg.msg_iov != iov)
+		kfree(kern_msg.msg_iov);
+	return err;
 }
 
-asmlinkage int sys32_recvmsg(int fd, u32 msg, unsigned int flags)
+asmlinkage int sys32_recvmsg(int fd, u32 user_msg, unsigned int user_flags)
 {
-	struct msghdr m;
-	int count;
-	struct iovec *v;
-	struct iovec vf[UIO_FASTIOV];
-	u32 i, vector;
-	long ret;
-	unsigned long old_fs;
-	
-	if (get_user ((long)m.msg_name, &(((struct msghdr32 *)A(msg))->msg_name)) ||
-	    __get_user (m.msg_namelen, &(((struct msghdr32 *)A(msg))->msg_namelen)) ||
-	    __get_user (vector, &(((struct msghdr32 *)A(msg))->msg_iov)) ||
-	    __get_user (m.msg_iovlen, &(((struct msghdr32 *)A(msg))->msg_iovlen)) ||
-	    __get_user ((long)m.msg_control, &(((struct msghdr32 *)A(msg))->msg_control)) ||
-	    __get_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)) ||
-	    __get_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)))
+	struct iovec iovstack[UIO_FASTIOV];
+	struct msghdr kern_msg;
+	char addr[MAX_SOCK_ADDR];
+	struct socket *sock;
+	struct iovec *iov = iovstack;
+	struct sockaddr *uaddr;
+	int *uaddr_len;
+	unsigned long cmsg_ptr;
+	int err, total_len, len = 0;
+
+	if(msghdr_from_user32_to_kern(&kern_msg, (struct msghdr32 *)A(user_msg)))
 		return -EFAULT;
-	
-	count = m.msg_iovlen;
-	if (!count) return 0; if (count > UIO_MAXIOV) return -EINVAL;
-	if (count <= UIO_FASTIOV)
-		v = vf;
-	else {
-		lock_kernel ();
-		v = kmalloc (count * sizeof (struct iovec), GFP_KERNEL);
-		if (!v) {
-			ret = -ENOMEM;
-			goto out;
-		}
-	}
+	if(kern_msg.msg_iovlen > UIO_MAXIOV)
+		return -EINVAL;
 
-	for (i = 0; i < count; i++) {
-		if (__get_user ((unsigned long)(v[i].iov_base), &((((struct iovec32 *)A(vector))+i)->iov_base)) ||
-		    __get_user (v[i].iov_len, &((((struct iovec32 *)A(vector))+i)->iov_len))) {
-		    	ret = -EFAULT;
-		    	goto out;
-		}
-	}
-	
-	m.msg_iov = v;
+	uaddr = kern_msg.msg_name;
+	uaddr_len = &((struct msghdr32 *)A(user_msg))->msg_namelen;
+	err = verify_iovec32(&kern_msg, iov, addr, VERIFY_WRITE);
+	if(err < 0)
+		return err;
+	total_len = err;
 
-	if (m.msg_controllen) {
-		/* XXX Handle msg_control stuff... Or should that go into ip_sockglue.c etc.? */
-	}
-	old_fs = get_fs();
-	set_fs (KERNEL_DS);
-	ret = sys_recvmsg(fd, &m, flags);
-	set_fs (old_fs);
-	if (ret >= 0) {
-		/* XXX Handle msg_control stuff... */
-		if (put_user (m.msg_flags, &(((struct msghdr32 *)A(msg))->msg_flags)) ||
-		    __put_user (m.msg_controllen, &(((struct msghdr32 *)A(msg))->msg_controllen)))
-			return -EFAULT;
+	cmsg_ptr = (unsigned long) kern_msg.msg_control;
+	kern_msg.msg_flags = 0;
+
+	lock_kernel();
+	if(current->files->fd[fd]->f_flags & O_NONBLOCK)
+		user_flags |= MSG_DONTWAIT;
+	if((sock = sockfd_lookup(fd, &err)) != NULL) {
+		err = sock_recvmsg(sock, &kern_msg, total_len, user_flags);
+		if(err >= 0)
+			len = err;
+		sockfd_put(sock);
 	}
-out:
-	if (count > UIO_FASTIOV) {
-		kfree (v);
-		unlock_kernel ();
+	unlock_kernel();
+
+	if(kern_msg.msg_iov != iov)
+		kfree(kern_msg.msg_iov);
+	if(uaddr != NULL && err >= 0)
+		err = move_addr_to_user(addr, kern_msg.msg_namelen, uaddr, uaddr_len);
+	if(err >= 0) {
+		err = __put_user(kern_msg.msg_flags,
+				 &((struct msghdr32 *)A(user_msg))->msg_flags);
+		if(!err) {
+			/* XXX Convert cmsg back into userspace 32-bit format... */
+			err = __put_user((unsigned long)kern_msg.msg_control - cmsg_ptr,
+					 &((struct msghdr32 *)A(user_msg))->msg_controllen);
+		}
 	}
-	return ret;
+	if(err < 0)
+		return err;
+	return len;
 }
 
+/* Argument list sizes for sys_socketcall */
+#define AL(x) ((x) * sizeof(u32))
+static unsigned char nargs[18]={AL(0),AL(3),AL(3),AL(3),AL(2),AL(3),
+                                AL(3),AL(3),AL(4),AL(4),AL(4),AL(6),
+                                AL(6),AL(2),AL(5),AL(5),AL(3),AL(3)};
+#undef AL
+
+extern asmlinkage int sys_socket(int family, int type, int protocol);
+extern asmlinkage int sys_socketpair(int family, int type, int protocol,
+				     int usockvec[2]);
+extern asmlinkage int sys_shutdown(int fd, int how);
+extern asmlinkage int sys_listen(int fd, int backlog);
+
 asmlinkage int sys32_socketcall(int call, u32 args)
 {
-	static unsigned char nargs[18]={0,3,3,3,2,3,3,3,
-				        4,4,4,6,6,2,5,5,3,3};
 	u32 a[6];
 	u32 a0,a1;
-	int err = -EINVAL;
-	int i;
 				 
-	lock_kernel();
-	if(call<1||call>SYS_RECVMSG)
-		goto out;
-	err = -EFAULT;
-
-	for (i = 0; i < nargs[call]; i++, args += sizeof (u32))
-		if (get_user(a[i], (u32 *)A(args)))
-			goto out;
-		
+	if (call<SYS_SOCKET||call>SYS_RECVMSG)
+		return -EINVAL;
+	if (copy_from_user(a, (u32 *)A(args), nargs[call]))
+		return -EFAULT;
 	a0=a[0];
 	a1=a[1];
 	
 	switch(call) 
 	{
 		case SYS_SOCKET:
-			err = sys_socket(a0, a1, a[2]);
-			break;
+			return sys_socket(a0, a1, a[2]);
 		case SYS_BIND:
-			err = sys32_bind(a0, a1, a[2]);
-			break;
+			return sys32_bind(a0, a1, a[2]);
 		case SYS_CONNECT:
-			err = sys32_connect(a0, a1, a[2]);
-			break;
+			return sys32_connect(a0, a1, a[2]);
 		case SYS_LISTEN:
-			err = sys_listen(a0, a1);
-			break;
+			return sys_listen(a0, a1);
 		case SYS_ACCEPT:
-			err = sys32_accept(a0, a1, a[2]);
-			break;
+			return sys32_accept(a0, a1, a[2]);
 		case SYS_GETSOCKNAME:
-			err = sys32_getsockname(a0, a1, a[2]);
-			break;
+			return sys32_getsockname(a0, a1, a[2]);
 		case SYS_GETPEERNAME:
-			err = sys32_getpeername(a0, a1, a[2]);
-			break;
+			return sys32_getpeername(a0, a1, a[2]);
 		case SYS_SOCKETPAIR:
-			err = sys_socketpair(a0, a1, a[2], (int *)A(a[3]));
-			break;
+			return sys_socketpair(a0, a1, a[2], (int *)A(a[3]));
 		case SYS_SEND:
-			err = sys32_send(a0, a1, a[2], a[3]);
-			break;
+			return sys32_send(a0, a1, a[2], a[3]);
 		case SYS_SENDTO:
-			err = sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]);
-			break;
+			return sys32_sendto(a0, a1, a[2], a[3], a[4], a[5]);
 		case SYS_RECV:
-			err = sys32_recv(a0, a1, a[2], a[3]);
-			break;
+			return sys32_recv(a0, a1, a[2], a[3]);
 		case SYS_RECVFROM:
-			err = sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]);
-			break;
+			return sys32_recvfrom(a0, a1, a[2], a[3], a[4], a[5]);
 		case SYS_SHUTDOWN:
-			err = sys_shutdown(a0,a1);
-			break;
+			return sys_shutdown(a0,a1);
 		case SYS_SETSOCKOPT:
-			err = sys32_setsockopt(a0, a1, a[2], a[3], a[4]);
-			break;
+			return sys32_setsockopt(a0, a1, a[2], a[3], a[4]);
 		case SYS_GETSOCKOPT:
-			err = sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
-			break;
+			return sys32_getsockopt(a0, a1, a[2], a[3], a[4]);
 		case SYS_SENDMSG:
-			err = sys32_sendmsg(a0, a1, a[2]);
-			break;
+			return sys32_sendmsg(a0, a1, a[2]);
 		case SYS_RECVMSG:
-			err = sys32_recvmsg(a0, a1, a[2]);
-			break;
-		default:
-			err = -EINVAL;
-			break;
+			return sys32_recvmsg(a0, a1, a[2]);
 	}
-out:
-	unlock_kernel();
-	return err;
+	return -EINVAL;
 }
 
 extern void check_pending(int signum);
@@ -2060,6 +2407,8 @@
 	return err;
 }
 
+extern asmlinkage int sys_nfsservctl(int cmd, void *argp, void *resp);
+
 asmlinkage int sys32_nfsservctl(int cmd, u32 argp, u32 resp)
 {
 	/* XXX handle argp and resp args */
@@ -2202,6 +2551,12 @@
         	(u32 *)A((u32)regs->u_regs[base + UREG_I2]), regs);
         putname(filename);
         return error;
+}
+
+/* Modules will be supported with 64bit modutils only */
+asmlinkage int sys32_no_modules(void)
+{
+	return -ENOSYS;
 }
 
 struct ncp_mount_data32 {
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/systbls.S linux/arch/sparc64/kernel/systbls.S
--- v2.1.42/linux/arch/sparc64/kernel/systbls.S	Thu May 29 21:53:04 1997
+++ linux/arch/sparc64/kernel/systbls.S	Thu Jun 12 16:22:05 1997
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.11 1997/05/27 19:30:20 jj Exp $
+/* $Id: systbls.S,v 1.13 1997/06/04 13:05:29 jj Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -53,20 +53,20 @@
 	.xword sys32_quotactl, sys_nis_syscall, sys32_mount, sys32_ustat, sys_nis_syscall
 /*170*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getdents
 	.xword sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys_nis_syscall
+/*180*/	.xword sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_sigpending, sys32_no_modules
 	.xword sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_newuname
-/*190*/	.xword sys_nis_syscall, sys32_personality, sys_prof, sys_break, sys_lock
+/*190*/	.xword sys32_no_modules, sys32_personality, sys_prof, sys_break, sys_lock
 	.xword sys_mpx, sys_ulimit, sys_getppid, sparc32_sigaction, sys_sgetmask
 /*200*/	.xword sys_ssetmask, sys_sigsuspend, sys32_newlstat, sys32_uselib, old32_readdir
 	.xword sys_nis_syscall, sys32_socketcall, sys32_syslog, sys32_olduname, sys_nis_syscall
 /*210*/	.xword sys_idle, sys_nis_syscall, sys32_waitpid, sys32_swapoff, sys32_sysinfo
 	.xword sys32_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
-/*220*/	.xword sys32_sigprocmask, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getpgid
+/*220*/	.xword sys32_sigprocmask, sys32_no_modules, sys32_no_modules, sys32_no_modules, sys_getpgid
 	.xword sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
 /*230*/	.xword sys32_llseek, sys32_time, sys_nis_syscall, sys_stime, sys_nis_syscall
 	.xword sys_nis_syscall, sys32_llseek, sys32_mlock, sys32_munlock, sys_mlockall
 /*240*/	.xword sys_munlockall, sys32_sched_setparam, sys32_sched_getparam, sys_nis_syscall, sys_nis_syscall
-	.xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys_nanosleep
+	.xword sys_nis_syscall, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, sys32_nanosleep
 /*250*/	.xword sys32_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl
 	.xword sys_aplib, sys_nis_syscall
 
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
--- v2.1.42/linux/arch/sparc64/kernel/traps.c	Thu May 29 21:53:04 1997
+++ linux/arch/sparc64/kernel/traps.c	Thu Jun 12 16:22:05 1997
@@ -1,7 +1,7 @@
-/* $Id: traps.c,v 1.13 1997/05/27 19:30:08 jj Exp $
+/* $Id: traps.c,v 1.19 1997/06/05 06:22:49 davem Exp $
  * arch/sparc/kernel/traps.c
  *
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
@@ -23,6 +23,7 @@
 #include <asm/pgtable.h>
 #include <asm/unistd.h>
 #include <asm/uaccess.h>
+#include <asm/fpumacro.h>
 
 /* #define SYSCALL_TRACING */
 /* #define VERBOSE_SYSCALL_TRACING */
@@ -122,7 +123,8 @@
 	int i;
 #endif
 
-	printk("SYS[%s:%d]: <%d> ", current->comm, current->pid, (int)g1);
+	printk("SYS[%s:%d]: PC(%016lx) <%3d> ",
+	       current->comm, current->pid, regs->tpc, (int)g1);
 #ifdef VERBOSE_SYSCALL_TRACING
 	sdp = NULL;
 	for(i = 0; i < NUM_SDESC_ENTRIES; i++)
@@ -151,7 +153,7 @@
 
 unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs)
 {
-	printk("ret[%08x]\n", (unsigned int) retval);
+	printk("ret[%016lx]\n", retval);
 	return retval;
 }
 #endif /* SYSCALL_TRACING */
@@ -254,25 +256,143 @@
 		barrier();
 }
 
+static unsigned long init_fsr = 0x0UL;
+static unsigned int init_fregs[64] __attribute__ ((aligned (64))) =
+                { ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+		  ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+		  ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+		  ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+		  ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+		  ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+		  ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+		  ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U };
+
 void do_fpdis(struct pt_regs *regs)
 {
-	printk("FPDIS: at %016lx\n", regs->tpc);
-	while(1)
-		barrier();
+	lock_kernel();
+
+	regs->tstate |= TSTATE_PEF;
+	fprs_write(FPRS_FEF);
+
+	/* This is allowed now because the V9 ABI varargs passes floating
+	 * point args in floating point registers, so vsprintf() and sprintf()
+	 * cause problems.  Luckily we never actually pass floating point values
+	 * to those routines in the kernel and the code generated just does
+	 * stores of them to the stack.  Therefore, for the moment this fix
+	 * is sufficient. -DaveM
+	 */
+	if(regs->tstate & TSTATE_PRIV)
+		goto out;
+
+#ifndef __SMP__
+	if(last_task_used_math == current)
+		goto out;
+	if(last_task_used_math) {
+		struct task_struct *fptask = last_task_used_math;
+
+		if(fptask->tss.flags & SPARC_FLAG_32BIT)
+			fpsave32((unsigned long *)&fptask->tss.float_regs[0],
+				 &fptask->tss.fsr);
+		else
+			fpsave((unsigned long *)&fptask->tss.float_regs[0],
+			       &fptask->tss.fsr);
+	}
+	last_task_used_math = current;
+	if(current->used_math) {
+		if(current->tss.flags & SPARC_FLAG_32BIT)
+			fpload32(&current->tss.float_regs[0],
+				 &current->tss.fsr);
+		else
+			fpload(&current->tss.float_regs[0],
+			       &current->tss.fsr);
+	} else {
+		/* Set inital sane state. */
+		fpload(&init_fregs[0], &init_fsr);
+		current->used_math = 1;
+	}
+#else
+	if(!current->used_math) {
+		fpload(&init_fregs[0], &init_fsr);
+		current->used_math = 1;
+	} else {
+		if(current->tss.flags & SPARC_FLAG_32BIT)
+			fpload32(&current->tss.float_regs[0],
+				 &current->tss.fsr);
+		else
+			fpload(&current->tss.float_regs[0],
+			       &current->tss.fsr);
+	}
+	current->flags |= PF_USEDFPU;
+#endif
+#ifndef __SMP__
+out:
+#endif
+	unlock_kernel();
+}
+
+static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
+static unsigned long fake_fsr;
+
+void do_fpe_common(struct pt_regs *regs)
+{
+	static int calls = 0;
+#ifndef __SMP__
+	struct task_struct *fpt = last_task_used_math;
+#else
+	struct task_struct *fpt = current;
+#endif
+
+	lock_kernel();
+	fprs_write(FPRS_FEF);
+
+#ifndef __SMP__
+	if(!fpt) {
+#else
+	if(!(fpt->flags & PF_USEDFPU)) {
+#endif
+		fpsave(&fake_regs[0], &fake_fsr);
+		regs->tstate &= ~(TSTATE_PEF);
+		goto out;
+	}
+	if(fpt->tss.flags & SPARC_FLAG_32BIT)
+		fpsave32((unsigned long *)&fpt->tss.float_regs[0], &fpt->tss.fsr);
+	else
+		fpsave((unsigned long *)&fpt->tss.float_regs[0], &fpt->tss.fsr);
+	fpt->tss.sig_address = regs->tpc;
+	fpt->tss.sig_desc = SUBSIG_FPERROR;
+#ifdef __SMP__
+	fpt->flags &= ~PF_USEDFPU;
+#endif
+	if(regs->tstate & TSTATE_PRIV) {
+		printk("WARNING: FPU exception from kernel mode. at pc=%016lx\n",
+		       regs->tpc);
+		regs->tpc = regs->tnpc;
+		regs->tnpc += 4;
+		calls++;
+		if(calls > 2)
+			die_if_kernel("Too many Penguin-FPU traps from kernel mode",
+				      regs);
+		goto out;
+	}
+	send_sig(SIGFPE, fpt, 1);
+#ifndef __SMP__
+	last_task_used_math = NULL;
+#endif
+	regs->tstate &= ~TSTATE_PEF;
+	if(calls > 0)
+		calls = 0;
+out:
+	unlock_kernel();
 }
 
 void do_fpieee(struct pt_regs *regs)
 {
-	printk("FPIEEE: at %016lx\n", regs->tpc);
-	while(1)
-		barrier();
+	do_fpe_common(regs);
 }
 
 void do_fpother(struct pt_regs *regs)
 {
-	printk("FPOTHER: at %016lx\n", regs->tpc);
-	while(1)
-		barrier();
+	do_fpe_common(regs);
 }
 
 void do_tof(struct pt_regs *regs)
@@ -352,23 +472,29 @@
 		printk("Ill instr. at pc=%016lx ", pc);
 		get_user(insn, ((unsigned int *)pc));
 		printk("insn=[%08x]\n", insn);
+		show_regs(regs);
 	}
 #endif
 	current->tss.sig_address = pc;
 	current->tss.sig_desc = SUBSIG_ILLINST;
 	send_sig(SIGILL, current, 1);
 	unlock_kernel();
-
-	while(1)
-		barrier();
 }
 
-void do_mna(struct pt_regs *regs)
+void mem_address_unaligned(struct pt_regs *regs)
 {
 	printk("AIEEE: do_mna at %016lx\n", regs->tpc);
 	show_regs(regs);
-	while(1)
-		barrier();
+	if(regs->tstate & TSTATE_PRIV) {
+		printk("MNA from kernel, spinning\n");
+		sti();
+		while(1)
+			barrier();
+	} else {
+		current->tss.sig_address = regs->tpc;
+		current->tss.sig_desc = SUBSIG_PRIVINST;
+		send_sig(SIGBUS, current, 1);
+	}
 }
 
 void do_privop(struct pt_regs *regs)
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/ttable.S linux/arch/sparc64/kernel/ttable.S
--- v2.1.42/linux/arch/sparc64/kernel/ttable.S	Sat May 24 09:10:23 1997
+++ linux/arch/sparc64/kernel/ttable.S	Thu Jun 12 16:22:06 1997
@@ -1,4 +1,4 @@
-/* $Id: ttable.S,v 1.12 1997/05/17 08:22:30 davem Exp $
+/* $Id: ttable.S,v 1.13 1997/06/02 06:33:34 davem Exp $
  * ttable.S: Sparc V9 Trap Table(s) with SpitFire extensions.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -30,7 +30,7 @@
 tl0_resv031:	BTRAP(0x31)
 tl0_dae:	TRAP(do_dae)
 tl0_resv033:	BTRAP(0x33)
-tl0_mna:	TRAP(do_mna)
+tl0_mna:	TRAP_NOSAVE(do_mna)
 tl0_lddfmna:	TRAP(do_lddfmna)
 tl0_stdfmna:	TRAP(do_stdfmna)
 tl0_privact:	TRAP(do_privact)
@@ -163,7 +163,7 @@
 tl1_resv031:	BTRAPTL1(0x31)
 tl1_dae:	TRAPTL1(do_dae_tl1)
 tl1_resv033:	BTRAPTL1(0x33)
-tl1_mna:	TRAPTL1(do_mna_tl1)
+tl1_mna:	TRAP_NOSAVE(do_mna)
 tl1_lddfmna:	TRAPTL1(do_lddfmna_tl1)
 tl1_stdfmna:	TRAPTL1(do_stdfmna_tl1)
 tl1_privact:	BTRAPTL1(0x37)
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/winfixup.S linux/arch/sparc64/kernel/winfixup.S
--- v2.1.42/linux/arch/sparc64/kernel/winfixup.S	Sat May 24 09:10:23 1997
+++ linux/arch/sparc64/kernel/winfixup.S	Thu Jun 12 16:22:06 1997
@@ -1,4 +1,4 @@
-/* $Id: winfixup.S,v 1.3 1997/05/18 22:52:26 davem Exp $
+/* $Id: winfixup.S,v 1.8 1997/06/02 06:33:35 davem Exp $
  *
  * winfixup.S: Handle cases where user stack pointer is found to be bogus.
  *
@@ -10,6 +10,7 @@
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/processor.h>
+#include <asm/spitfire.h>
 #include <asm/asm_offsets.h>
 
 	.text
@@ -28,74 +29,223 @@
 	 */
 	.globl	winfix_trampoline, fill_fixup, spill_fixup
 fill_fixup:
-	ba,pt	%xcc, etrap
-	 rd	%pc, %g7
-	mov	%l5, %o4
-	mov	%l4, %o5
-	srlx	%l5, PAGE_SHIFT, %o3
-	clr	%o1
-	sllx	%o3, PAGE_SHIFT, %o3
-	and	%l4, 0x4, %o2
-
-	call	do_sparc64_fault
-	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0
-	ba,a,pt	%xcc, rtrap
+	rdpr		%tstate, %g1
+	andcc		%g1, TSTATE_PRIV, %g0
+	be,pt		%xcc, window_scheisse_from_user_common
+	 and		%g1, TSTATE_CWP, %g1
+
+	/* This is the extremely complex case, but it does happen from
+	 * time to time if things are just right.  Essentially the restore
+	 * done in rtrap right before going back to user mode, with tl=1
+	 * and that levels trap stack registers all setup, took a fill trap,
+	 * the user stack was not mapped in the tlb, and tlb miss occurred,
+	 * the pte found was not valid, and a simple ref bit watch update
+	 * could not satisfy the miss, so we got here.
+	 *
+	 * We must carefully unwind the state so we get back to tl=0, preserve
+	 * all the register values we were going to give to the user.  Luckily
+	 * most things are where they need to be, we also have the address
+	 * which triggered the fault handy as well.
+	 *
+	 * First, get into the window where the original restore was executed.
+	 */
+
+	rdpr		%wstate, %g2			! Grab user mode wstate.
+	wrpr		%g1, %cwp			! Get into the right window.
+	sll		%g2, 3, %g2			! NORMAL-->OTHER
+	wrpr		%g0, 0x0, %canrestore		! Standard etrap stuff.
+
+	wrpr		%g2, 0x0, %wstate		! This must be consistant.
+	wrpr		%g0, 0x0, %otherwin		! We know this.
+	sethi		%uhi(KERNBASE), %g2		! Set this up
+	sllx		%g2, 32, %g2			! for the iflush
+	mov		PRIMARY_CONTEXT, %g1		! Change contexts...
+	stxa		%g0, [%g1] ASI_DMMU		! Back into the nucleus.
+	flush		%g2				! Flush instruction buffers
+	rdpr		%pstate, %l1			! Prepare to change globals.
+	mov		%g4, %o5			! Setup args for
+	mov		%g5, %o4			! final call to do_sparc64_fault.
+
+	wrpr		%g0, 0x0, %tl			! Out of trap levels.
+	wrpr		%l1, (PSTATE_IE | PSTATE_AG), %pstate
+	sethi		%uhi(KERNBASE), %g4		! Restore med-any global reg.
+	rd		%pic, %g6			! Get current as well.
+	b,pt		%xcc, window_scheisse_merge	! And merge.
+	 sllx		%g4, 32, %g4			! Finish med-any reg setup.
+
+	/* Be very careful about usage of the alternate globals here.
+	 * You cannot touch %g4/%g5 as that has the fault information
+	 * should this be from usermode.  Also be careful for the case
+	 * where we get here from the save instruction in etrap.S when
+	 * coming from either user or kernel (does not matter which, it
+	 * is the same problem in both cases).  Essentially this means
+	 * do not touch %g7 or %g2 so we handle the two cases fine.
+	 */
+spill_fixup:
+	rd		%pic, %g1
+	ldx		[%g1 + AOFF_task_tss + AOFF_thread_flags], %g6
+	andcc		%g6, SPARC_FLAG_32BIT, %g0
+	ldx		[%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g6
+	sll		%g6, 3, %g3
+	add		%g1, %g3, %g3
+	stx		%sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+	sll		%g6, 7, %g3
+
+	bne,pt		%xcc, 1f
+	 add		%g1, %g3, %g3
+	stx		%l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+	stx		%l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+	stx		%l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+	stx		%l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+	stx		%l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+	stx		%l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+
+	stx		%l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+	stx		%l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+	stx		%i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
+	stx		%i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
+	stx		%i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
+	stx		%i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
+	stx		%i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
+	stx		%i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
+
+	stx		%i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
+	stx		%i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+	b,pt		%xcc, 2f
+	 add		%g6, 1, %g6
+1:	std		%l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+	std		%l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+	std		%l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+	std		%l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+
+	std		%i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+	std		%i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+	std		%i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+	std		%i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+	add		%g6, 1, %g6
+2:	stx		%g6, [%g1 + AOFF_task_tss + AOFF_thread_w_saved]
+	rdpr		%tstate, %g1
 	nop
+
+	andcc		%g1, TSTATE_PRIV, %g0
+	saved
+	and		%g1, TSTATE_CWP, %g1
+	be,a,pn		%xcc, window_scheisse_from_user_common
+	 or		%g4, 0x4, %g4			! we know it was a write
+	retry
+window_scheisse_from_user_common:
+	nop
+	wrpr		%g1, %cwp
+
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
+	mov		%l5, %o4
+	mov		%l4, %o5
+window_scheisse_merge:
+	srlx		%o4, PAGE_SHIFT, %o3
+	clr		%o1
+	sllx		%o3, PAGE_SHIFT, %o3
+	and		%o5, 0x4, %o2
+
+	call		do_sparc64_fault
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,pt		%xcc, rtrap
+	 clr		%l6
 winfix_trampoline:
-	andn		%g5, 0x7f, %g5
-	add		%g5, 0x7c, %g5
-	wrpr		%g5, %tnpc
+	andn		%g3, 0x7f, %g3
+	add		%g3, 0x7c, %g3
+	wrpr		%g3, %tnpc
 	done
 
-spill_fixup:
-	rd	%pic, %g1
-	ldx	[%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g2
-	sll	%g2, 3, %g5
-	ldx	[%g1 + AOFF_task_tss + AOFF_thread_flags], %g7
-	add	%g1, %g5, %g5
-	andcc	%g7, SPARC_FLAG_32BIT, %g0
-	stx	%sp, [%g5 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
-	sll	%g2, 5, %g5
-
-	bne,pt	%xcc, 1f
-	 add	%g1, %g5, %g5
-	stx	%l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
-	stx	%l1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
-	stx	%l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
-	stx	%l3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
-	stx	%l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
-	stx	%l5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
-
-	stx	%l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
-	stx	%l7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
-	stx	%i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
-	stx	%i1, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
-	stx	%i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
-	stx	%i3, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
-	stx	%i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
-	stx	%i5, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
-
-	stx	%i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
-	stx	%i7, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
-	b,a,pt	%xcc, 2f
-	 add	%g2, 1, %g2
-1:
-	std	%l0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
-	std	%l2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
-	std	%l4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
-	std	%l6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
-
-	std	%i0, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
-	std	%i2, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
-	std	%i4, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
-	std	%i6, [%g5 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
-	add	%g2, 1, %g2
-2:
-	stx	%g2, [%g1 + AOFF_task_tss + AOFF_thread_w_saved]
-	rdpr	%tstate, %g1
+	.globl		winfix_mna, fill_fixup_mna, spill_fixup_mna
+winfix_mna:
+	andn		%g3, 0x7f, %g3
+	add		%g3, 0x78, %g3
+	wrpr		%g3, %tnpc
+	done
+fill_fixup_mna:
+	rdpr		%tstate, %g1
+	andcc		%g1, TSTATE_PRIV, %g0
+	be,pt		%xcc, window_mna_from_user_common
+	 and		%g1, TSTATE_CWP, %g1
+	rdpr		%wstate, %g2			! Grab user mode wstate.
+	wrpr		%g1, %cwp			! Get into the right window.
+	sll		%g2, 3, %g2			! NORMAL-->OTHER
+	wrpr		%g0, 0x0, %canrestore		! Standard etrap stuff.
+	wrpr		%g2, 0x0, %wstate		! This must be consistant.
+	wrpr		%g0, 0x0, %otherwin		! We know this.
+	sethi		%uhi(KERNBASE), %g2		! Set this up
+	sllx		%g2, 32, %g2			! for the iflush
+	mov		PRIMARY_CONTEXT, %g1		! Change contexts...
+	stxa		%g0, [%g1] ASI_DMMU		! Back into the nucleus.
+	flush		%g2				! Flush instruction buffers
+	rdpr		%pstate, %l1			! Prepare to change globals.
+	mov		%g4, %o5			! Setup args for
+	mov		%g5, %o4			! final call to do_sparc64_fault.
+	wrpr		%g0, 0x0, %tl			! Out of trap levels.
+	wrpr		%l1, (PSTATE_IE | PSTATE_AG), %pstate
+	sethi		%uhi(KERNBASE), %g4		! Restore med-any global reg.
+	rd		%pic, %g6			! Get current as well.
+	b,pt		%xcc, window_mna_merge		! And merge.
+	 sllx		%g4, 32, %g4			! Finish med-any reg setup.
+spill_fixup_mna:
+	rd		%pic, %g1
+	ldx		[%g1 + AOFF_task_tss + AOFF_thread_flags], %g6
+	andcc		%g6, SPARC_FLAG_32BIT, %g0
+	ldx		[%g1 + AOFF_task_tss + AOFF_thread_w_saved], %g6
+	sll		%g6, 3, %g3
+	add		%g1, %g3, %g3
+	stx		%sp, [%g3 + AOFF_task_tss + AOFF_thread_rwbuf_stkptrs]
+	sll		%g6, 7, %g3
+
+	bne,pt		%xcc, 1f
+	 add		%g1, %g3, %g3
+	stx		%l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+	stx		%l1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+	stx		%l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+	stx		%l3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+	stx		%l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+	stx		%l5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+
+	stx		%l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+	stx		%l7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+	stx		%i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x40]
+	stx		%i1, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x48]
+	stx		%i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x50]
+	stx		%i3, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x58]
+	stx		%i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x60]
+	stx		%i5, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x68]
+
+	stx		%i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x70]
+	stx		%i7, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x78]
+	b,pt		%xcc, 2f
+	 add		%g6, 1, %g6
+1:	std		%l0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x00]
+	std		%l2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x08]
+	std		%l4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x10]
+	std		%l6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x18]
+
+	std		%i0, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x20]
+	std		%i2, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x28]
+	std		%i4, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x30]
+	std		%i6, [%g3 + AOFF_task_tss + AOFF_thread_reg_window + 0x38]
+	add		%g6, 1, %g6
+2:	stx		%g6, [%g1 + AOFF_task_tss + AOFF_thread_w_saved]
+	rdpr		%tstate, %g1
 	nop
 
-	andcc	%g1, TSTATE_PRIV, %g0
-	be,pn	%xcc, fill_fixup
-	 saved
+	andcc		%g1, TSTATE_PRIV, %g0
+	saved
+	be,pn		%xcc, window_mna_from_user_common
+	 and		%g1, TSTATE_CWP, %g1
 	retry
+window_mna_from_user_common:
+	wrpr		%g1, %cwp
+	ba,pt		%xcc, etrap
+	 rd		%pc, %g7
+window_mna_merge:
+	call		mem_address_unaligned
+	 add		%sp, STACK_BIAS + REGWIN_SZ, %o0
+	ba,pt		%xcc, rtrap
+	 clr		%l6
+	
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/lib/checksum.S linux/arch/sparc64/lib/checksum.S
--- v2.1.42/linux/arch/sparc64/lib/checksum.S	Thu May 15 16:48:02 1997
+++ linux/arch/sparc64/lib/checksum.S	Thu Jun 12 16:22:06 1997
@@ -71,8 +71,9 @@
 	or	%o5, %o4, %o4			! coalese with hword (if any)
 6:	addcc	%o4, %o2, %o2			! add to sum
 1:	sllx	%g4, 32, %g4			! give gfp back
+	addc	%g0, %o2, %o0			! add final carry into retval
 	retl					! get outta here
-	 addc	%g0, %o2, %o0			! add final carry into retval
+	 srl	%o0, 0, %o0
 
 	/* Also do alignment out of band to get better cache patterns. */
 csum_partial_fix_alignment:
@@ -82,7 +83,9 @@
 	 */
 	.globl	csum_partial
 csum_partial:						/* %o0=buf, %o1=len, %o2=sum */
+	srl	%o1, 0, %o1				! doof scheiss
 	andcc	%o0, 0x7, %g0				! alignment problems?
+	srl	%o2, 0, %o2
 	be,pt	%icc, csum_partial_fix_aligned		! yep, handle it
 	 andn	%o1, 0x7f, %o3				! num loop iterations
 	cmp	%o1, 6
@@ -154,31 +157,31 @@
 99:     ba,pt %xcc, 30f;                        \
          a, b, %o3;                             \
         .section __ex_table,z##alloc;           \
-        .align  4;                              \
-        .word   98b, 99b;                       \
+        .align  8;                              \
+        .xword   98b, 99b;                      \
         .text;                                  \
         .align  4
 
 #define EX2(x,y,z)                          	\
 98:     x,y;                                    \
         .section __ex_table,z##alloc;           \
-        .align  4;                              \
-        .word   98b, 30f;                       \
+        .align  8;                              \
+        .xword   98b, 30f;                      \
         .text;                                  \
         .align  4
 
 #define EX3(x,y,z)                          	\
 98:     x,y;                                    \
         .section __ex_table,z##alloc;           \
-        .align  4;                              \
-        .word   98b, 96f;                       \
+        .align  8;                              \
+        .xword   98b, 96f;                      \
         .text;                                  \
         .align  4
 
 #define EXT(start,end,handler,z)                \
         .section __ex_table,z##alloc;           \
-        .align  4;                              \
-        .word   start, 0, end, handler;         \
+        .align  8;                              \
+        .xword   start, 0, end, handler;        \
         .text;                                  \
         .align  4
 
@@ -189,12 +192,12 @@
 	 * please check the fixup code below as well.
 	 */
 #define CSUMCOPY_BIGCHUNK_ALIGNED(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7)	\
-	ldd	[src + off + 0x00], t0;							\
-	ldd	[src + off + 0x08], t2;							\
+	ldda	[src + off + 0x00] %asi, t0;						\
+	ldda	[src + off + 0x08] %asi, t2;						\
 	addccc	t0, sum, sum;								\
-	ldd	[src + off + 0x10], t4;							\
+	ldda	[src + off + 0x10] %asi, t4;						\
 	addccc	t1, sum, sum;								\
-	ldd	[src + off + 0x18], t6;							\
+	ldda	[src + off + 0x18] %asi, t6;						\
 	addccc	t2, sum, sum;								\
 	std	t0, [dst + off + 0x00];							\
 	addccc	t3, sum, sum;								\
@@ -211,10 +214,10 @@
 	 * Viking MXCC into streaming mode.  Ho hum...
 	 */
 #define CSUMCOPY_BIGCHUNK(src, dst, sum, off, t0, t1, t2, t3, t4, t5, t6, t7)	\
-	ldd	[src + off + 0x00], t0;						\
-	ldd	[src + off + 0x08], t2;						\
-	ldd	[src + off + 0x10], t4;						\
-	ldd	[src + off + 0x18], t6;						\
+	ldda	[src + off + 0x00] %asi, t0;					\
+	ldda	[src + off + 0x08] %asi, t2;					\
+	ldda	[src + off + 0x10] %asi, t4;					\
+	ldda	[src + off + 0x18] %asi, t6;					\
 	st	t0, [dst + off + 0x00];						\
 	addccc	t0, sum, sum;							\
 	st	t1, [dst + off + 0x04];						\
@@ -234,8 +237,8 @@
 
 	/* Yuck, 6 superscalar cycles... */
 #define CSUMCOPY_LASTCHUNK(src, dst, sum, off, t0, t1, t2, t3)	\
-	ldd	[src - off - 0x08], t0;				\
-	ldd	[src - off - 0x00], t2;				\
+	ldda	[src - off - 0x08] %asi, t0;			\
+	ldda	[src - off - 0x00] %asi, t2;			\
 	addccc	t0, sum, sum;					\
 	st	t0, [dst - off - 0x08];				\
 	addccc	t1, sum, sum;					\
@@ -250,7 +253,7 @@
 	andcc	%o3, 8, %g0		! begin checks for that code
 	be,pn	%icc, 1f
 	 and	%o3, 4, %g5
-	EX(ldd	[%o0 + 0x00], %g2, and %o3, 0xf,#)
+	EX(ldda	[%o0 + 0x00] %asi, %g2, and %o3, 0xf,#)
 	add	%o1, 8, %o1
 	addcc	%g2, %g7, %g7
 	add	%o0, 8, %o0
@@ -260,7 +263,7 @@
 	EX2(st	%g3, [%o1 - 0x04],#)
 1:	brz,pt	%g5, 1f
 	 andcc	%o3, 3, %o3
-	EX(ld	[%o0 + 0x00], %g2, add %o3, 4,#)
+	EX(lda	[%o0 + 0x00] %asi, %g2, add %o3, 4,#)
 	add	%o1, 4, %o1
 	addcc	%g2, %g7, %g7
 	EX2(st	%g2, [%o1 - 0x04],#)
@@ -272,20 +275,21 @@
 	 subcc	%o3, 2, %o3
 	ba,pt	%xcc, 4f
 	 clr	%o4
-2:	EX(lduh	[%o0 + 0x00], %o4, add %o3, 2,#)
+2:	EX(lduha [%o0 + 0x00] %asi, %o4, add %o3, 2,#)
 	add	%o0, 2, %o0
 	EX2(sth	%o4, [%o1 + 0x00],#)
 	be,pn	%icc, 6f
 	 add	%o1, 2, %o1
 	sll	%o4, 16, %o4
-4:	EX(ldub	[%o0 + 0x00], %o5, add %g0, 1,#)
+4:	EX(lduba [%o0 + 0x00] %asi, %o5, add %g0, 1,#)
 	EX2(stb	%o5, [%o1 + 0x00],#)
 	sll	%o5, 8, %o5
 	or	%o5, %o4, %o4
 6:	addcc	%o4, %g7, %g7
 1:	sllx	%g4, 32, %g4
+	addc	%g0, %g7, %o0
 	retl
-	 addc	%g0, %g7, %o0
+	 srl	%o0, 0, %o0
 
 	/* Sun, you just can't beat me, you just can't.  Stop trying,
 	 * give up.  I'm serious, I am going to kick the living shit
@@ -295,7 +299,9 @@
 	.globl	__csum_partial_copy_sparc_generic
 __csum_partial_copy_sparc_generic:
 					/* %o0=src, %o1=dest, %g1=len, %g7=sum */
+	srl	%g7, 0, %g7		! you neve know...
 	xor	%o0, %o1, %o4		! get changing bits
+	srl	%g1, 0, %g1		! doof scheiss
 	andcc	%o4, 3, %g0		! check for mismatched alignment
 	bne,pn	%icc, ccslow		! better this than unaligned/fixups
 	 andcc	%o0, 7, %g0		! need to align things?
@@ -309,7 +315,7 @@
 	 andcc	%o0, 0x2, %g0
 	be,pn	%icc, 1f
 	 andcc	%o0, 0x4, %g0
-	EX(lduh	[%o0 + 0x00], %g4, add %g1, 0,#)
+	EX(lduha [%o0 + 0x00] %asi, %g4, add %g1, 0,#)
 	sub	%g1, 2, %g1
 	EX2(sth	%g4, [%o1 + 0x00],#)
 	add	%o0, 2, %o0
@@ -325,7 +331,7 @@
 	or	%g3, %g7, %g7
 1:	be,pt	%icc, 3f
 	 andn	%g1, 0x7f, %g2
-	EX(ld	[%o0 + 0x00], %g4, add %g1, 0,#)
+	EX(lda	[%o0 + 0x00] %asi, %g4, add %g1, 0,#)
 	sub	%g1, 4, %g1
 	EX2(st	%g4, [%o1 + 0x00],#)
 	add	%o0, 4, %o0
@@ -372,8 +378,9 @@
 ccte:	bne,pn	%icc, cc_end_cruft	! something left, handle it out of band
 	 sethi	%uhi(KERNBASE), %g4	! restore gfp
 	mov	%g7, %o0		! give em the computed checksum
+	sllx	%g4, 32, %g4		! finish gfp restoration
 	retl				! return
-	 sllx	%g4, 32, %g4		! finish gfp restoration
+	 srl	%o0, 0, %o0
 ccdbl:	CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x00,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
 	CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x20,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
 	CSUMCOPY_BIGCHUNK_ALIGNED(%o0,%o1,%g7,0x40,%o4,%o5,%g2,%g3,%g4,%g5,%o2,%o3)
@@ -394,7 +401,7 @@
 	be,a,pt	%icc, 1f
 	 srl	%g1, 1, %o3		
 	sub	%g1, 1, %g1	
-	EX(ldub	[%o0], %g5, add %g1, 1,#)
+	EX(lduba [%o0] %asi, %g5, add %g1, 1,#)
 	add	%o0, 1, %o0	
 	EX2(stb	%g5, [%o1],#)
 	srl	%g1, 1, %o3
@@ -404,7 +411,7 @@
 	andcc	%o0, 2, %g0	
 	be,a,pt	%icc, 1f
 	 srl	%o3, 1, %o3
-	EX(lduh	[%o0], %o4, add %g1, 0,#)
+	EX(lduha [%o0] %asi, %o4, add %g1, 0,#)
 	sub	%g1, 2, %g1	
 	srl	%o4, 8, %g2
 	sub	%o3, 1, %o3	
@@ -416,7 +423,7 @@
 	add	%o1, 2, %o1
 1:	brz,a,pn %o3, 2f		
 	 andcc	%g1, 2, %g0
-	EX3(ld	[%o0], %o4,#)
+	EX3(lda	[%o0] %asi, %o4,#)
 5:	srl	%o4, 24, %g2
 	srl	%o4, 16, %g3
 	EX2(stb	%g2, [%o1],#)
@@ -430,7 +437,7 @@
 	add	%o1, 4, %o1	! is worthy). Maybe some day - with the sll/srl
 	subcc	%o3, 1, %o3	! tricks
 	bne,a,pt %icc, 5b
-	 EX3(ld	[%o0], %o4,#)
+	 EX3(lda [%o0] %asi, %o4,#)
 	sll	%g5, 16, %g2
 	srl	%g5, 16, %g5
 	srl	%g2, 16, %g2
@@ -438,7 +445,7 @@
 	add	%g2, %g5, %g5 
 2:	be,a,pt	%icc, 3f		
 	 andcc	%g1, 1, %g0
-	EX(lduh	[%o0], %o4, and %g1, 3,#)
+	EX(lduha [%o0] %asi, %o4, and %g1, 3,#)
 	andcc	%g1, 1, %g0
 	srl	%o4, 8, %g2
 	add	%o0, 2, %o0	
@@ -448,7 +455,7 @@
 	add	%o1, 2, %o1
 3:	be,a,pt	%icc, 1f		
 	 sll	%g5, 16, %o4
-	EX(ldub	[%o0], %g2, add %g0, 1,#)
+	EX(lduba [%o0] %asi, %g2, add %g0, 1,#)
 	sll	%g2, 8, %o4	
 	EX2(stb	%g2, [%o1],#)
 	add	%g5, %o4, %g5
@@ -463,8 +470,9 @@
 	sll	%g2, 8, %g2
 	or	%g2, %o4, %g5
 4:	addcc	%g7, %g5, %g7
+	addc	%g0, %g7, %o0
 	retl	
-	 addc	%g0, %g7, %o0
+	 srl	%o0, 0, %o0
 __csum_partial_copy_end:
 
         .section .fixup,#alloc,#execinstr
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/lib/copy_from_user.S linux/arch/sparc64/lib/copy_from_user.S
--- v2.1.42/linux/arch/sparc64/lib/copy_from_user.S	Tue May 13 22:41:04 1997
+++ linux/arch/sparc64/lib/copy_from_user.S	Thu Jun 12 16:22:06 1997
@@ -27,8 +27,8 @@
 	retl;					\
 	 a, b, %o0;				\
 	.section __ex_table,z##alloc;		\
-	.align	4;				\
-	.word	98b, 99b;			\
+	.align	8;				\
+	.xword	98b, 99b;			\
 	.text;					\
 	.align	4
 
@@ -41,23 +41,23 @@
 	retl;					\
 	 a, b, %o0;				\
 	.section __ex_table,z##alloc;		\
-	.align	4;				\
-	.word	98b, 99b;			\
+	.align	8;				\
+	.xword	98b, 99b;			\
 	.text;					\
 	.align	4
 
 #define EXO2(x,y,z) 				\
 98: 	x,##y;					\
 	.section __ex_table,z##alloc;		\
-	.align	4;				\
-	.word	98b, 97f;			\
+	.align	8;				\
+	.xword	98b, 97f;			\
 	.text;					\
 	.align	4
 
 #define EXT(start,end,handler,z) 		\
 	.section __ex_table,z##alloc;		\
-	.align	4;				\
-	.word	start, 0, end, handler;		\
+	.align	8;				\
+	.xword	start, 0, end, handler;		\
 	.text;					\
 	.align	4
 
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/lib/copy_to_user.S linux/arch/sparc64/lib/copy_to_user.S
--- v2.1.42/linux/arch/sparc64/lib/copy_to_user.S	Tue May 13 22:41:04 1997
+++ linux/arch/sparc64/lib/copy_to_user.S	Thu Jun 12 16:22:06 1997
@@ -27,8 +27,8 @@
 	retl;					\
 	 a, b, %o0;				\
 	.section __ex_table,z##alloc;		\
-	.align	4;				\
-	.word	98b, 99b;			\
+	.align	8;				\
+	.xword	98b, 99b;			\
 	.text;					\
 	.align	4
 
@@ -41,23 +41,23 @@
 	retl;					\
 	 a, b, %o0;				\
 	.section __ex_table,z##alloc;		\
-	.align	4;				\
-	.word	98b, 99b;			\
+	.align	8;				\
+	.xword	98b, 99b;			\
 	.text;					\
 	.align	4
 
 #define EXO2(x,y,z) 				\
 98: 	x,##y;					\
 	.section __ex_table,z##alloc;		\
-	.align	4;				\
-	.word	98b, 97f;			\
+	.align	8;				\
+	.xword	98b, 97f;			\
 	.text;					\
 	.align	4
 
 #define EXT(start,end,handler,z) 		\
 	.section __ex_table,z##alloc;		\
-	.align	4;				\
-	.word	start, 0, end, handler;		\
+	.align	8;				\
+	.xword	start, 0, end, handler;		\
 	.text;					\
 	.align	4
 
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/lib/memset.S linux/arch/sparc64/lib/memset.S
--- v2.1.42/linux/arch/sparc64/lib/memset.S	Mon Apr 14 16:28:10 1997
+++ linux/arch/sparc64/lib/memset.S	Thu Jun 12 16:22:06 1997
@@ -17,15 +17,15 @@
 99:	ba,pt	%xcc, 30f;			\
 	 a, b, %o0;				\
 	.section __ex_table,z##alloc;		\
-	.align	4;				\
-	.word	98b, 99b;			\
+	.align	8;				\
+	.xword	98b, 99b;			\
 	.text;					\
 	.align	4
 
 #define EXT(start,end,handler,z) 		\
 	.section __ex_table,z##alloc;		\
-	.align	4;				\
-	.word	start, 0, end, handler;		\
+	.align	8;				\
+	.xword	start, 0, end, handler;		\
 	.text;					\
 	.align	4
 
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/lib/strlen_user.S linux/arch/sparc64/lib/strlen_user.S
--- v2.1.42/linux/arch/sparc64/lib/strlen_user.S	Sat May 24 09:10:23 1997
+++ linux/arch/sparc64/lib/strlen_user.S	Thu Jun 12 16:22:06 1997
@@ -92,10 +92,10 @@
          clr    %o0
 
 	.section __ex_table,#alloc
-	.align	4
+	.align	8
 
-	.word	10b, 30b
-	.word	11b, 30b
-	.word	12b, 30b
-	.word	13b, 30b
-	.word	14b, 30b
+	.xword	10b, 30b
+	.xword	11b, 30b
+	.xword	12b, 30b
+	.xword	13b, 30b
+	.xword	14b, 30b
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/lib/strncpy_from_user.S linux/arch/sparc64/lib/strncpy_from_user.S
--- v2.1.42/linux/arch/sparc64/lib/strncpy_from_user.S	Sat May 24 09:10:23 1997
+++ linux/arch/sparc64/lib/strncpy_from_user.S	Thu Jun 12 16:22:06 1997
@@ -49,6 +49,6 @@
 	 mov	-EFAULT, %o0
 
 	.section __ex_table,#alloc
-	.align	4
-	.word	10b, 4b
-	.word	11b, 4b
+	.align	8
+	.xword	10b, 4b
+	.xword	11b, 4b
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
--- v2.1.42/linux/arch/sparc64/mm/fault.c	Thu May 29 21:53:04 1997
+++ linux/arch/sparc64/mm/fault.c	Thu Jun 12 16:22:06 1997
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.9 1997/05/19 05:58:54 davem Exp $
+/* $Id: fault.c,v 1.11 1997/06/01 05:46:15 davem Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -135,6 +135,7 @@
 }
 
 /* #define FAULT_TRACER */
+/* #define FAULT_TRACER_VERBOSE */
 
 asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write,
 				 unsigned long address, unsigned long tag,
@@ -150,12 +151,23 @@
 	static unsigned long last_addr = 0;
 	static int rcnt = 0;
 
-	printk("FAULT(PC[%016lx],t[%d],w[%d],addr[%016lx])\n",
+#ifdef FAULT_TRACER_VERBOSE
+	printk("FAULT(PC[%016lx],t[%d],w[%d],addr[%016lx])...",
 	       regs->tpc, text_fault, write, address);
-	if(address == last_addr && rcnt++ > 5) {
-		printk("Wheee lotsa bogus faults, something wrong, spinning\n");
-		while(1)
-			barrier();
+#else
+	printk("F[%016lx:%016lx:w(%d)", regs->tpc, address, write);
+#endif
+	if(address == last_addr) {
+		if(rcnt++ > 15) {
+			printk("Wheee lotsa bogus faults, something wrong, spinning\n");
+			__asm__ __volatile__("flushw");
+			printk("o7[%016lx] i7[%016lx]\n",
+			       regs->u_regs[UREG_I7],
+		    ((struct reg_window *)(regs->u_regs[UREG_FP]+STACK_BIAS))->ins[7]);
+			sti();
+			while(1)
+				barrier();
+		}
 	} else rcnt = 0;
 	last_addr = address;
 #endif
@@ -205,6 +217,13 @@
 		goto out;
 	}
 	if(from_user) {
+#if 1
+		unsigned long cpc;
+		__asm__ __volatile__("mov %%i7, %0" : "=r" (cpc));
+		printk("[%s:%d] SIGSEGV pc[%016lx] addr[%016lx] w[%d] sfsr[%016lx] "
+		       "caller[%016lx]\n", current->comm, current->pid, regs->tpc,
+		       address, write, sfsr, cpc);
+#endif
 		tsk->tss.sig_address = address;
 		tsk->tss.sig_desc = SUBSIG_NOMAPPING;
 		send_sig(SIGSEGV, tsk, 1);
@@ -213,4 +232,12 @@
 	unhandled_fault (address, tsk, regs);
 out:
 	unlock_kernel();
+#ifdef FAULT_TRACER
+#ifdef FAULT_TRACER_VERBOSE
+	printk(" done\n");
+#else
+	printk("]");
+#endif
+#endif
 }
+
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/vmlinux.lds linux/arch/sparc64/vmlinux.lds
--- v2.1.42/linux/arch/sparc64/vmlinux.lds	Mon Apr 14 16:28:11 1997
+++ linux/arch/sparc64/vmlinux.lds	Thu Jun 12 16:22:06 1997
@@ -26,6 +26,7 @@
   _edata  =  .;
   PROVIDE (edata = .);
   .fixup   : { *(.fixup) }
+  . = ALIGN(16);
   __start___ex_table = .;
   __ex_table : { *(__ex_table) }
   __stop___ex_table = .;
diff -u --recursive --new-file v2.1.42/linux/drivers/ap1000/ringbuf.c linux/drivers/ap1000/ringbuf.c
--- v2.1.42/linux/drivers/ap1000/ringbuf.c	Sun Jan 26 02:07:10 1997
+++ linux/drivers/ap1000/ringbuf.c	Thu Jun 12 16:22:06 1997
@@ -318,7 +318,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/drivers/block/genhd.c linux/drivers/block/genhd.c
--- v2.1.42/linux/drivers/block/genhd.c	Sat May 24 09:10:23 1997
+++ linux/drivers/block/genhd.c	Thu Jun 12 16:22:06 1997
@@ -380,7 +380,7 @@
 				   && (q->sector & 63) == 1
 				   && (q->end_sector & 63) == 63) {
 					unsigned int heads = q->end_head + 1;
-					if (heads == 32 || heads == 64 || heads == 128) {
+					if (heads == 32 || heads == 64 || heads == 128 || heads == 255) {
 
 						(void) ide_xlate_1024(dev, heads, " [PTBL]");
 						break;
@@ -672,6 +672,141 @@
 }
 #endif /* CONFIG_AMIGA_PARTITION */
 
+#ifdef CONFIG_ATARI_PARTITION
+#include <asm/atari_rootsec.h>
+
+/* ++guenther: this should be settable by the user ("make config")?.
+ */
+#define ICD_PARTS
+
+static int atari_partition (struct gendisk *hd, kdev_t dev,
+			    unsigned long first_sector)
+{
+  int minor = current_minor, m_lim = current_minor + hd->max_p;
+  struct buffer_head *bh;
+  struct rootsector *rs;
+  struct partition_info *pi;
+  ulong extensect;
+#ifdef ICD_PARTS
+  int part_fmt = 0; /* 0:unknown, 1:AHDI, 2:ICD/Supra */
+#endif
+
+  bh = bread (dev, 0, get_ptable_blocksize(dev));
+  if (!bh)
+    {
+      printk (" unable to read block 0\n");
+      return -1;
+    }
+
+  rs = (struct rootsector *) bh->b_data;
+  pi = &rs->part[0];
+  printk (" AHDI");
+  for (; pi < &rs->part[4] && minor < m_lim; minor++, pi++)
+    {
+      if (pi->flg & 1)
+	/* active partition */
+	{
+	  if (memcmp (pi->id, "XGM", 3) == 0)
+	    /* extension partition */
+	    {
+	      struct rootsector *xrs;
+	      struct buffer_head *xbh;
+	      ulong partsect;
+
+#ifdef ICD_PARTS
+	      part_fmt = 1;
+#endif
+	      printk(" XGM<");
+	      partsect = extensect = pi->st;
+	      while (1)
+		{
+		  xbh = bread (dev, partsect / 2, 1024);
+		  if (!xbh)
+		    {
+		      printk (" block %ld read failed\n", partsect);
+		      brelse(bh);
+		      return 0;
+		    }
+		  if (partsect & 1)
+		    xrs = (struct rootsector *) &xbh->b_data[512];
+		  else
+		    xrs = (struct rootsector *) &xbh->b_data[0];
+
+		  /* ++roman: sanity check: bit 0 of flg field must be set */
+		  if (!(xrs->part[0].flg & 1)) {
+		    printk( "\nFirst sub-partition in extended partition is not valid!\n" );
+		    break;
+		  }
+
+		  add_partition(hd, minor, partsect + xrs->part[0].st,
+				xrs->part[0].siz);
+
+		  if (!(xrs->part[1].flg & 1)) {
+		    /* end of linked partition list */
+		    brelse( xbh );
+		    break;
+		  }
+		  if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) {
+		    printk( "\nID of extended partition is not XGM!\n" );
+		    brelse( xbh );
+		    break;
+		  }
+
+		  partsect = xrs->part[1].st + extensect;
+		  brelse (xbh);
+		  minor++;
+		  if (minor >= m_lim) {
+		    printk( "\nMaximum number of partitions reached!\n" );
+		    break;
+		  }
+		}
+	      printk(" >");
+	    }
+	  else
+	    {
+	      /* we don't care about other id's */
+	      add_partition (hd, minor, pi->st, pi->siz);
+	    }
+	}
+    }
+#ifdef ICD_PARTS
+  if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */
+  {
+    pi = &rs->icdpart[0];
+    /* sanity check: no ICD format if first partition invalid */
+    if (memcmp (pi->id, "GEM", 3) == 0 ||
+        memcmp (pi->id, "BGM", 3) == 0 ||
+        memcmp (pi->id, "LNX", 3) == 0 ||
+        memcmp (pi->id, "SWP", 3) == 0 ||
+        memcmp (pi->id, "RAW", 3) == 0 )
+    {
+      printk(" ICD<");
+      for (; pi < &rs->icdpart[8] && minor < m_lim; minor++, pi++)
+      {
+        /* accept only GEM,BGM,RAW,LNX,SWP partitions */
+        if (pi->flg & 1 && 
+            (memcmp (pi->id, "GEM", 3) == 0 ||
+             memcmp (pi->id, "BGM", 3) == 0 ||
+             memcmp (pi->id, "LNX", 3) == 0 ||
+             memcmp (pi->id, "SWP", 3) == 0 ||
+             memcmp (pi->id, "RAW", 3) == 0) )
+        {
+          part_fmt = 2;
+	  add_partition (hd, minor, pi->st, pi->siz);
+        }
+      }
+      printk(" >");
+    }
+  }
+#endif
+  brelse (bh);
+
+  printk ("\n");
+
+  return 1;
+}
+#endif /* CONFIG_ATARI_PARTITION */
+
 static void check_partition(struct gendisk *hd, kdev_t dev)
 {
 	static int first_time = 1;
@@ -707,6 +842,10 @@
 #endif
 #ifdef CONFIG_AMIGA_PARTITION
 	if(amiga_partition(hd, dev, first_sector))
+		return;
+#endif
+#ifdef CONFIG_ATARI_PARTITION
+	if(atari_partition(hd, dev, first_sector))
 		return;
 #endif
 	printk(" unknown partition table\n");
diff -u --recursive --new-file v2.1.42/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- v2.1.42/linux/drivers/block/ide.c	Tue May 13 22:41:05 1997
+++ linux/drivers/block/ide.c	Thu Jun 12 16:22:06 1997
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c	Version 6.02  Mar  11, 1997
+ *  linux/drivers/block/ide.c	Version 6.03  June 4, 1997
  *
  *  Copyright (C) 1994-1997  Linus Torvalds & authors (see below)
  */
@@ -280,6 +280,7 @@
  *			support HDIO_GETGEO for floppies
  * Version 6.02		fix ide_ack_intr() call
  *			check partition table on floppies
+ * Version 6.03		handle bad status bit sequencing in ide_wait_stat()
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -1044,27 +1045,24 @@
 	byte stat;
 	unsigned long flags;
 
-test:
-	udelay(1);	/* spec allows drive 400ns to change "BUSY" */
-	if (OK_STAT((stat = GET_STAT()), good, bad))
-		return 0;	/* fast exit for most frequent case */
-	if (!(stat & BUSY_STAT)) {
-		ide_error(drive, "status error", stat);
-		return 1;
-	}
-
-	save_flags(flags);
-	ide_sti();
-	timeout += jiffies;
-	do {
-		if (!((stat = GET_STAT()) & BUSY_STAT)) {
-			restore_flags(flags);
-			goto test;
+	udelay(1);	/* spec allows drive 400ns to assert "BUSY" */
+	if ((stat = GET_STAT()) & BUSY_STAT) {
+		save_flags(flags);
+		ide_sti();
+		timeout += jiffies;
+		while ((stat = GET_STAT()) & BUSY_STAT) {
+			if (jiffies > timeout) {
+				restore_flags(flags);
+				ide_error(drive, "status timeout", stat);
+				return 1;
+			}
 		}
-	} while (jiffies <= timeout);
-
-	restore_flags(flags);
-	ide_error(drive, "status timeout", GET_STAT());
+		restore_flags(flags);
+	}
+	udelay(1);	/* allow status to settle, then read it again */
+	if (OK_STAT((stat = GET_STAT()), good, bad))
+		return 0;
+	ide_error(drive, "status error", stat);
 	return 1;
 }
 
diff -u --recursive --new-file v2.1.42/linux/drivers/block/ide.h linux/drivers/block/ide.h
--- v2.1.42/linux/drivers/block/ide.h	Thu Jun 12 15:28:48 1997
+++ linux/drivers/block/ide.h	Sun Jun 15 15:12:43 1997
@@ -134,7 +134,7 @@
 #define BAD_W_STAT		(BAD_R_STAT  | WRERR_STAT)
 #define BAD_STAT		(BAD_R_STAT  | DRQ_STAT)
 #define DRIVE_READY		(READY_STAT  | SEEK_STAT)
-#define DATA_READY		(DRIVE_READY | DRQ_STAT)
+#define DATA_READY		(DRQ_STAT)
 
 /*
  * Some more useful definitions
diff -u --recursive --new-file v2.1.42/linux/drivers/block/loop.c linux/drivers/block/loop.c
--- v2.1.42/linux/drivers/block/loop.c	Tue May 13 22:41:05 1997
+++ linux/drivers/block/loop.c	Thu Jun 12 16:22:06 1997
@@ -318,7 +318,7 @@
 	}
 
 	lo->lo_inode = inode;
-	lo->lo_inode->i_count++;
+	atomic_inc(&lo->lo_inode->i_count);
 	lo->transfer = NULL;
 	figure_loop_size(lo);
 	MOD_INC_USE_COUNT;
diff -u --recursive --new-file v2.1.42/linux/drivers/block/md.c linux/drivers/block/md.c
--- v2.1.42/linux/drivers/block/md.c	Tue May 13 22:41:05 1997
+++ linux/drivers/block/md.c	Thu Jun 12 16:22:06 1997
@@ -202,9 +202,10 @@
 {
   int i;
   
-  if (inode->i_count>1 || md_dev[minor].busy>1) /* ioctl : one open channel */
+  if (atomic_read(&inode->i_count)>1 || md_dev[minor].busy>1) /* ioctl : one open channel */
   {
-    printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", minor, inode->i_count, md_dev[minor].busy);
+    printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", minor,
+	    atomic_read(&inode->i_count), md_dev[minor].busy);
     return -EBUSY;
   }
   
diff -u --recursive --new-file v2.1.42/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- v2.1.42/linux/drivers/char/Makefile	Sat May 24 09:10:23 1997
+++ linux/drivers/char/Makefile	Thu Jun 12 16:22:06 1997
@@ -44,6 +44,9 @@
 ifneq ($(ARCH),m68k)
 L_OBJS += pc_keyb.o defkeymap.o
 endif
+ifdef CONFIG_MAGIC_SYSRQ
+L_OBJS += sysrq.o
+endif
 endif
 
 ifeq ($(CONFIG_ATARI_DSP56K),y)
diff -u --recursive --new-file v2.1.42/linux/drivers/char/atarimouse.c linux/drivers/char/atarimouse.c
--- v2.1.42/linux/drivers/char/atarimouse.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/atarimouse.c	Thu Jun 12 16:22:06 1997
@@ -176,7 +176,7 @@
 #define	MIN_THRESHOLD 1
 #define	MAX_THRESHOLD 20	/* more seems not reasonable... */
 
-void atari_mouse_setup( char *str, int *ints )
+__initfunc(void atari_mouse_setup( char *str, int *ints ))
 {
     if (ints[0] < 1) {
 	printk( "atari_mouse_setup: no arguments!\n" );
diff -u --recursive --new-file v2.1.42/linux/drivers/char/console.c linux/drivers/char/console.c
--- v2.1.42/linux/drivers/char/console.c	Tue May 13 22:41:06 1997
+++ linux/drivers/char/console.c	Thu Jun 12 16:22:06 1997
@@ -111,11 +111,11 @@
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 
-#include "kbd_kern.h"
-#include "vt_kern.h"
-#include "consolemap.h"
-#include "selection.h"
-#include "console_struct.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 
 #ifndef MIN
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
diff -u --recursive --new-file v2.1.42/linux/drivers/char/console_struct.h linux/drivers/char/console_struct.h
--- v2.1.42/linux/drivers/char/console_struct.h	Mon Nov 20 22:34:54 1995
+++ linux/drivers/char/console_struct.h	Wed Dec 31 16:00:00 1969
@@ -1,141 +0,0 @@
-/*
- * console_struct.h
- *
- * Data structure and defines shared between console.c, vga.c and tga.c
- */
-
-#define NPAR 16
-
-struct vc_data {
-	unsigned long	vc_screenbuf_size;
-	unsigned short	vc_video_erase_char;	/* Background erase character */
-	unsigned char	vc_attr;		/* Current attributes */
-	unsigned char	vc_def_color;		/* Default colors */
-	unsigned char	vc_color;		/* Foreground & background */
-	unsigned char	vc_s_color;		/* Saved foreground & background */
-	unsigned char	vc_ulcolor;		/* Colour for underline mode */
-	unsigned char	vc_halfcolor;		/* Colour for half intensity mode */
-	unsigned long	vc_origin;		/* Used for EGA/VGA fast scroll	*/
-	unsigned long	vc_scr_end;		/* Used for EGA/VGA fast scroll	*/
-	unsigned long	vc_pos;
-	unsigned long	vc_x,vc_y;
-	unsigned long	vc_top,vc_bottom;
-	unsigned long	vc_state;
-	unsigned long	vc_npar,vc_par[NPAR];
-	unsigned long	vc_video_mem_start;	/* Start of video RAM		*/
-	unsigned long	vc_video_mem_end;	/* End of video RAM (sort of)	*/
-	unsigned long	vc_saved_x;
-	unsigned long	vc_saved_y;
-	/* mode flags */
-	unsigned long	vc_charset	: 1;	/* Character set G0 / G1 */
-	unsigned long	vc_s_charset	: 1;	/* Saved character set */
-	unsigned long	vc_disp_ctrl	: 1;	/* Display chars < 32? */
-	unsigned long	vc_toggle_meta	: 1;	/* Toggle high bit? */
-	unsigned long	vc_decscnm	: 1;	/* Screen Mode */
-	unsigned long	vc_decom	: 1;	/* Origin Mode */
-	unsigned long	vc_decawm	: 1;	/* Autowrap Mode */
-	unsigned long	vc_deccm	: 1;	/* Cursor Visible */
-	unsigned long	vc_decim	: 1;	/* Insert Mode */
-	unsigned long	vc_deccolm	: 1;	/* 80/132 Column Mode */
-	/* attribute flags */
-	unsigned long	vc_intensity	: 2;	/* 0=half-bright, 1=normal, 2=bold */
-	unsigned long	vc_underline	: 1;
-	unsigned long	vc_blink	: 1;
-	unsigned long	vc_reverse	: 1;
-	unsigned long	vc_s_intensity	: 2;	/* saved rendition */
-	unsigned long	vc_s_underline	: 1;
-	unsigned long	vc_s_blink	: 1;
-	unsigned long	vc_s_reverse	: 1;
-	/* misc */
-	unsigned long	vc_ques		: 1;
-	unsigned long	vc_need_wrap	: 1;
-	unsigned long	vc_has_scrolled : 1;	/* Info for unblank_screen */
-	unsigned long	vc_kmalloced	: 1;	/* kfree_s() needed */
-	unsigned long	vc_report_mouse : 2;
-	unsigned char	vc_utf		: 1;	/* Unicode UTF-8 encoding */
-	unsigned char	vc_utf_count;
-		 long	vc_utf_char;
-	unsigned long	vc_tab_stop[5];		/* Tab stops. 160 columns. */
-	unsigned char   vc_palette[16*3];       /* Colour palette for VGA+ */
-	unsigned short * vc_translate;
-	unsigned char 	vc_G0_charset;
-	unsigned char 	vc_G1_charset;
-	unsigned char 	vc_saved_G0;
-	unsigned char 	vc_saved_G1;
-	unsigned int	vc_bell_pitch;		/* Console bell pitch */
-	unsigned int	vc_bell_duration;	/* Console bell duration */
-	/* additional information is in vt_kern.h */
-};
-
-struct vc {
-	struct vc_data *d;
-
-	/* might add  scrmem, vt_struct, kbd  at some time,
-	   to have everything in one place - the disadvantage
-	   would be that vc_cons etc can no longer be static */
-};
-
-extern struct vc vc_cons [MAX_NR_CONSOLES];
-
-#define screenbuf_size	(vc_cons[currcons].d->vc_screenbuf_size)
-#define origin		(vc_cons[currcons].d->vc_origin)
-#define scr_end	(vc_cons[currcons].d->vc_scr_end)
-#define pos		(vc_cons[currcons].d->vc_pos)
-#define top		(vc_cons[currcons].d->vc_top)
-#define bottom		(vc_cons[currcons].d->vc_bottom)
-#define x		(vc_cons[currcons].d->vc_x)
-#define y		(vc_cons[currcons].d->vc_y)
-#define vc_state	(vc_cons[currcons].d->vc_state)
-#define npar		(vc_cons[currcons].d->vc_npar)
-#define par		(vc_cons[currcons].d->vc_par)
-#define ques		(vc_cons[currcons].d->vc_ques)
-#define attr		(vc_cons[currcons].d->vc_attr)
-#define saved_x	(vc_cons[currcons].d->vc_saved_x)
-#define saved_y	(vc_cons[currcons].d->vc_saved_y)
-#define translate	(vc_cons[currcons].d->vc_translate)
-#define G0_charset	(vc_cons[currcons].d->vc_G0_charset)
-#define G1_charset	(vc_cons[currcons].d->vc_G1_charset)
-#define saved_G0	(vc_cons[currcons].d->vc_saved_G0)
-#define saved_G1	(vc_cons[currcons].d->vc_saved_G1)
-#define utf		(vc_cons[currcons].d->vc_utf)
-#define utf_count	(vc_cons[currcons].d->vc_utf_count)
-#define utf_char	(vc_cons[currcons].d->vc_utf_char)
-#define video_mem_start (vc_cons[currcons].d->vc_video_mem_start)
-#define video_mem_end	(vc_cons[currcons].d->vc_video_mem_end)
-#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)
-#define disp_ctrl	(vc_cons[currcons].d->vc_disp_ctrl)
-#define toggle_meta	(vc_cons[currcons].d->vc_toggle_meta)
-#define decscnm	(vc_cons[currcons].d->vc_decscnm)
-#define decom		(vc_cons[currcons].d->vc_decom)
-#define decawm		(vc_cons[currcons].d->vc_decawm)
-#define deccm		(vc_cons[currcons].d->vc_deccm)
-#define decim		(vc_cons[currcons].d->vc_decim)
-#define deccolm	(vc_cons[currcons].d->vc_deccolm)
-#define need_wrap	(vc_cons[currcons].d->vc_need_wrap)
-#define has_scrolled	(vc_cons[currcons].d->vc_has_scrolled)
-#define kmalloced	(vc_cons[currcons].d->vc_kmalloced)
-#define report_mouse	(vc_cons[currcons].d->vc_report_mouse)
-#define color		(vc_cons[currcons].d->vc_color)
-#define s_color	(vc_cons[currcons].d->vc_s_color)
-#define def_color	(vc_cons[currcons].d->vc_def_color)
-#define 	foreground	(color & 0x0f)
-#define 	background	(color & 0xf0)
-#define charset	(vc_cons[currcons].d->vc_charset)
-#define s_charset	(vc_cons[currcons].d->vc_s_charset)
-#define	intensity	(vc_cons[currcons].d->vc_intensity)
-#define	underline	(vc_cons[currcons].d->vc_underline)
-#define	blink		(vc_cons[currcons].d->vc_blink)
-#define	reverse		(vc_cons[currcons].d->vc_reverse)
-#define	s_intensity	(vc_cons[currcons].d->vc_s_intensity)
-#define	s_underline	(vc_cons[currcons].d->vc_s_underline)
-#define	s_blink		(vc_cons[currcons].d->vc_s_blink)
-#define	s_reverse	(vc_cons[currcons].d->vc_s_reverse)
-#define	ulcolor		(vc_cons[currcons].d->vc_ulcolor)
-#define	halfcolor	(vc_cons[currcons].d->vc_halfcolor)
-#define tab_stop	(vc_cons[currcons].d->vc_tab_stop)
-#define palette		(vc_cons[currcons].d->vc_palette)
-#define bell_pitch	(vc_cons[currcons].d->vc_bell_pitch)
-#define bell_duration	(vc_cons[currcons].d->vc_bell_duration)
-
-#define vcmode		(vt_cons[currcons]->vc_mode)
-#define structsize	(sizeof(struct vc_data) + sizeof(struct vt_struct))
diff -u --recursive --new-file v2.1.42/linux/drivers/char/consolemap.c linux/drivers/char/consolemap.c
--- v2.1.42/linux/drivers/char/consolemap.c	Tue May 13 22:41:06 1997
+++ linux/drivers/char/consolemap.c	Thu Jun 12 16:22:06 1997
@@ -13,7 +13,7 @@
 #include <linux/malloc.h>
 #include <linux/init.h>
 #include <asm/uaccess.h>
-#include "consolemap.h"
+#include <linux/consolemap.h>
 
 static unsigned short translations[][256] = {
   /* 8-bit Latin-1 mapped to Unicode -- trivial mapping */
diff -u --recursive --new-file v2.1.42/linux/drivers/char/consolemap.h linux/drivers/char/consolemap.h
--- v2.1.42/linux/drivers/char/consolemap.h	Sun Sep 17 21:42:44 1995
+++ linux/drivers/char/consolemap.h	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-/*
- * consolemap.h
- *
- * Interface between console.c, selection.c  and consolemap.c
- */
-#define LAT1_MAP 0
-#define GRAF_MAP 1
-#define IBMPC_MAP 2
-#define USER_MAP 3
-
-extern int hashtable_contents_valid;
-extern unsigned char inverse_translate(int glyph);
-extern unsigned short *set_translate(int m);
-extern int conv_uni_to_pc(long ucs);
diff -u --recursive --new-file v2.1.42/linux/drivers/char/diacr.h linux/drivers/char/diacr.h
--- v2.1.42/linux/drivers/char/diacr.h	Thu Feb  6 02:55:18 1997
+++ linux/drivers/char/diacr.h	Wed Dec 31 16:00:00 1969
@@ -1,8 +0,0 @@
-#ifndef _DIACR_H
-#define _DIACR_H
-#include <linux/kd.h>
-
-extern struct kbdiacr accent_table[];
-extern unsigned int accent_table_size;
-
-#endif /* _DIACR_H */
diff -u --recursive --new-file v2.1.42/linux/drivers/char/dsp56k.c linux/drivers/char/dsp56k.c
--- v2.1.42/linux/drivers/char/dsp56k.c	Tue May 13 22:41:06 1997
+++ linux/drivers/char/dsp56k.c	Thu Jun 12 16:22:06 1997
@@ -488,7 +488,7 @@
 	return 0;
 }
 
-static void dsp56k_release(struct inode *inode, struct file *file)
+static int dsp56k_release(struct inode *inode, struct file *file)
 {
 	int dev = MINOR(inode->i_rdev) & 0x0f;
 
@@ -501,12 +501,13 @@
 		break;
 	default:
 		printk("DSP56k driver: Unknown minor device: %d\n", dev);
-		return;
+		return -ENXIO;
 	}
 
 #ifdef MODULE
 	MOD_DEC_USE_COUNT;
-#endif /* MODULE */
+#endif
+	return 0;
 }
 
 static struct file_operations dsp56k_fops = {
diff -u --recursive --new-file v2.1.42/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c
--- v2.1.42/linux/drivers/char/fbmem.c	Tue May 13 22:41:07 1997
+++ linux/drivers/char/fbmem.c	Thu Jun 12 16:22:06 1997
@@ -222,7 +222,7 @@
 			     vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 	vma->vm_inode = inode;
-	inode->i_count++;
+	atomic_inc(&inode->i_count);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.42/linux/drivers/char/kbd_kern.h linux/drivers/char/kbd_kern.h
--- v2.1.42/linux/drivers/char/kbd_kern.h	Thu Jun 12 15:29:05 1997
+++ linux/drivers/char/kbd_kern.h	Wed Dec 31 16:00:00 1969
@@ -1,141 +0,0 @@
-#ifndef _KBD_KERN_H
-#define _KBD_KERN_H
-
-#include <linux/interrupt.h>
-#include <linux/keyboard.h>
-
-extern int shift_state;
-
-extern char *func_table[MAX_NR_FUNC];
-extern char func_buf[];
-extern char *funcbufptr;
-extern int funcbufsize, funcbufleft;
-
-/*
- * kbd->xxx contains the VC-local things (flag settings etc..)
- *
- * Note: externally visible are LED_SCR, LED_NUM, LED_CAP defined in kd.h
- *       The code in KDGETLED / KDSETLED depends on the internal and
- *       external order being the same.
- *
- * Note: lockstate is used as index in the array key_map.
- */
-struct kbd_struct {
-
-	unsigned char lockstate;
-/* 8 modifiers - the names do not have any meaning at all;
-   they can be associated to arbitrarily chosen keys */
-#define VC_SHIFTLOCK	KG_SHIFT	/* shift lock mode */
-#define VC_ALTGRLOCK	KG_ALTGR	/* altgr lock mode */
-#define VC_CTRLLOCK	KG_CTRL 	/* control lock mode */
-#define VC_ALTLOCK	KG_ALT  	/* alt lock mode */
-#define VC_SHIFTLLOCK	KG_SHIFTL	/* shiftl lock mode */
-#define VC_SHIFTRLOCK	KG_SHIFTR	/* shiftr lock mode */
-#define VC_CTRLLLOCK	KG_CTRLL 	/* ctrll lock mode */
-#define VC_CTRLRLOCK	KG_CTRLR 	/* ctrlr lock mode */
-	unsigned char slockstate; 	/* for `sticky' Shift, Ctrl, etc. */
-
-	unsigned char ledmode:2; 	/* one 2-bit value */
-#define LED_SHOW_FLAGS 0        /* traditional state */
-#define LED_SHOW_IOCTL 1        /* only change leds upon ioctl */
-#define LED_SHOW_MEM 2          /* `heartbeat': peek into memory */
-
-	unsigned char ledflagstate:3;	/* flags, not lights */
-	unsigned char default_ledflagstate:3;
-#define VC_SCROLLOCK	0	/* scroll-lock mode */
-#define VC_NUMLOCK	1	/* numeric lock mode */
-#define VC_CAPSLOCK	2	/* capslock mode */
-
-	unsigned char kbdmode:2;	/* one 2-bit value */
-#define VC_XLATE	0	/* translate keycodes using keymap */
-#define VC_MEDIUMRAW	1	/* medium raw (keycode) mode */
-#define VC_RAW		2	/* raw (scancode) mode */
-#define VC_UNICODE	3	/* Unicode mode */
-
-	unsigned char modeflags:5;
-#define VC_APPLIC	0	/* application key mode */
-#define VC_CKMODE	1	/* cursor key mode */
-#define VC_REPEAT	2	/* keyboard repeat */
-#define VC_CRLF		3	/* 0 - enter sends CR, 1 - enter sends CRLF */
-#define VC_META		4	/* 0 - meta, 1 - meta=prefix with ESC */
-};
-
-extern struct kbd_struct kbd_table[];
-
-extern int kbd_init(void);
-
-extern unsigned char getledstate(void);
-extern void setledstate(struct kbd_struct *kbd, unsigned int led);
-
-extern int do_poke_blanked_console;
-
-extern inline void show_console(void)
-{
-	do_poke_blanked_console = 1;
-	mark_bh(CONSOLE_BH);
-}
-
-extern inline void set_console(int nr)
-{
-	want_console = nr;
-	mark_bh(CONSOLE_BH);
-}
-
-extern inline void set_leds(void)
-{
-	mark_bh(KEYBOARD_BH);
-}
-
-extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
-{
-	return ((kbd->modeflags >> flag) & 1);
-}
-
-extern inline int vc_kbd_led(struct kbd_struct * kbd, int flag)
-{
-	return ((kbd->ledflagstate >> flag) & 1);
-}
-
-extern inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag)
-{
-	kbd->modeflags |= 1 << flag;
-}
-
-extern inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag)
-{
-	kbd->ledflagstate |= 1 << flag;
-}
-
-extern inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag)
-{
-	kbd->modeflags &= ~(1 << flag);
-}
-
-extern inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag)
-{
-	kbd->ledflagstate &= ~(1 << flag);
-}
-
-extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
-{
-	kbd->lockstate ^= 1 << flag;
-}
-
-extern inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag)
-{
-	kbd->slockstate ^= 1 << flag;
-}
-
-extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
-{
-	kbd->modeflags ^= 1 << flag;
-}
-
-extern inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
-{
-	kbd->ledflagstate ^= 1 << flag;
-}
-
-#define U(x) ((x) ^ 0xf000)
-
-#endif
diff -u --recursive --new-file v2.1.42/linux/drivers/char/keyboard.c linux/drivers/char/keyboard.c
--- v2.1.42/linux/drivers/char/keyboard.c	Sat May 24 09:10:23 1997
+++ linux/drivers/char/keyboard.c	Thu Jun 12 16:22:06 1997
@@ -17,8 +17,11 @@
  * Modified to provide 'generic' keyboard support by Hamish Macdonald
  * Merge with the m68k keyboard driver and split-off of the PC low-level
  * parts by Geert Uytterhoeven, May 1997
+ *
+ * 27-05-97: Added support for the Magic SysRq Key (Martin Mares)
  */
 
+#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -30,9 +33,10 @@
 #include <asm/keyboard.h>
 #include <asm/bitops.h>
 
-#include "kbd_kern.h"
-#include "diacr.h"
-#include "vt_kern.h"
+#include <linux/kbd_kern.h>
+#include <linux/kbd_diacr.h>
+#include <linux/vt_kern.h>
+#include <linux/kbd_ll.h>
 
 #define SIZE(x) (sizeof(x)/sizeof((x)[0]))
 
@@ -82,7 +86,7 @@
  * the variable must be global, or a new procedure must be created to 
  * return the value. I chose the former way.
  */
-/*static*/ int shift_state = 0;
+int shift_state = 0;
 static int npadch = -1;			/* -1 or number assembled on pad */
 static unsigned char diacr = 0;
 static char rep = 0;			/* flag telling character repeat */
@@ -140,8 +144,14 @@
 static void put_queue(int);
 static unsigned char handle_diacr(unsigned char);
 
-/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
-struct pt_regs * pt_regs;
+/* kbd_pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
+struct pt_regs * kbd_pt_regs;
+
+#ifdef CONFIG_MAGIC_SYSRQ
+#define SYSRQ_KEY 0x54
+extern void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *);
+static int sysrq_pressed;
+#endif
 
 /*
  * Many other routines do put_queue, but I think either
@@ -223,6 +233,17 @@
 	} else
  		rep = test_and_set_bit(keycode, key_down);
 
+#ifdef CONFIG_MAGIC_SYSRQ		/* Handle the SysRq Hack */
+	if (keycode == SYSRQ_KEY) {
+		sysrq_pressed = !up_flag;
+		return;
+	} else if (sysrq_pressed) {
+		if (!up_flag)
+			handle_sysrq(keycode, kbd_pt_regs, kbd, tty);
+		return;
+	}
+#endif
+
 	if (kbd->kbdmode == VC_MEDIUMRAW) {
 		/* soon keycodes will require more than one byte */
  		put_queue(keycode + up_flag);
@@ -346,8 +367,8 @@
 
 static void show_ptregs(void)
 {
-	if (pt_regs)
-		show_regs(pt_regs);
+	if (kbd_pt_regs)
+		show_regs(kbd_pt_regs);
 }
 
 static void hold(void)
diff -u --recursive --new-file v2.1.42/linux/drivers/char/lp_m68k.c linux/drivers/char/lp_m68k.c
--- v2.1.42/linux/drivers/char/lp_m68k.c	Tue May 13 22:41:07 1997
+++ linux/drivers/char/lp_m68k.c	Thu Jun 12 16:22:06 1997
@@ -462,7 +462,6 @@
 EXPORT_SYMBOL(lp_table);
 EXPORT_SYMBOL(lp_irq);
 EXPORT_SYMBOL(lp_interrupt);
-EXPORT_SYMBOL(lp_init);
 EXPORT_SYMBOL(register_parallel);
 EXPORT_SYMBOL(unregister_parallel);
 
diff -u --recursive --new-file v2.1.42/linux/drivers/char/mem.c linux/drivers/char/mem.c
--- v2.1.42/linux/drivers/char/mem.c	Thu May 15 16:48:02 1997
+++ linux/drivers/char/mem.c	Thu Jun 12 16:22:06 1997
@@ -35,6 +35,33 @@
 void pcwatchdog_init(void);
 #endif
 
+static long do_write_mem(struct file * file,
+	void *p, unsigned long realp, 					 
+	const char * buf, unsigned long count)
+{
+	unsigned long written;
+
+	written = 0;
+#if defined(__sparc__) || defined(__mc68000__)
+	/* we don't have page 0 mapped on sparc and m68k.. */
+	if (realp < PAGE_SIZE) {
+		unsigned long sz = PAGE_SIZE-realp;
+		if (sz > count) sz = count; 
+		/* Hmm. Do something? */
+		buf+=sz;
+		p+=sz;
+		count-=sz;
+		written+=sz;
+	}
+#endif
+	if (copy_from_user(p, buf, count) < 0) 
+		return -EFAULT;
+	written += count;
+	file->f_pos += written;
+	return count;
+}
+
+
 /*
  * This funcion reads the *physical* memory. The f_pos points directly to the 
  * memory location. 
@@ -45,7 +72,7 @@
 	unsigned long p = file->f_pos;
 	unsigned long end_mem;
 	unsigned long read;
-
+	
 	end_mem = __pa(high_memory);
 	if (p >= end_mem)
 		return 0;
@@ -54,15 +81,22 @@
 	read = 0;
 #if defined(__sparc__) || defined(__mc68000__)
 	/* we don't have page 0 mapped on sparc and m68k.. */
-	while (p < PAGE_SIZE && count > 0) {
-		put_user(0,buf);
-		buf++;
-		p++;
-		count--;
-		read++;
+	if (p < PAGE_SIZE) {
+		unsigned long sz = PAGE_SIZE-p;
+		if (sz > count) 
+			sz = count; 
+		if (sz > 0) {
+			if (clear_user(buf, sz))
+				return -EFAULT;
+			buf += sz; 
+			p += sz; 
+			count -= sz; 
+			read += sz; 
+		}
 	}
 #endif
-	copy_to_user(buf, __va(p), count);
+	if (copy_to_user(buf, __va(p), count) < 0)
+		return -EFAULT;
 	read += count;
 	file->f_pos += read;
 	return read;
@@ -73,35 +107,19 @@
 {
 	unsigned long p = file->f_pos;
 	unsigned long end_mem;
-	unsigned long written;
 
 	end_mem = __pa(high_memory);
 	if (p >= end_mem)
 		return 0;
 	if (count > end_mem - p)
 		count = end_mem - p;
-	written = 0;
-#if defined(__sparc__) || defined(__mc68000__)
-	/* we don't have page 0 mapped on sparc and m68k.. */
-	while (p < PAGE_SIZE && count > 0) {
-		/* Hmm. Do something? */
-		buf++;
-		p++;
-		count--;
-		written++;
-	}
-#endif
-	copy_from_user(__va(p), buf, count);
-	written += count;
-	file->f_pos += written;
-	return count;
+	return do_write_mem(file,__va(p),p,buf,count);
 }
 
 static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_struct * vma)
 {
 	unsigned long offset = vma->vm_offset;
 
-	
 	if (offset & ~PAGE_MASK)
 		return -ENXIO;
 #if defined(__i386__)
@@ -117,7 +135,7 @@
 	if (remap_page_range(vma->vm_start, offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
 		return -EAGAIN;
 	vma->vm_inode = inode;
-	inode->i_count++;
+	atomic_inc(&inode->i_count);
 	return 0;
 }
 
@@ -166,27 +184,12 @@
 	const char * buf, unsigned long count)
 {
 	unsigned long p = file->f_pos;
-	unsigned long written;
 
 	if (p >= (unsigned long) high_memory)
 		return 0;
 	if (count > (unsigned long) high_memory - p)
 		count = (unsigned long) high_memory - p;
-	written = 0;
-#if defined(__sparc__) || defined(__mc68000__)
-	/* we don't have page 0 mapped on sparc and m68k.. */
-	while (p < PAGE_SIZE && count > 0) {
-		/* Hmm. Do something? */
-		buf++;
-		p++;
-		count--;
-		written++;
-	}
-#endif
-	copy_from_user((char *) p, buf, count);
-	written += count;
-	file->f_pos += written;
-	return count;
+	return do_write_mem(file,(void*)p,p,buf,count);
 }
 
 static long read_port(struct inode * inode, struct file * file,
@@ -195,8 +198,11 @@
 	unsigned int i = file->f_pos;
 	char * tmp = buf;
 
+	if (verify_area(VERIFY_WRITE,buf,count))
+		return -EFAULT; 
 	while (count-- > 0 && i < 65536) {
-		put_user(inb(i),tmp);
+		if (__put_user(inb(i),tmp) < 0) 
+			return -EFAULT;  
 		i++;
 		tmp++;
 	}
@@ -210,9 +216,12 @@
 	unsigned int i = file->f_pos;
 	const char * tmp = buf;
 
+	if (verify_area(VERIFY_READ,buf,count))
+		return -EFAULT;
 	while (count-- > 0 && i < 65536) {
 		char c;
-		get_user(c, tmp);
+		if (__get_user(c, tmp)) 
+			return -EFAULT; 
 		outb(c,i);
 		i++;
 		tmp++;
diff -u --recursive --new-file v2.1.42/linux/drivers/char/misc.c linux/drivers/char/misc.c
--- v2.1.42/linux/drivers/char/misc.c	Tue May 13 22:41:07 1997
+++ linux/drivers/char/misc.c	Thu Jun 12 16:22:06 1997
@@ -44,8 +44,8 @@
 #include <linux/apm_bios.h>
 #endif
 
-#include <linux/tty.h> /* needed by selection.h */
-#include "selection.h" /* export its symbols */
+#include <linux/tty.h>
+#include <linux/selection.h>
 #ifdef CONFIG_KERNELD
 #include <linux/kerneld.h>
 #endif
diff -u --recursive --new-file v2.1.42/linux/drivers/char/pc_keyb.c linux/drivers/char/pc_keyb.c
--- v2.1.42/linux/drivers/char/pc_keyb.c	Thu May 29 21:53:05 1997
+++ linux/drivers/char/pc_keyb.c	Thu Jun 12 16:22:06 1997
@@ -1,20 +1,10 @@
 /*
  * linux/drivers/char/pc_keyb.c
  *
- * Written for linux by Johan Myreen as a translation from
- * the assembly version by Linus (with diacriticals added)
- *
- * Some additional features added by Christoph Niemann (ChN), March 1993
- *
- * Loadable keymaps by Risto Kankkunen, May 1993
- *
- * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
- * Added decr/incr_console, dynamic keymaps, Unicode support,
- * dynamic function/string keys, led setting,  Sept 1994
- * `Sticky' modifier keys, 951006.
- * 11-11-96: SAK should now work in the raw mode (Martin Mares)
- * 
  * Separation of the PC low-level part by Geert Uytterhoeven, May 1997
+ * See keyboard.c for the whole history.
+ *
+ * Major cleanup by Martin Mares, May 1997
  */
 
 #include <linux/sched.h>
@@ -24,46 +14,181 @@
 #include <linux/signal.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
+#include <linux/kbd_ll.h>
 
 #include <asm/keyboard.h>
 #include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+/* Some configuration switches are present in the include file... */
+
+#include "pc_keyb.h"
 
 /*
- * On non-x86 hardware we do a full keyboard controller
- * initialization, in case the bootup software hasn't done
- * it. On a x86, the BIOS will already have initialized the
- * keyboard.
+ * In case we run on a non-x86 hardware we need to initialize both the keyboard
+ * controller and the keyboard. On a x86, the BIOS will already have initialized
+ * them.
  */
+
 #ifdef INIT_KBD
-static int initialize_kbd(void);
-#endif
 
-#include <asm/io.h>
-#include <asm/system.h>
+__initfunc(static int kbd_wait_for_input(void))
+{
+        int     n;
+        int     status, data;
 
-unsigned char kbd_read_mask = 0x01;	/* modified by psaux.c */
+        n = KBD_TIMEOUT;
+        do {
+                status = inb(KBD_STATUS_REG);
+                /*
+                 * Wait for input data to become available.  This bit will
+                 * then be cleared by the following read of the DATA
+                 * register.
+                 */
+
+                if (!(status & KBD_STAT_OBF))
+			continue;
+
+		data = inb(KBD_DATA_REG);
+
+                /*
+                 * Check to see if a timeout error has occurred.  This means
+                 * that transmission was started but did not complete in the
+                 * normal time cycle.  PERR is set when a parity error occurred
+                 * in the last transmission.
+                 */
+                if (status & (KBD_STAT_GTO | KBD_STAT_PERR)) {
+			continue;
+                }
+		return (data & 0xff);
+        } while (--n);
+        return -1;	/* timed-out if fell through to here... */
+}
+
+__initfunc(static void kbd_write(int address, int data))
+{
+	int status;
+
+	do {
+		status = inb(KBD_STATUS_REG);
+	} while (status & KBD_STAT_IBF);
+	outb(data, address);
+}
+
+__initfunc(static char *initialize_kbd2(void))
+{
+	/* Flush any pending input. */
+
+	while (kbd_wait_for_input() != -1)
+		;
+
+	/*
+	 * Test the keyboard interface.
+	 * This seems to be the only way to get it going.
+	 * If the test is successful a x55 is placed in the input buffer.
+	 */
+
+	kbd_write(KBD_CNTL_REG, KBD_CCMD_SELF_TEST);
+	if (kbd_wait_for_input() != 0x55)
+		return "Keyboard failed self test";
+
+	/*
+	 * Perform a keyboard interface test.  This causes the controller
+	 * to test the keyboard clock and data lines.  The results of the
+	 * test are placed in the input buffer.
+	 */
+
+	kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_TEST);
+	if (kbd_wait_for_input() != 0x00)
+		return "Keyboard interface failed self test";
+
+	/* Enable the keyboard by allowing the keyboard clock to run. */
+
+	kbd_write(KBD_CNTL_REG, KBD_CCMD_KBD_ENABLE);
+
+	/*
+	 * Reset keyboard. If the read times out
+	 * then the assumption is that no keyboard is
+	 * plugged into the machine.
+	 * This defaults the keyboard to scan-code set 2.
+	 */
+
+	kbd_write(KBD_DATA_REG, KBD_CMD_RESET);
+	if (kbd_wait_for_input() != KBD_REPLY_ACK)
+		return "Keyboard reset failed, no ACK";
+	if (kbd_wait_for_input() != KBD_REPLY_POR)
+		return "Keyboard reset failed, no POR";
+
+	/*
+	 * Set keyboard controller mode. During this, the keyboard should be
+	 * in the disabled state.
+	 */
+
+	kbd_write(KBD_DATA_REG, KBD_CMD_DISABLE);
+	if (kbd_wait_for_input() != KBD_REPLY_ACK)
+		return "Disable keyboard: no ACK";
+
+	kbd_write(KBD_CNTL_REG, KBD_CCMD_WRITE_MODE);
+	kbd_write(KBD_DATA_REG, KBD_MODE_KBD_INT
+		              | KBD_MODE_SYS
+		              | KBD_MODE_DISABLE_MOUSE
+		              | KBD_MODE_KCC);
+
+	kbd_write(KBD_DATA_REG, KBD_CMD_ENABLE);
+	if (kbd_wait_for_input() != KBD_REPLY_ACK)
+		return "Enable keyboard: no ACK";
+
+	/*
+	 * Finally, set the typematic rate to maximum.
+	 */
+
+	kbd_write(KBD_DATA_REG, KBD_CMD_SET_RATE);
+	if (kbd_wait_for_input() != KBD_REPLY_ACK)
+		return "Set rate: no ACK";
+	kbd_write(KBD_DATA_REG, 0x00);
+	if (kbd_wait_for_input() != KBD_REPLY_ACK)
+		return "Set rate: no ACK";
+
+	return NULL;
+}
+
+__initfunc(static void initialize_kbd(void))
+{
+	unsigned long flags;
+	char *msg;
+
+	save_flags(flags); cli();
+	msg = initialize_kbd2();
+	restore_flags(flags);
+
+	if (msg)
+		printk(KERN_WARNING "initialize_kbd: %s\n", msg);
+}
+
+#endif /* INIT_KBD */
+
+unsigned char kbd_read_mask = KBD_STAT_OBF; /* Modified by psaux.c */
 
 /* used only by send_data - set by keyboard_interrupt */
 static volatile unsigned char reply_expected = 0;
 static volatile unsigned char acknowledge = 0;
 static volatile unsigned char resend = 0;
 
-/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */
+/*
+ *	Wait for keyboard controller input buffer is empty.
+ */
+
 static inline void kb_wait(void)
 {
 	int i;
 
-	for (i=0; i<0x100000; i++)
-		if ((inb_p(0x64) & 0x02) == 0)
+	for (i=0; i<KBD_TIMEOUT; i++)
+		if (! (inb_p(KBD_STATUS_REG) & KBD_STAT_IBF))
 			return;
 	printk(KERN_WARNING "Keyboard timed out\n");
 }
 
-extern struct pt_regs *pt_regs;
-
-extern void handle_scancode(unsigned char scancode);
-
-
 /*
  * Translation of escaped scancodes to keycodes.
  * This is now user-settable.
@@ -204,11 +329,11 @@
 static inline void send_cmd(unsigned char c)
 {
 	kb_wait();
-	outb(c,0x64);
+	outb(c, KBD_CNTL_REG);
 }
 
-#define disable_keyboard()	do { send_cmd(0xAD); kb_wait(); } while (0)
-#define enable_keyboard()	send_cmd(0xAE)
+#define disable_keyboard()	do { send_cmd(KBD_CCMD_KBD_DISABLE); kb_wait(); } while (0)
+#define enable_keyboard()	send_cmd(KBD_CCMD_KBD_ENABLE)
 #else
 #define disable_keyboard()	/* nothing */
 #define enable_keyboard()	/* nothing */
@@ -217,18 +342,21 @@
 static int do_acknowledge(unsigned char scancode)
 {
 	if (reply_expected) {
-	  /* 0xfa, 0xfe only mean "acknowledge", "resend" for most keyboards */
-	  /* but they are the key-up scancodes for PF6, PF10 on a FOCUS 9000 */
-		reply_expected = 0;
-		if (scancode == 0xfa) {
+	  /* Unfortunately, we must recognise these codes only if we know they
+	   * are known to be valid (i.e., after sending a command), because there
+	   * are some brain-damaged keyboards (yes, FOCUS 9000 again) which have
+	   * keys with such codes :(
+	   */
+		if (scancode == KBD_REPLY_ACK) {
 			acknowledge = 1;
+			reply_expected = 0;
 			return 0;
-		} else if (scancode == 0xfe) {
+		} else if (scancode == KBD_REPLY_RESEND) {
 			resend = 1;
+			reply_expected = 0;
 			return 0;
 		}
-		/* strange ... */
-		reply_expected = 1;
+		/* Should not happen... */
 #if 0
 		printk(KERN_DEBUG "keyboard reply expected - got %02x\n",
 		       scancode);
@@ -359,23 +487,23 @@
 {
 	unsigned char status;
 
-	pt_regs = regs;
+	kbd_pt_regs = regs;
 	disable_keyboard();
 
-	status = inb_p(0x64);
+	status = inb_p(KBD_STATUS_REG);
 	do {
 		unsigned char scancode;
 
 		/* mouse data? */
-		if (status & kbd_read_mask & 0x20)
+		if (status & kbd_read_mask & KBD_STAT_MOUSE_OBF)
 			break;
 
-		scancode = inb(0x60);
-		if ((status & 0x01) && do_acknowledge(scancode))
+		scancode = inb(KBD_DATA_REG);
+		if ((status & KBD_STAT_OBF) && do_acknowledge(scancode))
 			handle_scancode(scancode);
 
-		status = inb(0x64);
-	} while (status & 0x01);
+		status = inb(KBD_STATUS_REG);
+	} while (status & (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF));
 
 	mark_bh(KEYBOARD_BH);
 	enable_keyboard();
@@ -396,9 +524,9 @@
 		acknowledge = 0;
 		resend = 0;
 		reply_expected = 1;
-		outb_p(data, 0x60);
+		outb_p(data, KBD_DATA_REG);
 		for(i=0; i<0x200000; i++) {
-			inb_p(0x64);		/* just as a delay */
+			inb_p(KBD_STATUS_REG); /* just as a delay */
 			if (acknowledge)
 				return 1;
 			if (resend)
@@ -412,197 +540,15 @@
 
 void pckbd_leds(unsigned char leds)
 {
-	if (!send_data(0xed) || !send_data(leds))
-	    send_data(0xf4);	/* re-enable kbd if any errors */
+	if (!send_data(KBD_CMD_SET_LEDS) || !send_data(leds))
+	    send_data(KBD_CMD_ENABLE);	/* re-enable kbd if any errors */
 }
 
 __initfunc(void pckbd_init_hw(void))
 {
 	request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
-	request_region(0x60,16,"keyboard");
+	request_region(0x60, 16, "keyboard");
 #ifdef INIT_KBD
 	initialize_kbd();
 #endif
 }
-
-#ifdef INIT_KBD
-/*
- * keyboard controller registers
- */
-#define KBD_STATUS_REG      (unsigned int) 0x64
-#define KBD_CNTL_REG        (unsigned int) 0x64
-#define KBD_DATA_REG	    (unsigned int) 0x60
-/*
- * controller commands
- */
-#define KBD_READ_MODE	    (unsigned int) 0x20
-#define KBD_WRITE_MODE	    (unsigned int) 0x60
-#define KBD_SELF_TEST	    (unsigned int) 0xAA
-#define KBD_SELF_TEST2	    (unsigned int) 0xAB
-#define KBD_CNTL_ENABLE	    (unsigned int) 0xAE
-/*
- * keyboard commands
- */
-#define KBD_ENABLE	    (unsigned int) 0xF4
-#define KBD_DISABLE	    (unsigned int) 0xF5
-#define KBD_RESET	    (unsigned int) 0xFF
-/*
- * keyboard replies
- */
-#define KBD_ACK		    (unsigned int) 0xFA
-#define KBD_POR		    (unsigned int) 0xAA
-/*
- * status register bits
- */
-#define KBD_OBF		    (unsigned int) 0x01
-#define KBD_IBF		    (unsigned int) 0x02
-#define KBD_GTO		    (unsigned int) 0x40
-#define KBD_PERR	    (unsigned int) 0x80
-/*
- * keyboard controller mode register bits
- */
-#define KBD_EKI		    (unsigned int) 0x01
-#define KBD_SYS		    (unsigned int) 0x04
-#define KBD_DMS		    (unsigned int) 0x20
-#define KBD_KCC		    (unsigned int) 0x40
-
-#define TIMEOUT_CONST	    500000
-
-static int kbd_wait_for_input(void)
-{
-        int     n;
-        int     status, data;
-
-        n = TIMEOUT_CONST;
-        do {
-                status = inb(KBD_STATUS_REG);
-                /*
-                 * Wait for input data to become available.  This bit will
-                 * then be cleared by the following read of the DATA
-                 * register.
-                 */
-
-                if (!(status & KBD_OBF))
-			continue;
-
-		data = inb(KBD_DATA_REG);
-
-                /*
-                 * Check to see if a timeout error has occurred.  This means
-                 * that transmission was started but did not complete in the
-                 * normal time cycle.  PERR is set when a parity error occurred
-                 * in the last transmission.
-                 */
-                if (status & (KBD_GTO | KBD_PERR)) {
-			continue;
-                }
-		return (data & 0xff);
-        } while (--n);
-        return (-1);	/* timed-out if fell through to here... */
-}
-
-static void kbd_write(int address, int data)
-{
-	int status;
-
-	do {
-		status = inb(KBD_STATUS_REG);  /* spin until input buffer empty*/
-	} while (status & KBD_IBF);
-	outb(data, address);               /* write out the data*/
-}
-
-__initfunc(static int initialize_kbd(void))
-{
-	unsigned long flags;
-
-	save_flags(flags); cli();
-
-	/* Flush any pending input. */
-	while (kbd_wait_for_input() != -1)
-		continue;
-
-	/*
-	 * Test the keyboard interface.
-	 * This seems to be the only way to get it going.
-	 * If the test is successful a x55 is placed in the input buffer.
-	 */
-	kbd_write(KBD_CNTL_REG, KBD_SELF_TEST);
-	if (kbd_wait_for_input() != 0x55) {
-		printk(KERN_WARNING "initialize_kbd: "
-		       "keyboard failed self test.\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	/*
-	 * Perform a keyboard interface test.  This causes the controller
-	 * to test the keyboard clock and data lines.  The results of the
-	 * test are placed in the input buffer.
-	 */
-	kbd_write(KBD_CNTL_REG, KBD_SELF_TEST2);
-	if (kbd_wait_for_input() != 0x00) {
-		printk(KERN_WARNING "initialize_kbd: "
-		       "keyboard failed self test 2.\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	/* Enable the keyboard by allowing the keyboard clock to run. */
-	kbd_write(KBD_CNTL_REG, KBD_CNTL_ENABLE);
-
-	/*
-	 * Reset keyboard. If the read times out
-	 * then the assumption is that no keyboard is
-	 * plugged into the machine.
-	 * This defaults the keyboard to scan-code set 2.
-	 */
-	kbd_write(KBD_DATA_REG, KBD_RESET);
-	if (kbd_wait_for_input() != KBD_ACK) {
-		printk(KERN_WARNING "initialize_kbd: "
-		       "reset kbd failed, no ACK.\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	if (kbd_wait_for_input() != KBD_POR) {
-		printk(KERN_WARNING "initialize_kbd: "
-		       "reset kbd failed, not POR.\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	/*
-	 * now do a DEFAULTS_DISABLE always
-	 */
-	kbd_write(KBD_DATA_REG, KBD_DISABLE);
-	if (kbd_wait_for_input() != KBD_ACK) {
-		printk(KERN_WARNING "initialize_kbd: "
-		       "disable kbd failed, no ACK.\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	/*
-	 * Enable keyboard interrupt, operate in "sys" mode,
-	 *  enable keyboard (by clearing the disable keyboard bit),
-	 *  disable mouse, do conversion of keycodes.
-	 */
-	kbd_write(KBD_CNTL_REG, KBD_WRITE_MODE);
-	kbd_write(KBD_DATA_REG, KBD_EKI|KBD_SYS|KBD_DMS|KBD_KCC);
-
-	/*
-	 * now ENABLE the keyboard to set it scanning...
-	 */
-	kbd_write(KBD_DATA_REG, KBD_ENABLE);
-	if (kbd_wait_for_input() != KBD_ACK) {
-		printk(KERN_WARNING "initialize_kbd: "
-		       "keyboard enable failed.\n");
-		restore_flags(flags);
-		return(-1);
-	}
-
-	restore_flags(flags);
-
-	return (1);
-}
-#endif /* INIT_KBD */
diff -u --recursive --new-file v2.1.42/linux/drivers/char/pc_keyb.h linux/drivers/char/pc_keyb.h
--- v2.1.42/linux/drivers/char/pc_keyb.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/pc_keyb.h	Thu Jun 12 16:22:06 1997
@@ -0,0 +1,107 @@
+/*
+ *	linux/drivers/char/pc_keyb.h
+ *
+ *	PC Keyboard And Keyboard Controller
+ *
+ *	(c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+/*
+ *	Configuration Switches
+ */
+
+#define KBD_REPORT_ERR			/* Report keyboard errors */
+#define KBD_REPORT_UNKN			/* Report unknown scan codes */
+#undef KBD_IS_FOCUS_9000		/* We have the brain-damaged FOCUS-9000 keyboard */
+#define KBD_TIMEOUT 0x100000		/* Timeout for sending of commands */
+
+/*
+ *	Internal variables of the driver
+ */
+
+extern unsigned char kbd_read_mask;
+extern unsigned char aux_device_present;
+
+/*
+ *	Keyboard Controller Registers
+ */
+
+#define KBD_STATUS_REG		0x64	/* Status register (R) */
+#define KBD_CNTL_REG		0x64	/* Controller command register (W) */
+#define KBD_DATA_REG		0x60	/* Keyboard data register (R/W) */
+
+/*
+ *	Keyboard Controller Commands
+ */
+
+#define KBD_CCMD_READ_MODE	0x20	/* Read mode bits */
+#define KBD_CCMD_WRITE_MODE	0x60	/* Write mode bits */
+#define KBD_CCMD_GET_VERSION	0xA1	/* Get controller version */
+#define KBD_CCMD_MOUSE_DISABLE	0xA7	/* Disable mouse interface */
+#define KBD_CCMD_MOUSE_ENABLE	0xA8	/* Enable mouse interface */
+#define KBD_CCMD_TEST_MOUSE	0xA9	/* Mouse interface test */
+#define KBD_CCMD_SELF_TEST	0xAA	/* Controller self test */
+#define KBD_CCMD_KBD_TEST	0xAB	/* Keyboard interface test */
+#define KBD_CCMD_KBD_DISABLE	0xAD	/* Keyboard interface disable */
+#define KBD_CCMD_KBD_ENABLE	0xAE	/* Keyboard interface enable */
+#define KBD_CCMD_WRITE_MOUSE	0xD4	/* Write the following byte to the mouse */
+
+/*
+ *	Keyboard Commands
+ */
+
+#define KBD_CMD_SET_LEDS	0xED	/* Set keyboard leds */
+#define KBD_CMD_SET_RATE	0xF3	/* Set typematic rate */
+#define KBD_CMD_ENABLE		0xF4	/* Enable scanning */
+#define KBD_CMD_DISABLE		0xF5	/* Disable scanning */
+#define KBD_CMD_RESET		0xFF	/* Reset */
+
+/*
+ *	Keyboard Replies
+ */
+
+#define KBD_REPLY_POR		0xAA	/* Power on reset */
+#define KBD_REPLY_ACK		0xFA	/* Command ACK */
+#define KBD_REPLY_RESEND	0xFE	/* Command NACK, send the cmd again */
+
+/*
+ *	Status Register Bits
+ */
+
+#define KBD_STAT_OBF 		0x01	/* Keyboard output buffer full */
+#define KBD_STAT_IBF 		0x02	/* Keyboard input buffer full */
+#define KBD_STAT_SELFTEST	0x04	/* Self test successful */
+#define KBD_STAT_CMD		0x08	/* Last write was a command write (0=data) */
+#define KBD_STAT_UNLOCKED	0x10	/* Zero if keyboard locked */
+#define KBD_STAT_MOUSE_OBF	0x20	/* Mouse output buffer full */
+#define KBD_STAT_GTO 		0x40	/* General receive/xmit timeout */
+#define KBD_STAT_PERR 		0x80	/* Parity error */
+
+#define AUX_STAT_OBF (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF)
+
+/*
+ *	Controller Mode Register Bits
+ */
+
+#define KBD_MODE_KBD_INT	0x01	/* Keyboard data generage IRQ1 */
+#define KBD_MODE_MOUSE_INT	0x02	/* Mouse data generate IRQ12 */
+#define KBD_MODE_SYS 		0x04	/* The system flag (?) */
+#define KBD_MODE_NO_KEYLOCK	0x08	/* The keylock doesn't affect the keyboard if set */
+#define KBD_MODE_DISABLE_KBD	0x10	/* Disable keyboard interface */
+#define KBD_MODE_DISABLE_MOUSE	0x20	/* Disable mouse interface */
+#define KBD_MODE_KCC 		0x40	/* Scan code conversion to PC format */
+#define KBD_MODE_RFU		0x80
+
+/*
+ *	Mouse Commands
+ */
+
+#define AUX_SET_RES		0xE8	/* Set resolution */
+#define AUX_SET_SCALE11		0xE6	/* Set 1:1 scaling */
+#define AUX_SET_SCALE21		0xE7	/* Set 2:1 scaling */
+#define AUX_GET_SCALE		0xE9	/* Get scaling factor */
+#define AUX_SET_STREAM		0xEA	/* Set stream mode */
+#define AUX_SET_SAMPLE		0xF3	/* Set sample rate */
+#define AUX_ENABLE_DEV		0xF4	/* Enable aux device */
+#define AUX_DISABLE_DEV		0xF5	/* Disable aux device */
+#define AUX_RESET		0xFF	/* Reset aux device */
diff -u --recursive --new-file v2.1.42/linux/drivers/char/psaux.c linux/drivers/char/psaux.c
--- v2.1.42/linux/drivers/char/psaux.c	Wed Apr 23 19:01:17 1997
+++ linux/drivers/char/psaux.c	Thu Jun 12 16:22:06 1997
@@ -28,6 +28,8 @@
  *
  * Fixed keyboard lockups at open time
  * 3-Jul-96, 22-Aug-96 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ * Cleanup by Martin Mares, 01-Jun-97 (now uses the new PC kbd include)
  */
 
 /* Uncomment the following line if your mouse needs initialization. */
@@ -54,66 +56,15 @@
 
 #include <linux/config.h>
 
-#define PSMOUSE_MINOR      1            /* minor device # for this mouse */
+#include "pc_keyb.h"
 
-/* aux controller ports */
-#define AUX_INPUT_PORT	0x60		/* Aux device output buffer */
-#define AUX_OUTPUT_PORT	0x60		/* Aux device input buffer */
-#define AUX_COMMAND	0x64		/* Aux device command buffer */
-#define AUX_STATUS	0x64		/* Aux device status reg */
-
-/* aux controller status bits */
-#define AUX_OBUF_FULL	0x21		/* output buffer (from device) full */
-#define AUX_IBUF_FULL	0x02		/* input buffer (to device) full */
-
-/* aux controller commands */
-#define AUX_CMD_WRITE	0x60		/* value to write to controller */
-#define AUX_MAGIC_WRITE	0xd4		/* value to send aux device data */
-
-#define AUX_INTS_ON	0x47		/* enable controller interrupts */
-#define AUX_INTS_OFF	0x65		/* disable controller interrupts */
-
-#define AUX_DISABLE	0xa7		/* disable aux */
-#define AUX_ENABLE	0xa8		/* enable aux */
-
-/* aux device commands */
-#define AUX_SET_RES	0xe8		/* set resolution */
-#define AUX_SET_SCALE11	0xe6		/* set 1:1 scaling */
-#define AUX_SET_SCALE21	0xe7		/* set 2:1 scaling */
-#define AUX_GET_SCALE	0xe9		/* get scaling factor */
-#define AUX_SET_STREAM	0xea		/* set stream mode */
-#define AUX_SET_SAMPLE	0xf3		/* set sample rate */
-#define AUX_ENABLE_DEV	0xf4		/* enable aux device */
-#define AUX_DISABLE_DEV	0xf5		/* disable aux device */
-#define AUX_RESET	0xff		/* reset aux device */
+/*
+ *	Generic declarations for both PS2 and 82C710
+ */
 
-#define MAX_RETRIES	60		/* some aux operations take long time*/
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-# define AUX_IRQ	9		/* Jensen is odd indeed */
-#else
-# define AUX_IRQ	12
-#endif
+#define PSMOUSE_MINOR      1	       		/* Minor device # for this mouse */
 #define AUX_BUF_SIZE	2048
 
-/* 82C710 definitions */
-
-#define QP_DATA         0x310		/* Data Port I/O Address */
-#define QP_STATUS       0x311		/* Status Port I/O Address */
-
-#define QP_DEV_IDLE     0x01		/* Device Idle */
-#define QP_RX_FULL      0x02		/* Device Char received */
-#define QP_TX_IDLE      0x04		/* Device XMIT Idle */
-#define QP_RESET        0x08		/* Device Reset */
-#define QP_INTS_ON      0x10		/* Device Interrupt On */
-#define QP_ERROR_FLAG   0x20		/* Device Error */
-#define QP_CLEAR        0x40		/* Device Clear */
-#define QP_ENABLE       0x80		/* Device Enable */
-
-#define QP_IRQ          12
-
-extern unsigned char aux_device_present;
-extern unsigned char kbd_read_mask;	/* from keyboard.c */
-
 struct aux_queue {
 	unsigned long head;
 	unsigned long tail;
@@ -126,20 +77,84 @@
 static int aux_ready = 0;
 static int aux_count = 0;
 static int aux_present = 0;
-static int poll_aux_status(void);
-static int poll_aux_status_nosleep(void);
-static int fasync_aux(struct inode *inode, struct file *filp, int on);
 
-#ifdef CONFIG_82C710_MOUSE
-static int qp_present = 0;
-static int qp_count = 0;
-static int qp_data = QP_DATA;
-static int qp_status = QP_STATUS;
+/*
+ *	Shared subroutines
+ */
 
-static int poll_qp_status(void);
-static int probe_qp(void);
+static unsigned int get_from_queue(void)
+{
+	unsigned int result;
+	unsigned long flags;
+
+	save_flags(flags);
+	cli();
+	result = queue->buf[queue->tail];
+	queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
+	restore_flags(flags);
+	return result;
+}
+
+
+static inline int queue_empty(void)
+{
+	return queue->head == queue->tail;
+}
+
+static int fasync_aux(struct inode *inode, struct file *filp, int on)
+{
+	int retval;
+
+	retval = fasync_helper(inode, filp, on, &queue->fasync);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+/*
+ *	PS/2 Aux Device
+ */
+
+#define AUX_INTS_OFF (KBD_MODE_KCC | KBD_MODE_DISABLE_MOUSE | KBD_MODE_SYS | KBD_MODE_KBD_INT)
+#define AUX_INTS_ON  (KBD_MODE_KCC | KBD_MODE_SYS | KBD_MODE_MOUSE_INT | KBD_MODE_KBD_INT)
+
+#define MAX_RETRIES	60		/* some aux operations take long time*/
+#if defined(__alpha__) && !defined(CONFIG_PCI)
+# define AUX_IRQ	9		/* Jensen is odd indeed */
+#else
+# define AUX_IRQ	12
 #endif
 
+/*
+ *	Status polling
+ */
+
+static int poll_aux_status(void)
+{
+	int retries=0;
+
+	while ((inb(KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < MAX_RETRIES) {
+ 		if ((inb_p(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
+			inb_p(KBD_DATA_REG);
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + (5*HZ + 99) / 100;
+		schedule();
+		retries++;
+	}
+	return !(retries==MAX_RETRIES);
+}
+
+static int poll_aux_status_nosleep(void)
+{
+	int retries = 0;
+
+	while ((inb(KBD_STATUS_REG) & (KBD_STAT_IBF | KBD_STAT_OBF)) && retries < 1000000) {
+ 		if ((inb_p(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
+			inb_p(KBD_DATA_REG);
+		retries++;
+	}
+	return !(retries == 1000000);
+}
 
 /*
  * Write to aux device
@@ -148,28 +163,32 @@
 static void aux_write_dev(int val)
 {
 	poll_aux_status();
-	outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);	/* write magic cookie */
+	outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);	    /* Write magic cookie */
 	poll_aux_status();
-	outb_p(val,AUX_OUTPUT_PORT);		/* write data */
+	outb_p(val, KBD_DATA_REG);			    /* Write data */
+}
+
+__initfunc(static void aux_write_dev_nosleep(int val))
+{
+	poll_aux_status_nosleep();
+	outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);
+	poll_aux_status_nosleep();
+	outb_p(val, KBD_DATA_REG);
 }
 
 /*
  * Write to device & handle returned ack
  */
-#if defined INITIALIZE_DEVICE
-static int aux_write_ack(int val)
-{
-	int retries = 0;
 
-	poll_aux_status_nosleep();
-	outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);
-	poll_aux_status_nosleep();
-	outb_p(val,AUX_OUTPUT_PORT);
+#ifdef INITIALIZE_DEVICE
+__initfunc(static int aux_write_ack(int val))
+{
+	aux_write_dev_nosleep(val);
 	poll_aux_status_nosleep();
 
-	if ((inb(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)
+	if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) == AUX_STAT_OBF)
 	{
-		return (inb(AUX_INPUT_PORT));
+		return (inb(KBD_DATA_REG));
 	}
 	return 0;
 }
@@ -182,33 +201,11 @@
 static void aux_write_cmd(int val)
 {
 	poll_aux_status();
-	outb_p(AUX_CMD_WRITE,AUX_COMMAND);
+	outb_p(KBD_CCMD_WRITE_MODE, KBD_CNTL_REG);
 	poll_aux_status();
-	outb_p(val,AUX_OUTPUT_PORT);
-}
-
-
-static unsigned int get_from_queue(void)
-{
-	unsigned int result;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	result = queue->buf[queue->tail];
-	queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1);
-	restore_flags(flags);
-	return result;
+	outb_p(val, KBD_DATA_REG);
 }
 
-
-static inline int queue_empty(void)
-{
-	return queue->head == queue->tail;
-}
-
-
-
 /*
  * Interrupt from the auxiliary device: a character
  * is waiting in the keyboard/aux controller.
@@ -219,10 +216,10 @@
 	int head = queue->head;
 	int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
 
-	if ((inb(AUX_STATUS) & AUX_OBUF_FULL) != AUX_OBUF_FULL)
+	if ((inb(KBD_STATUS_REG) & AUX_STAT_OBF) != AUX_STAT_OBF)
 		return;
 
-	add_mouse_randomness(queue->buf[head] = inb(AUX_INPUT_PORT));
+	add_mouse_randomness(queue->buf[head] = inb(KBD_DATA_REG));
 	if (head != maxhead) {
 		head++;
 		head &= AUX_BUF_SIZE-1;
@@ -234,31 +231,6 @@
 	wake_up_interruptible(&queue->proc_list);
 }
 
-/*
- * Interrupt handler for the 82C710 mouse port. A character
- * is waiting in the 82C710.
- */
-
-#ifdef CONFIG_82C710_MOUSE
-static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
-{
-	int head = queue->head;
-	int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
-
-	add_mouse_randomness(queue->buf[head] = inb(qp_data));
-	if (head != maxhead) {
-		head++;
-		head &= AUX_BUF_SIZE-1;
-	}
-	queue->head = head;
-	aux_ready = 1;
-	if (queue->fasync)
-		kill_fasync(queue->fasync, SIGIO);
-	wake_up_interruptible(&queue->proc_list);
-}
-#endif
-
-
 static int release_aux(struct inode * inode, struct file * file)
 {
 	fasync_aux(inode, file, 0);
@@ -266,9 +238,9 @@
 		return 0;
 	/* disable kbd bh to avoid mixing of cmd bytes */
 	disable_bh(KEYBOARD_BH);
-	aux_write_cmd(AUX_INTS_OFF);		/* disable controller ints */
+	aux_write_cmd(AUX_INTS_OFF);			    /* Disable controller ints */
 	poll_aux_status();
-	outb_p(AUX_DISABLE,AUX_COMMAND);      	/* Disable Aux device */
+	outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG);	    /* Disable Aux device */
 	poll_aux_status();
 	/* reenable kbd bh */
 	enable_bh(KEYBOARD_BH);
@@ -281,36 +253,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_82C710_MOUSE
-static int release_qp(struct inode * inode, struct file * file)
-{
-	unsigned char status;
-
-	fasync_aux(inode, file, 0);
-	if (!--qp_count) {
-		if (!poll_qp_status())
-			printk("Warning: Mouse device busy in release_qp()\n");
-		status = inb_p(qp_status);
-		outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
-		if (!poll_qp_status())
-			printk("Warning: Mouse device busy in release_qp()\n");
-		free_irq(QP_IRQ, NULL);
-		MOD_DEC_USE_COUNT;
-	}
-	return 0;
-}
-#endif
-
-static int fasync_aux(struct inode *inode, struct file *filp, int on)
-{
-	int retval;
-
-	retval = fasync_helper(inode, filp, on, &queue->fasync);
-	if (retval < 0)
-		return retval;
-	return 0;
-}
-
 /*
  * Install interrupt handler.
  * Enable auxiliary device.
@@ -339,9 +281,9 @@
 	/* disable kbd bh to avoid mixing of cmd bytes */
 	disable_bh(KEYBOARD_BH);
 	poll_aux_status();
-	outb_p(AUX_ENABLE,AUX_COMMAND);		/* Enable Aux */
-	aux_write_dev(AUX_ENABLE_DEV);		/* enable aux device */
-	aux_write_cmd(AUX_INTS_ON);		/* enable controller ints */
+	outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG);	    /* Enable Aux */
+	aux_write_dev(AUX_ENABLE_DEV);			    /* Enable aux device */
+	aux_write_cmd(AUX_INTS_ON);			    /* Enable controller ints */
 	poll_aux_status();
 	/* reenable kbd bh */
 	enable_bh(KEYBOARD_BH);
@@ -350,7 +292,112 @@
 	return 0;
 }
 
+/*
+ * Write to the aux device.
+ */
+
+static long write_aux(struct inode * inode, struct file * file,
+	const char * buffer, unsigned long count)
+{
+	int retval = 0;
+
+	if (count) {
+		int written = 0;
+
+		/* disable kbd bh to avoid mixing of cmd bytes */
+		disable_bh(KEYBOARD_BH);
+
+		do {
+			char c;
+			if (!poll_aux_status())
+				break;
+			outb_p(KBD_CCMD_WRITE_MOUSE, KBD_CNTL_REG);
+			if (!poll_aux_status())
+				break;
+			get_user(c, buffer++);
+			outb_p(c, KBD_DATA_REG);
+			written++;
+		} while (--count);
+		/* reenable kbd bh */
+		enable_bh(KEYBOARD_BH);
+		retval = -EIO;
+		if (written) {
+			retval = written;
+			inode->i_mtime = CURRENT_TIME;
+		}
+	}
+
+	return retval;
+}
+
+/*
+ *	82C710 Interface
+ */
+
 #ifdef CONFIG_82C710_MOUSE
+
+#define QP_DATA         0x310		/* Data Port I/O Address */
+#define QP_STATUS       0x311		/* Status Port I/O Address */
+
+#define QP_DEV_IDLE     0x01		/* Device Idle */
+#define QP_RX_FULL      0x02		/* Device Char received */
+#define QP_TX_IDLE      0x04		/* Device XMIT Idle */
+#define QP_RESET        0x08		/* Device Reset */
+#define QP_INTS_ON      0x10		/* Device Interrupt On */
+#define QP_ERROR_FLAG   0x20		/* Device Error */
+#define QP_CLEAR        0x40		/* Device Clear */
+#define QP_ENABLE       0x80		/* Device Enable */
+
+#define QP_IRQ          12
+
+static int qp_present = 0;
+static int qp_count = 0;
+static int qp_data = QP_DATA;
+static int qp_status = QP_STATUS;
+
+static int poll_qp_status(void);
+static int probe_qp(void);
+
+/*
+ * Interrupt handler for the 82C710 mouse port. A character
+ * is waiting in the 82C710.
+ */
+
+static void qp_interrupt(int cpl, void *dev_id, struct pt_regs * regs)
+{
+	int head = queue->head;
+	int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1);
+
+	add_mouse_randomness(queue->buf[head] = inb(qp_data));
+	if (head != maxhead) {
+		head++;
+		head &= AUX_BUF_SIZE-1;
+	}
+	queue->head = head;
+	aux_ready = 1;
+	if (queue->fasync)
+		kill_fasync(queue->fasync, SIGIO);
+	wake_up_interruptible(&queue->proc_list);
+}
+
+static int release_qp(struct inode * inode, struct file * file)
+{
+	unsigned char status;
+
+	fasync_aux(inode, file, 0);
+	if (!--qp_count) {
+		if (!poll_qp_status())
+			printk("Warning: Mouse device busy in release_qp()\n");
+		status = inb_p(qp_status);
+		outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status);
+		if (!poll_qp_status())
+			printk("Warning: Mouse device busy in release_qp()\n");
+		free_irq(QP_IRQ, NULL);
+		MOD_DEC_USE_COUNT;
+	}
+	return 0;
+}
+
 /*
  * Install interrupt handler.
  * Enable the device, enable interrupts. 
@@ -394,48 +441,7 @@
 	MOD_INC_USE_COUNT;
 	return 0;
 }
-#endif
-
-/*
- * Write to the aux device.
- */
-
-static long write_aux(struct inode * inode, struct file * file,
-	const char * buffer, unsigned long count)
-{
-	int retval = 0;
-
-	if (count) {
-		int written = 0;
-
-		/* disable kbd bh to avoid mixing of cmd bytes */
-		disable_bh(KEYBOARD_BH);
-
-		do {
-			char c;
-			if (!poll_aux_status())
-				break;
-			outb_p(AUX_MAGIC_WRITE,AUX_COMMAND);
-			if (!poll_aux_status())
-				break;
-			get_user(c, buffer++);
-			outb_p(c, AUX_OUTPUT_PORT);
-			written++;
-		} while (--count);
-		/* reenable kbd bh */
-		enable_bh(KEYBOARD_BH);
-		retval = -EIO;
-		if (written) {
-			retval = written;
-			inode->i_mtime = CURRENT_TIME;
-		}
-	}
-
-	return retval;
-}
-
 
-#ifdef CONFIG_82C710_MOUSE
 /*
  * Write to the 82C710 mouse device.
  */
@@ -455,8 +461,64 @@
 	inode->i_mtime = CURRENT_TIME;
 	return count;
 }
+
+/*
+ * Wait for device to send output char and flush any input char.
+ */
+
+static int poll_qp_status(void)
+{
+	int retries=0;
+
+	while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE))
+		       != (QP_DEV_IDLE|QP_TX_IDLE)
+		       && retries < MAX_RETRIES) {
+
+		if (inb_p(qp_status)&(QP_RX_FULL))
+			inb_p(qp_data);
+		current->state = TASK_INTERRUPTIBLE;
+		current->timeout = jiffies + (5*HZ + 99) / 100;
+		schedule();
+		retries++;
+	}
+	return !(retries==MAX_RETRIES);
+}
+
+/*
+ * Function to read register in 82C710.
+ */
+
+static inline unsigned char read_710(unsigned char index)
+{
+	outb_p(index, 0x390);			/* Write index */
+	return inb_p(0x391);			/* Read the data */
+}
+
+/*
+ * See if we can find a 82C710 device. Read mouse address.
+ */
+
+__initfunc(static int probe_qp(void))
+{
+	outb_p(0x55, 0x2fa);			/* Any value except 9, ff or 36 */
+	outb_p(0xaa, 0x3fa);			/* Inverse of 55 */
+	outb_p(0x36, 0x3fa);			/* Address the chip */
+	outb_p(0xe4, 0x3fa);			/* 390/4; 390 = config address */
+	outb_p(0x1b, 0x2fa);			/* Inverse of e4 */
+	if (read_710(0x0f) != 0xe4)		/* Config address found? */
+	  return 0;				/* No: no 82C710 here */
+	qp_data = read_710(0x0d)*4;		/* Get mouse I/O address */
+	qp_status = qp_data+1;
+	outb_p(0x0f, 0x390);
+	outb_p(0x0f, 0x391);			/* Close config mode */
+	return 1;
+}
+
 #endif
 
+/*
+ *	Generic part continues...
+ */
 
 /*
  * Put bytes from input queue to buffer.
@@ -497,7 +559,6 @@
 	return 0;
 }
 
-
 static unsigned int aux_poll(struct file *file, poll_table * wait)
 {
 	poll_wait(&queue->proc_list, wait);
@@ -506,7 +567,6 @@
 	return 0;
 }
 
-
 struct file_operations psaux_fops = {
 	NULL,		/* seek */
 	read_aux,
@@ -521,7 +581,6 @@
 	fasync_aux,
 };
 
-
 /*
  * Initialize driver. First check for a 82C710 chip; if found
  * forget about the Aux port and use the *_qp functions.
@@ -548,7 +607,7 @@
 		printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n");
 	 	aux_present = 1;
 #ifdef CONFIG_VT
-		kbd_read_mask = AUX_OBUF_FULL;
+		kbd_read_mask = AUX_STAT_OBF;
 #endif
 	} else {
 		return -EIO;
@@ -559,8 +618,8 @@
 	queue->head = queue->tail = 0;
 	queue->proc_list = NULL;
 	if (!qp_found) {
-#if defined INITIALIZE_DEVICE
-		outb_p(AUX_ENABLE,AUX_COMMAND);		/* Enable Aux */
+#ifdef INITIALIZE_DEVICE
+		outb_p(KBD_CCMD_MOUSE_ENABLE, KBD_CNTL_REG); /* Enable Aux */
 		aux_write_ack(AUX_SET_SAMPLE);
 		aux_write_ack(100);			/* 100 samples/sec */
 		aux_write_ack(AUX_SET_RES);
@@ -568,11 +627,8 @@
 		aux_write_ack(AUX_SET_SCALE21);		/* 2:1 scaling */
 		poll_aux_status_nosleep();
 #endif /* INITIALIZE_DEVICE */
-		outb_p(AUX_DISABLE,AUX_COMMAND);   /* Disable Aux device */
-		poll_aux_status_nosleep();
-		outb_p(AUX_CMD_WRITE,AUX_COMMAND);
-		poll_aux_status_nosleep();             /* Disable interrupts */
-		outb_p(AUX_INTS_OFF, AUX_OUTPUT_PORT); /*  on the controller */
+		outb_p(KBD_CCMD_MOUSE_DISABLE, KBD_CNTL_REG); /* Disable Aux device */
+		aux_write_dev_nosleep(AUX_INTS_OFF);	    /* Disable controller interrupts */
 	}
 	return 0;
 }
@@ -580,93 +636,12 @@
 #ifdef MODULE
 int init_module(void)
 {
-	return psaux_init(); /*?? Bjorn */
+	return psaux_init();
 }
 
 void cleanup_module(void)
 {
 	misc_deregister(&psaux_mouse);
 	kfree(queue);
-}
-#endif
-
-static int poll_aux_status(void)
-{
-	int retries=0;
-
-	while ((inb(AUX_STATUS)&0x03) && retries < MAX_RETRIES) {
- 		if ((inb_p(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)
-			inb_p(AUX_INPUT_PORT);
-		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + (5*HZ + 99) / 100;
-		schedule();
-		retries++;
-	}
-	return !(retries==MAX_RETRIES);
-}
-
-static int poll_aux_status_nosleep(void)
-{
-	int retries = 0;
-
-	while ((inb(AUX_STATUS)&0x03) && retries < 1000000) {
- 		if ((inb_p(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)
-			inb_p(AUX_INPUT_PORT);
-		retries++;
-	}
-	return !(retries == 1000000);
-}
-
-#ifdef CONFIG_82C710_MOUSE
-/*
- * Wait for device to send output char and flush any input char.
- */
-
-static int poll_qp_status(void)
-{
-	int retries=0;
-
-	while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE))
-		       != (QP_DEV_IDLE|QP_TX_IDLE)
-		       && retries < MAX_RETRIES) {
-
-		if (inb_p(qp_status)&(QP_RX_FULL))
-			inb_p(qp_data);
-		current->state = TASK_INTERRUPTIBLE;
-		current->timeout = jiffies + (5*HZ + 99) / 100;
-		schedule();
-		retries++;
-	}
-	return !(retries==MAX_RETRIES);
-}
-
-/*
- * Function to read register in 82C710.
- */
-
-static inline unsigned char read_710(unsigned char index)
-{
-	outb_p(index, 0x390);			/* Write index */
-	return inb_p(0x391);			/* Read the data */
-}
-
-/*
- * See if we can find a 82C710 device. Read mouse address.
- */
-
-__initfunc(static int probe_qp(void))
-{
-	outb_p(0x55, 0x2fa);			/* Any value except 9, ff or 36 */
-	outb_p(0xaa, 0x3fa);			/* Inverse of 55 */
-	outb_p(0x36, 0x3fa);			/* Address the chip */
-	outb_p(0xe4, 0x3fa);			/* 390/4; 390 = config address */
-	outb_p(0x1b, 0x2fa);			/* Inverse of e4 */
-	if (read_710(0x0f) != 0xe4)		/* Config address found? */
-	  return 0;				/* No: no 82C710 here */
-	qp_data = read_710(0x0d)*4;		/* Get mouse I/O address */
-	qp_status = qp_data+1;
-	outb_p(0x0f, 0x390);
-	outb_p(0x0f, 0x391);			/* Close config mode */
-	return 1;
 }
 #endif
diff -u --recursive --new-file v2.1.42/linux/drivers/char/rtc.c linux/drivers/char/rtc.c
--- v2.1.42/linux/drivers/char/rtc.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/char/rtc.c	Thu Jun 12 16:22:06 1997
@@ -43,6 +43,7 @@
  *	this driver.)
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/miscdevice.h>
@@ -156,10 +157,6 @@
 	if (count < sizeof(unsigned long))
 		return -EINVAL;
 
-	retval = verify_area(VERIFY_WRITE, buf, sizeof(unsigned long));
-	if (retval)
-		return retval;
-
 	add_wait_queue(&rtc_wait, &wait);
 
 	current->state = TASK_INTERRUPTIBLE;
@@ -183,8 +180,7 @@
 		data = rtc_irq_data;
 		rtc_irq_data = 0;
 		restore_flags(flags);
-		copy_to_user(buf, &data, sizeof(unsigned long));
-		retval = sizeof(unsigned long);
+		retval = put_user(data, (unsigned long *)buf)) ?: sizeof(unsigned long);
 	}
 
 	current->state = TASK_RUNNING;
@@ -198,6 +194,7 @@
 {
 
 	unsigned long flags;
+	struct rtc_time wtime; 
 
 	switch (cmd) {
 		case RTC_AIE_OFF:	/* Mask alarm int. enab. bit	*/
@@ -254,18 +251,9 @@
 			 * means "don't care" or "match all". Only the tm_hour,
 			 * tm_min, and tm_sec values are filled in.
 			 */
-			int retval;
-			struct rtc_time alm_tm;
-
-			retval = verify_area(VERIFY_WRITE, (struct rtc_time*)arg, sizeof(struct rtc_time));
-			if (retval != 0 )
-				return retval;
-
-			get_rtc_alm_time(&alm_tm);
 
-			copy_to_user((struct rtc_time*)arg, &alm_tm, sizeof(struct rtc_time));
-			
-			return 0;
+			get_rtc_alm_time(&wtime);
+			break; 
 		}
 		case RTC_ALM_SET:	/* Store a time into the alarm */
 		{
@@ -278,11 +266,8 @@
 			unsigned char hrs, min, sec;
 			struct rtc_time alm_tm;
 
-			retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time));
-			if (retval != 0 )
-				return retval;
-
-			copy_from_user(&alm_tm, (struct rtc_time*)arg, sizeof(struct rtc_time));
+			if (copy_from_user(&alm_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
+				return -EFAULT;
 
 			hrs = alm_tm.tm_hour;
 			min = alm_tm.tm_min;
@@ -315,16 +300,8 @@
 		}
 		case RTC_RD_TIME:	/* Read the time/date from RTC	*/
 		{
-			int retval;
-			struct rtc_time rtc_tm;
-			
-			retval = verify_area(VERIFY_WRITE, (struct rtc_time*)arg, sizeof(struct rtc_time));
-			if (retval !=0 )
-				return retval;
-
-			get_rtc_time(&rtc_tm);
-			copy_to_user((struct rtc_time*)arg, &rtc_tm, sizeof(struct rtc_time));
-			return 0;
+			get_rtc_time(&wtime);
+			break;
 		}
 		case RTC_SET_TIME:	/* Set the RTC */
 		{
@@ -338,11 +315,8 @@
 			if (!suser())
 				return -EACCES;
 
-			retval = verify_area(VERIFY_READ, (struct rtc_time*)arg, sizeof(struct rtc_time));
-			if (retval !=0 )
-				return retval;
-
-			copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time));
+			if (copy_from_user(&rtc_tm, (struct rtc_time*)arg, sizeof(struct rtc_time)))
+				return -EFAULT;
 
 			yrs = rtc_tm.tm_year + 1900 + ARCFUDGE;
 			mon = rtc_tm.tm_mon + 1;   /* tm_mon starts at zero */
@@ -403,14 +377,7 @@
 		}
 		case RTC_IRQP_READ:	/* Read the periodic IRQ rate.	*/
 		{
-			int retval;
-
-			retval = verify_area(VERIFY_WRITE, (unsigned long*)arg, sizeof(unsigned long));
-			if (retval != 0)
-				return retval;
-
-			copy_to_user((unsigned long*)arg, &rtc_freq, sizeof(unsigned long));
-			return 0;
+			return put_user(rtc_freq, (unsigned long *)arg);
 		}
 		case RTC_IRQP_SET:	/* Set periodic IRQ rate.	*/
 		{
@@ -451,6 +418,7 @@
 		default:
 			return -EINVAL;
 	}
+	return copy_to_user(arg, &wtime, sizeof wtime) ? -EFAULT : 0;
 }
 
 /*
@@ -536,11 +504,11 @@
 {
 	unsigned long flags;
 
-	printk("Real Time Clock Driver v%s\n", RTC_VERSION);
+	printk(KERN_INFO "Real Time Clock Driver v%s\n", RTC_VERSION);
 	if(request_irq(RTC_IRQ, rtc_interrupt, SA_INTERRUPT, "rtc", NULL))
 	{
 		/* Yeah right, seeing as irq 8 doesn't even hit the bus. */
-		printk("rtc: IRQ %d is not free.\n", RTC_IRQ);
+		printk(KERN_ERR "rtc: IRQ %d is not free.\n", RTC_IRQ);
 		return -EIO;
 	}
 	misc_register(&rtc_dev);
diff -u --recursive --new-file v2.1.42/linux/drivers/char/selection.c linux/drivers/char/selection.c
--- v2.1.42/linux/drivers/char/selection.c	Thu May 29 21:53:05 1997
+++ linux/drivers/char/selection.c	Thu Jun 12 16:22:06 1997
@@ -21,9 +21,9 @@
 
 #include <asm/uaccess.h>
 
-#include "vt_kern.h"
-#include "consolemap.h"
-#include "selection.h"
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
 
 #ifndef MIN
 #define MIN(a,b)	((a) < (b) ? (a) : (b))
@@ -101,9 +101,9 @@
 }
 
 /* does screen address p correspond to character at LH/RH edge of screen? */
-static inline int atedge(const int p)
+static inline int atedge(const int p, int size_row)
 {
-	return (!(p % video_size_row) || !((p + 2) % video_size_row));
+	return (!(p % size_row)	|| !((p + 2) % size_row));
 }
 
 /* constrain v such that v <= u */
@@ -227,9 +227,9 @@
 
 	/* select to end of line if on trailing space */
 	if (new_sel_end > new_sel_start &&
-		!atedge(new_sel_end) && isspace(sel_pos(new_sel_end))) {
+		!atedge(new_sel_end, size_row) && isspace(sel_pos(new_sel_end))) {
 		for (pe = new_sel_end + 2; ; pe += 2)
-			if (!isspace(sel_pos(pe)) || atedge(pe))
+			if (!isspace(sel_pos(pe)) || atedge(pe, size_row))
 				break;
 		if (isspace(sel_pos(pe)))
 			new_sel_end = pe;
diff -u --recursive --new-file v2.1.42/linux/drivers/char/selection.h linux/drivers/char/selection.h
--- v2.1.42/linux/drivers/char/selection.h	Thu Jun 12 15:29:05 1997
+++ linux/drivers/char/selection.h	Wed Dec 31 16:00:00 1969
@@ -1,210 +0,0 @@
-/*
- * selection.h
- *
- * Interface between console.c, tty_io.c, vt.c, vc_screen.c and selection.c
- */
-
-#include <linux/config.h>
-
-extern int sel_cons;
-
-extern void clear_selection(void);
-extern int set_selection(const unsigned long arg, struct tty_struct *tty, int user);
-extern int paste_selection(struct tty_struct *tty);
-extern int sel_loadlut(const unsigned long arg);
-extern int mouse_reporting(void);
-extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry);
-
-#ifdef CONFIG_FB_CONSOLE
-extern unsigned long get_video_num_columns(unsigned int console);
-extern unsigned long get_video_num_lines(unsigned int console);
-extern unsigned long get_video_size_row(unsigned int console);
-#else
-#define get_video_num_columns(dummy) video_num_columns
-#define get_video_num_lines(dummy) video_num_lines
-#define get_video_size_row(dummy) video_size_row
-#endif
-
-extern unsigned long video_num_columns;
-extern unsigned long video_num_lines;
-extern unsigned long video_size_row;
-extern unsigned char video_type;
-extern unsigned long video_mem_base;
-extern unsigned long video_mem_term;
-extern unsigned long video_screen_size;
-extern unsigned short video_port_reg;
-extern unsigned short video_port_val;
-
-extern int console_blanked;
-extern int can_do_color;
-
-extern unsigned long video_font_height;
-extern unsigned long video_scan_lines;
-extern unsigned long default_font_height;
-extern int video_font_is_default;
-
-extern unsigned char color_table[];
-extern int default_red[];
-extern int default_grn[];
-extern int default_blu[];
-
-extern unsigned short __real_origin;
-extern unsigned short __origin;
-extern unsigned char has_wrapped;
-
-extern unsigned short *vc_scrbuf[MAX_NR_CONSOLES];
-
-extern void do_unblank_screen(void);
-extern unsigned short *screen_pos(int currcons, int w_offset, int viewed);
-extern unsigned short screen_word(int currcons, int offset, int viewed);
-extern int scrw2glyph(unsigned short scr_word);
-extern void complement_pos(int currcons, int offset);
-extern void invert_screen(int currcons, int offset, int count, int shift);
-
-#define reverse_video_char(a)	(((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77))
-#define reverse_video_short(a)	(((a) & 0x88ff) | \
-	(((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4))
-/* this latter line used to have masks 0xf000 and 0x0f00, but selection
-   requires a self-inverse operation; moreover, the old version looks wrong */
-
-extern void getconsxy(int currcons, char *p);
-extern void putconsxy(int currcons, char *p);
-
-
-/* how to access screen memory */
-
-#include <linux/config.h>
-
-#if defined(CONFIG_TGA_CONSOLE)
-
-extern int tga_blitc(unsigned int, unsigned long);
-extern unsigned long video_mem_term;
-
-/*
- * TGA console screen memory access
- * 
- * TGA is *not* a character/attribute cell device; font bitmaps must be rendered
- * to the screen pixels.
- *
- * We must test for an Alpha kernel virtual address that falls within
- *  the "shadow screen" memory. This condition indicates we really want 
- *  to write to the screen, so, we do... :-)
- *
- * NOTE also: there's only *TWO* operations: to put/get a character/attribute.
- *  All the others needed by VGA support go away, as Not Applicable for TGA.
- */
-static inline void scr_writew(unsigned short val, unsigned short * addr)
-{
-        /*
-         * always deposit the char/attr, then see if it was to "screen" mem.
-	 * if so, then render the char/attr onto the real screen.
-         */
-        *addr = val;
-        if ((unsigned long)addr < video_mem_term &&
-	    (unsigned long)addr >= video_mem_base) {
-                tga_blitc(val, (unsigned long) addr);
-        }
-}
-
-static inline unsigned short scr_readw(unsigned short * addr)
-{
-	return *addr;
-}
-
-#elif defined(CONFIG_SUN_CONSOLE)
-#include "vt_kern.h"
-#include <linux/kd.h>
-extern int sun_blitc(unsigned int, unsigned long);
-extern void memsetw(void * s, unsigned short c, unsigned int count);
-extern void memcpyw(unsigned short *to, unsigned short *from, unsigned int count);
-extern unsigned long video_mem_term;
-
-/* Basically the same as the TGA stuff. */
-static inline void scr_writew(unsigned short val, unsigned short * addr)
-{
-        /*
-         * always deposit the char/attr, then see if it was to "screen" mem.
-	 * if so, then render the char/attr onto the real screen.
-         */
-	if (*addr != val) {
-        	*addr = val;
-		if ((unsigned long)addr < video_mem_term &&
-		    (unsigned long)addr >= video_mem_base &&
-		    vt_cons [fg_console]->vc_mode == KD_TEXT)
-			sun_blitc(val, (unsigned long) addr);
-	}
-}
-
-static inline unsigned short scr_readw(unsigned short * addr)
-{
-	return *addr;
-}
-
-#else /* CONFIG_TGA_CONSOLE  || CONFIG_SUN_CONSOLE */
-
-/*
- * normal VGA console access
- *
- */ 
-
-#include <asm/io.h> 
-
-/*
- * NOTE: "(long) addr < 0" tests for an Alpha kernel virtual address; this
- *  indicates a VC's backing store; otherwise, it's a bus memory address, for
- *  the VGA's screen memory, so we do the Alpha "swizzle"... :-)
- */
-static inline void scr_writeb(unsigned char val, unsigned char * addr)
-{
-	if ((long) addr < 0)
-		*addr = val;
-	else
-		writeb(val, (unsigned long) addr);
-}
-
-static inline unsigned char scr_readb(unsigned char * addr)
-{
-	if ((long) addr < 0)
-		return *addr;
-	return readb((unsigned long) addr);
-}
-
-static inline void scr_writew(unsigned short val, unsigned short * addr)
-{
-	if ((long) addr < 0)
-		*addr = val;
-	else
-		writew(val, (unsigned long) addr);
-}
-
-static inline unsigned short scr_readw(unsigned short * addr)
-{
-	if ((long) addr < 0)
-		return *addr;
-	return readw((unsigned long) addr);
-}
-
-#endif /* CONFIG_TGA_CONSOLE */
-
-#ifndef CONFIG_SUN_CONSOLE
-static inline void memsetw(void * s, unsigned short c, unsigned int count)
-{
-	unsigned short * addr = (unsigned short *) s;
-
-	count /= 2;
-	while (count) {
-		count--;
-		scr_writew(c, addr++);
-	}
-}
-
-static inline void memcpyw(unsigned short *to, unsigned short *from,
-			   unsigned int count)
-{
-	count /= 2;
-	while (count) {
-		count--;
-		scr_writew(scr_readw(from++), to++);
-	}
-}
-#endif /* CONFIG_SUN_CONSOLE */
diff -u --recursive --new-file v2.1.42/linux/drivers/char/softdog.c linux/drivers/char/softdog.c
--- v2.1.42/linux/drivers/char/softdog.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/char/softdog.c	Thu Jun 12 16:22:06 1997
@@ -42,6 +42,10 @@
 
 static int soft_margin = TIMER_MARGIN;	/* in seconds */
 
+#ifdef MODULE
+MODULE_PARM(soft_margin,"i");
+#endif
+
 /*
  *	Our timer
  */
diff -u --recursive --new-file v2.1.42/linux/drivers/char/sysrq.c linux/drivers/char/sysrq.c
--- v2.1.42/linux/drivers/char/sysrq.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/sysrq.c	Thu Jun 12 16:22:06 1997
@@ -0,0 +1,248 @@
+/* -*- linux-c -*-
+ *
+ *	$Id: sysrq.c,v 1.2 1997/05/31 18:33:11 mj Exp $
+ *
+ *	Linux Magic System Request Key Hacks
+ *
+ *	(c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ *	based on ideas by Pavel Machek <pavel@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <linux/config.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/kdev_t.h>
+#include <linux/major.h>
+#include <linux/reboot.h>
+#include <linux/sysrq.h>
+#include <linux/kbd_kern.h>
+#include <asm/ptrace.h>
+#include <asm/smp_lock.h>
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+#endif
+
+extern void wakeup_bdflush(int);
+extern void reset_vc(unsigned int);
+extern int console_loglevel;
+extern struct vfsmount *vfsmntlist;
+
+#ifdef __sparc__
+extern void halt_now(void);
+#endif
+
+/* Send a signal to all user processes */
+
+static void send_sig_all(int sig, int even_init)
+{
+	struct task_struct *p;
+
+	for_each_task(p) {
+		if (p->pid && p->mm != &init_mm) {	    /* Not swapper nor kernel thread */
+			if (p->pid == 1 && even_init)	    /* Ugly hack to kill init */
+				p->pid = 0x8000;
+			force_sig(sig, p);
+		}
+	}
+}
+
+/*
+ * This function is called by the keyboard handler when SysRq is pressed
+ * and any other keycode arrives.
+ */
+
+void handle_sysrq(int key, struct pt_regs *pt_regs,
+		  struct kbd_struct *kbd, struct tty_struct *tty)
+{
+	int orig_log_level = console_loglevel;
+
+	console_loglevel = 7;
+	printk(KERN_INFO "SysRq: ");
+	switch (key) {
+	case 19:					    /* R -- Reset raw mode */
+		kbd->kbdmode = VC_XLATE;
+		printk("Keyboard mode set to XLATE\n");
+		break;
+	case 30:					    /* A -- SAK */
+		printk("SAK\n");
+		do_SAK(tty);
+		reset_vc(fg_console);
+		break;
+	case 48:					    /* B -- boot immediately */
+		printk("Resetting\n");
+		machine_restart(NULL);
+		break;
+#ifdef __sparc__
+	case 35:					    /* H -- halt immediately */
+		printk("Halting\n");
+		halt_now();
+		break;
+#endif
+#ifdef CONFIG_APM
+	case 24:					    /* O -- power off */
+		printk("Power off\n");
+		apm_set_power_state(APM_STATE_OFF);
+		break;
+#endif
+	case 31:					    /* S -- emergency sync */
+		printk("Emergency Sync\n");
+		emergency_sync_scheduled = EMERG_SYNC;
+		wakeup_bdflush(0);
+		break;
+	case 22:					    /* U -- emergency remount R/O */
+		printk("Emergency Remount R/O\n");
+		emergency_sync_scheduled = EMERG_REMOUNT;
+		wakeup_bdflush(0);
+		break;
+	case 25:					    /* P -- show PC */
+		printk("Show Regs\n");
+		if (pt_regs)
+			show_regs(pt_regs);
+		break;
+	case 20:					    /* T -- show task info */
+		printk("Show State\n");
+		show_state();
+		break;
+	case 50:					    /* M -- show memory info */
+		printk("Show Memory\n");
+		show_mem();
+		break;
+	case 2 ... 11:					    /* 0-9 -- set console logging level */
+		key -= 2;
+		if (key == 10)
+			key = 0;
+		orig_log_level = key;
+		printk("Log level set to %d\n", key);
+		break;
+	case 18:					    /* E -- terminate all user processes */
+		printk("Terminate All Tasks\n");
+		send_sig_all(SIGTERM, 0);
+		orig_log_level = 8;			    /* We probably have killed syslogd */
+		break;
+	case 37:					    /* K -- kill all user processes */
+		printk("Kill All Tasks\n");
+		send_sig_all(SIGKILL, 0);
+		orig_log_level = 8;
+		break;
+	case 38:					    /* L -- kill all processes including init */
+		printk("Kill ALL Tasks (even init)\n");
+		send_sig_all(SIGKILL, 1);
+		orig_log_level = 8;
+		break;
+	default:					    /* Unknown: help */
+		printk("unRaw sAk Boot "
+#ifdef __sparc__
+		       "Halt "
+#endif
+#ifdef CONFIG_APM
+		       "Off "
+#endif
+		       "Sync Unmount showPc showTasks showMem loglevel0-8 tErm Kill killalL\n");
+	}
+
+	console_loglevel = orig_log_level;
+}
+
+/* Aux routines for the syncer */
+
+static void all_files_read_only(void)	    /* Kill write permissions of all files */
+{
+	struct file *file;
+
+	for (file = inuse_filps; file; file = file->f_next)
+		if (file->f_inode && file->f_count && S_ISREG(file->f_inode->i_mode))
+			file->f_mode &= ~2;
+}
+
+static int is_local_disk(kdev_t dev)	    /* Guess if the device is a local hard drive */
+{
+	unsigned int major = MAJOR(dev);
+
+	switch (major) {
+	case IDE0_MAJOR:
+	case IDE1_MAJOR:
+	case IDE2_MAJOR:
+	case IDE3_MAJOR:
+	case SCSI_DISK_MAJOR:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+static void go_sync(kdev_t dev, int remount_flag)
+{
+	printk(KERN_INFO "%sing device %04x ... ",
+	       remount_flag ? "Remount" : "Sync",
+	       dev);
+
+	if (remount_flag) {				    /* Remount R/O */
+		struct super_block *sb = get_super(dev);
+		struct vfsmount *vfsmnt;
+		int ret, flags;
+
+		if (!sb) {
+			printk("Superblock not found\n");
+			return;
+		}
+		if (sb->s_flags & MS_RDONLY) {
+			printk("R/O\n");
+			return;
+		}
+		quota_off(dev, -1);
+		fsync_dev(dev);
+		flags = MS_RDONLY;
+		if (sb->s_op && sb->s_op->remount_fs) {
+			ret = sb->s_op->remount_fs(sb, &flags, NULL);
+			if (ret)
+				printk("error %d\n", ret);
+			else {
+				sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
+				if ((vfsmnt = lookup_vfsmnt(sb->s_dev)))
+					vfsmnt->mnt_flags = sb->s_flags;
+				printk("OK\n");
+			}
+		} else
+			printk("nothing to do\n");
+	} else {
+		fsync_dev(dev);				    /* Sync only */
+		printk("OK\n");
+	}
+}
+
+/*
+ * Emergency Sync or Unmount. We cannot do it directly, so we set a special
+ * flag and wake up the bdflush kernel thread which immediately calls this function.
+ * We process all mounted hard drives first to recover from crashed experimental
+ * block devices and malfunctional network filesystems.
+ */
+
+int emergency_sync_scheduled;
+
+void do_emergency_sync(void)
+{
+	struct vfsmount *mnt;
+	int remount_flag;
+
+	lock_kernel();
+	remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT);
+	emergency_sync_scheduled = 0;
+
+	if (remount_flag)
+		all_files_read_only();
+
+	for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next)
+		if (is_local_disk(mnt->mnt_dev))
+			go_sync(mnt->mnt_dev, remount_flag);
+
+	for (mnt = vfsmntlist; mnt; mnt = mnt->mnt_next)
+		if (!is_local_disk(mnt->mnt_dev) && MAJOR(mnt->mnt_dev))
+			go_sync(mnt->mnt_dev, remount_flag);
+
+	unlock_kernel();
+	printk(KERN_INFO "Done.\n");
+}
diff -u --recursive --new-file v2.1.42/linux/drivers/char/tga.c linux/drivers/char/tga.c
--- v2.1.42/linux/drivers/char/tga.c	Tue May 13 22:41:07 1997
+++ linux/drivers/char/tga.c	Thu Jun 12 16:22:06 1997
@@ -33,11 +33,11 @@
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 
-#include "kbd_kern.h"
-#include "vt_kern.h"
-#include "consolemap.h"
-#include "selection.h"
-#include "console_struct.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 
 extern struct console vt_console_driver;
 
diff -u --recursive --new-file v2.1.42/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- v2.1.42/linux/drivers/char/tty_io.c	Mon May 19 12:57:38 1997
+++ linux/drivers/char/tty_io.c	Thu Jun 12 16:22:06 1997
@@ -77,9 +77,9 @@
 #include <asm/system.h>
 #include <asm/bitops.h>
 
-#include "kbd_kern.h"
-#include "vt_kern.h"
-#include "selection.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
 
 #ifdef CONFIG_KERNELD
 #include <linux/kerneld.h>
diff -u --recursive --new-file v2.1.42/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c
--- v2.1.42/linux/drivers/char/vc_screen.c	Thu May 29 21:53:05 1997
+++ linux/drivers/char/vc_screen.c	Thu Jun 12 16:22:06 1997
@@ -31,9 +31,9 @@
 #include <linux/interrupt.h>
 #include <linux/mm.h>
 #include <linux/init.h>
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
 #include <asm/uaccess.h>
-#include "vt_kern.h"
-#include "selection.h"
 
 #undef attr
 #undef org
diff -u --recursive --new-file v2.1.42/linux/drivers/char/vga.c linux/drivers/char/vga.c
--- v2.1.42/linux/drivers/char/vga.c	Tue May 13 22:41:07 1997
+++ linux/drivers/char/vga.c	Thu Jun 12 16:22:06 1997
@@ -60,11 +60,11 @@
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
 
-#include "kbd_kern.h"
-#include "vt_kern.h"
-#include "consolemap.h"
-#include "selection.h"
-#include "console_struct.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 
 #define CAN_LOAD_EGA_FONTS    /* undefine if the user must not do this */
 #define CAN_LOAD_PALETTE      /* undefine if the user must not do this */
diff -u --recursive --new-file v2.1.42/linux/drivers/char/vt.c linux/drivers/char/vt.c
--- v2.1.42/linux/drivers/char/vt.c	Tue May 13 22:41:07 1997
+++ linux/drivers/char/vt.c	Thu Jun 12 16:22:06 1997
@@ -26,10 +26,10 @@
 #include <asm/io.h>
 #include <asm/uaccess.h>
 
-#include "kbd_kern.h"
-#include "vt_kern.h"
-#include "diacr.h"
-#include "selection.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/kbd_diacr.h>
+#include <linux/selection.h>
 
 char vt_dont_switch = 0;
 extern struct tty_driver console_driver;
diff -u --recursive --new-file v2.1.42/linux/drivers/char/vt_kern.h linux/drivers/char/vt_kern.h
--- v2.1.42/linux/drivers/char/vt_kern.h	Sun Mar 24 03:35:08 1996
+++ linux/drivers/char/vt_kern.h	Wed Dec 31 16:00:00 1969
@@ -1,39 +0,0 @@
-#ifndef _VT_KERN_H
-#define _VT_KERN_H
-
-/*
- * this really is an extension of the vc_cons structure in console.c, but
- * with information needed by the vt package
- */
-
-#include <linux/vt.h>
-
-/*
- * Presently, a lot of graphics programs do not restore the contents of
- * the higher font pages.  Defining this flag will avoid use of them, but
- * will lose support for PIO_FONTRESET.  Note that many font operations are
- * not likely to work with these programs anyway; they need to be
- * fixed.  The linux/Documentation directory includes a code snippet
- * to save and restore the text font.
- */
-#define BROKEN_GRAPHICS_PROGRAMS 1
-
-extern struct vt_struct {
-	int vc_num;				/* The console number */
-	unsigned char	vc_mode;		/* KD_TEXT, ... */
-	unsigned char	vc_kbdraw;
-	unsigned char	vc_kbde0;
-	unsigned char   vc_kbdleds;
-	struct vt_mode	vt_mode;
-	int		vt_pid;
-	int		vt_newvt;
-	struct wait_queue *paste_wait;
-} *vt_cons[MAX_NR_CONSOLES];
-
-void (*kd_mksound)(unsigned int hz, unsigned int ticks);
-int vc_allocate(unsigned int console);
-int vc_cons_allocated(unsigned int console);
-int vc_resize(unsigned long lines, unsigned long cols);
-void vc_disallocate(unsigned int console);
-
-#endif /* _VT_KERN_H */
diff -u --recursive --new-file v2.1.42/linux/drivers/isdn/hisax/callc.c linux/drivers/isdn/hisax/callc.c
--- v2.1.42/linux/drivers/isdn/hisax/callc.c	Thu May 29 21:53:05 1997
+++ linux/drivers/isdn/hisax/callc.c	Thu Jun 12 16:22:06 1997
@@ -1,4 +1,4 @@
-/* $Id: callc.c,v 1.29 1997/04/23 20:09:49 fritz Exp $
+/* $Id: callc.c,v 1.30 1997/05/29 10:40:43 keil Exp $
 
  * Author       Karsten Keil (keil@temic-ech.spacenet.de)
  *              based on the teles driver from Jan den Ouden
@@ -7,6 +7,9 @@
  *              Fritz Elfert
  *
  * $Log: callc.c,v $
+ * Revision 1.30  1997/05/29 10:40:43  keil
+ * chanp->impair was uninitialised
+ *
  * Revision 1.29  1997/04/23 20:09:49  fritz
  * Removed tmp, used by removed debugging code.
  *
@@ -109,7 +112,7 @@
 #endif
 #endif				/* MODULE */
 
-const char *l4_revision = "$Revision: 1.29 $";
+const char *l4_revision = "$Revision: 1.30 $";
 
 extern struct IsdnCard cards[];
 extern int nrcards;
@@ -1504,6 +1507,7 @@
 	chanp->debug = 0;
 	chanp->Flags = 0;
 	chanp->leased = 0;
+	chanp->impair = 0;
 	init_is(chanp, ces);
 
 	chanp->fi.fsm = &callcfsm;
diff -u --recursive --new-file v2.1.42/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- v2.1.42/linux/drivers/net/Config.in	Thu May 29 21:53:07 1997
+++ linux/drivers/net/Config.in	Thu Jun 12 16:22:06 1997
@@ -139,10 +139,15 @@
       bool 'Soundmodem support for Soundblaster and compatible cards' CONFIG_SOUNDMODEM_SBC
       bool 'Soundmodem support for WSS and Crystal cards' CONFIG_SOUNDMODEM_WSS
       bool 'Soundmodem support for 1200 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK1200
+      bool 'Soundmodem support for 2400 baud AFSK modulation (7.3728MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_7
+      bool 'Soundmodem support for 2400 baud AFSK modulation (8MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_8
       bool 'Soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800
       bool 'Soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600
-      if [ "$CONFIG_M586" = "y" -o "$CONFIG_M686" = "y" ]; then
-        bool 'Soundmodem using floating point' CONFIG_SOUNDMODEM_FLOAT
+      if [ -f drivers/net/soundmodem/sm_afsk2666.c ]; then
+        bool 'Soundmodem support for 2666 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK2666
+      fi
+      if [ -f drivers/net/soundmodem/sm_psk4800.c ]; then
+        bool 'Soundmodem support for 4800 baud PSK modulation' CONFIG_SOUNDMODEM_PSK4800
       fi
     fi
   fi
diff -u --recursive --new-file v2.1.42/linux/drivers/net/arcnet.c linux/drivers/net/arcnet.c
--- v2.1.42/linux/drivers/net/arcnet.c	Tue May 13 22:41:08 1997
+++ linux/drivers/net/arcnet.c	Thu Jun 12 16:22:06 1997
@@ -751,8 +751,8 @@
  * FIXME: grab all devices in one shot and eliminate the big static array.
  */
 
-static int ports[(0x3f0 - 0x200) / 16 + 1] __initdata;
-static u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] __initdata;
+static int ports[(0x3f0 - 0x200) / 16 + 1] __initdata = { 0 };
+static u_long shmems[(0xFF800 - 0xA0000) / 2048 + 1] __initdata = { 0 };
 
 __initfunc(int arcnet_probe(struct device *dev))
 {
diff -u --recursive --new-file v2.1.42/linux/drivers/net/baycom.c linux/drivers/net/baycom.c
--- v2.1.42/linux/drivers/net/baycom.c	Wed Apr 23 19:01:18 1997
+++ linux/drivers/net/baycom.c	Thu Jun 12 16:22:06 1997
@@ -68,6 +68,7 @@
  *  History:
  *   0.1  26.06.96  Adapted from baycom.c and made network driver interface
  *        18.10.96  Changed to new user space access routines (copy_{to,from}_user)
+ *   0.3  26.04.96  init code/data tagged
  */
 
 /*****************************************************************************/
@@ -89,7 +90,6 @@
 #include <linux/netdevice.h>
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
-#include <linux/init.h>
 
 /* --------------------------------------------------------------------- */
 
@@ -133,6 +133,14 @@
 }
 #endif
 
+#if LINUX_VERSION_CODE >= 0x20123
+#include <linux/init.h>
+#else
+#define __init
+#define __initdata
+#define __initfunc(x) x
+#endif
+
 /* --------------------------------------------------------------------- */
 
 #define BAYCOM_DEBUG
@@ -1001,7 +1009,7 @@
 
 #endif
 
-int init_module(void)
+__initfunc(int init_module(void))
 {
 	baycom_ports[0].mode = mode;
 	baycom_ports[0].iobase = iobase;
diff -u --recursive --new-file v2.1.42/linux/drivers/net/defxx.c linux/drivers/net/defxx.c
--- v2.1.42/linux/drivers/net/defxx.c	Sat May 24 09:10:23 1997
+++ linux/drivers/net/defxx.c	Thu Jun 12 16:22:06 1997
@@ -229,7 +229,11 @@
 #define DYNAMIC_BUFFERS 1
 
 #define SKBUFF_RX_COPYBREAK 200
-#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX)
+/*
+ * NEW_SKB_SIZE = PI_RCV_DATA_K_SIZE_MAX+128 to allow 128 byte
+ * alignment for compatibility with old EISA boards.
+ */
+#define NEW_SKB_SIZE (PI_RCV_DATA_K_SIZE_MAX+128)
 
 /* Define global routines */
 
@@ -2944,6 +2948,12 @@
 			bp->descr_block_virt->rcv_data[i+j].long_0 = (u32) (PI_RCV_DESCR_M_SOP |
 				((PI_RCV_DATA_K_SIZE_MAX / PI_ALIGN_K_RCV_DATA_BUFF) << PI_RCV_DESCR_V_SEG_LEN));
 			newskb = dev_alloc_skb(NEW_SKB_SIZE);
+			/*
+			 * align to 128 bytes for compatibility with
+			 * the old EISA boards.
+			 */
+			newskb->data = (char *)((unsigned long)
+						(newskb->data+127) & ~128);
 			bp->descr_block_virt->rcv_data[i+j].long_1 = virt_to_bus(newskb->data);
 			/*
 			 * p_rcv_buff_va is only used inside the
@@ -3012,8 +3022,6 @@
 	u32					descr, pkt_len;		/* FMC descriptor field and packet length */
 	struct sk_buff		*skb;				/* pointer to a sk_buff to hold incoming packet data */
 
-	static int testing_dyn;
-
 	/* Service all consumed LLC receive frames */
 
 	p_type_2_cons = (PI_TYPE_2_CONSUMER *)(&bp->cons_block_virt->xmt_rcv_data);
@@ -3056,18 +3064,12 @@
 					newskb = dev_alloc_skb(NEW_SKB_SIZE);
 					if (newskb){
 						rx_in_place = 1;
-#define JES_TESTING
-#ifdef JES_TESTING
-						if(testing_dyn++ < 5)
-						  printk("Skipping a memcpy\n");
+
+						newskb->data = (char *)((unsigned long)(newskb->data+127) & ~128);
 						skb = (struct sk_buff *)bp->p_rcv_buff_va[entry];
 						skb->data += RCV_BUFF_K_PADDING;
 						bp->p_rcv_buff_va[entry] = (char *)newskb;
 						bp->descr_block_virt->rcv_data[entry].long_1 = virt_to_bus(newskb->data);
-#else
-						memcpy(newskb->data, p_buff + RCV_BUFF_K_PADDING, pkt_len+3);
-						skb = newskb;
-#endif
 					} else
 						skb = 0;
 				} else
@@ -3240,12 +3242,14 @@
 	p_xmt_descr = &(bp->descr_block_virt->xmt_data[prod]);
 
 	/*
-	 * Get pointer to auxiliary queue entry to contain information for this packet.
+	 * Get pointer to auxiliary queue entry to contain information
+	 * for this packet.
 	 *
-	 * Note: The current xmt producer index will become the current xmt completion
-	 *       index when we complete this packet later on.  So, we'll get the
-	 *       pointer to the next auxiliary queue entry now before we bump the
-	 *		 producer index.
+	 * Note: The current xmt producer index will become the
+	 *	 current xmt completion index when we complete this
+	 *	 packet later on.  So, we'll get the pointer to the
+	 *	 next auxiliary queue entry now before we bump the
+	 *	 producer index.
 	 */
 
 	p_xmt_drv_descr = &(bp->xmt_drv_descr_blk[prod++]);	/* also bump producer index */
@@ -3290,15 +3294,15 @@
 	 * Verify that descriptor is actually available
 	 *
 	 * Note: If descriptor isn't available, return 1 which tells
-	 *		 the upper layer to requeue the packet for later
-	 *		 transmission.
+	 *	 the upper layer to requeue the packet for later
+	 *	 transmission.
 	 *
 	 *       We need to ensure that the producer never reaches the
-	 *		 completion, except to indicate that the queue is empty.
+	 *	 completion, except to indicate that the queue is empty.
 	 */
 
 	if (prod == bp->rcv_xmt_reg.index.xmt_comp)
-		return(1);						/* requeue packet for later */
+		return(1);			/* requeue packet for later */
 
 	/*
 	 * Save info for this packet for xmt done indication routine
@@ -3311,9 +3315,9 @@
 	 * one (1) for each completed packet.
 	 *
 	 * Note: If this assumption changes and we're presented with
-	 *		 an inconsistent number of transmit fragments for packet
-	 *		 data, we'll need to modify this code to save the current
-	 *		 transmit producer index.
+	 *	 an inconsistent number of transmit fragments for packet
+	 *	 data, we'll need to modify this code to save the current
+	 *	 transmit producer index.
 	 */
 
 	p_xmt_drv_descr->p_skb = skb;
diff -u --recursive --new-file v2.1.42/linux/drivers/net/hdlcdrv.c linux/drivers/net/hdlcdrv.c
--- v2.1.42/linux/drivers/net/hdlcdrv.c	Tue May 13 22:41:09 1997
+++ linux/drivers/net/hdlcdrv.c	Thu Jun 12 16:22:06 1997
@@ -32,6 +32,7 @@
  *                  (copy_{to,from}_user)
  *   0.2  21.11.96  various small changes
  *   0.3  03.03.97  fixed (hopefully) IP not working with ax.25 as a module
+ *   0.4  16.04.97  init code/data tagged
  */
 
 /*****************************************************************************/
@@ -119,6 +120,23 @@
 
 /* --------------------------------------------------------------------- */
 
+#if LINUX_VERSION_CODE >= 0x20123
+#include <linux/init.h>
+#else
+#define __init
+#define __initdata
+#define __initfunc(x) x
+#endif
+
+/* --------------------------------------------------------------------- */
+
+#if LINUX_VERSION_CODE < 0x20125
+#define test_and_set_bit set_bit
+#define test_and_clear_bit clear_bit
+#endif
+
+/* --------------------------------------------------------------------- */
+
 /*
  * The name of the card. Is used for messages and in the requests for
  * io regions, irqs and dma channels
@@ -998,10 +1016,10 @@
 
 /* --------------------------------------------------------------------- */
 
-int init_module(void)
+__initfunc(int init_module(void))
 {
 	printk(KERN_INFO "hdlcdrv: (C) 1996 Thomas Sailer HB9JNX/AE4WA\n");
-	printk(KERN_INFO "hdlcdrv: version 0.3 compiled " __TIME__ " " __DATE__ "\n");
+	printk(KERN_INFO "hdlcdrv: version 0.4 compiled " __TIME__ " " __DATE__ "\n");
 #if LINUX_VERSION_CODE < 0x20115
         register_symtab(&hdlcdrv_syms);
 #endif
diff -u --recursive --new-file v2.1.42/linux/drivers/net/net_init.c linux/drivers/net/net_init.c
--- v2.1.42/linux/drivers/net/net_init.c	Sun Apr 13 10:18:21 1997
+++ linux/drivers/net/net_init.c	Thu Jun 12 16:22:06 1997
@@ -248,7 +248,7 @@
 
 #endif
 
-#ifdef CONFIG_ATALK
+#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
 
 static int ltalk_change_mtu(struct device *dev, int mtu)
 {
diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/Makefile linux/drivers/net/soundmodem/Makefile
--- v2.1.42/linux/drivers/net/soundmodem/Makefile	Thu Feb 27 10:57:31 1997
+++ linux/drivers/net/soundmodem/Makefile	Thu Jun 12 16:22:06 1997
@@ -21,6 +21,12 @@
 ifeq ($(CONFIG_SOUNDMODEM_AFSK1200),y)
 O_OBJS		+= sm_afsk1200.o
 endif
+ifeq ($(CONFIG_SOUNDMODEM_AFSK2400_7),y)
+O_OBJS		+= sm_afsk2400_7.o
+endif
+ifeq ($(CONFIG_SOUNDMODEM_AFSK2400_8),y)
+O_OBJS		+= sm_afsk2400_8.o
+endif
 ifeq ($(CONFIG_SOUNDMODEM_AFSK2666),y)
 O_OBJS		+= sm_afsk2666.o
 endif
@@ -39,7 +45,8 @@
 gentbl:		gentbl.c
 		$(HOSTCC) -Wall $< -o $@ -lm
 
-TBLHDR		:= sm_tbl_afsk1200.h sm_tbl_afsk2666.h sm_tbl_psk4800.h
+TBLHDR		:= sm_tbl_afsk1200.h sm_tbl_afsk2400_8.h 
+TBLHDR		+= sm_tbl_afsk2666.h sm_tbl_psk4800.h
 TBLHDR		+= sm_tbl_hapn4800.h sm_tbl_fsk9600.h
 
 $(TBLHDR):	gentbl
diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/gentbl.c linux/drivers/net/soundmodem/gentbl.c
--- v2.1.42/linux/drivers/net/soundmodem/gentbl.c	Thu Feb 27 10:57:31 1997
+++ linux/drivers/net/soundmodem/gentbl.c	Thu Jun 12 16:22:06 1997
@@ -31,27 +31,44 @@
 
 /* -------------------------------------------------------------------- */
 
-#define OFFSCOSTABBITS 6
-#define OFFSCOSTABSIZE (1<<OFFSCOSTABBITS)
-
-static void gentbl_offscostab(FILE *f)
+static void gentbl_offscostab(FILE *f, unsigned int nbits)
 {
 	int i;
 
 	fprintf(f, "\n/*\n * small cosine table in U8 format\n */\n"
 		"#define OFFSCOSTABBITS %u\n"
 		"#define OFFSCOSTABSIZE (1<<OFFSCOSTABBITS)\n\n", 
-		OFFSCOSTABBITS);
+		nbits);
 	fprintf(f, "static unsigned char offscostab[OFFSCOSTABSIZE] = {\n\t");
-	for (i = 0; i < OFFSCOSTABSIZE; i++) {
+	for (i = 0; i < (1<<nbits); i++) {
 		fprintf(f, "%4u", (int)
-			(128+127.0*cos(i*2.0*M_PI/OFFSCOSTABSIZE)));
-		if (i < OFFSCOSTABSIZE-1) 
+			(128+127.0*cos(i*2.0*M_PI/(1<<nbits))));
+		if (i < (1<<nbits)-1) 
 			fprintf(f, "%s", (i & 7) == 7 ? ",\n\t" : ",");
 	}
 	fprintf(f, "\n};\n\n"
 		"#define OFFSCOS(x) offscostab[((x)>>%d)&0x%x]\n\n",
-		16-OFFSCOSTABBITS, OFFSCOSTABSIZE-1);
+		16-nbits, (1<<nbits)-1);
+}
+
+/* -------------------------------------------------------------------- */
+
+static void gentbl_costab(FILE *f, unsigned int nbits)
+{
+        int i;
+
+	fprintf(f, "\n/*\n * more accurate cosine table\n */\n\n"
+		"static const short costab[%d] = {", (1<<nbits));
+        for (i = 0; i < (1<<nbits); i++) {
+                if (!(i & 7))
+                        fprintf(f, "\n\t");
+                fprintf(f, "%6d", (int)(32767.0*cos(i*2.0*M_PI/(1<<nbits))));
+                if (i != ((1<<nbits)-1))
+                        fprintf(f, ", ");
+        }
+        fprintf(f, "\n};\n\n#define COS(x) costab[((x)>>%d)&0x%x]\n"
+		"#define SIN(x) COS((x)+0xc000)\n\n", 16-nbits,
+		(1<<nbits)-1);
 }
 
 /* -------------------------------------------------------------------- */
@@ -63,7 +80,8 @@
 
 static void gentbl_afsk1200(FILE *f)
 {
-        int i;
+        int i, v, sum;
+	float fv, fsum;
 
 #define ARGLO(x) 2.0*M_PI*(double)x*(double)AFSK12_TX_FREQ_LO/(double)AFSK12_SAMPLE_RATE
 #define ARGHI(x) 2.0*M_PI*(double)x*(double)AFSK12_TX_FREQ_HI/(double)AFSK12_SAMPLE_RATE
@@ -75,42 +93,58 @@
 		"#define AFSK12_CORRLEN %u\n\n",
 		AFSK12_SAMPLE_RATE, AFSK12_TX_FREQ_LO, 
 		AFSK12_TX_FREQ_HI, AFSK12_CORRLEN);
-	fprintf(f, "#if defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && "
+	fprintf(f, "#if defined(CONFIG_SOUNDMODEM_FLOAT) && "
 		"(defined(CONFIG_M586) || defined(CONFIG_M686))\n\n"
 		"static const float afsk12_tx_lo_i_f[] = {\n\t");
-        for(i = 0; i < AFSK12_CORRLEN; i++) 
-                fprintf(f, " %7f%c", cos(ARGLO(i)),
-                        (i < AFSK12_CORRLEN-1) ? ',' : ' ');
-        fprintf(f, "\n};\n\nstatic const float afsk12_tx_lo_q_f[] = {\n\t");
-        for(i = 0; i < AFSK12_CORRLEN; i++) 
-                fprintf(f, " %7f%c", sin(ARGLO(i)),
-                        (i < AFSK12_CORRLEN-1) ? ',' : ' ');
-        fprintf(f, "\n};\n\nstatic const float afsk12_tx_hi_i_f[] = {\n\t");
-        for(i = 0; i < AFSK12_CORRLEN; i++) 
-                fprintf(f, " %7f%c", cos(ARGHI(i)),
-                        (i < AFSK12_CORRLEN-1) ? ',' : ' ');
-        fprintf(f, "\n};\n\nstatic const float afsk12_tx_hi_q_f[] = {\n\t");
-        for(i = 0; i < AFSK12_CORRLEN; i++) 
-                fprintf(f, " %7f%c", sin(ARGHI(i)), 
-                        (i < AFSK12_CORRLEN-1) ? ',' : ' ');
-	fprintf(f, "\n};\n\n#else /* CONFIG_SOUNDMODEM_AFSK1200_FP */\n\n"
-		"static const signed char afsk12_tx_lo_i[] = {\n\t");
-        for(i = 0; i < AFSK12_CORRLEN; i++) 
-                fprintf(f, " %4i%c", (int)(127.0*cos(ARGLO(i))),
-                        (i < AFSK12_CORRLEN-1) ? ',' : ' ');
-        fprintf(f, "\n};\n\nstatic const signed char afsk12_tx_lo_q[] = {\n\t");
-        for(i = 0; i < AFSK12_CORRLEN; i++) 
-                fprintf(f, " %4i%c", (int)(127.0*sin(ARGLO(i))),
-                        (i < AFSK12_CORRLEN-1) ? ',' : ' ');
-        fprintf(f, "\n};\n\nstatic const signed char afsk12_tx_hi_i[] = {\n\t");
-        for(i = 0; i < AFSK12_CORRLEN; i++) 
-                fprintf(f, " %4i%c", (int)(127.0*cos(ARGHI(i))),
-                        (i < AFSK12_CORRLEN-1) ? ',' : ' ');
-        fprintf(f, "\n};\n\nstatic const signed char afsk12_tx_hi_q[] = {\n\t");
-        for(i = 0; i < AFSK12_CORRLEN; i++) 
-                fprintf(f, " %4i%c", (int)(127.0*sin(ARGHI(i))), 
-                        (i < AFSK12_CORRLEN-1) ? ',' : ' ');
-	fprintf(f, "\n};\n\n#endif /* CONFIG_SOUNDMODEM_AFSK1200_FP */\n\n");
+        for(fsum = i = 0; i < AFSK12_CORRLEN; i++) {
+		fsum += (fv = cos(ARGLO(i)));
+                fprintf(f, " %7f%c", fv, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+	}
+        fprintf(f, "\n};\n#define SUM_AFSK12_TX_LO_Q %7f\n\n"
+		"static const float afsk12_tx_lo_q_f[] = {\n\t", fsum);
+        for(fsum = i = 0; i < AFSK12_CORRLEN; i++) {
+		fsum += (fv = sin(ARGLO(i)));
+                fprintf(f, " %7f%c", fv, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+	}
+        fprintf(f, "\n};\n#define SUM_AFSK12_TX_LO_Q %7f\n\n"
+		"static const float afsk12_tx_hi_i_f[] = {\n\t", fsum);
+        for(fsum = i = 0; i < AFSK12_CORRLEN; i++) {
+		fsum += (fv = cos(ARGHI(i)));
+                fprintf(f, " %7f%c", fv, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+	}
+        fprintf(f, "\n};\n#define SUM_AFSK12_TX_HI_I %7f\n\n"
+		"static const float afsk12_tx_hi_q_f[] = {\n\t", fsum);
+        for(fsum = i = 0; i < AFSK12_CORRLEN; i++) {
+		fsum += (fv = sin(ARGHI(i)));
+                fprintf(f, " %7f%c", fv, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+	}
+	fprintf(f, "\n};\n#define SUM_AFSK12_TX_HI_Q %7f\n\n"
+		"#else /* CONFIG_SOUNDMODEM_FLOAT */\n\n"
+		"static const int afsk12_tx_lo_i[] = {\n\t", fsum);
+        for(sum = i = 0; i < AFSK12_CORRLEN; i++) {
+		sum += (v = 127.0*cos(ARGLO(i)));
+                fprintf(f, " %4i%c", v, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+	}
+        fprintf(f, "\n};\n#define SUM_AFSK12_TX_LO_I %d\n\n"
+		"static const int afsk12_tx_lo_q[] = {\n\t", sum);
+        for(sum = i = 0; i < AFSK12_CORRLEN; i++) {
+		sum += (v = 127.0*sin(ARGLO(i))); 
+                fprintf(f, " %4i%c", v, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+	}
+        fprintf(f, "\n};\n#define SUM_AFSK12_TX_LO_Q %d\n\n"
+		"static const int afsk12_tx_hi_i[] = {\n\t", sum);
+        for(sum = i = 0; i < AFSK12_CORRLEN; i++) {
+		sum += (v = 127.0*cos(ARGHI(i))); 
+                fprintf(f, " %4i%c", v, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+	}
+        fprintf(f, "\n};\n#define SUM_AFSK12_TX_HI_I %d\n\n"
+		"static const int afsk12_tx_hi_q[] = {\n\t", sum);
+        for(sum = i = 0; i < AFSK12_CORRLEN; i++)  {
+		sum += (v = 127.0*sin(ARGHI(i)));
+                fprintf(f, " %4i%c", v, (i < AFSK12_CORRLEN-1) ? ',' : ' ');
+	}
+	fprintf(f, "\n};\n#define SUM_AFSK12_TX_HI_Q %d\n\n"
+		"#endif /* CONFIG_SOUNDMODEM_FLOAT */\n\n", sum);
 #undef ARGLO
 #undef ARGHI
 }
@@ -252,7 +286,7 @@
 
 static void gentbl_afsk2666(FILE *f)
 {
-        int i, j, k, l, o;
+        int i, j, k, l, o, v, sumi, sumq;
         float window[AFSK26_DEMCORRLEN*AFSK26_RXOVER];
 	int cfreq[AFSK26_NUMCAR];
 
@@ -274,32 +308,30 @@
                 window[i] = AFSK26_WINDOW(((float)i)/(AFSK26_DEMCORRLEN*
 						      AFSK26_RXOVER)) * 127.0;
         fprintf(f, "\nstatic const struct {\n\t"
-               "signed char i[%d];\n\tsigned char q[%d];\n} afsk26_dem_tables[%d][2] = {\n", 
-               AFSK26_DEMCORRLEN, AFSK26_DEMCORRLEN, AFSK26_RXOVER);
+               "int i[%d];\n\tint q[%d];\n} afsk26_dem_tables[%d][%d] = {\n", 
+               AFSK26_DEMCORRLEN, AFSK26_DEMCORRLEN, AFSK26_RXOVER, AFSK26_NUMCAR);
         for (o = AFSK26_RXOVER-1; o >= 0; o--) {
                 fprintf(f, "\t{\n");
                 for (i = 0; i < AFSK26_NUMCAR; i++) {
                         j = cfreq[i];
                         fprintf(f, "\t\t{{ ");
-                        for (l = AFSK26_DEMCORRLEN-1, 
-				     k = (j * o)/AFSK26_RXOVER; l >= 0; 
-                             l--, k = (k+j)&0xffffu)
-                                fprintf(f, "%6d%s", (int)
-					(AFSK26_AMPL(i)*
-					 window[l*AFSK26_RXOVER+o]*
-					 cos(M_PI*k/32768.0)),
-					l ? ", " : " }, { ");
-                        for (l = AFSK26_DEMCORRLEN-1, 
-				     k = (j * o)/AFSK26_RXOVER; l >= 0; 
-                             l--, k = (k+j)&0xffffu)
-                                fprintf(f, "%6d%s", (int)
-					(AFSK26_AMPL(i)*
-					 window[l*AFSK26_RXOVER+o]*
-					 sin(M_PI*k/32768.0)),
-					l ? ", " : " }}");
+                        for (l = AFSK26_DEMCORRLEN-1, k = (j * o)/AFSK26_RXOVER, sumi = 0; l >= 0; 
+                             l--, k = (k+j)&0xffffu) {
+				sumi += (v = AFSK26_AMPL(i)*window[l*AFSK26_RXOVER+o]*
+					 cos(M_PI*k/32768.0));
+                                fprintf(f, "%6d%s", v, l ? ", " : " }, { ");
+			}
+                        for (l = AFSK26_DEMCORRLEN-1, k = (j * o)/AFSK26_RXOVER, sumq = 0; l >= 0; 
+                             l--, k = (k+j)&0xffffu) {
+				sumq += (v = AFSK26_AMPL(i)*window[l*AFSK26_RXOVER+o]*
+					 sin(M_PI*k/32768.0));
+                                fprintf(f, "%6d%s", v, l ? ", " : " }}");
+			}
                         if (i < 1)
                                 fprintf(f, ",");
-                        fprintf(f, "\n");
+                        fprintf(f, "\n#define AFSK26_DEM_SUM_I_%d_%d %d\n"
+				"#define AFSK26_DEM_SUM_Q_%d_%d %d\n", 
+				AFSK26_RXOVER-1-o, i, sumi, AFSK26_RXOVER-1-o, i, sumq);
                 }
                 fprintf(f, "\t}%s\n", o ? "," : "");
         }
@@ -308,28 +340,6 @@
 
 /* -------------------------------------------------------------------- */
 
-#define COSTABBITS 8
-
-static void gentbl_costab(FILE *f)
-{
-        int i;
-
-	fprintf(f, "\n/*\n * more accurate cosine table\n */\n\n"
-		"static const short costab[%d] = {", (1<<COSTABBITS));
-        for (i = 0; i < (1<<COSTABBITS); i++) {
-                if (!(i & 7))
-                        fprintf(f, "\n\t");
-                fprintf(f, "%6d", (int)(32767.0*cos(i*2.0*M_PI/(1<<COSTABBITS))));
-                if (i != ((1<<COSTABBITS)-1))
-                        fprintf(f, ", ");
-        }
-        fprintf(f, "\n};\n\n#define COS(x) costab[((x)>>%d)&0x%x]\n"
-		"#define SIN(x) COS((x)+0xc000)\n\n", 16-COSTABBITS,
-		(1<<COSTABBITS)-1);
-}
-
-/* -------------------------------------------------------------------- */
-
 #define ATAN_TABLEN 1024
 
 static void gentbl_atantab(FILE *f)
@@ -578,6 +588,85 @@
 
 /* -------------------------------------------------------------------- */
 
+#define AFSK24_SAMPLERATE  16000
+#define AFSK24_CORRLEN     14
+
+static void gentbl_afsk2400(FILE *f, float tcm3105clk)
+{
+	int i, sum, v;
+	float fsum, fv;
+
+	fprintf(f, "\n/*\n * afsk2400 specific tables (tcm3105 clk %7fHz)\n */\n"
+		"#define AFSK24_TX_FREQ_LO %d\n"
+		"#define AFSK24_TX_FREQ_HI %d\n"
+		"#define AFSK24_BITPLL_INC %d\n"
+		"#define AFSK24_SAMPLERATE %d\n\n", tcm3105clk, 
+		(int)(tcm3105clk/3694.0), (int)(tcm3105clk/2015.0), 
+		0x10000*2400/AFSK24_SAMPLERATE, AFSK24_SAMPLERATE);
+
+#define ARGLO(x) 2.0*M_PI*(double)x*(tcm3105clk/3694.0)/(double)AFSK24_SAMPLERATE
+#define ARGHI(x) 2.0*M_PI*(double)x*(tcm3105clk/2015.0)/(double)AFSK24_SAMPLERATE
+#define WINDOW(x) hamming((float)(x)/(AFSK24_CORRLEN-1.0))
+
+	fprintf(f, "#if defined(CONFIG_SOUNDMODEM_FLOAT) && "
+		"(defined(CONFIG_M586) || defined(CONFIG_M686))\n\n"
+		"static const float afsk24_tx_lo_i_f[] = {\n\t");
+        for(fsum = i = 0; i < AFSK24_CORRLEN; i++) {
+		fsum += (fv = cos(ARGLO(i))*WINDOW(i));
+                fprintf(f, " %7f%c", fv, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+	}
+        fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_Q %7f\n\n"
+		"static const float afsk24_tx_lo_q_f[] = {\n\t", fsum);
+        for(fsum = i = 0; i < AFSK24_CORRLEN; i++) {
+		fsum += (fv = sin(ARGLO(i))*WINDOW(i));
+                fprintf(f, " %7f%c", fv, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+	}
+        fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_Q %7f\n\n"
+		"static const float afsk24_tx_hi_i_f[] = {\n\t", fsum);
+        for(fsum = i = 0; i < AFSK24_CORRLEN; i++) {
+		fsum += (fv = cos(ARGHI(i))*WINDOW(i));
+                fprintf(f, " %7f%c", fv, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+	}
+        fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_I %7f\n\n"
+		"static const float afsk24_tx_hi_q_f[] = {\n\t", fsum);
+        for(fsum = i = 0; i < AFSK24_CORRLEN; i++) {
+		fsum += (fv = sin(ARGHI(i))*WINDOW(i));
+                fprintf(f, " %7f%c", fv, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+	}
+	fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_Q %7f\n\n"
+		"#else /* CONFIG_SOUNDMODEM_FLOAT */\n\n"
+		"static const int afsk24_tx_lo_i[] = {\n\t", fsum);
+        for(sum = i = 0; i < AFSK24_CORRLEN; i++) {
+		sum += (v = 127.0*cos(ARGLO(i))*WINDOW(i));
+                fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+	}
+        fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_I %d\n\n"
+		"static const int afsk24_tx_lo_q[] = {\n\t", sum);
+        for(sum = i = 0; i < AFSK24_CORRLEN; i++) {
+		sum += (v = 127.0*sin(ARGLO(i))*WINDOW(i)); 
+                fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+	}
+        fprintf(f, "\n};\n#define SUM_AFSK24_TX_LO_Q %d\n\n"
+		"static const int afsk24_tx_hi_i[] = {\n\t", sum);
+        for(sum = i = 0; i < AFSK24_CORRLEN; i++) {
+		sum += (v = 127.0*cos(ARGHI(i))*WINDOW(i)); 
+                fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+	}
+        fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_I %d\n\n"
+		"static const int afsk24_tx_hi_q[] = {\n\t", sum);
+        for(sum = i = 0; i < AFSK24_CORRLEN; i++)  {
+		sum += (v = 127.0*sin(ARGHI(i))*WINDOW(i));
+                fprintf(f, " %4i%c", v, (i < AFSK24_CORRLEN-1) ? ',' : ' ');
+	}
+	fprintf(f, "\n};\n#define SUM_AFSK24_TX_HI_Q %d\n\n"
+		"#endif /* CONFIG_SOUNDMODEM_FLOAT */\n\n", sum);
+#undef ARGLO
+#undef ARGHI
+#undef WINDOW
+}
+
+/* -------------------------------------------------------------------- */
+
 static char *progname;
 
 static void gentbl_banner(FILE *f)
@@ -586,6 +675,11 @@
 		"DO NOT EDIT!\n */\n\n", progname);
 }
 
+static void gentbl_needs_config(FILE *f)
+{
+	fprintf(f, "\n#include <linux/config.h>\n\n");
+}
+
 /* -------------------------------------------------------------------- */
 
 void main(int argc, char *argv[])
@@ -596,20 +690,23 @@
 	if (!(f = fopen("sm_tbl_afsk1200.h", "w")))
 		exit(1);
 	gentbl_banner(f);
-	gentbl_offscostab(f);
+	gentbl_needs_config(f);
+	gentbl_offscostab(f, 6);
+	gentbl_costab(f, 6);
 	gentbl_afsk1200(f);
 	fclose(f);
 	if (!(f = fopen("sm_tbl_afsk2666.h", "w")))
 		exit(1);
 	gentbl_banner(f);
-	gentbl_offscostab(f);
+	gentbl_offscostab(f, 6);
+	gentbl_costab(f, 6);
 	gentbl_afsk2666(f);
 	fclose(f);
 	if (!(f = fopen("sm_tbl_psk4800.h", "w")))
 		exit(1);
 	gentbl_banner(f);
 	gentbl_psk4800(f);
-	gentbl_costab(f);
+	gentbl_costab(f, 8);
 	gentbl_atantab(f);
 	fclose(f);
 	if (!(f = fopen("sm_tbl_hapn4800.h", "w")))
@@ -621,6 +718,22 @@
 		exit(1);
 	gentbl_banner(f);
 	gentbl_fsk9600(f);
+	fclose(f);
+	if (!(f = fopen("sm_tbl_afsk2400_8.h", "w")))
+		exit(1);
+	gentbl_banner(f);
+	gentbl_needs_config(f);
+	gentbl_offscostab(f, 6);
+	gentbl_costab(f, 6);
+	gentbl_afsk2400(f, 8000000);
+	fclose(f);
+	if (!(f = fopen("sm_tbl_afsk2400_7.h", "w")))
+		exit(1);
+	gentbl_banner(f);
+	gentbl_needs_config(f);
+	gentbl_offscostab(f, 6);
+	gentbl_costab(f, 6);
+	gentbl_afsk2400(f, 7372800);
 	fclose(f);
 	exit(0);
 }
diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm.c linux/drivers/net/soundmodem/sm.c
--- v2.1.42/linux/drivers/net/soundmodem/sm.c	Thu May 29 21:53:07 1997
+++ linux/drivers/net/soundmodem/sm.c	Thu Jun 12 16:22:07 1997
@@ -38,6 +38,7 @@
  *        18.10.96  Changed to new user space access routines (copy_{to,from}_user)
  *   0.4  21.01.97  Separately compileable soundcard/modem modules
  *   0.5  03.03.97  fixed LPT probing (check_lpt result was interpreted the wrong way round)
+ *   0.6  16.04.97  init code/data tagged
  */
 
 /*****************************************************************************/
@@ -56,7 +57,6 @@
 #include <asm/bitops.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
-#include <linux/init.h>
 #include "sm.h"
 
 /* --------------------------------------------------------------------- */
@@ -101,18 +101,32 @@
 }
 #endif
 
+#if LINUX_VERSION_CODE >= 0x20123
+#include <linux/init.h>
+#else
+#define __init
+#define __initdata
+#define __initfunc(x) x
+#endif
+
 /* --------------------------------------------------------------------- */
 
-const char sm_drvname[] = "soundmodem";
-static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996 Thomas Sailer, HB9JNX/AE4WA\n"
-KERN_INFO "soundmodem: version 0.5 compiled " __TIME__ " " __DATE__ "\n";
+/*static*/ const char sm_drvname[] = "soundmodem";
+static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-1997 Thomas Sailer, HB9JNX/AE4WA\n"
+KERN_INFO "soundmodem: version 0.6 compiled " __TIME__ " " __DATE__ "\n";
 
 /* --------------------------------------------------------------------- */
 
-const struct modem_tx_info *sm_modem_tx_table[] = {
+/*static*/ const struct modem_tx_info *sm_modem_tx_table[] = {
 #ifdef CONFIG_SOUNDMODEM_AFSK1200
 	&sm_afsk1200_tx,
 #endif /* CONFIG_SOUNDMODEM_AFSK1200 */
+#ifdef CONFIG_SOUNDMODEM_AFSK2400_7
+	&sm_afsk2400_7_tx,
+#endif /* CONFIG_SOUNDMODEM_AFSK2400_7 */
+#ifdef CONFIG_SOUNDMODEM_AFSK2400_8
+	&sm_afsk2400_8_tx,
+#endif /* CONFIG_SOUNDMODEM_AFSK2400_8 */
 #ifdef CONFIG_SOUNDMODEM_AFSK2666
 	&sm_afsk2666_tx,
 #endif /* CONFIG_SOUNDMODEM_AFSK2666 */
@@ -132,10 +146,16 @@
 	NULL
 };
 
-const struct modem_rx_info *sm_modem_rx_table[] = {
+/*static*/ const struct modem_rx_info *sm_modem_rx_table[] = {
 #ifdef CONFIG_SOUNDMODEM_AFSK1200
 	&sm_afsk1200_rx,
 #endif /* CONFIG_SOUNDMODEM_AFSK1200 */
+#ifdef CONFIG_SOUNDMODEM_AFSK2400_7
+	&sm_afsk2400_7_rx,
+#endif /* CONFIG_SOUNDMODEM_AFSK2400_7 */
+#ifdef CONFIG_SOUNDMODEM_AFSK2400_8
+	&sm_afsk2400_8_rx,
+#endif /* CONFIG_SOUNDMODEM_AFSK2400_8 */
 #ifdef CONFIG_SOUNDMODEM_AFSK2666
 	&sm_afsk2666_rx,
 #endif /* CONFIG_SOUNDMODEM_AFSK2666 */
@@ -344,7 +364,7 @@
 	int invert_dcd = 0;
 	int invert_ptt = 0;
 
-	int ptt = hdlcdrv_ptt(&sm->hdrv) ^ invert_ptt;
+	int ptt = /*hdlcdrv_ptt(&sm->hdrv)*/(sm->dma.ptt_cnt > 0) ^ invert_ptt;
 	int dcd = (!!sm->hdrv.hdlcrx.dcd) ^ invert_dcd;
 
 	if (sm->hdrv.ptt_out.flags & SP_SER) {
@@ -457,9 +477,9 @@
 		return err;
 	sm_output_open(sm);
 	MOD_INC_USE_COUNT;
-	printk(KERN_INFO "%s: %s mode %s.%s at iobase 0x%lx irq %u dma %u\n",
+	printk(KERN_INFO "%s: %s mode %s.%s at iobase 0x%lx irq %u dma %u dma2 %u\n",
 	       sm_drvname, sm->hwdrv->hw_name, sm->mode_tx->name,
-	       sm->mode_rx->name, dev->base_addr, dev->irq, dev->dma);
+	       sm->mode_rx->name, dev->base_addr, dev->irq, dev->dma, sm->hdrv.ptt_out.dma2);
 	return 0;
 }
 
@@ -664,7 +684,56 @@
 
 /* --------------------------------------------------------------------- */
 
+#ifdef __i386__
+
+int sm_x86_capability = 0;
+
+__initfunc(static void i386_capability(void))
+{
+	unsigned long flags;
+	unsigned long fl1;
+	union {
+		struct {
+			unsigned int ebx, edx, ecx;
+		} r;
+		unsigned char s[13];
+	} id;
+	unsigned int eax;
+
+	save_flags(flags);
+	flags |= 0x200000;
+	restore_flags(flags);
+	save_flags(flags);
+	fl1 = flags;
+	flags &= ~0x200000;
+	restore_flags(flags);
+	save_flags(flags);
+	if (!(fl1 & 0x200000) || (flags & 0x200000)) {
+		printk(KERN_WARNING "%s: cpu does not support CPUID\n", sm_drvname);
+		return;
+	}
+	__asm__ ("cpuid" : "=a" (eax), "=b" (id.r.ebx), "=c" (id.r.ecx), "=d" (id.r.edx) :
+		 "0" (0));
+	id.s[12] = 0;
+	if (eax < 1) {
+		printk(KERN_WARNING "%s: cpu (vendor string %s) does not support capability "
+		       "list\n", sm_drvname, id.s);
+		return;
+	}
+	printk(KERN_INFO "%s: cpu: vendor string %s ", sm_drvname, id.s);
+	__asm__ ("cpuid" : "=a" (eax), "=d" (sm_x86_capability) : "0" (1) : "ebx", "ecx");
+	printk("fam %d mdl %d step %d cap 0x%x\n", (eax >> 8) & 15, (eax >> 4) & 15,
+	       eax & 15, sm_x86_capability);
+}	
+#endif /* __i386__ */	
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+__initfunc(static int sm_init(void))
+#else /* MODULE */
 __initfunc(int sm_init(void))
+#endif /* MODULE */
 {
 	int i, j, found = 0;
 	char set_hw = 1;
@@ -672,6 +741,9 @@
 	char ifname[HDLCDRV_IFNAMELEN];
 
 	printk(sm_drvinfo);
+#ifdef __i386__
+	i386_capability();
+#endif /* __i386__ */	
 	/*
 	 * register net devices
 	 */
@@ -745,7 +817,7 @@
 
 #endif
 
-int init_module(void)
+__initfunc(int init_module(void))
 {
 	if (mode) {
 		if (iobase == -1)
diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm.h linux/drivers/net/soundmodem/sm.h
--- v2.1.42/linux/drivers/net/soundmodem/sm.h	Thu May 29 21:53:07 1997
+++ linux/drivers/net/soundmodem/sm.h	Thu Jun 12 16:22:07 1997
@@ -30,16 +30,11 @@
 
 /* ---------------------------------------------------------------------- */
 
-#include <linux/config.h>
 #include <linux/hdlcdrv.h>
 #include <linux/soundmodem.h>
 
 #define SM_DEBUG
 
-/* --------------------------------------------------------------------- */
-
-#define DMA_MODE_AUTOINIT      0x10
-
 /* ---------------------------------------------------------------------- */
 /*
  * Information that need to be kept for each board.
@@ -56,6 +51,18 @@
 	/*
 	 * Hardware (soundcard) access routines state
 	 */
+	struct {
+		void *ibuf;
+		unsigned int ifragsz;
+		unsigned int ifragptr;
+		unsigned int i16bit;
+		void *obuf;
+		unsigned int ofragsz;
+		unsigned int ofragptr;
+		unsigned int o16bit;
+		int ptt_cnt;
+	} dma;
+
 	union {
 		long hw[32/sizeof(long)];
 	} hw;
@@ -101,9 +108,9 @@
 	unsigned int loc_storage;
 	int srate;
 	int bitrate;
-	unsigned int dmabuflenmodulo;
-	void (*modulator)(struct sm_state *, unsigned char *, int);
-	void (*init)(struct sm_state *);
+        void (*modulator_u8)(struct sm_state *, unsigned char *, unsigned int);
+        void (*modulator_s16)(struct sm_state *, short *, unsigned int);
+        void (*init)(struct sm_state *);
 };
 
 struct modem_rx_info {
@@ -111,10 +118,11 @@
 	unsigned int loc_storage;
 	int srate;
 	int bitrate;
-	unsigned int dmabuflenmodulo;
+	unsigned int overlap;
 	unsigned int sperbit;
-	void (*demodulator)(struct sm_state *, unsigned char *, int);
-	void (*init)(struct sm_state *);
+        void (*demodulator_u8)(struct sm_state *, const unsigned char *, unsigned int);
+        void (*demodulator_s16)(struct sm_state *, const short *, unsigned int);
+        void (*init)(struct sm_state *);
 };
 
 /* ---------------------------------------------------------------------- */
@@ -281,30 +289,41 @@
  */
 
 
-#if defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686))
+#ifdef __i386__
+
+extern int sm_x86_capability;
+
+#define HAS_RDTSC (sm_x86_capability & 0x10)
 
 /*
  * only do 32bit cycle counter arithmetic; we hope we won't overflow :-)
  * in fact, overflowing modems would require over 2THz clock speeds :-)
  */
 
-#define time_exec(var,cmd)                                      \
-({                                                              \
-	unsigned int cnt1, cnt2, cnt3;                          \
-	__asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3));  \
-	cmd;                                                    \
-	__asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt3));  \
-	var = cnt2-cnt1;                                        \
+#define time_exec(var,cmd)                                              \
+({                                                                      \
+	if (HAS_RDTSC) {                                                \
+		unsigned int cnt1, cnt2, cnt3;                          \
+		__asm__(".byte 0x0f,0x31" : "=a" (cnt1), "=d" (cnt3));  \
+		cmd;                                                    \
+		__asm__(".byte 0x0f,0x31" : "=a" (cnt2), "=d" (cnt3));  \
+		var = cnt2-cnt1;                                        \
+	} else {                                                        \
+		cmd;                                                    \
+	}                                                               \
 })
-#else /* defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */
+
+#else /* __i386__ */
 
 #define time_exec(var,cmd) cmd
 
-#endif /* defined(SM_DEBUG) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */
+#endif /* __i386__ */
 
 /* --------------------------------------------------------------------- */
 
 extern const struct modem_tx_info sm_afsk1200_tx;
+extern const struct modem_tx_info sm_afsk2400_7_tx;
+extern const struct modem_tx_info sm_afsk2400_8_tx;
 extern const struct modem_tx_info sm_afsk2666_tx;
 extern const struct modem_tx_info sm_psk4800_tx;
 extern const struct modem_tx_info sm_hapn4800_8_tx;
@@ -315,6 +334,8 @@
 extern const struct modem_tx_info sm_fsk9600_5_tx;
 
 extern const struct modem_rx_info sm_afsk1200_rx;
+extern const struct modem_rx_info sm_afsk2400_7_rx;
+extern const struct modem_rx_info sm_afsk2400_8_rx;
 extern const struct modem_rx_info sm_afsk2666_rx;
 extern const struct modem_rx_info sm_psk4800_rx;
 extern const struct modem_rx_info sm_hapn4800_8_rx;
diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_afsk1200.c linux/drivers/net/soundmodem/sm_afsk1200.c
--- v2.1.42/linux/drivers/net/soundmodem/sm_afsk1200.c	Thu May 29 21:53:07 1997
+++ linux/drivers/net/soundmodem/sm_afsk1200.c	Thu Jun 12 16:22:07 1997
@@ -38,174 +38,176 @@
 	int dcd_sum0, dcd_sum1, dcd_sum2;
 	unsigned int dcd_time;
 	unsigned char last_rxbit;
-	union {
-		signed char c[8];
-		float f[8];
-	} filt;
 };
 
 struct mod_state_afsk12 {
 	unsigned int shreg;
 	unsigned char tx_bit;
 	unsigned int bit_pll;
+	unsigned int dds_inc;
+	unsigned int txphase;
 };
 
 /* --------------------------------------------------------------------- */
 
-static void modulator_1200(struct sm_state *sm, unsigned char *buf, int buflen)
+static const int dds_inc[2] = { 
+	AFSK12_TX_FREQ_LO*0x10000/AFSK12_SAMPLE_RATE,
+	AFSK12_TX_FREQ_HI*0x10000/AFSK12_SAMPLE_RATE 
+};
+
+static void modulator_1200_u8(struct sm_state *sm, unsigned char *buf, 
+			      unsigned int buflen)
 {
 	struct mod_state_afsk12 *st = (struct mod_state_afsk12 *)(&sm->m);
-	static const int dds_inc[2] = { AFSK12_TX_FREQ_LO*0x10000/AFSK12_SAMPLE_RATE,
-					AFSK12_TX_FREQ_HI*0x10000/AFSK12_SAMPLE_RATE };
-	int j, k;
-
-	for (; buflen >= 8; buflen -= 8) {
-		if (st->shreg <= 1)
-			st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
-		st->tx_bit = (st->tx_bit ^ 
-				       (!(st->shreg & 1))) & 1;
-		st->shreg >>= 1;
-		k = dds_inc[st->tx_bit & 1];
-		for (j = 0; j < 8; j++) {
-			*buf++ = OFFSCOS(st->bit_pll);
-			st->bit_pll += k;
+
+	for (; buflen > 0; buflen--) {
+		if (!((st->txphase++) & 7)) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
+			st->shreg >>= 1;
 		}
+		st->dds_inc = dds_inc[st->tx_bit & 1];
+		*buf++ = OFFSCOS(st->bit_pll);
+		st->bit_pll += st->dds_inc;
 	}
 }
 
 /* --------------------------------------------------------------------- */
 
+static void modulator_1200_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+	struct mod_state_afsk12 *st = (struct mod_state_afsk12 *)(&sm->m);
 
-/*
- * should eventually move to an asm header file
- */
-
-
-#if defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686))
-
-
-
-#define ENV_STORAGE unsigned char fpu_save[108];
-
-#define ENV_SAVE asm("fsave %0;\n\tfninit;\n\t" : "=m" (*fpu_save) : : "memory");
-#define ENV_RESTORE asm("frstor %0;\n\t" : : "m" (*fpu_save));
-
-static inline float convolution8(const float *st, const float *coeff)
-{
-	float f;
-
-	/*
-	 * from Phil Karn, KA9Q's home page
-	 */
-	asm volatile ("flds (%1);\n\t"
-	    "fmuls (%2);\n\t"
-	    "flds 4(%1);\n\t"
-	    "fmuls 4(%2);\n\t"
-	    "flds 8(%1);\n\t"
-	    "fmuls 8(%2);\n\t"
-	    "fxch %%st(2);\n\t"
-	    "faddp;\n\t"
-	    "flds 12(%1);\n\t"
-	    "fmuls 12(%2);\n\t"
-	    "fxch %%st(2);\n\t"
-	    "faddp;\n\t"
-	    "flds 16(%1);\n\t"
-	    "fmuls 16(%2);\n\t"
-	    "fxch %%st(2);\n\t"
-	    "faddp;\n\t"
-	    "flds 20(%1);\n\t"
-	    "fmuls 20(%2);\n\t"
-	    "fxch %%st(2);\n\t"
-	    "faddp;\n\t"
-	    "flds 24(%1);\n\t"
-	    "fmuls 24(%2);\n\t"
-	    "fxch %%st(2);\n\t"
-	    "faddp;\n\t"
-	    "flds 28(%1);\n\t"
-	    "fmuls 28(%2);\n\t"
-	    "fxch %%st(2);\n\t"
-	    "faddp;\n\t"
-	    "faddp;\n\t"
-	    "fmul %%st(0),%%st;\n\t" :
-	    "=t" (f) :
-	    "r" (st),
-	    "r" (coeff) : "memory");
-
-	return f;
-}
-
-static inline int do_filter_1200(struct demod_state_afsk12 *st, unsigned char newval)
-{
-	float sum;
-
-	memmove(st->filt.f+1, st->filt.f,sizeof(st->filt.f) - sizeof(st->filt.f[0]));
-	st->filt.f[0] = (((int)newval)-0x80);
-
-	sum = convolution8(st->filt.f, afsk12_tx_lo_i_f);
-	sum += convolution8(st->filt.f, afsk12_tx_lo_q_f);
-	sum -= convolution8(st->filt.f, afsk12_tx_hi_i_f);
-	sum -= convolution8(st->filt.f, afsk12_tx_hi_q_f);
-	return sum;
+	for (; buflen > 0; buflen--) {
+		if (!((st->txphase++) & 7)) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
+			st->shreg >>= 1;
+		}
+		st->dds_inc = dds_inc[st->tx_bit & 1];
+		*buf++ = COS(st->bit_pll);
+		st->bit_pll += st->dds_inc;
+	}
 }
 
-#else /* defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */
-
-#define ENV_STORAGE 
-#define ENV_SAVE
-#define ENV_RESTORE
+/* --------------------------------------------------------------------- */
 
-static inline void datamove8(signed char *st, unsigned char newval)
+extern __inline__ int convolution8_u8(const unsigned char *st, const int *coeff, int csum)
 {
-	memmove(st+1, st, 7);
-	*st = newval - 0x80;
+	int sum = -0x80 * csum;
+	
+	sum += (st[0] * coeff[0]);
+	sum += (st[-1] * coeff[1]);
+	sum += (st[-2] * coeff[2]);
+	sum += (st[-3] * coeff[3]);
+	sum += (st[-4] * coeff[4]);
+	sum += (st[-5] * coeff[5]);
+	sum += (st[-6] * coeff[6]);
+	sum += (st[-7] * coeff[7]);
+
+	sum >>= 7;
+	return sum * sum;
 }
 
-static inline int convolution8(const signed char *st, const signed char *coeff)
+extern __inline__ int convolution8_s16(const short *st, const int *coeff, int csum)
 {
-	int sum = (st[0] * coeff[0]);
+	int sum = 0;
 	
-	sum += (st[1] * coeff[1]);
-	sum += (st[2] * coeff[2]);
-	sum += (st[3] * coeff[3]);
-	sum += (st[4] * coeff[4]);
-	sum += (st[5] * coeff[5]);
-	sum += (st[6] * coeff[6]);
-	sum += (st[7] * coeff[7]);
+	sum += (st[0] * coeff[0]);
+	sum += (st[-1] * coeff[1]);
+	sum += (st[-2] * coeff[2]);
+	sum += (st[-3] * coeff[3]);
+	sum += (st[-4] * coeff[4]);
+	sum += (st[-5] * coeff[5]);
+	sum += (st[-6] * coeff[6]);
+	sum += (st[-7] * coeff[7]);
 
-	sum >>= 7;
+	sum >>= 15;
 	return sum * sum;
 }
 
-static inline int do_filter_1200(struct demod_state_afsk12 *st, unsigned char newval)
+extern __inline__ int do_filter_1200_u8(const unsigned char *buf)
 {
-	int sum;
+	int sum = convolution8_u8(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I);
+	sum += convolution8_u8(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q);
+	sum -= convolution8_u8(buf, afsk12_tx_hi_i, SUM_AFSK12_TX_HI_I);
+	sum -= convolution8_u8(buf, afsk12_tx_hi_q, SUM_AFSK12_TX_HI_Q);
+	return sum;
+}
 
-	datamove8(st->filt.c, newval);
-	
-	sum = convolution8(st->filt.c, afsk12_tx_lo_i);
-	sum += convolution8(st->filt.c, afsk12_tx_lo_q);
-	sum -= convolution8(st->filt.c, afsk12_tx_hi_i);
-	sum -= convolution8(st->filt.c, afsk12_tx_hi_q);
+extern __inline__ int do_filter_1200_s16(const short *buf)
+{
+	int sum = convolution8_s16(buf, afsk12_tx_lo_i, SUM_AFSK12_TX_LO_I);
+	sum += convolution8_s16(buf, afsk12_tx_lo_q, SUM_AFSK12_TX_LO_Q);
+	sum -= convolution8_s16(buf, afsk12_tx_hi_i, SUM_AFSK12_TX_HI_I);
+	sum -= convolution8_s16(buf, afsk12_tx_hi_q, SUM_AFSK12_TX_HI_Q);
 	return sum;
 }
 
-#endif /* defined (CONFIG_SOUNDMODEM__AFSK1200_FP) && (defined(CONFIG_M586) || defined(CONFIG_M686)) */
+/* --------------------------------------------------------------------- */
 
+static const int pll_corr[2] = { -0x1000, 0x1000 };
+
+static void demodulator_1200_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
+{
+	struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d);
+	int j;
+	int sum;
+	unsigned char newsample;
+
+	for (; buflen > 0; buflen--, buf++) {
+		sum = do_filter_1200_u8(buf);
+		st->dcd_shreg <<= 1;
+		st->bit_pll += 0x2000;
+		newsample = (sum > 0);
+		if (st->last_sample ^ newsample) {
+			st->last_sample = newsample;
+			st->dcd_shreg |= 1;
+			st->bit_pll += pll_corr
+				[st->bit_pll < 0x9000];
+			j = 4 * hweight8(st->dcd_shreg & 0x38)
+				- hweight16(st->dcd_shreg & 0x7c0);
+			st->dcd_sum0 += j;
+		}
+		hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+		if ((--st->dcd_time) <= 0) {
+			hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + 
+						   st->dcd_sum1 + 
+						   st->dcd_sum2) < 0);
+			st->dcd_sum2 = st->dcd_sum1;
+			st->dcd_sum1 = st->dcd_sum0;
+			st->dcd_sum0 = 2; /* slight bias */
+			st->dcd_time = 120;
+		}
+		if (st->bit_pll >= 0x10000) {
+			st->bit_pll &= 0xffff;
+			st->shreg >>= 1;
+			st->shreg |= (!(st->last_rxbit ^
+					st->last_sample)) << 16;
+			st->last_rxbit = st->last_sample;
+			diag_trigger(sm);
+			if (st->shreg & 1) {
+				hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+				st->shreg = 0x10000;
+			}
+		}
+		diag_add(sm, (((int)*buf)-0x80) << 8, sum);
+	}
+}
 
 /* --------------------------------------------------------------------- */
 
-static void demodulator_1200(struct sm_state *sm, unsigned char *buf, int buflen)
+static void demodulator_1200_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
 {
 	struct demod_state_afsk12 *st = (struct demod_state_afsk12 *)(&sm->d);
-	static const int pll_corr[2] = { -0x1000, 0x1000 };
 	int j;
 	int sum;
 	unsigned char newsample;
-	ENV_STORAGE;
 
-	ENV_SAVE;
 	for (; buflen > 0; buflen--, buf++) {
-		sum = do_filter_1200(st, *buf);
+		sum = do_filter_1200_s16(buf);
 		st->dcd_shreg <<= 1;
 		st->bit_pll += 0x2000;
 		newsample = (sum > 0);
@@ -240,9 +242,8 @@
 				st->shreg = 0x10000;
 			}
 		}
-		diag_add(sm, (((int)*buf)-0x80) << 8, sum);
+		diag_add(sm, *buf, sum);
 	}
-	ENV_RESTORE;
 }
 
 /* --------------------------------------------------------------------- */
@@ -259,13 +260,13 @@
 
 const struct modem_tx_info sm_afsk1200_tx = {
 	"afsk1200", sizeof(struct mod_state_afsk12), 
-	AFSK12_SAMPLE_RATE, 1200, AFSK12_SAMPLE_RATE/1200, modulator_1200, NULL
+	AFSK12_SAMPLE_RATE, 1200, modulator_1200_u8, modulator_1200_s16, NULL
 };
 
 const struct modem_rx_info sm_afsk1200_rx = {
 	"afsk1200", sizeof(struct demod_state_afsk12), 
-	AFSK12_SAMPLE_RATE, 1200, AFSK12_SAMPLE_RATE/1200, 
-	AFSK12_SAMPLE_RATE/1200, demodulator_1200, demod_init_1200
+	AFSK12_SAMPLE_RATE, 1200, 8, AFSK12_SAMPLE_RATE/1200, 
+	demodulator_1200_u8, demodulator_1200_s16, demod_init_1200
 };
 
 /* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_afsk2400_7.c linux/drivers/net/soundmodem/sm_afsk2400_7.c
--- v2.1.42/linux/drivers/net/soundmodem/sm_afsk2400_7.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/soundmodem/sm_afsk2400_7.c	Thu Jun 12 16:22:07 1997
@@ -0,0 +1,297 @@
+/*****************************************************************************/
+
+/*
+ *	sm_afsk2400_7.c  -- soundcard radio modem driver, 2400 baud AFSK modem
+ *
+ *	Copyright (C) 1996  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Please note that the GPL allows you to use the driver, NOT the radio.
+ *  In order to use the radio, you need a license from the communications
+ *  authority of your country.
+ *
+ */
+
+/*
+ * This driver is intended to be compatible with TCM3105 modems
+ * overclocked to 7.3728MHz. The mark and space frequencies therefore
+ * lie at 3658 and 1996 Hz.
+ * Note that I do _not_ recommend the building of such links, I provide
+ * this only for the users who live in the coverage area of such
+ * a "legacy" link.
+ */
+
+#include <linux/config.h>
+#include "sm.h"
+#include "sm_tbl_afsk2400_7.h"
+
+/* --------------------------------------------------------------------- */
+
+struct demod_state_afsk24 {
+	unsigned int shreg;
+	unsigned int bit_pll;
+	unsigned char last_sample;
+	unsigned int dcd_shreg;
+	int dcd_sum0, dcd_sum1, dcd_sum2;
+	unsigned int dcd_time;
+	unsigned char last_rxbit;
+};
+
+struct mod_state_afsk24 {
+	unsigned int shreg;
+	unsigned char tx_bit;
+	unsigned int bit_pll;
+	unsigned int tx_seq;
+	unsigned int phinc;
+};
+
+/* --------------------------------------------------------------------- */
+
+static const int dds_inc[2] = { AFSK24_TX_FREQ_LO*0x10000/AFSK24_SAMPLERATE,
+				AFSK24_TX_FREQ_HI*0x10000/AFSK24_SAMPLERATE };
+
+static void modulator_2400_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
+{
+	struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m);
+
+	for (; buflen > 0; buflen--, buf++) {
+		if (st->tx_seq < 0x5555) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
+			st->shreg >>= 1;
+			st->phinc = dds_inc[st->tx_bit & 1];
+		}
+		st->tx_seq += 0x5555;
+		st->tx_seq &= 0xffff;
+		*buf = OFFSCOS(st->bit_pll);
+		st->bit_pll += st->phinc;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+	struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m);
+
+	for (; buflen > 0; buflen--, buf++) {
+		if (st->tx_seq < 0x5555) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
+			st->shreg >>= 1;
+			st->phinc = dds_inc[st->tx_bit & 1];
+		}
+		st->tx_seq += 0x5555;
+		st->tx_seq &= 0xffff;
+		*buf = COS(st->bit_pll);
+		st->bit_pll += st->phinc;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
+{
+	int sum = -0x80 * csum;
+	
+	sum += (st[0] * coeff[0]);
+	sum += (st[-1] * coeff[1]);
+	sum += (st[-2] * coeff[2]);
+	sum += (st[-3] * coeff[3]);
+	sum += (st[-4] * coeff[4]);
+	sum += (st[-5] * coeff[5]);
+	sum += (st[-6] * coeff[6]);
+	sum += (st[-7] * coeff[7]);
+	sum += (st[-8] * coeff[8]);
+	sum += (st[-9] * coeff[9]);
+	sum += (st[-10] * coeff[10]);
+	sum += (st[-11] * coeff[11]);
+	sum += (st[-12] * coeff[12]);
+	sum += (st[-13] * coeff[13]);
+
+	sum >>= 7;
+	return sum * sum;
+}
+
+extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
+{
+	int sum = 0;
+	
+	sum += (st[0] * coeff[0]);
+	sum += (st[-1] * coeff[1]);
+	sum += (st[-2] * coeff[2]);
+	sum += (st[-3] * coeff[3]);
+	sum += (st[-4] * coeff[4]);
+	sum += (st[-5] * coeff[5]);
+	sum += (st[-6] * coeff[6]);
+	sum += (st[-7] * coeff[7]);
+	sum += (st[-8] * coeff[8]);
+	sum += (st[-9] * coeff[9]);
+	sum += (st[-10] * coeff[10]);
+	sum += (st[-11] * coeff[11]);
+	sum += (st[-12] * coeff[12]);
+	sum += (st[-13] * coeff[13]);
+
+	sum >>= 15;
+	return sum * sum;
+}
+
+extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
+{
+	int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
+	sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
+	sum -= convolution14_u8(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I);
+	sum -= convolution14_u8(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q);
+	return sum;
+}
+
+extern __inline__ int do_filter_2400_s16(const short *buf)
+{
+	int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
+	sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
+	sum -= convolution14_s16(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I);
+	sum -= convolution14_s16(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q);
+	return sum;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_2400_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
+{
+	struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
+	int j;
+	int sum;
+	unsigned char newsample;
+
+	for (; buflen > 0; buflen--, buf++) {
+		sum = do_filter_2400_u8(buf);
+		st->dcd_shreg <<= 1;
+		st->bit_pll += AFSK24_BITPLL_INC;
+		newsample = (sum > 0);
+		if (st->last_sample ^ newsample) {
+			st->last_sample = newsample;
+			st->dcd_shreg |= 1;
+			if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2))
+				st->bit_pll += AFSK24_BITPLL_INC/2;
+			else
+				st->bit_pll -= AFSK24_BITPLL_INC/2;
+			j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c)
+				- hweight16(st->dcd_shreg & 0x1e0);
+			st->dcd_sum0 += j;
+		}
+		hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+		if ((--st->dcd_time) <= 0) {
+			hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + 
+						   st->dcd_sum1 + 
+						   st->dcd_sum2) < 0);
+			st->dcd_sum2 = st->dcd_sum1;
+			st->dcd_sum1 = st->dcd_sum0;
+			st->dcd_sum0 = 2; /* slight bias */
+			st->dcd_time = 120;
+		}
+		if (st->bit_pll >= 0x10000) {
+			st->bit_pll &= 0xffff;
+			st->shreg >>= 1;
+			st->shreg |= (!(st->last_rxbit ^
+					st->last_sample)) << 16;
+			st->last_rxbit = st->last_sample;
+			diag_trigger(sm);
+			if (st->shreg & 1) {
+				hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+				st->shreg = 0x10000;
+			}
+		}
+		diag_add(sm, (((int)*buf)-0x80) << 8, sum);
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_2400_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
+{
+	struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
+	int j;
+	int sum;
+	unsigned char newsample;
+
+	for (; buflen > 0; buflen--, buf++) {
+		sum = do_filter_2400_s16(buf);
+		st->dcd_shreg <<= 1;
+		st->bit_pll += AFSK24_BITPLL_INC;
+		newsample = (sum > 0);
+		if (st->last_sample ^ newsample) {
+			st->last_sample = newsample;
+			st->dcd_shreg |= 1;
+			if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2))
+				st->bit_pll += AFSK24_BITPLL_INC/2;
+			else
+				st->bit_pll -= AFSK24_BITPLL_INC/2;
+			j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c)
+				- hweight16(st->dcd_shreg & 0x1e0);
+			st->dcd_sum0 += j;
+		}
+		hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+		if ((--st->dcd_time) <= 0) {
+			hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + 
+						   st->dcd_sum1 + 
+						   st->dcd_sum2) < 0);
+			st->dcd_sum2 = st->dcd_sum1;
+			st->dcd_sum1 = st->dcd_sum0;
+			st->dcd_sum0 = 2; /* slight bias */
+			st->dcd_time = 120;
+		}
+		if (st->bit_pll >= 0x10000) {
+			st->bit_pll &= 0xffff;
+			st->shreg >>= 1;
+			st->shreg |= (!(st->last_rxbit ^
+					st->last_sample)) << 16;
+			st->last_rxbit = st->last_sample;
+			diag_trigger(sm);
+			if (st->shreg & 1) {
+				hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+				st->shreg = 0x10000;
+			}
+		}
+		diag_add(sm, *buf, sum);
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demod_init_2400(struct sm_state *sm)
+{
+	struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
+
+       	st->dcd_time = 120;
+	st->dcd_sum0 = 2;
+}
+
+/* --------------------------------------------------------------------- */
+
+const struct modem_tx_info sm_afsk2400_7_tx = {
+	"afsk2400_7", sizeof(struct mod_state_afsk24), AFSK24_SAMPLERATE, 2400, 
+	modulator_2400_u8, modulator_2400_s16, NULL
+};
+
+const struct modem_rx_info sm_afsk2400_7_rx = {
+	"afsk2400_7", sizeof(struct demod_state_afsk24), 
+	AFSK24_SAMPLERATE, 2400, 14, AFSK24_SAMPLERATE/2400, 
+	demodulator_2400_u8, demodulator_2400_s16, demod_init_2400
+};
+
+/* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_afsk2400_8.c linux/drivers/net/soundmodem/sm_afsk2400_8.c
--- v2.1.42/linux/drivers/net/soundmodem/sm_afsk2400_8.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/soundmodem/sm_afsk2400_8.c	Thu Jun 12 16:22:07 1997
@@ -0,0 +1,297 @@
+/*****************************************************************************/
+
+/*
+ *	sm_afsk2400_8.c  -- soundcard radio modem driver, 2400 baud AFSK modem
+ *
+ *	Copyright (C) 1996  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Please note that the GPL allows you to use the driver, NOT the radio.
+ *  In order to use the radio, you need a license from the communications
+ *  authority of your country.
+ *
+ */
+
+/*
+ * This driver is intended to be compatible with TCM3105 modems
+ * overclocked to 8MHz. The mark and space frequencies therefore
+ * lie at 3970 and 2165 Hz.
+ * Note that I do _not_ recommend the building of such links, I provide
+ * this only for the users who live in the coverage area of such
+ * a "legacy" link.
+ */
+
+#include <linux/config.h>
+#include "sm.h"
+#include "sm_tbl_afsk2400_8.h"
+
+/* --------------------------------------------------------------------- */
+
+struct demod_state_afsk24 {
+	unsigned int shreg;
+	unsigned int bit_pll;
+	unsigned char last_sample;
+	unsigned int dcd_shreg;
+	int dcd_sum0, dcd_sum1, dcd_sum2;
+	unsigned int dcd_time;
+	unsigned char last_rxbit;
+};
+
+struct mod_state_afsk24 {
+	unsigned int shreg;
+	unsigned char tx_bit;
+	unsigned int bit_pll;
+	unsigned int tx_seq;
+	unsigned int phinc;
+};
+
+/* --------------------------------------------------------------------- */
+
+static const int dds_inc[2] = { AFSK24_TX_FREQ_LO*0x10000/AFSK24_SAMPLERATE,
+				AFSK24_TX_FREQ_HI*0x10000/AFSK24_SAMPLERATE };
+
+static void modulator_2400_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
+{
+	struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m);
+
+	for (; buflen > 0; buflen--, buf++) {
+		if (st->tx_seq < 0x5555) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
+			st->shreg >>= 1;
+			st->phinc = dds_inc[st->tx_bit & 1];
+		}
+		st->tx_seq += 0x5555;
+		st->tx_seq &= 0xffff;
+		*buf = OFFSCOS(st->bit_pll);
+		st->bit_pll += st->phinc;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_2400_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+	struct mod_state_afsk24 *st = (struct mod_state_afsk24 *)(&sm->m);
+
+	for (; buflen > 0; buflen--, buf++) {
+		if (st->tx_seq < 0x5555) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = (st->tx_bit ^ (!(st->shreg & 1))) & 1;
+			st->shreg >>= 1;
+			st->phinc = dds_inc[st->tx_bit & 1];
+		}
+		st->tx_seq += 0x5555;
+		st->tx_seq &= 0xffff;
+		*buf = COS(st->bit_pll);
+		st->bit_pll += st->phinc;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ int convolution14_u8(const unsigned char *st, const int *coeff, int csum)
+{
+	int sum = -0x80 * csum;
+	
+	sum += (st[0] * coeff[0]);
+	sum += (st[-1] * coeff[1]);
+	sum += (st[-2] * coeff[2]);
+	sum += (st[-3] * coeff[3]);
+	sum += (st[-4] * coeff[4]);
+	sum += (st[-5] * coeff[5]);
+	sum += (st[-6] * coeff[6]);
+	sum += (st[-7] * coeff[7]);
+	sum += (st[-8] * coeff[8]);
+	sum += (st[-9] * coeff[9]);
+	sum += (st[-10] * coeff[10]);
+	sum += (st[-11] * coeff[11]);
+	sum += (st[-12] * coeff[12]);
+	sum += (st[-13] * coeff[13]);
+
+	sum >>= 7;
+	return sum * sum;
+}
+
+extern __inline__ int convolution14_s16(const short *st, const int *coeff, int csum)
+{
+	int sum = 0;
+	
+	sum += (st[0] * coeff[0]);
+	sum += (st[-1] * coeff[1]);
+	sum += (st[-2] * coeff[2]);
+	sum += (st[-3] * coeff[3]);
+	sum += (st[-4] * coeff[4]);
+	sum += (st[-5] * coeff[5]);
+	sum += (st[-6] * coeff[6]);
+	sum += (st[-7] * coeff[7]);
+	sum += (st[-8] * coeff[8]);
+	sum += (st[-9] * coeff[9]);
+	sum += (st[-10] * coeff[10]);
+	sum += (st[-11] * coeff[11]);
+	sum += (st[-12] * coeff[12]);
+	sum += (st[-13] * coeff[13]);
+
+	sum >>= 15;
+	return sum * sum;
+}
+
+extern __inline__ int do_filter_2400_u8(const unsigned char *buf)
+{
+	int sum = convolution14_u8(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
+	sum += convolution14_u8(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
+	sum -= convolution14_u8(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I);
+	sum -= convolution14_u8(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q);
+	return sum;
+}
+
+extern __inline__ int do_filter_2400_s16(const short *buf)
+{
+	int sum = convolution14_s16(buf, afsk24_tx_lo_i, SUM_AFSK24_TX_LO_I);
+	sum += convolution14_s16(buf, afsk24_tx_lo_q, SUM_AFSK24_TX_LO_Q);
+	sum -= convolution14_s16(buf, afsk24_tx_hi_i, SUM_AFSK24_TX_HI_I);
+	sum -= convolution14_s16(buf, afsk24_tx_hi_q, SUM_AFSK24_TX_HI_Q);
+	return sum;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_2400_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
+{
+	struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
+	int j;
+	int sum;
+	unsigned char newsample;
+
+	for (; buflen > 0; buflen--, buf++) {
+		sum = do_filter_2400_u8(buf);
+		st->dcd_shreg <<= 1;
+		st->bit_pll += AFSK24_BITPLL_INC;
+		newsample = (sum > 0);
+		if (st->last_sample ^ newsample) {
+			st->last_sample = newsample;
+			st->dcd_shreg |= 1;
+			if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2))
+				st->bit_pll += AFSK24_BITPLL_INC/2;
+			else
+				st->bit_pll -= AFSK24_BITPLL_INC/2;
+			j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c)
+				- hweight16(st->dcd_shreg & 0x1e0);
+			st->dcd_sum0 += j;
+		}
+		hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+		if ((--st->dcd_time) <= 0) {
+			hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + 
+						   st->dcd_sum1 + 
+						   st->dcd_sum2) < 0);
+			st->dcd_sum2 = st->dcd_sum1;
+			st->dcd_sum1 = st->dcd_sum0;
+			st->dcd_sum0 = 2; /* slight bias */
+			st->dcd_time = 120;
+		}
+		if (st->bit_pll >= 0x10000) {
+			st->bit_pll &= 0xffff;
+			st->shreg >>= 1;
+			st->shreg |= (!(st->last_rxbit ^
+					st->last_sample)) << 16;
+			st->last_rxbit = st->last_sample;
+			diag_trigger(sm);
+			if (st->shreg & 1) {
+				hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+				st->shreg = 0x10000;
+			}
+		}
+		diag_add(sm, (((int)*buf)-0x80) << 8, sum);
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_2400_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
+{
+	struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
+	int j;
+	int sum;
+	unsigned char newsample;
+
+	for (; buflen > 0; buflen--, buf++) {
+		sum = do_filter_2400_s16(buf);
+		st->dcd_shreg <<= 1;
+		st->bit_pll += AFSK24_BITPLL_INC;
+		newsample = (sum > 0);
+		if (st->last_sample ^ newsample) {
+			st->last_sample = newsample;
+			st->dcd_shreg |= 1;
+			if (st->bit_pll < (0x8000+AFSK24_BITPLL_INC/2))
+				st->bit_pll += AFSK24_BITPLL_INC/2;
+			else
+				st->bit_pll -= AFSK24_BITPLL_INC/2;
+			j = /* 2 * */ hweight8(st->dcd_shreg & 0x1c)
+				- hweight16(st->dcd_shreg & 0x1e0);
+			st->dcd_sum0 += j;
+		}
+		hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+		if ((--st->dcd_time) <= 0) {
+			hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + 
+						   st->dcd_sum1 + 
+						   st->dcd_sum2) < 0);
+			st->dcd_sum2 = st->dcd_sum1;
+			st->dcd_sum1 = st->dcd_sum0;
+			st->dcd_sum0 = 2; /* slight bias */
+			st->dcd_time = 120;
+		}
+		if (st->bit_pll >= 0x10000) {
+			st->bit_pll &= 0xffff;
+			st->shreg >>= 1;
+			st->shreg |= (!(st->last_rxbit ^
+					st->last_sample)) << 16;
+			st->last_rxbit = st->last_sample;
+			diag_trigger(sm);
+			if (st->shreg & 1) {
+				hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+				st->shreg = 0x10000;
+			}
+		}
+		diag_add(sm, *buf, sum);
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demod_init_2400(struct sm_state *sm)
+{
+	struct demod_state_afsk24 *st = (struct demod_state_afsk24 *)(&sm->d);
+
+       	st->dcd_time = 120;
+	st->dcd_sum0 = 2;
+}
+
+/* --------------------------------------------------------------------- */
+
+const struct modem_tx_info sm_afsk2400_8_tx = {
+	"afsk2400_8", sizeof(struct mod_state_afsk24), AFSK24_SAMPLERATE, 2400, 
+	modulator_2400_u8, modulator_2400_s16, NULL
+};
+
+const struct modem_rx_info sm_afsk2400_8_rx = {
+	"afsk2400_8", sizeof(struct demod_state_afsk24), 
+	AFSK24_SAMPLERATE, 2400, 14, AFSK24_SAMPLERATE/2400, 
+	demodulator_2400_u8, demodulator_2400_s16, demod_init_2400
+};
+
+/* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_fsk9600.c linux/drivers/net/soundmodem/sm_fsk9600.c
--- v2.1.42/linux/drivers/net/soundmodem/sm_fsk9600.c	Thu May 29 21:53:07 1997
+++ linux/drivers/net/soundmodem/sm_fsk9600.c	Thu Jun 12 16:22:07 1997
@@ -45,6 +45,8 @@
 	unsigned int shreg;
 	unsigned long scram;
 	unsigned char tx_bit;
+	unsigned char *txtbl;
+	unsigned int txphase;
 };
 
 /* --------------------------------------------------------------------- */
@@ -62,30 +64,57 @@
 
 /* --------------------------------------------------------------------- */
 
-static void modulator_9600_4(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_9600_4_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
 {
 	struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m);
-	int j;
-	const unsigned char *cp;
 
-	for (; buflen >= 4; buflen -= 4) {
-		if (st->shreg <= 1)
-			st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
-		st->scram = (st->scram << 1) | (st->scram & 1);
-		st->scram ^= !(st->shreg & 1);
-		st->shreg >>= 1;
-		if (st->scram & (SCRAM_TAP1 << 1))
-			st->scram ^= SCRAM_TAPN << 1;
-		st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2)));
-		cp = fsk96_txfilt_4 + (st->tx_bit & 0xff);
-		for (j = 0; j < 4; j++, cp += 0x100)
-			*buf++ = *cp;
+	for (; buflen > 0; buflen--) {
+		if (!st->txphase++) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->scram = (st->scram << 1) | (st->scram & 1);
+			st->scram ^= !(st->shreg & 1);
+			st->shreg >>= 1;
+			if (st->scram & (SCRAM_TAP1 << 1))
+				st->scram ^= SCRAM_TAPN << 1;
+			st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2)));
+			st->txtbl = fsk96_txfilt_4 + (st->tx_bit & 0xff);
+		}
+		if (st->txphase >= 4)
+			st->txphase = 0;
+		*buf++ = *st->txtbl;
+		st->txtbl += 0x100;
 	}
 }
 
 /* --------------------------------------------------------------------- */
 
-static void demodulator_9600_4(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_9600_4_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+	struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m);
+
+	for (; buflen > 0; buflen--) {
+		if (!st->txphase++) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->scram = (st->scram << 1) | (st->scram & 1);
+			st->scram ^= !(st->shreg & 1);
+			st->shreg >>= 1;
+			if (st->scram & (SCRAM_TAP1 << 1))
+				st->scram ^= SCRAM_TAPN << 1;
+			st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2)));
+			st->txtbl = fsk96_txfilt_4 + (st->tx_bit & 0xff);
+		}
+		if (st->txphase >= 4)
+			st->txphase = 0;
+		*buf++ = ((*st->txtbl)-0x80) << 8;
+		st->txtbl += 0x100;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_9600_4_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
 {
 	struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d);
 	static const int pll_corr[2] = { -0x1000, 0x1000 };
@@ -133,30 +162,105 @@
 
 /* --------------------------------------------------------------------- */
 
-static void modulator_9600_5(struct sm_state *sm, unsigned char *buf, int buflen)
+static void demodulator_9600_4_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
+{
+	struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d);
+	static const int pll_corr[2] = { -0x1000, 0x1000 };
+	unsigned char curbit;
+	unsigned int descx;
+
+	for (; buflen > 0; buflen--, buf++) {
+		st->dcd_shreg <<= 1;
+		st->bit_pll += 0x4000;
+		curbit = (*buf >= 0);
+		if (st->last_sample ^ curbit) {
+			st->dcd_shreg |= 1;
+			st->bit_pll += pll_corr[st->bit_pll < 0xa000];
+			st->dcd_sum0 += 8 * hweight8(st->dcd_shreg & 0x0c) - 
+				!!(st->dcd_shreg & 0x10);
+		}
+		st->last_sample = curbit;
+		hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+		if ((--st->dcd_time) <= 0) {
+			hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + 
+						   st->dcd_sum1 + 
+						   st->dcd_sum2) < 0);
+			st->dcd_sum2 = st->dcd_sum1;
+			st->dcd_sum1 = st->dcd_sum0;
+			st->dcd_sum0 = 2; /* slight bias */
+			st->dcd_time = 240;
+		}
+		if (st->bit_pll >= 0x10000) {
+			st->bit_pll &= 0xffff;
+			st->descram = (st->descram << 1) | curbit;
+			descx = st->descram ^ (st->descram >> 1);
+			descx ^= ((descx >> DESCRAM_TAPSH1) ^
+				  (descx >> DESCRAM_TAPSH2));
+			st->shreg >>= 1;
+			st->shreg |= (!(descx & 1)) << 16;
+			if (st->shreg & 1) {
+				hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+				st->shreg = 0x10000;
+			}
+			diag_trigger(sm);
+		}
+		diag_add_one(sm, *buf);
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_9600_5_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
 {
 	struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m);
-	int j;
-	const unsigned char *cp;
 
-	for (; buflen >= 5; buflen -= 5) {
-		if (st->shreg <= 1)
-			st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
-		st->scram = (st->scram << 1) | (st->scram & 1);
-		st->scram ^= !(st->shreg & 1);
-		st->shreg >>= 1;
-		if (st->scram & (SCRAM_TAP1 << 1))
-			st->scram ^= SCRAM_TAPN << 1;
-		st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2)));
-		cp = fsk96_txfilt_5 + (st->tx_bit & 0xff);
-		for (j = 0; j < 5; j++, cp += 0x100)
-			*buf++ = *cp;
+	for (; buflen > 0; buflen--) {
+		if (!st->txphase++) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->scram = (st->scram << 1) | (st->scram & 1);
+			st->scram ^= !(st->shreg & 1);
+			st->shreg >>= 1;
+			if (st->scram & (SCRAM_TAP1 << 1))
+				st->scram ^= SCRAM_TAPN << 1;
+			st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2)));
+			st->txtbl = fsk96_txfilt_5 + (st->tx_bit & 0xff);
+		}
+		if (st->txphase >= 5)
+			st->txphase = 0;
+		*buf++ = *st->txtbl;
+		st->txtbl += 0x100;
 	}
 }
 
 /* --------------------------------------------------------------------- */
 
-static void demodulator_9600_5(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_9600_5_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+	struct mod_state_fsk96 *st = (struct mod_state_fsk96 *)(&sm->m);
+
+	for (; buflen > 0; buflen--) {
+		if (!st->txphase++) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->scram = (st->scram << 1) | (st->scram & 1);
+			st->scram ^= !(st->shreg & 1);
+			st->shreg >>= 1;
+			if (st->scram & (SCRAM_TAP1 << 1))
+				st->scram ^= SCRAM_TAPN << 1;
+			st->tx_bit = (st->tx_bit << 1) | (!!(st->scram & (SCRAM_TAP1 << 2)));
+			st->txtbl = fsk96_txfilt_5 + (st->tx_bit & 0xff);
+		}
+		if (st->txphase >= 5)
+			st->txphase = 0;
+		*buf++ = ((*st->txtbl)-0x80)<<8;
+		st->txtbl += 0x100;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_9600_5_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
 {
 	struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d);
 	static const int pll_corr[2] = { -0x1000, 0x1000 };
@@ -204,6 +308,54 @@
 
 /* --------------------------------------------------------------------- */
 
+static void demodulator_9600_5_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
+{
+	struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d);
+	static const int pll_corr[2] = { -0x1000, 0x1000 };
+	unsigned char curbit;
+	unsigned int descx;
+
+	for (; buflen > 0; buflen--, buf++) {
+		st->dcd_shreg <<= 1;
+		st->bit_pll += 0x3333;
+		curbit = (*buf >= 0);
+		if (st->last_sample ^ curbit) {
+			st->dcd_shreg |= 1;
+			st->bit_pll += pll_corr[st->bit_pll < 0x9999];
+			st->dcd_sum0 += 16 * hweight8(st->dcd_shreg & 0x0c) - 
+				hweight8(st->dcd_shreg & 0x70);
+		}
+		st->last_sample = curbit;
+		hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
+		if ((--st->dcd_time) <= 0) {
+			hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + 
+						   st->dcd_sum1 + 
+						   st->dcd_sum2) < 0);
+			st->dcd_sum2 = st->dcd_sum1;
+			st->dcd_sum1 = st->dcd_sum0;
+			st->dcd_sum0 = 2; /* slight bias */
+			st->dcd_time = 240;
+		}
+		if (st->bit_pll >= 0x10000) {
+			st->bit_pll &= 0xffff;
+			st->descram = (st->descram << 1) | curbit;
+			descx = st->descram ^ (st->descram >> 1);
+			descx ^= ((descx >> DESCRAM_TAPSH1) ^
+				  (descx >> DESCRAM_TAPSH2));
+			st->shreg >>= 1;
+			st->shreg |= (!(descx & 1)) << 16;
+			if (st->shreg & 1) {
+				hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+				st->shreg = 0x10000;
+			}
+			diag_trigger(sm);
+		}
+		diag_add_one(sm, *buf);
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
 static void demod_init_9600(struct sm_state *sm)
 {
 	struct demod_state_fsk96 *st = (struct demod_state_fsk96 *)(&sm->d);
@@ -215,25 +367,25 @@
 /* --------------------------------------------------------------------- */
 
 const struct modem_tx_info sm_fsk9600_4_tx = {
-	"fsk9600", sizeof(struct mod_state_fsk96), 38400, 9600, 4,
-	modulator_9600_4, NULL
+	"fsk9600", sizeof(struct mod_state_fsk96), 38400, 9600,
+	modulator_9600_4_u8, modulator_9600_4_s16, NULL
 };
 
 const struct modem_rx_info sm_fsk9600_4_rx = {
-	"fsk9600", sizeof(struct demod_state_fsk96), 38400, 9600, 4, 4,
-	demodulator_9600_4, demod_init_9600
+	"fsk9600", sizeof(struct demod_state_fsk96), 38400, 9600, 1, 4,
+	demodulator_9600_4_u8, demodulator_9600_4_s16, demod_init_9600
 };
 
 /* --------------------------------------------------------------------- */
 
 const struct modem_tx_info sm_fsk9600_5_tx = {
-	"fsk9600", sizeof(struct mod_state_fsk96), 48000, 9600, 5, 
-	modulator_9600_5, NULL
+	"fsk9600", sizeof(struct mod_state_fsk96), 48000, 9600,
+	modulator_9600_5_u8, modulator_9600_5_s16, NULL
 };
 
 const struct modem_rx_info sm_fsk9600_5_rx = {
-	"fsk9600", sizeof(struct demod_state_fsk96), 48000, 9600, 5, 5, 
-	demodulator_9600_5, demod_init_9600
+	"fsk9600", sizeof(struct demod_state_fsk96), 48000, 9600, 1, 5, 
+	demodulator_9600_5_u8, demodulator_9600_5_s16, demod_init_9600
 };
 
 /* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_hapn4800.c linux/drivers/net/soundmodem/sm_hapn4800.c
--- v2.1.42/linux/drivers/net/soundmodem/sm_hapn4800.c	Thu May 29 21:53:07 1997
+++ linux/drivers/net/soundmodem/sm_hapn4800.c	Thu Jun 12 16:22:07 1997
@@ -49,133 +49,290 @@
 	unsigned int dcd_shreg;
 	int dcd_sum0, dcd_sum1, dcd_sum2;
 	unsigned int dcd_time;
-	int inphist[5];
 	int lvlhi, lvllo;
 };
 
 struct mod_state_hapn48 {
 	unsigned int shreg;
 	unsigned char tx_bit;
+	unsigned int tx_seq;
+	const unsigned char *tbl;
 };
 
 /* --------------------------------------------------------------------- */
 
-static void modulator_hapn4800_10(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_hapn4800_10_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
 {
 	struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
-	int j;
-	const unsigned char *cp;
 
-	for (; buflen >= 10; buflen -= 10) {
-		if (st->shreg <= 1)
-			st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
-		st->tx_bit = ((st->tx_bit << 1) |
-				     (st->tx_bit & 1));
-		st->tx_bit ^= (!(st->shreg & 1));
-		st->shreg >>= 1;
-		cp = hapn48_txfilt_10 + (st->tx_bit & 0xf);
-		for (j = 0; j < 10; j++, cp += 0x10)
-			*buf++ = *cp;
+	for (; buflen > 0; buflen--, buf++) {
+		if (!st->tx_seq++) { 
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = ((st->tx_bit << 1) |
+				      (st->tx_bit & 1));
+			st->tx_bit ^= (!(st->shreg & 1));
+			st->shreg >>= 1;
+			st->tbl = hapn48_txfilt_10 + (st->tx_bit & 0xf);
+		}
+		if (st->tx_seq >= 10)
+			st->tx_seq = 0;
+		*buf = *st->tbl;
+		st->tbl += 0x10;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_hapn4800_10_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+	struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
+
+	for (; buflen > 0; buflen--, buf++) {
+		if (!st->tx_seq++) { 
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = ((st->tx_bit << 1) |
+				      (st->tx_bit & 1));
+			st->tx_bit ^= (!(st->shreg & 1));
+			st->shreg >>= 1;
+			st->tbl = hapn48_txfilt_10 + (st->tx_bit & 0xf);
+		}
+		if (st->tx_seq >= 10)
+			st->tx_seq = 0;
+		*buf = ((*st->tbl)-0x80)<<8;
+		st->tbl += 0x10;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_hapn4800_8_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
+{
+	struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
+
+	for (; buflen > 0; buflen--, buf++) {
+		if (!st->tx_seq++) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1);
+			st->tx_bit ^= !(st->shreg & 1);
+			st->shreg >>= 1;
+			st->tbl = hapn48_txfilt_8 + (st->tx_bit & 0xf);
+		}
+		if (st->tx_seq >= 8)
+			st->tx_seq = 0;
+		*buf = *st->tbl;
+		st->tbl += 0x10;
 	}
 }
 
 /* --------------------------------------------------------------------- */
 
-static void modulator_hapn4800_8(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_hapn4800_8_s16(struct sm_state *sm, short *buf, unsigned int buflen)
 {
 	struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
-	int j;
-	const unsigned char *cp;
 
-	for (; buflen >= 8; buflen -= 8) {
-		if (st->shreg <= 1)
-			st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
-		st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1);
-		st->tx_bit ^= !(st->shreg & 1);
-		st->shreg >>= 1;
-		cp = hapn48_txfilt_8 + (st->tx_bit & 0xf);
-		for (j = 0; j < 8; j++, cp += 0x10)
-			*buf++ = *cp;
+	for (; buflen > 0; buflen--, buf++) {
+		if (!st->tx_seq++) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1);
+			st->tx_bit ^= !(st->shreg & 1);
+			st->shreg >>= 1;
+			st->tbl = hapn48_txfilt_8 + (st->tx_bit & 0xf);
+		}
+		if (st->tx_seq >= 8)
+			st->tx_seq = 0;
+		*buf = ((*st->tbl)-0x80)<<8;
+		st->tbl += 0x10;
 	}
 }
 
 /* --------------------------------------------------------------------- */
 
-static void modulator_hapn4800_pm10(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_hapn4800_pm10_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
 {
 	struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
-	int j;
-	const unsigned char *cp;
 
-	for (; buflen >= 10; buflen -= 10) {
-		if (st->shreg <= 1)
-			st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
-		st->tx_bit = ((st->tx_bit << 1) |
-				     (st->tx_bit & 1));
-		st->tx_bit ^= (!(st->shreg & 1));
-		st->shreg >>= 1;
-		cp = hapn48_txfilt_pm10 + (st->tx_bit & 0xf);
-		for (j = 0; j < 10; j++, cp += 0x10)
-			*buf++ = *cp;
+	for (; buflen > 0; buflen--, buf++) {
+		if (!st->tx_seq++) { 
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = ((st->tx_bit << 1) |
+				      (st->tx_bit & 1));
+			st->tx_bit ^= (!(st->shreg & 1));
+			st->shreg >>= 1;
+			st->tbl = hapn48_txfilt_pm10 + (st->tx_bit & 0xf);
+		}
+		if (st->tx_seq >= 10)
+			st->tx_seq = 0;
+		*buf = *st->tbl;
+		st->tbl += 0x10;
 	}
 }
 
 /* --------------------------------------------------------------------- */
 
-static void modulator_hapn4800_pm8(struct sm_state *sm, unsigned char *buf, int buflen)
+static void modulator_hapn4800_pm10_s16(struct sm_state *sm, short *buf, unsigned int buflen)
 {
 	struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
-	int j;
-	const unsigned char *cp;
 
-	for (; buflen >= 8; buflen -= 8) {
-		if (st->shreg <= 1)
-			st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
-		st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1);
-		st->tx_bit ^= !(st->shreg & 1);
-		st->shreg >>= 1;
-		cp = hapn48_txfilt_pm8 + (st->tx_bit & 0xf);
-		for (j = 0; j < 8; j++, cp += 0x10)
-			*buf++ = *cp;
+	for (; buflen > 0; buflen--, buf++) {
+		if (!st->tx_seq++) { 
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = ((st->tx_bit << 1) |
+				      (st->tx_bit & 1));
+			st->tx_bit ^= (!(st->shreg & 1));
+			st->shreg >>= 1;
+			st->tbl = hapn48_txfilt_pm10 + (st->tx_bit & 0xf);
+		}
+		if (st->tx_seq >= 10)
+			st->tx_seq = 0;
+		*buf = ((*st->tbl)-0x80)<<8;
+		st->tbl += 0x10;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_hapn4800_pm8_u8(struct sm_state *sm, unsigned char *buf, unsigned int buflen)
+{
+	struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
+
+	for (; buflen > 0; buflen--, buf++) {
+		if (!st->tx_seq++) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1);
+			st->tx_bit ^= !(st->shreg & 1);
+			st->shreg >>= 1;
+			st->tbl = hapn48_txfilt_pm8 + (st->tx_bit & 0xf);
+		}
+		if (st->tx_seq >= 8)
+			st->tx_seq = 0;
+		*buf = *st->tbl;
+		st->tbl += 0x10;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void modulator_hapn4800_pm8_s16(struct sm_state *sm, short *buf, unsigned int buflen)
+{
+	struct mod_state_hapn48 *st = (struct mod_state_hapn48 *)(&sm->m);
+
+	for (; buflen > 0; buflen--, buf++) {
+		if (!st->tx_seq++) {
+			if (st->shreg <= 1)
+				st->shreg = hdlcdrv_getbits(&sm->hdrv) | 0x10000;
+			st->tx_bit = (st->tx_bit << 1) | (st->tx_bit & 1);
+			st->tx_bit ^= !(st->shreg & 1);
+			st->shreg >>= 1;
+			st->tbl = hapn48_txfilt_pm8 + (st->tx_bit & 0xf);
+		}
+		if (st->tx_seq >= 8)
+			st->tx_seq = 0;
+		*buf = ((*st->tbl)-0x80)<<8;
+		st->tbl += 0x10;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_hapn4800_10_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
+{
+	struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d);
+	static const int pll_corr[2] = { -0x800, 0x800 };
+	int curst, cursync;
+	int inv;
+
+	for (; buflen > 0; buflen--, buf++) {
+		inv = ((int)(buf[-2])-0x80) << 8;
+		st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */
+		st->lvllo = (st->lvllo * 65309) >> 16; /* decay */
+		if (inv > st->lvlhi)
+			st->lvlhi = inv;
+		if (inv < st->lvllo)
+			st->lvllo = inv;
+		if (buflen & 1)
+			st->dcd_shreg <<= 1;
+		st->bit_pll += 0x199a;
+		curst = cursync = 0;
+		if (inv > st->lvlhi >> 1) {
+			curst = 1;
+			cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] &&
+				   buf[-2] > buf[-0] && buf[-2] > buf[-4]);
+		} else if (inv < st->lvllo >> 1) {
+			curst = -1;
+			cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] &&
+				   buf[-2] < buf[-0] && buf[-2] < buf[-4]);
+		}
+		if (cursync) {
+			st->dcd_shreg |= cursync;
+			st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x8ccdu];
+			st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x18c6318c) - 
+				hweight32(st->dcd_shreg & 0xe739ce70);
+		}
+		hdlcdrv_channelbit(&sm->hdrv, cursync);
+		if ((--st->dcd_time) <= 0) {
+			hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + 
+						   st->dcd_sum1 + 
+						   st->dcd_sum2) < 0);
+			st->dcd_sum2 = st->dcd_sum1;
+			st->dcd_sum1 = st->dcd_sum0;
+			st->dcd_sum0 = 2; /* slight bias */
+			st->dcd_time = 240;
+		}
+		if (st->bit_pll >= 0x10000) {
+			st->bit_pll &= 0xffff;
+			st->last_bit2 = st->last_bit;
+			if (curst < 0)
+				st->last_bit = 0;
+			else if (curst > 0)
+				st->last_bit = 1;
+			st->shreg >>= 1;
+			st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16;
+			if (st->shreg & 1) {
+				hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+				st->shreg = 0x10000;
+			}
+			diag_trigger(sm);
+		}
+		diag_add_one(sm, inv);
 	}
 }
 
 /* --------------------------------------------------------------------- */
 
-static void demodulator_hapn4800_10(struct sm_state *sm, unsigned char *buf, int buflen)
+static void demodulator_hapn4800_10_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
 {
 	struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d);
 	static const int pll_corr[2] = { -0x800, 0x800 };
 	int curst, cursync;
+	int inv;
 
 	for (; buflen > 0; buflen--, buf++) {
-		st->inphist[4] = st->inphist[3];
-		st->inphist[3] = st->inphist[2];
-		st->inphist[2] = st->inphist[1];
-		st->inphist[1] = st->inphist[0];
-		st->inphist[0] = ((int)(*buf)-0x80) << 8;
+		inv = buf[-2];
 		st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */
 		st->lvllo = (st->lvllo * 65309) >> 16; /* decay */
-		if (st->inphist[2] > st->lvlhi)
-			st->lvlhi = st->inphist[2];
-		if (st->inphist[2] < st->lvllo)
-			st->lvllo = st->inphist[2];
+		if (inv > st->lvlhi)
+			st->lvlhi = inv;
+		if (inv < st->lvllo)
+			st->lvllo = inv;
 		if (buflen & 1)
 			st->dcd_shreg <<= 1;
 		st->bit_pll += 0x199a;
 		curst = cursync = 0;
-		if (st->inphist[2] > st->lvlhi >> 1) {
+		if (inv > st->lvlhi >> 1) {
 			curst = 1;
-			cursync = (st->inphist[2] > st->inphist[1] &&
-				   st->inphist[2] > st->inphist[3] &&
-				   st->inphist[2] > st->inphist[0] &&
-				   st->inphist[2] > st->inphist[4]);
-		} else if (st->inphist[2] < st->lvllo >> 1) {
+			cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] &&
+				   buf[-2] > buf[-0] && buf[-2] > buf[-4]);
+		} else if (inv < st->lvllo >> 1) {
 			curst = -1;
-			cursync = (st->inphist[2] < st->inphist[1] &&
-				   st->inphist[2] < st->inphist[3] &&
-				   st->inphist[2] < st->inphist[0] &&
-				   st->inphist[2] < st->inphist[4]);
+			cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] &&
+				   buf[-2] < buf[-0] && buf[-2] < buf[-4]);
 		}
 		if (cursync) {
 			st->dcd_shreg |= cursync;
@@ -208,46 +365,104 @@
 			}
 			diag_trigger(sm);
 		}
-		diag_add_one(sm, st->inphist[2]);
+		diag_add_one(sm, inv);
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void demodulator_hapn4800_8_u8(struct sm_state *sm, const unsigned char *buf, unsigned int buflen)
+{
+	struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d);
+	static const int pll_corr[2] = { -0x800, 0x800 };
+	int curst, cursync;
+	int inv;
+
+	for (; buflen > 0; buflen--, buf++) {
+		inv = ((int)(buf[-2])-0x80) << 8;
+		st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */
+		st->lvllo = (st->lvllo * 65309) >> 16; /* decay */
+		if (inv > st->lvlhi)
+			st->lvlhi = inv;
+		if (inv < st->lvllo)
+			st->lvllo = inv;
+		if (buflen & 1)
+			st->dcd_shreg <<= 1;
+		st->bit_pll += 0x2000;
+		curst = cursync = 0;
+		if (inv > st->lvlhi >> 1) {
+			curst = 1;
+			cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] &&
+				   buf[-2] > buf[-0] && buf[-2] > buf[-4]);
+		} else if (inv < st->lvllo >> 1) {
+			curst = -1;
+			cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] &&
+				   buf[-2] < buf[-0] && buf[-2] < buf[-4]);
+		}
+		if (cursync) {
+			st->dcd_shreg |= cursync;
+			st->bit_pll += pll_corr[((st->bit_pll - 0x8000u) & 0xffffu) < 0x9000u];
+			st->dcd_sum0 += 16 * hweight32(st->dcd_shreg & 0x44444444) - 
+				hweight32(st->dcd_shreg & 0xbbbbbbbb);
+		}
+		hdlcdrv_channelbit(&sm->hdrv, cursync);
+		if ((--st->dcd_time) <= 0) {
+			hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 + 
+						   st->dcd_sum1 + 
+						   st->dcd_sum2) < 0);
+			st->dcd_sum2 = st->dcd_sum1;
+			st->dcd_sum1 = st->dcd_sum0;
+			st->dcd_sum0 = 2; /* slight bias */
+			st->dcd_time = 240;
+		}
+		if (st->bit_pll >= 0x10000) {
+			st->bit_pll &= 0xffff;
+			st->last_bit2 = st->last_bit;
+			if (curst < 0)
+				st->last_bit = 0;
+			else if (curst > 0)
+				st->last_bit = 1;
+			st->shreg >>= 1;
+			st->shreg |= ((st->last_bit ^ st->last_bit2 ^ 1) & 1) << 16;
+			if (st->shreg & 1) {
+				hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
+				st->shreg = 0x10000;
+			}
+			diag_trigger(sm);
+		}
+		diag_add_one(sm, inv);
 	}
 }
 
 /* --------------------------------------------------------------------- */
 
-static void demodulator_hapn4800_8(struct sm_state *sm, unsigned char *buf, int buflen)
+static void demodulator_hapn4800_8_s16(struct sm_state *sm, const short *buf, unsigned int buflen)
 {
 	struct demod_state_hapn48 *st = (struct demod_state_hapn48 *)(&sm->d);
 	static const int pll_corr[2] = { -0x800, 0x800 };
 	int curst, cursync;
+	int inv;
 
 	for (; buflen > 0; buflen--, buf++) {
-		st->inphist[4] = st->inphist[3];
-		st->inphist[3] = st->inphist[2];
-		st->inphist[2] = st->inphist[1];
-		st->inphist[1] = st->inphist[0];
-		st->inphist[0] = ((int)(*buf)-0x80) << 8;
+		inv = buf[-2];
 		st->lvlhi = (st->lvlhi * 65309) >> 16; /* decay */
 		st->lvllo = (st->lvllo * 65309) >> 16; /* decay */
-		if (st->inphist[2] > st->lvlhi)
-			st->lvlhi = st->inphist[2];
-		if (st->inphist[2] < st->lvllo)
-			st->lvllo = st->inphist[2];
+		if (inv > st->lvlhi)
+			st->lvlhi = inv;
+		if (inv < st->lvllo)
+			st->lvllo = inv;
 		if (buflen & 1)
 			st->dcd_shreg <<= 1;
 		st->bit_pll += 0x2000;
 		curst = cursync = 0;
-		if (st->inphist[2] > st->lvlhi >> 1) {
+		if (inv > st->lvlhi >> 1) {
 			curst = 1;
-			cursync = (st->inphist[2] > st->inphist[1] &&
-				   st->inphist[2] > st->inphist[3] &&
-				   st->inphist[2] > st->inphist[0] &&
-				   st->inphist[2] > st->inphist[4]);
-		} else if (st->inphist[2] < st->lvllo >> 1) {
+			cursync = (buf[-2] > buf[-1] && buf[-2] > buf[-3] &&
+				   buf[-2] > buf[-0] && buf[-2] > buf[-4]);
+		} else if (inv < st->lvllo >> 1) {
 			curst = -1;
-			cursync = (st->inphist[2] < st->inphist[1] &&
-				   st->inphist[2] < st->inphist[3] &&
-				   st->inphist[2] < st->inphist[0] &&
-				   st->inphist[2] < st->inphist[4]);
+			cursync = (buf[-2] < buf[-1] && buf[-2] < buf[-3] &&
+				   buf[-2] < buf[-0] && buf[-2] < buf[-4]);
 		}
 		if (cursync) {
 			st->dcd_shreg |= cursync;
@@ -280,7 +495,7 @@
 			}
 			diag_trigger(sm);
 		}
-		diag_add_one(sm, st->inphist[2]);
+		diag_add_one(sm, inv);
 	}
 }
 
@@ -297,51 +512,49 @@
 /* --------------------------------------------------------------------- */
 
 const struct modem_tx_info sm_hapn4800_8_tx = {
-	"hapn4800", sizeof(struct mod_state_hapn48), 
-	38400, 4800, 8, modulator_hapn4800_8, NULL
+	"hapn4800", sizeof(struct mod_state_hapn48), 38400, 4800, 
+	modulator_hapn4800_8_u8, modulator_hapn4800_8_s16, NULL
 };
 
 const struct modem_rx_info sm_hapn4800_8_rx = {
-	"hapn4800", sizeof(struct demod_state_hapn48), 
-	38400, 4800, 8, 8, demodulator_hapn4800_8, demod_init_hapn4800
+	"hapn4800", sizeof(struct demod_state_hapn48), 38400, 4800, 5, 8, 
+	demodulator_hapn4800_8_u8, demodulator_hapn4800_8_s16, demod_init_hapn4800
 };
 
 /* --------------------------------------------------------------------- */
 
 const struct modem_tx_info sm_hapn4800_10_tx = {
-	"hapn4800", sizeof(struct mod_state_hapn48), 
-	48000, 4800, 10, 
-	modulator_hapn4800_10, NULL
+	"hapn4800", sizeof(struct mod_state_hapn48), 48000, 4800,
+	modulator_hapn4800_10_u8, modulator_hapn4800_10_s16, NULL
 };
 
 const struct modem_rx_info sm_hapn4800_10_rx = {
-	"hapn4800", sizeof(struct demod_state_hapn48), 
-	48000, 4800, 10, 10, demodulator_hapn4800_10, demod_init_hapn4800
+	"hapn4800", sizeof(struct demod_state_hapn48), 48000, 4800, 5, 10, 
+	demodulator_hapn4800_10_u8, demodulator_hapn4800_10_s16, demod_init_hapn4800
 };
 
 /* --------------------------------------------------------------------- */
 
 const struct modem_tx_info sm_hapn4800_pm8_tx = {
-	"hapn4800pm", sizeof(struct mod_state_hapn48), 
-	38400, 4800, 8, modulator_hapn4800_pm8, NULL
+	"hapn4800pm", sizeof(struct mod_state_hapn48), 38400, 4800, 
+	modulator_hapn4800_pm8_u8, modulator_hapn4800_pm8_s16, NULL
 };
 
 const struct modem_rx_info sm_hapn4800_pm8_rx = {
-	"hapn4800pm", sizeof(struct demod_state_hapn48), 
-	38400, 4800, 8, 8, demodulator_hapn4800_8, demod_init_hapn4800
+	"hapn4800pm", sizeof(struct demod_state_hapn48), 38400, 4800, 5, 8, 
+	demodulator_hapn4800_8_u8, demodulator_hapn4800_8_s16, demod_init_hapn4800
 };
 
 /* --------------------------------------------------------------------- */
 
 const struct modem_tx_info sm_hapn4800_pm10_tx = {
-	"hapn4800pm", sizeof(struct mod_state_hapn48), 
-	48000, 4800, 10, 
-	modulator_hapn4800_pm10, NULL
+	"hapn4800pm", sizeof(struct mod_state_hapn48), 48000, 4800,
+	modulator_hapn4800_pm10_u8, modulator_hapn4800_pm10_s16, NULL
 };
 
 const struct modem_rx_info sm_hapn4800_pm10_rx = {
-	"hapn4800pm", sizeof(struct demod_state_hapn48), 
-	48000, 4800, 10, 10, demodulator_hapn4800_10, demod_init_hapn4800
+	"hapn4800pm", sizeof(struct demod_state_hapn48), 48000, 4800, 5, 10,
+	demodulator_hapn4800_10_u8, demodulator_hapn4800_10_s16, demod_init_hapn4800
 };
 
 /* --------------------------------------------------------------------- */
diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_sbc.c linux/drivers/net/soundmodem/sm_sbc.c
--- v2.1.42/linux/drivers/net/soundmodem/sm_sbc.c	Thu May 29 21:53:07 1997
+++ linux/drivers/net/soundmodem/sm_sbc.c	Thu Jun 12 16:22:07 1997
@@ -26,12 +26,14 @@
  */
 
 #include <linux/ptrace.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/ioport.h>
 #include <linux/soundmodem.h>
 #include "sm.h"
+#include "smdma.h"
 
 /* --------------------------------------------------------------------- */
 
@@ -81,12 +83,6 @@
 	unsigned char revhi, revlo;
 	unsigned char fmt[2];
 	unsigned int sr[2];
-	unsigned int dmabuflen;
-	unsigned char *dmabuf;
-	unsigned char *dmabuf2;
-	unsigned char dmabufidx;
-	unsigned char dma2bufidx;
-	unsigned char ptt;
 };
 
 #define SCSTATE ((struct sc_state_sbc *)(&sm->hw))
@@ -136,6 +132,7 @@
 #define SBC4_OUT8_AI           0xc6
 #define SBC4_IN8_AI            0xce
 #define SBC4_MODE_UNS_MONO     0x00
+#define SBC4_MODE_SIGN_MONO    0x10
 
 #define SBC4_OUT16_AI          0xb6
 #define SBC4_IN16_AI           0xbe
@@ -260,9 +257,8 @@
 	realdma = inb(DSP_MIXER_DATA(dev->base_addr));
 	restore_flags(flags);
 	if ((~realirq) & irqreg || (~realdma) & dmareg) {
-		printk(KERN_ERR "%s: sbc resource registers cannot be set; "
-		       "PnP device and IRQ/DMA specified wrongly?\n",
-		       sm_drvname);
+		printk(KERN_ERR "%s: sbc resource registers cannot be set; PnP device "
+		       "and IRQ/DMA specified wrongly?\n", sm_drvname);
 		return -EINVAL;
 	}
 	return 0;
@@ -292,41 +288,31 @@
 		{ SBC_HI_INPUT_AUTOINIT, SBC_HI_OUTPUT_AUTOINIT }
 	};
 	static const unsigned char sbc4mode[2] = { SBC4_IN8_AI, SBC4_OUT8_AI };
-        static const unsigned char dmamode[2] = { 
-		DMA_MODE_READ | DMA_MODE_AUTOINIT, DMA_MODE_WRITE  | DMA_MODE_AUTOINIT
-	};
 	static const unsigned char sbcskr[2] = { SBC_SPEAKER_OFF, SBC_SPEAKER_ON };
-	unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf);
+	unsigned int nsamps;
 
 	send = !!send;
         if (!reset_dsp(dev)) {
                 printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname);
                 return;
         }
-        if ((dmabufaddr & 0xffff) + SCSTATE->dmabuflen > 0x10000)
-                panic("sm: DMA buffer violates DMA boundary!");
         save_flags(flags);
         cli();
         sbc_int_ack_8bit(dev);
         write_dsp(dev, SBC_SAMPLE_RATE); /* set sampling rate */
         write_dsp(dev, SCSTATE->fmt[send]);
         write_dsp(dev, sbcskr[send]); 
-        disable_dma(dev->dma);
-        clear_dma_ff(dev->dma);
-        set_dma_mode(dev->dma, dmamode[send]);
-        set_dma_addr(dev->dma, dmabufaddr);
-        set_dma_count(dev->dma, SCSTATE->dmabuflen);
-        enable_dma(dev->dma);
+	nsamps = dma_setup(sm, send, dev->dma) - 1;
         sbc_int_ack_8bit(dev);
 	if (SCSTATE->revhi >= 4) {
 		write_dsp(dev, sbc4mode[send]);
 		write_dsp(dev, SBC4_MODE_UNS_MONO);
-		write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
-		write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+		write_dsp(dev, nsamps & 0xff);
+		write_dsp(dev, nsamps >> 8);
 	} else {
 		write_dsp(dev, SBC_BLOCKSIZE);
-		write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
-		write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+		write_dsp(dev, nsamps & 0xff);
+		write_dsp(dev, nsamps >> 8);
 		write_dsp(dev, sbcmode[SCSTATE->fmt[send] >= 180][send]);
 		/* hispeed mode if sample rate > 13kHz */
 	}
@@ -339,53 +325,41 @@
 {
 	struct device *dev = (struct device *)dev_id;
 	struct sm_state *sm = (struct sm_state *)dev->priv;
-	unsigned char new_ptt;
-	unsigned char *buf;
+	unsigned int curfrag;
 
 	if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC)
 		return;
-	new_ptt = hdlcdrv_ptt(&sm->hdrv);
+	cli();
  	sbc_int_ack_8bit(dev);
- 	buf = SCSTATE->dmabuf;
-	if (SCSTATE->dmabufidx)
-		buf += SCSTATE->dmabuflen/2;
-	SCSTATE->dmabufidx = !SCSTATE->dmabufidx;
+	disable_dma(dev->dma);
+	clear_dma_ff(dev->dma);
+	dma_ptr(sm, sm->dma.ptt_cnt > 0, dev->dma, &curfrag);
+	enable_dma(dev->dma);
 	sm_int_freq(sm);
 	sti();
-	if (new_ptt && !SCSTATE->ptt) {
-		/* starting to transmit */
-		disable_dma(dev->dma);
- 		SCSTATE->dmabufidx = 0;
-		time_exec(sm->debug_vals.demod_cyc, 
-			  sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2));
-		time_exec(sm->debug_vals.mod_cyc, 
-			  sm->mode_tx->modulator(sm, SCSTATE->dmabuf, 
-						 SCSTATE->dmabuflen/2));
- 		setup_dma_dsp(dev, sm, 1);
-		time_exec(sm->debug_vals.mod_cyc, 
-			  sm->mode_tx->modulator(sm, SCSTATE->dmabuf + 
-						 SCSTATE->dmabuflen/2,
-						 SCSTATE->dmabuflen/2));
-	} else if (SCSTATE->ptt == 1 && !new_ptt) {
+	if (sm->dma.ptt_cnt <= 0) {
+		dma_receive(sm, curfrag);
+		if (hdlcdrv_ptt(&sm->hdrv)) {
+			/* starting to transmit */
+			disable_dma(dev->dma);
+			dma_start_transmit(sm);
+			setup_dma_dsp(dev, sm, 1);
+			dma_transmit(sm);
+		}
+	} else if (dma_end_transmit(sm, curfrag)) {
 		/* stopping transmission */
 		disable_dma(dev->dma);
- 		SCSTATE->dmabufidx = 0;
+		sti();
+		dma_init_receive(sm);
 		setup_dma_dsp(dev, sm, 0);
-		SCSTATE->ptt = 0;
-	} else if (SCSTATE->ptt) {
-                SCSTATE->ptt--;
-		time_exec(sm->debug_vals.mod_cyc, 
-			  sm->mode_tx->modulator(sm, buf, SCSTATE->dmabuflen/2));
         } else {
-		time_exec(sm->debug_vals.demod_cyc, 
-			  sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2));
+		dma_transmit(sm);
 		hdlcdrv_arbitrate(dev, &sm->hdrv);
         }
-        if (new_ptt)
-                SCSTATE->ptt = 2;
 	sm_output_status(sm);
 	hdlcdrv_transmitter(dev, &sm->hdrv);
 	hdlcdrv_receiver(dev, &sm->hdrv);
+
 }
 
 /* --------------------------------------------------------------------- */
@@ -393,6 +367,7 @@
 static int sbc_open(struct device *dev, struct sm_state *sm) 
 {
 	int err;
+	unsigned int dmasz, u;
 
 	if (sizeof(sm->m) < sizeof(struct sc_state_sbc)) {
 		printk(KERN_ERR "sm sbc: sbc state too big: %d > %d\n", 
@@ -409,12 +384,17 @@
 	/*
 	 * check if a card is available
 	 */
-	if (!reset_dsp(dev))
+	if (!reset_dsp(dev)) {
+		printk(KERN_ERR "%s: sbc: no card at io address 0x%lx\n",
+		       sm_drvname, dev->base_addr);
 		return -ENODEV;
+	}
 	write_dsp(dev, SBC_GET_REVISION);
 	if (!read_dsp(dev, &SCSTATE->revhi) || 
 	    !read_dsp(dev, &SCSTATE->revlo))
 		return -ENODEV;
+	printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%d\n", sm_drvname, 
+	       SCSTATE->revhi, SCSTATE->revlo);
 	if (SCSTATE->revhi < 2) {
 		printk(KERN_ERR "%s: your card is an antiquity, at least DSP "
 		       "rev 2.00 required\n", sm_drvname);
@@ -435,9 +415,19 @@
 	/*
 	 * initialize some variables
 	 */
-	if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA)))
+	dma_init_receive(sm);
+	dmasz = (NUM_FRAGMENTS + 1) * sm->dma.ifragsz;
+	if (sm->dma.i16bit)
+		dmasz <<= 1;
+	u = NUM_FRAGMENTS * sm->dma.ofragsz;
+	if (sm->dma.o16bit)
+		u <<= 1;
+	if (u > dmasz)
+		dmasz = u;
+	if (!(sm->dma.ibuf = sm->dma.obuf = kmalloc(dmasz, GFP_KERNEL | GFP_DMA)))
 		return -ENOMEM;
-	SCSTATE->dmabufidx = SCSTATE->ptt = 0;
+	dma_init_transmit(sm);
+	dma_init_receive(sm);
 
 	memset(&sm->m, 0, sizeof(sm->m));
 	memset(&sm->d, 0, sizeof(sm->d));
@@ -447,13 +437,13 @@
 		sm->mode_rx->init(sm);
 
 	if (request_dma(dev->dma, sm->hwdrv->hw_name)) {
-		kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+		kfree_s(sm->dma.obuf, dmasz);
 		return -EBUSY;
 	}
 	if (request_irq(dev->irq, sbc_interrupt, SA_INTERRUPT, 
 			sm->hwdrv->hw_name, dev)) {
 		free_dma(dev->dma);
-		kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+		kfree_s(sm->dma.obuf, dmasz);
 		return -EBUSY;
 	}
 	request_region(dev->base_addr, SBC_EXTENT, sm->hwdrv->hw_name);
@@ -475,7 +465,7 @@
 	free_irq(dev->irq, dev);	
 	free_dma(dev->dma);	
 	release_region(dev->base_addr, SBC_EXTENT);
-	kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+	kfree(sm->dma.obuf);
 	return 0;
 }
 
@@ -486,7 +476,6 @@
 	char *cp = strchr(mode, '.');
 	const struct modem_tx_info **mtp = sm_modem_tx_table;
 	const struct modem_rx_info **mrp;
-	int dv;
 
 	if (!strcmp(mode, "off")) {
 		sm->mode_tx = NULL;
@@ -507,12 +496,16 @@
 			continue;
 		if ((*mtp)->srate < 5000 || (*mtp)->srate > 44100)
 			continue;
+		if (!(*mtp)->modulator_u8)
+			continue;
 		for (mrp = sm_modem_rx_table; *mrp; mrp++) {
 			if ((*mrp)->loc_storage > sizeof(sm->d)) {
 				printk(KERN_ERR "%s: insufficient storage for demodulator %s (%d)\n",
 				       sm_drvname, (*mrp)->name, (*mrp)->loc_storage);
 				continue;
 			}
+			if (!(*mrp)->demodulator_u8)
+				continue;
 			if ((*mrp)->name && !strcmp((*mrp)->name, cp) &&
 			    (*mrp)->srate >= 5000 && (*mrp)->srate <= 44100) {
 				sm->mode_tx = *mtp;
@@ -521,11 +514,11 @@
 							 sm->mode_rx->srate);
 				SCSTATE->fmt[1] = 256-((1000000L+sm->mode_tx->srate/2)/
 							 sm->mode_tx->srate);
-				dv = lcm(sm->mode_tx->dmabuflenmodulo, 
-					 sm->mode_rx->dmabuflenmodulo);
-				SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1;
-				SCSTATE->dmabuflen /= dv;
-				SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */
+				sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100;
+				sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100;
+				if (sm->dma.ifragsz < sm->mode_rx->overlap)
+					sm->dma.ifragsz = sm->mode_rx->overlap;
+				sm->dma.i16bit = sm->dma.o16bit = 0;
 				return 0;
 			}
 		}
@@ -633,50 +626,61 @@
 static void setup_dma_fdx_dsp(struct device *dev, struct sm_state *sm)
 {
         unsigned long flags;
-	unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf);
-	unsigned long dmabuf2addr = virt_to_bus(SCSTATE->dmabuf2);
+	unsigned int isamps, osamps;
 
         if (!reset_dsp(dev)) {
                 printk(KERN_ERR "%s: sbc: cannot reset sb dsp\n", sm_drvname);
                 return;
         }
-        if (((dmabufaddr & 0xffff) + SCSTATE->dmabuflen > 0x10000) ||
-	    ((dmabuf2addr & 0xffff) + 2*(SCSTATE->dmabuflen) > 0x10000))
-		panic("sm: DMA buffer violates DMA boundary!");
         save_flags(flags);
         cli();
         sbc_int_ack_8bit(dev);
         sbc_int_ack_16bit(dev);
 	/* should eventually change to set rates individually by SBC_SAMPLE_RATE_{IN/OUT} */
-        write_dsp(dev, SBC_SAMPLE_RATE); /* set sampling rate */
-        write_dsp(dev, SCSTATE->fmt[0]);
+	write_dsp(dev, SBC_SAMPLE_RATE_IN);
+	write_dsp(dev, SCSTATE->sr[0] >> 8);
+	write_dsp(dev, SCSTATE->sr[0] & 0xff);
+	write_dsp(dev, SBC_SAMPLE_RATE_OUT);
+	write_dsp(dev, SCSTATE->sr[1] >> 8);
+	write_dsp(dev, SCSTATE->sr[1] & 0xff);
         write_dsp(dev, SBC_SPEAKER_ON);
-	/*
-	 * DMA channel 1 (8bit) does input (capture),
-	 * DMA channel 2 (16bit) does output (playback)
-	 */
-        disable_dma(dev->dma);
-        disable_dma(sm->hdrv.ptt_out.dma2);
-        clear_dma_ff(dev->dma);
-        set_dma_mode(dev->dma, DMA_MODE_READ | DMA_MODE_AUTOINIT);
-        set_dma_addr(dev->dma, dmabufaddr);
-        set_dma_count(dev->dma, SCSTATE->dmabuflen);
-        clear_dma_ff(sm->hdrv.ptt_out.dma2);
-        set_dma_mode(sm->hdrv.ptt_out.dma2, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
-        set_dma_addr(sm->hdrv.ptt_out.dma2, dmabuf2addr);
-        set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen);
-        enable_dma(dev->dma);
-        enable_dma(sm->hdrv.ptt_out.dma2);
-        sbc_int_ack_8bit(dev);
-        sbc_int_ack_16bit(dev);
-	write_dsp(dev, SBC4_IN8_AI);
-	write_dsp(dev, SBC4_MODE_UNS_MONO);
-	write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
-	write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
-	write_dsp(dev, SBC4_OUT16_AI);
-	write_dsp(dev, SBC4_MODE_UNS_MONO);
-	write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
-	write_dsp(dev, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+	if (sm->dma.o16bit) {
+		/*
+		 * DMA channel 1 (8bit) does input (capture),
+		 * DMA channel 2 (16bit) does output (playback)
+		 */
+		isamps = dma_setup(sm, 0, dev->dma) - 1;
+		osamps = dma_setup(sm, 1, sm->hdrv.ptt_out.dma2) - 1;
+		sbc_int_ack_8bit(dev);
+		sbc_int_ack_16bit(dev);
+		write_dsp(dev, SBC4_IN8_AI);
+		write_dsp(dev, SBC4_MODE_UNS_MONO);
+		write_dsp(dev, isamps & 0xff);
+		write_dsp(dev, isamps >> 8);
+		write_dsp(dev, SBC4_OUT16_AI);
+		write_dsp(dev, SBC4_MODE_SIGN_MONO);
+		write_dsp(dev, osamps & 0xff);
+		write_dsp(dev, osamps >> 8);
+	} else {
+		/*
+		 * DMA channel 1 (8bit) does output (playback),
+		 * DMA channel 2 (16bit) does input (capture)
+		 */
+		isamps = dma_setup(sm, 0, sm->hdrv.ptt_out.dma2) - 1;
+		osamps = dma_setup(sm, 1, dev->dma) - 1;
+		sbc_int_ack_8bit(dev);
+		sbc_int_ack_16bit(dev);
+		write_dsp(dev, SBC4_OUT8_AI);
+		write_dsp(dev, SBC4_MODE_UNS_MONO);
+		write_dsp(dev, osamps & 0xff);
+		write_dsp(dev, osamps >> 8);
+		write_dsp(dev, SBC4_IN16_AI);
+		write_dsp(dev, SBC4_MODE_SIGN_MONO);
+		write_dsp(dev, isamps & 0xff);
+		write_dsp(dev, isamps >> 8);
+	}
+	dma_init_receive(sm);
+	dma_init_transmit(sm);
         restore_flags(flags);
 }
 
@@ -686,41 +690,58 @@
 {
 	struct device *dev = (struct device *)dev_id;
 	struct sm_state *sm = (struct sm_state *)dev->priv;
-	unsigned char *buf;
-	unsigned char *buf2;
-	unsigned char intsrc;
+	unsigned char intsrc, pbint = 0, captint = 0;
+	unsigned int ocfrag, icfrag;
+	unsigned long flags;
 
 	if (!dev || !sm || sm->hdrv.magic != HDLCDRV_MAGIC)
 		return;
-	buf = SCSTATE->dmabuf;
-	buf2 = SCSTATE->dmabuf2;
+	save_flags(flags);
+	cli();
 	outb(0x82, DSP_MIXER_ADDR(dev->base_addr));
 	intsrc = inb(DSP_MIXER_DATA(dev->base_addr));
 	if (intsrc & 0x01) {
 		sbc_int_ack_8bit(dev);
-		if (SCSTATE->dmabufidx)
-			buf += SCSTATE->dmabuflen/2;
-		SCSTATE->dmabufidx = !SCSTATE->dmabufidx;
+		if (sm->dma.o16bit) {
+			captint = 1;
+			disable_dma(dev->dma);
+			clear_dma_ff(dev->dma);
+			dma_ptr(sm, 0, dev->dma, &icfrag);
+			enable_dma(dev->dma);
+		} else {     
+			pbint = 1;
+			disable_dma(dev->dma);
+			clear_dma_ff(dev->dma);
+			dma_ptr(sm, 1, dev->dma, &ocfrag);
+			enable_dma(dev->dma);
+		}
 	}
 	if (intsrc & 0x02) {
 		sbc_int_ack_16bit(dev);
-		if (SCSTATE->dma2bufidx)
-			buf2 += SCSTATE->dmabuflen/2;
-		SCSTATE->dma2bufidx = !SCSTATE->dma2bufidx;
+		if (sm->dma.o16bit) {
+			pbint = 1;
+			disable_dma(sm->hdrv.ptt_out.dma2);
+			clear_dma_ff(sm->hdrv.ptt_out.dma2);
+			dma_ptr(sm, 1, sm->hdrv.ptt_out.dma2, &ocfrag);
+			enable_dma(sm->hdrv.ptt_out.dma2);
+		} else {
+			captint = 1;
+			disable_dma(sm->hdrv.ptt_out.dma2);
+			clear_dma_ff(sm->hdrv.ptt_out.dma2);
+			dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag);
+			enable_dma(sm->hdrv.ptt_out.dma2);
+		}
 	}
+	restore_flags(flags);
 	sm_int_freq(sm);
 	sti();
-	if (intsrc & 0x02) {
-		if ((SCSTATE->ptt = hdlcdrv_ptt(&sm->hdrv))) 
-			time_exec(sm->debug_vals.mod_cyc, 
-				  sm->mode_tx->modulator(sm, buf2, SCSTATE->dmabuflen/2));
-		else
-			time_exec(sm->debug_vals.mod_cyc, 
-				  memset(buf2, 0x80, SCSTATE->dmabuflen/2));
+	if (pbint) {
+		if (dma_end_transmit(sm, ocfrag))
+			dma_clear_transmit(sm);
+		dma_transmit(sm);
 	}
-	if (intsrc & 0x01) {
-		time_exec(sm->debug_vals.demod_cyc, 
-			  sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2));
+	if (captint) { 
+		dma_receive(sm, icfrag);
 		hdlcdrv_arbitrate(dev, &sm->hdrv);
 	}
 	sm_output_status(sm);
@@ -749,12 +770,17 @@
 	/*
 	 * check if a card is available
 	 */
-	if (!reset_dsp(dev))
+	if (!reset_dsp(dev)) {
+		printk(KERN_ERR "%s: sbc: no card at io address 0x%lx\n",
+		       sm_drvname, dev->base_addr);
 		return -ENODEV;
+	}
 	write_dsp(dev, SBC_GET_REVISION);
 	if (!read_dsp(dev, &SCSTATE->revhi) || 
 	    !read_dsp(dev, &SCSTATE->revlo))
 		return -ENODEV;
+	printk(KERN_INFO "%s: SoundBlaster DSP revision %d.%d\n", sm_drvname, 
+	       SCSTATE->revhi, SCSTATE->revlo);
 	if (SCSTATE->revhi < 4) {
 		printk(KERN_ERR "%s: at least DSP rev 4.00 required\n", sm_drvname);
 		return -ENODEV;
@@ -766,13 +792,14 @@
 	/*
 	 * initialize some variables
 	 */
-	if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA)))
+	if (!(sm->dma.ibuf = kmalloc(sm->dma.ifragsz * (NUM_FRAGMENTS+1), GFP_KERNEL | GFP_DMA)))
 		return -ENOMEM;
-	if (!(SCSTATE->dmabuf2 = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) {
-		kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+	if (!(sm->dma.obuf = kmalloc(sm->dma.ofragsz * NUM_FRAGMENTS, GFP_KERNEL | GFP_DMA))) {
+		kfree(sm->dma.ibuf);
 		return -ENOMEM;
 	}
-	SCSTATE->dmabufidx = SCSTATE->dma2bufidx = SCSTATE->ptt = 0;
+	dma_init_transmit(sm);
+	dma_init_receive(sm);
 
 	memset(&sm->m, 0, sizeof(sm->m));
 	memset(&sm->d, 0, sizeof(sm->d));
@@ -782,20 +809,20 @@
 		sm->mode_rx->init(sm);
 
 	if (request_dma(dev->dma, sm->hwdrv->hw_name)) {
-		kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
-		kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+		kfree(sm->dma.ibuf);
+		kfree(sm->dma.obuf);
 		return -EBUSY;
 	}
 	if (request_dma(sm->hdrv.ptt_out.dma2, sm->hwdrv->hw_name)) {
-		kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
-		kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+		kfree(sm->dma.ibuf);
+		kfree(sm->dma.obuf);
 		free_dma(dev->dma);
 		return -EBUSY;
 	}
 	if (request_irq(dev->irq, sbcfdx_interrupt, SA_INTERRUPT, 
 			sm->hwdrv->hw_name, dev)) {
-		kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
-		kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+		kfree(sm->dma.ibuf);
+		kfree(sm->dma.obuf);
 		free_dma(dev->dma);
 		free_dma(sm->hdrv.ptt_out.dma2);
 		return -EBUSY;
@@ -821,8 +848,8 @@
 	free_dma(dev->dma);	
 	free_dma(sm->hdrv.ptt_out.dma2);	
 	release_region(dev->base_addr, SBC_EXTENT);
-	kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
-	kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+	kfree(sm->dma.ibuf);
+	kfree(sm->dma.obuf);
 	return 0;
 }
 
@@ -833,7 +860,6 @@
 	char *cp = strchr(mode, '.');
 	const struct modem_tx_info **mtp = sm_modem_tx_table;
 	const struct modem_rx_info **mrp;
-	int dv;
 
 	if (!strcmp(mode, "off")) {
 		sm->mode_tx = NULL;
@@ -867,13 +893,25 @@
 				sm->mode_rx = *mrp;
 				SCSTATE->sr[0] = sm->mode_rx->srate;
 				SCSTATE->sr[1] = sm->mode_tx->srate;
-				dv = lcm(sm->mode_tx->dmabuflenmodulo, 
-					 sm->mode_rx->dmabuflenmodulo);
-				if (dv & 1)
-					dv <<= 1; /* dmabuflen must be a multiple of 4 */
-				SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1;
-				SCSTATE->dmabuflen /= dv;
-				SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */
+				sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100;
+				sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100;
+				if (sm->dma.ifragsz < sm->mode_rx->overlap)
+					sm->dma.ifragsz = sm->mode_rx->overlap;
+				if (sm->mode_rx->demodulator_s16 && sm->mode_tx->modulator_u8) {
+					sm->dma.i16bit = 1;
+					sm->dma.o16bit = 0;
+					sm->dma.ifragsz <<= 1;
+				} else if (sm->mode_rx->demodulator_u8 && sm->mode_tx->modulator_s16) {
+					sm->dma.i16bit = 0;
+					sm->dma.o16bit = 1;
+					sm->dma.ofragsz <<= 1;
+				} else {
+					printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname, 
+					       sm->mode_rx->name, sm->mode_tx->name);
+					sm->mode_tx = NULL;
+					sm->mode_rx = NULL;
+					return -EINVAL;
+				}
 				return 0;
 			}
 		}
diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/sm_wss.c linux/drivers/net/soundmodem/sm_wss.c
--- v2.1.42/linux/drivers/net/soundmodem/sm_wss.c	Thu Feb 27 10:57:31 1997
+++ linux/drivers/net/soundmodem/sm_wss.c	Thu Jun 12 16:22:07 1997
@@ -26,12 +26,14 @@
  */
 
 #include <linux/ptrace.h>
+#include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <linux/ioport.h>
 #include <linux/soundmodem.h>
 #include "sm.h"
+#include "smdma.h"
 
 /* --------------------------------------------------------------------- */
 
@@ -81,12 +83,6 @@
 	unsigned char revwss, revid, revv, revcid;
 	unsigned char fmt[2];
 	unsigned char crystal;
-	unsigned int dmabuflen;
-	unsigned char *dmabuf;
-	unsigned char dmabufidx;
-	unsigned char ptt;
-	/* Full Duplex extensions */
-	unsigned char *dmabuf2;
 };
 
 #define SCSTATE ((struct sc_state_wss *)(&sm->hw))
@@ -156,8 +152,8 @@
 
 /* --------------------------------------------------------------------- */
 
-static int wss_set_codec_fmt(struct device *dev, struct sm_state *sm, 
-			     unsigned char fmt, char fdx, char fullcalib)
+static int wss_set_codec_fmt(struct device *dev, struct sm_state *sm, unsigned char fmt, 
+			     unsigned char fmt2, char fdx, char fullcalib)
 {
 	unsigned long time;
 	unsigned long flags;
@@ -167,7 +163,7 @@
 	/* Clock and data format register */
 	write_codec(dev, 0x48, fmt);
 	if (SCSTATE->crystal) {
-		write_codec(dev, 0x5c, fmt & 0xf0);
+		write_codec(dev, 0x5c, fmt2 & 0xf0);
 		/* MCE and interface config reg */	
 		write_codec(dev, 0x49, (fdx ? 0 : 0x4) | (fullcalib ? 0x18 : 0));
 	} else 
@@ -306,7 +302,7 @@
 		write_codec(dev, 0x1d, 0x00); /* right out no att */
 	}
 
-	if (wss_set_codec_fmt(dev, sm, SCSTATE->fmt[0], fdx, 1))
+	if (wss_set_codec_fmt(dev, sm, SCSTATE->fmt[0], SCSTATE->fmt[0], fdx, 1))
 		goto codec_err;
 
         write_codec(dev, 0, reg0); /* left input control */
@@ -345,18 +341,14 @@
 {
         unsigned long flags;
         static const unsigned char codecmode[2] = { 0x0e, 0x0d };
-        static const unsigned char dmamode[2] = { 
-		DMA_MODE_READ | DMA_MODE_AUTOINIT, 
-		DMA_MODE_WRITE  | DMA_MODE_AUTOINIT
-	};
 	unsigned char oldcodecmode;
 	long abrt;
-	unsigned long dmabufaddr = virt_to_bus(SCSTATE->dmabuf);
+	unsigned char fmt;
+	unsigned int numsamps;
 
-        if ((dmabufaddr & 0xffffu) + SCSTATE->dmabuflen > 0x10000)
-                panic("%s: DMA buffer violates DMA boundary!", sm_drvname);
 	send = !!send;
-        save_flags(flags);
+	fmt = SCSTATE->fmt[send];
+	save_flags(flags);
         cli();
 	/*
 	 * perform the final DMA sequence to disable the codec request
@@ -365,28 +357,18 @@
         write_codec(dev, 9, 0xc); /* disable codec */
 	wss_ack_int(dev);
 	if (read_codec(dev, 11) & 0x10) {
-		disable_dma(dev->dma);
-		clear_dma_ff(dev->dma);
-		set_dma_mode(dev->dma, dmamode[oldcodecmode & 1]);
-		set_dma_addr(dev->dma, dmabufaddr);
-		set_dma_count(dev->dma, SCSTATE->dmabuflen);
-		enable_dma(dev->dma);
+		dma_setup(sm, oldcodecmode & 1, dev->dma);
 		abrt = 0;
 		while ((read_codec(dev, 11) & 0x10) || ((++abrt) >= 0x10000));
 	}
-        disable_dma(dev->dma);
-	if (read_codec(dev, 0x8) != SCSTATE->fmt[send])
-		wss_set_codec_fmt(dev, sm, SCSTATE->fmt[send], 0, 0);
-        clear_dma_ff(dev->dma);
-        set_dma_mode(dev->dma, dmamode[send]);
-        set_dma_addr(dev->dma, dmabufaddr);
-        set_dma_count(dev->dma, SCSTATE->dmabuflen);
-        enable_dma(dev->dma);
-	write_codec(dev, 15, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
-	write_codec(dev, 14, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+	if (read_codec(dev, 0x8) != fmt)
+		wss_set_codec_fmt(dev, sm, fmt, fmt, 0, 0);
+	numsamps = dma_setup(sm, send, dev->dma) - 1;
+	write_codec(dev, 15, numsamps & 0xff);
+	write_codec(dev, 14, numsamps >> 8);
 	if (SCSTATE->crystal) {
-		write_codec(dev, 31, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
-		write_codec(dev, 30, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+		write_codec(dev, 31, numsamps & 0xff);
+		write_codec(dev, 30, numsamps >> 8);
 	}
 	write_codec(dev, 9, codecmode[send]);
         restore_flags(flags);
@@ -398,74 +380,45 @@
 {
 	struct device *dev = (struct device *)dev_id;
 	struct sm_state *sm = (struct sm_state *)dev->priv;
-	unsigned char new_ptt;
-	unsigned char *buf;
-	int dmares;
+	unsigned int curfrag;
+	unsigned int nums;
 
 	if (!dev || !sm || !sm->mode_rx || !sm->mode_tx || 
 	    sm->hdrv.magic != HDLCDRV_MAGIC)
 		return;
-	new_ptt = hdlcdrv_ptt(&sm->hdrv);
 	cli();
 	wss_ack_int(dev);
 	disable_dma(dev->dma);
 	clear_dma_ff(dev->dma);
-	dmares = get_dma_residue(dev->dma);
-	if (dmares <= 0)
-		dmares = SCSTATE->dmabuflen;
-	buf = SCSTATE->dmabuf;
-	if (dmares > SCSTATE->dmabuflen/2) {
-		buf += SCSTATE->dmabuflen/2;
-		dmares -= SCSTATE->dmabuflen/2;
-	}
-#ifdef SM_DEBUG
-	if (!sm->debug_vals.dma_residue || 
-	    dmares < sm->debug_vals.dma_residue)
-		sm->debug_vals.dma_residue = dmares;
-#endif /* SM_DEBUG */
-	dmares--;
-	write_codec(dev, 15, dmares & 0xff);
-	write_codec(dev, 14, dmares >> 8);
+	nums = dma_ptr(sm, sm->dma.ptt_cnt > 0, dev->dma, &curfrag) - 1;
+	write_codec(dev, 15, nums  & 0xff);
+	write_codec(dev, 14, nums >> 8);
 	if (SCSTATE->crystal) {
-		write_codec(dev, 31, dmares & 0xff);
-		write_codec(dev, 30, dmares >> 8);
+		write_codec(dev, 31, nums & 0xff);
+		write_codec(dev, 30, nums >> 8);
 	}
 	enable_dma(dev->dma);
 	sm_int_freq(sm);
 	sti();
-	if (new_ptt && !SCSTATE->ptt) {
-		/* starting to transmit */
-		disable_dma(dev->dma);
-		sti();
- 		SCSTATE->dmabufidx = 0;
-		time_exec(sm->debug_vals.demod_cyc, 
-			  sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2));
-		time_exec(sm->debug_vals.mod_cyc, 
-			  sm->mode_tx->modulator(sm, SCSTATE->dmabuf, 
-						 SCSTATE->dmabuflen/2));
- 		setup_dma_wss(dev, sm, 1);
-		time_exec(sm->debug_vals.mod_cyc, 
-			  sm->mode_tx->modulator(sm, SCSTATE->dmabuf + 
-						 SCSTATE->dmabuflen/2,
-						 SCSTATE->dmabuflen/2));
-	} else if (SCSTATE->ptt == 1 && !new_ptt) {
+	if (sm->dma.ptt_cnt <= 0) {
+		dma_receive(sm, curfrag);
+		if (hdlcdrv_ptt(&sm->hdrv)) {
+			/* starting to transmit */
+			disable_dma(dev->dma);
+			dma_start_transmit(sm);
+			setup_dma_wss(dev, sm, 1);
+			dma_transmit(sm);
+		}
+	} else if (dma_end_transmit(sm, curfrag)) {
 		/* stopping transmission */
 		disable_dma(dev->dma);
 		sti();
- 		SCSTATE->dmabufidx = 0;
+		dma_init_receive(sm);
 		setup_dma_wss(dev, sm, 0);
-		SCSTATE->ptt = 0;
-	} else if (SCSTATE->ptt) {
-                SCSTATE->ptt--;
-		time_exec(sm->debug_vals.mod_cyc, 
-			  sm->mode_tx->modulator(sm, buf, SCSTATE->dmabuflen/2));
         } else {
-		time_exec(sm->debug_vals.demod_cyc, 
-			  sm->mode_rx->demodulator(sm, buf, SCSTATE->dmabuflen/2));
+		dma_transmit(sm);
 		hdlcdrv_arbitrate(dev, &sm->hdrv);
         }
-        if (new_ptt)
-                SCSTATE->ptt = 2;
 	sm_output_status(sm);
 	hdlcdrv_transmitter(dev, &sm->hdrv);
 	hdlcdrv_receiver(dev, &sm->hdrv);
@@ -475,6 +428,8 @@
 
 static int wss_open(struct device *dev, struct sm_state *sm) 
 {
+	unsigned int dmasz, u;
+
 	if (sizeof(sm->m) < sizeof(struct sc_state_wss)) {
 		printk(KERN_ERR "sm wss: wss state too big: %d > %d\n", 
 		       sizeof(struct sc_state_wss), sizeof(sm->m));
@@ -495,9 +450,19 @@
 	/*
 	 * initialize some variables
 	 */
-	if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA)))
+	dma_init_receive(sm);
+	dmasz = (NUM_FRAGMENTS + 1) * sm->dma.ifragsz;
+	if (sm->dma.i16bit)
+		dmasz <<= 1;
+	u = NUM_FRAGMENTS * sm->dma.ofragsz;
+	if (sm->dma.o16bit)
+		u <<= 1;
+	if (u > dmasz)
+		dmasz = u;
+	if (!(sm->dma.ibuf = sm->dma.obuf = kmalloc(dmasz, GFP_KERNEL | GFP_DMA)))
 		return -ENOMEM;
-	SCSTATE->dmabufidx = SCSTATE->ptt = 0;
+	dma_init_transmit(sm);
+	dma_init_receive(sm);
 
 	memset(&sm->m, 0, sizeof(sm->m));
 	memset(&sm->d, 0, sizeof(sm->d));
@@ -507,13 +472,13 @@
 		sm->mode_rx->init(sm);
 
 	if (request_dma(dev->dma, sm->hwdrv->hw_name)) {
-		kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+		kfree_s(sm->dma.obuf, dmasz);
 		return -EBUSY;
 	}
 	if (request_irq(dev->irq, wss_interrupt, SA_INTERRUPT, 
 			sm->hwdrv->hw_name, dev)) {
 		free_dma(dev->dma);
-		kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+		kfree_s(sm->dma.obuf, dmasz);
 		return -EBUSY;
 	}
 	request_region(dev->base_addr, WSS_EXTENT, sm->hwdrv->hw_name);
@@ -535,7 +500,7 @@
 	free_irq(dev->irq, dev);	
 	free_dma(dev->dma);	
 	release_region(dev->base_addr, WSS_EXTENT);
-	kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+	kfree(sm->dma.obuf);
 	return 0;
 }
 
@@ -546,7 +511,7 @@
 	char *cp = strchr(mode, '.');
 	const struct modem_tx_info **mtp = sm_modem_tx_table;
 	const struct modem_rx_info **mrp;
-	int i, j, dv;
+	int i, j;
 
 	if (!strcmp(mode, "off")) {
 		sm->mode_tx = NULL;
@@ -579,11 +544,57 @@
 				sm->mode_rx = *mrp;
 				SCSTATE->fmt[0] = j;
 				SCSTATE->fmt[1] = i;
-				dv = lcm(sm->mode_tx->dmabuflenmodulo, 
-					 sm->mode_rx->dmabuflenmodulo);
-				SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1;
-				SCSTATE->dmabuflen /= dv;
-				SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */
+				sm->dma.ifragsz = (sm->mode_rx->srate + 50)/100;
+				sm->dma.ofragsz = (sm->mode_tx->srate + 50)/100;
+				if (sm->dma.ifragsz < sm->mode_rx->overlap)
+					sm->dma.ifragsz = sm->mode_rx->overlap;
+				/* prefer same data format if possible to minimize switching times */
+				sm->dma.i16bit = sm->dma.o16bit = 2;
+				if (sm->mode_rx->srate == sm->mode_tx->srate) {
+					if (sm->mode_rx->demodulator_s16 && sm->mode_tx->modulator_s16)
+						sm->dma.i16bit = sm->dma.o16bit = 1;
+					else if (sm->mode_rx->demodulator_u8 && sm->mode_tx->modulator_u8)
+						sm->dma.i16bit = sm->dma.o16bit = 0;
+				}
+				if (sm->dma.i16bit == 2) {
+					if (sm->mode_rx->demodulator_s16)
+						sm->dma.i16bit = 1;
+					else if (sm->mode_rx->demodulator_u8)
+						sm->dma.i16bit = 0;
+				}
+				if (sm->dma.o16bit == 2) {
+					if (sm->mode_tx->modulator_s16)
+						sm->dma.o16bit = 1;
+					else if (sm->mode_tx->modulator_u8)
+						sm->dma.o16bit = 0;
+				}
+				if (sm->dma.i16bit == 2 ||  sm->dma.o16bit == 2) {
+					printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname, 
+					       sm->mode_rx->name, sm->mode_tx->name);
+					sm->mode_tx = NULL;
+					sm->mode_rx = NULL;
+					return -EINVAL;
+				}
+#ifdef __BIG_ENDIAN
+				/* big endian 16bit only works on crystal cards... */
+				if (sm->dma.i16bit) {
+					SCSTATE->fmt[0] |= 0xc0;
+					sm->dma.ifragsz <<= 1;
+				}
+				if (sm->dma.o16bit) {
+					SCSTATE->fmt[1] |= 0xc0;
+					sm->dma.ofragsz <<= 1;
+				}
+#else /* __BIG_ENDIAN */
+				if (sm->dma.i16bit) {
+					SCSTATE->fmt[0] |= 0x40;
+					sm->dma.ifragsz <<= 1;
+				}
+				if (sm->dma.o16bit) {
+					SCSTATE->fmt[1] |= 0x40;
+					sm->dma.ofragsz <<= 1;
+				}
+#endif /* __BIG_ENDIAN */
 				return 0;
 			}
 		}
@@ -663,12 +674,8 @@
         unsigned long flags;
 	unsigned char oldcodecmode, codecdma;
 	long abrt;
-	unsigned long dmabufaddr1 = virt_to_bus(SCSTATE->dmabuf);
-	unsigned long dmabufaddr2 = virt_to_bus(SCSTATE->dmabuf2);
-
-        if (((dmabufaddr1 & 0xffffu) + SCSTATE->dmabuflen > 0x10000) ||
-	    ((dmabufaddr2 & 0xffffu) + SCSTATE->dmabuflen > 0x10000))
-                panic("%s: DMA buffer violates DMA boundary!", sm_drvname);
+	unsigned int osamps, isamps;
+	
         save_flags(flags);
         cli();
 	/*
@@ -678,39 +685,19 @@
         write_codec(dev, 9, 0); /* disable codec DMA */
 	wss_ack_int(dev);
 	if ((codecdma = read_codec(dev, 11)) & 0x10) {
-		disable_dma(dev->dma);
-		disable_dma(sm->hdrv.ptt_out.dma2);
-		clear_dma_ff(dev->dma);
-		set_dma_mode(dev->dma, DMA_MODE_WRITE  | DMA_MODE_AUTOINIT);
-		set_dma_addr(dev->dma, dmabufaddr1);
-		set_dma_count(dev->dma, SCSTATE->dmabuflen);
-		clear_dma_ff(sm->hdrv.ptt_out.dma2);
-		set_dma_mode(sm->hdrv.ptt_out.dma2, DMA_MODE_READ  | DMA_MODE_AUTOINIT);
-		set_dma_addr(sm->hdrv.ptt_out.dma2, dmabufaddr2);
-		set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen);
-		enable_dma(dev->dma);
-		enable_dma(sm->hdrv.ptt_out.dma2);
+		dma_setup(sm, 1, dev->dma);
+		dma_setup(sm, 0, sm->hdrv.ptt_out.dma2);
 		abrt = 0;
-		while (((codecdma = read_codec(dev, 11)) & 0x10) ||
-		       ((++abrt) >= 0x10000));
+		while (((codecdma = read_codec(dev, 11)) & 0x10) || ((++abrt) >= 0x10000));
 	}
-        disable_dma(dev->dma);
-        disable_dma(sm->hdrv.ptt_out.dma2);
-	clear_dma_ff(dev->dma);
-	set_dma_mode(dev->dma, DMA_MODE_WRITE  | DMA_MODE_AUTOINIT);
-	set_dma_addr(dev->dma, dmabufaddr1);
-	set_dma_count(dev->dma, SCSTATE->dmabuflen);
-	clear_dma_ff(sm->hdrv.ptt_out.dma2);
-	set_dma_mode(sm->hdrv.ptt_out.dma2, DMA_MODE_READ  | DMA_MODE_AUTOINIT);
-	set_dma_addr(sm->hdrv.ptt_out.dma2, dmabufaddr2);
-	set_dma_count(sm->hdrv.ptt_out.dma2, SCSTATE->dmabuflen);
-        enable_dma(dev->dma);
-        enable_dma(sm->hdrv.ptt_out.dma2);
-	write_codec(dev, 15, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
-	write_codec(dev, 14, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+       	wss_set_codec_fmt(dev, sm, SCSTATE->fmt[1], SCSTATE->fmt[0], 1, 1);
+	osamps = dma_setup(sm, 1, dev->dma) - 1;
+	isamps = dma_setup(sm, 0, sm->hdrv.ptt_out.dma2) - 1;
+	write_codec(dev, 15, osamps & 0xff);
+	write_codec(dev, 14, osamps >> 8);
 	if (SCSTATE->crystal) {
-		write_codec(dev, 31, ((SCSTATE->dmabuflen >> 1) - 1) & 0xff);
-		write_codec(dev, 30, ((SCSTATE->dmabuflen >> 1) - 1) >> 8);
+		write_codec(dev, 31, isamps & 0xff);
+		write_codec(dev, 30, isamps >> 8);
 	}
 	write_codec(dev, 9, 3);
         restore_flags(flags);
@@ -722,68 +709,74 @@
 {
 	struct device *dev = (struct device *)dev_id;
 	struct sm_state *sm = (struct sm_state *)dev->priv;
-	unsigned char *buf1;
-	unsigned char *buf2;
 	unsigned long flags;
-	int dmares1, dmares2;
+	unsigned char cry_int_src;
+	unsigned icfrag, ocfrag, isamps, osamps;
 
 	if (!dev || !sm || !sm->mode_rx || !sm->mode_tx || 
 	    sm->hdrv.magic != HDLCDRV_MAGIC)
 		return;
 	save_flags(flags);
 	cli();
-	if (SCSTATE->crystal && (!(read_codec(dev, 0x18) & 0x20))) {
-		/* only regard Crystal Playback interrupts! */
+	if (SCSTATE->crystal) { 
+		/* Crystal has an essentially different interrupt handler! */
+		cry_int_src = read_codec(dev, 0x18);
 		wss_ack_int(dev);
+		if (cry_int_src & 0x10) {       /* playback interrupt */
+			disable_dma(dev->dma);
+			clear_dma_ff(dev->dma);
+			osamps = dma_ptr(sm, 1, dev->dma, &ocfrag)-1;
+			write_codec(dev, 15, osamps & 0xff);
+			write_codec(dev, 14, osamps >> 8);
+			enable_dma(dev->dma);
+		}
+		if (cry_int_src & 0x20) {       /* capture interrupt */
+			disable_dma(sm->hdrv.ptt_out.dma2);
+			clear_dma_ff(sm->hdrv.ptt_out.dma2);
+			isamps = dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag)-1;
+			write_codec(dev, 31, isamps & 0xff);
+			write_codec(dev, 30, isamps >> 8);
+			enable_dma(sm->hdrv.ptt_out.dma2);
+		}
+		restore_flags(flags);
+		sm_int_freq(sm);
+		sti();
+		if (cry_int_src & 0x10) {
+			if (dma_end_transmit(sm, ocfrag))
+				dma_clear_transmit(sm);
+			dma_transmit(sm);
+		}
+		if (cry_int_src & 0x20) { 
+			dma_receive(sm, icfrag);
+			hdlcdrv_arbitrate(dev, &sm->hdrv);
+		}
+		sm_output_status(sm);
+		hdlcdrv_transmitter(dev, &sm->hdrv);
+		hdlcdrv_receiver(dev, &sm->hdrv);
 		return;
 	}
 	wss_ack_int(dev);
 	disable_dma(dev->dma);
 	disable_dma(sm->hdrv.ptt_out.dma2);
 	clear_dma_ff(dev->dma);
-	dmares1 = get_dma_residue(dev->dma);
 	clear_dma_ff(sm->hdrv.ptt_out.dma2);
-	dmares2 = get_dma_residue(sm->hdrv.ptt_out.dma2);
-	if (dmares1 <= 0)
-		dmares1 = SCSTATE->dmabuflen;
-	buf1 = SCSTATE->dmabuf;
-	if (dmares1 > SCSTATE->dmabuflen/2) {
-		buf1 += SCSTATE->dmabuflen/2;
-		dmares1 -= SCSTATE->dmabuflen/2;
-	}
-	if (dmares2 <= 0)
-		dmares2 = SCSTATE->dmabuflen;
-	buf2 = SCSTATE->dmabuf2;
-	if (dmares2 > SCSTATE->dmabuflen/2) {
-		buf2 += SCSTATE->dmabuflen/2;
-		dmares2 -= SCSTATE->dmabuflen/2;
-	}
-#ifdef SM_DEBUG
-	if (!sm->debug_vals.dma_residue || 
-	    dmares1 < sm->debug_vals.dma_residue)
-		sm->debug_vals.dma_residue = dmares1;
-#endif /* SM_DEBUG */
-	dmares1--;
-	dmares2--;
-	write_codec(dev, 15, dmares1 & 0xff);
-	write_codec(dev, 14, dmares1 >> 8);
+	osamps = dma_ptr(sm, 1, dev->dma, &ocfrag)-1;
+	isamps = dma_ptr(sm, 0, sm->hdrv.ptt_out.dma2, &icfrag)-1;
+	write_codec(dev, 15, osamps & 0xff);
+	write_codec(dev, 14, osamps >> 8);
 	if (SCSTATE->crystal) {
-		write_codec(dev, 31, dmares2 & 0xff);
-		write_codec(dev, 30, dmares2 >> 8);
+		write_codec(dev, 31, isamps & 0xff);
+		write_codec(dev, 30, isamps >> 8);
 	}
 	enable_dma(dev->dma);
 	enable_dma(sm->hdrv.ptt_out.dma2);
 	restore_flags(flags);
 	sm_int_freq(sm);
 	sti();
-	if ((SCSTATE->ptt = hdlcdrv_ptt(&sm->hdrv))) 
-		time_exec(sm->debug_vals.mod_cyc, 
-			  sm->mode_tx->modulator(sm, buf1, SCSTATE->dmabuflen/2));
-	else
-		time_exec(sm->debug_vals.mod_cyc, 
-			  memset(buf1, 0x80, SCSTATE->dmabuflen/2));
-	time_exec(sm->debug_vals.demod_cyc, 
-		  sm->mode_rx->demodulator(sm, buf2, SCSTATE->dmabuflen/2));
+	if (dma_end_transmit(sm, ocfrag))
+		dma_clear_transmit(sm);
+	dma_transmit(sm);
+	dma_receive(sm, icfrag);
 	hdlcdrv_arbitrate(dev, &sm->hdrv);
 	sm_output_status(sm);
 	hdlcdrv_transmitter(dev, &sm->hdrv);
@@ -809,13 +802,14 @@
 	/*
 	 * initialize some variables
 	 */
-	if (!(SCSTATE->dmabuf = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA)))
+	if (!(sm->dma.ibuf = kmalloc(sm->dma.ifragsz * (NUM_FRAGMENTS+1), GFP_KERNEL | GFP_DMA)))
 		return -ENOMEM;
-	if (!(SCSTATE->dmabuf2 = kmalloc(SCSTATE->dmabuflen, GFP_KERNEL | GFP_DMA))) {
-		kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
+	if (!(sm->dma.obuf = kmalloc(sm->dma.ofragsz * NUM_FRAGMENTS, GFP_KERNEL | GFP_DMA))) {
+		kfree(sm->dma.ibuf);
 		return -ENOMEM;
 	}
-	SCSTATE->dmabufidx = SCSTATE->ptt = 0;
+	dma_init_transmit(sm);
+	dma_init_receive(sm);
 
 	memset(&sm->m, 0, sizeof(sm->m));
 	memset(&sm->d, 0, sizeof(sm->d));
@@ -825,20 +819,20 @@
 		sm->mode_rx->init(sm);
 
 	if (request_dma(dev->dma, sm->hwdrv->hw_name)) {
-		kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
-		kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+		kfree(sm->dma.ibuf);
+		kfree(sm->dma.obuf);
 		return -EBUSY;
 	}
 	if (request_dma(sm->hdrv.ptt_out.dma2, sm->hwdrv->hw_name)) {
-		kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
-		kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+		kfree(sm->dma.ibuf);
+		kfree(sm->dma.obuf);
 		free_dma(dev->dma);
 		return -EBUSY;
 	}
 	if (request_irq(dev->irq, wssfdx_interrupt, SA_INTERRUPT, 
 			sm->hwdrv->hw_name, dev)) {
-		kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
-		kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+		kfree(sm->dma.ibuf);
+		kfree(sm->dma.obuf);
 		free_dma(dev->dma);
 		free_dma(sm->hdrv.ptt_out.dma2);
 		return -EBUSY;
@@ -858,13 +852,14 @@
 	 * disable interrupts
 	 */
 	disable_dma(dev->dma);
+	disable_dma(sm->hdrv.ptt_out.dma2);
         write_codec(dev, 9, 0xc); /* disable codec */
 	free_irq(dev->irq, dev);	
 	free_dma(dev->dma);	
 	free_dma(sm->hdrv.ptt_out.dma2);	
 	release_region(dev->base_addr, WSS_EXTENT);
-	kfree_s(SCSTATE->dmabuf, SCSTATE->dmabuflen);
-	kfree_s(SCSTATE->dmabuf2, SCSTATE->dmabuflen);
+	kfree(sm->dma.ibuf);
+	kfree(sm->dma.obuf);
 	return 0;
 }
 
@@ -875,7 +870,7 @@
 	char *cp = strchr(mode, '.');
 	const struct modem_tx_info **mtp = sm_modem_tx_table;
 	const struct modem_rx_info **mrp;
-	int i, dv;
+	int i;
 
 	if (!strcmp(mode, "off")) {
 		sm->mode_tx = NULL;
@@ -907,11 +902,37 @@
 				sm->mode_tx = *mtp;
 				sm->mode_rx = *mrp;
 				SCSTATE->fmt[0] = SCSTATE->fmt[1] = i;
-				dv = lcm(sm->mode_tx->dmabuflenmodulo, 
-					 sm->mode_rx->dmabuflenmodulo);
-				SCSTATE->dmabuflen = sm->mode_rx->srate/100+dv-1;
-				SCSTATE->dmabuflen /= dv;
-				SCSTATE->dmabuflen *= 2*dv; /* make sure DMA buf is even */
+				sm->dma.ifragsz = sm->dma.ofragsz = (sm->mode_rx->srate + 50)/100;
+				if (sm->dma.ifragsz < sm->mode_rx->overlap)
+					sm->dma.ifragsz = sm->mode_rx->overlap;
+				sm->dma.i16bit = sm->dma.o16bit = 2;
+				if (sm->mode_rx->demodulator_s16) {
+					sm->dma.i16bit = 1;
+					sm->dma.ifragsz <<= 1;
+#ifdef __BIG_ENDIAN    /* big endian 16bit only works on crystal cards... */
+					SCSTATE->fmt[0] |= 0xc0;
+#else /* __BIG_ENDIAN */
+					SCSTATE->fmt[0] |= 0x40;
+#endif /* __BIG_ENDIAN */
+				} else if (sm->mode_rx->demodulator_u8)
+					sm->dma.i16bit = 0;
+				if (sm->mode_tx->modulator_s16) {
+					sm->dma.o16bit = 1;
+					sm->dma.ofragsz <<= 1;
+#ifdef __BIG_ENDIAN    /* big endian 16bit only works on crystal cards... */
+					SCSTATE->fmt[1] |= 0xc0;
+#else /* __BIG_ENDIAN */
+					SCSTATE->fmt[1] |= 0x40;
+#endif /* __BIG_ENDIAN */
+				} else if (sm->mode_tx->modulator_u8)
+					sm->dma.o16bit = 0;
+				if (sm->dma.i16bit == 2 ||  sm->dma.o16bit == 2) {
+					printk(KERN_INFO "%s: mode %s or %s unusable\n", sm_drvname, 
+					       sm->mode_rx->name, sm->mode_tx->name);
+					sm->mode_tx = NULL;
+					sm->mode_rx = NULL;
+					return -EINVAL;
+				}
 				return 0;
 			}
 		}
diff -u --recursive --new-file v2.1.42/linux/drivers/net/soundmodem/smdma.h linux/drivers/net/soundmodem/smdma.h
--- v2.1.42/linux/drivers/net/soundmodem/smdma.h	Wed Dec 31 16:00:00 1969
+++ linux/drivers/net/soundmodem/smdma.h	Thu Jun 12 16:22:07 1997
@@ -0,0 +1,210 @@
+/*****************************************************************************/
+
+/*
+ *	smdma.h  --  soundcard radio modem driver dma buffer routines.
+ *
+ *	Copyright (C) 1996  Thomas Sailer (sailer@ife.ee.ethz.ch)
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ *
+ *	You should have received a copy of the GNU General Public License
+ *	along with this program; if not, write to the Free Software
+ *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *  Please note that the GPL allows you to use the driver, NOT the radio.
+ *  In order to use the radio, you need a license from the communications
+ *  authority of your country.
+ *
+ */
+
+#ifndef _SMDMA_H
+#define _SMDMA_H
+
+/* ---------------------------------------------------------------------- */
+
+#include "sm.h"
+
+/* ---------------------------------------------------------------------- */
+
+#define DMA_MODE_AUTOINIT      0x10
+#define NUM_FRAGMENTS          4
+
+/* --------------------------------------------------------------------- */
+/*
+ * ===================== DMA buffer management ===========================
+ */
+
+/*
+ * returns the number of samples per fragment
+ */
+extern __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr)
+{
+	if (send) {
+		disable_dma(dmanr);
+		clear_dma_ff(dmanr);
+		set_dma_mode(dmanr, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
+		set_dma_addr(dmanr, virt_to_bus(sm->dma.obuf));
+		set_dma_count(dmanr, sm->dma.ofragsz * NUM_FRAGMENTS);
+		enable_dma(dmanr);
+		if (sm->dma.o16bit)
+			return sm->dma.ofragsz/2;
+		return sm->dma.ofragsz;
+	} else {
+		disable_dma(dmanr);
+		clear_dma_ff(dmanr);
+		set_dma_mode(dmanr, DMA_MODE_READ | DMA_MODE_AUTOINIT);
+		set_dma_addr(dmanr, virt_to_bus(sm->dma.ibuf));
+		set_dma_count(dmanr, sm->dma.ifragsz * NUM_FRAGMENTS);
+		enable_dma(dmanr);
+		if (sm->dma.i16bit)
+			return sm->dma.ifragsz/2;
+		return sm->dma.ifragsz;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr,
+				       unsigned int *curfrag)
+{
+	unsigned int dmaptr, sz, frg, offs;
+	
+	dmaptr = get_dma_residue(dmanr);
+	if (send) {
+		sz = sm->dma.ofragsz * NUM_FRAGMENTS;
+		if (dmaptr == 0 || dmaptr > sz)
+			dmaptr = sz;
+		dmaptr--;
+		frg = dmaptr / sm->dma.ofragsz;
+		offs = (dmaptr % sm->dma.ofragsz) + 1;
+		*curfrag = NUM_FRAGMENTS - 1 - frg;
+#ifdef SM_DEBUG
+		if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue)
+			sm->debug_vals.dma_residue = offs;
+#endif /* SM_DEBUG */
+		if (sm->dma.o16bit)
+			return offs/2;
+		return offs;
+	} else {
+		sz = sm->dma.ifragsz * NUM_FRAGMENTS;
+		if (dmaptr == 0 || dmaptr > sz)
+			dmaptr = sz;
+		dmaptr--;
+		frg = dmaptr / sm->dma.ifragsz;
+		offs = (dmaptr % sm->dma.ifragsz) + 1;
+		*curfrag = NUM_FRAGMENTS - 1 - frg;
+#ifdef SM_DEBUG
+		if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue)
+			sm->debug_vals.dma_residue = offs;
+#endif /* SM_DEBUG */
+		if (sm->dma.i16bit)
+			return offs/2;
+		return offs;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag)
+{
+	unsigned int diff = (NUM_FRAGMENTS + curfrag - sm->dma.ofragptr) % NUM_FRAGMENTS;
+
+	sm->dma.ofragptr = curfrag;
+	if (sm->dma.ptt_cnt <= 0) {
+		sm->dma.ptt_cnt = 0;
+		return 0;
+	}
+	sm->dma.ptt_cnt -= diff;
+	if (sm->dma.ptt_cnt <= 0) {
+		sm->dma.ptt_cnt = 0;
+		return -1;
+	}
+	return 0;
+}
+
+extern __inline__ void dma_transmit(struct sm_state *sm)
+{
+	void *p;
+
+	while (sm->dma.ptt_cnt < NUM_FRAGMENTS && hdlcdrv_ptt(&sm->hdrv)) {
+		p = (unsigned char *)sm->dma.obuf + sm->dma.ofragsz *
+			((sm->dma.ofragptr + sm->dma.ptt_cnt) % NUM_FRAGMENTS);
+		if (sm->dma.o16bit) {
+			time_exec(sm->debug_vals.mod_cyc, 
+				  sm->mode_tx->modulator_s16(sm, p, sm->dma.ofragsz/2));
+		} else {
+			time_exec(sm->debug_vals.mod_cyc, 
+				  sm->mode_tx->modulator_u8(sm, p, sm->dma.ofragsz));
+		}
+		sm->dma.ptt_cnt++;
+	}
+}
+
+extern __inline__ void dma_init_transmit(struct sm_state *sm)
+{
+	sm->dma.ofragptr = 0;
+	sm->dma.ptt_cnt = 0;
+}
+
+extern __inline__ void dma_start_transmit(struct sm_state *sm)
+{
+	sm->dma.ofragptr = 0;
+	if (sm->dma.o16bit) {
+		time_exec(sm->debug_vals.mod_cyc, 
+			  sm->mode_tx->modulator_s16(sm, sm->dma.obuf, sm->dma.ofragsz/2));
+	} else {
+		time_exec(sm->debug_vals.mod_cyc, 
+			  sm->mode_tx->modulator_u8(sm, sm->dma.obuf, sm->dma.ofragsz));
+	}
+	sm->dma.ptt_cnt = 1;
+}
+
+extern __inline__ void dma_clear_transmit(struct sm_state *sm)
+{
+	sm->dma.ptt_cnt = 0;
+	memset(sm->dma.obuf, (sm->dma.o16bit) ? 0 : 0x80, sm->dma.ofragsz * NUM_FRAGMENTS);
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag)
+{
+	void *p;
+
+	while (sm->dma.ifragptr != curfrag) {
+		if (sm->dma.ifragptr)
+			p = (unsigned char *)sm->dma.ibuf + 
+				sm->dma.ifragsz * sm->dma.ifragptr;
+		else {
+			p = (unsigned char *)sm->dma.ibuf + NUM_FRAGMENTS * sm->dma.ifragsz;
+			memcpy(p, sm->dma.ibuf, sm->dma.ifragsz);
+		}
+		if (sm->dma.o16bit) {
+			time_exec(sm->debug_vals.demod_cyc, 
+				  sm->mode_rx->demodulator_s16(sm, p, sm->dma.ifragsz/2));
+		} else {
+			time_exec(sm->debug_vals.demod_cyc, 
+				  sm->mode_rx->demodulator_u8(sm, p, sm->dma.ifragsz));
+		}
+		sm->dma.ifragptr = (sm->dma.ifragptr + 1) % NUM_FRAGMENTS;
+	}
+}
+
+extern __inline__ void dma_init_receive(struct sm_state *sm)
+{
+	sm->dma.ifragptr = 0;
+}
+
+/* --------------------------------------------------------------------- */
+#endif /* _SMDMA_H */
+
+
+
diff -u --recursive --new-file v2.1.42/linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- v2.1.42/linux/drivers/pci/pci.c	Sat May 24 09:10:24 1997
+++ linux/drivers/pci/pci.c	Thu Jun 12 16:22:07 1997
@@ -56,7 +56,9 @@
 	DEVICE( ATI,		ATI_68800,      "68800AX"),
 	DEVICE( ATI,		ATI_215CT222,   "215CT222"),
 	DEVICE( ATI,		ATI_210888CX,   "210888CX"),
+	DEVICE( ATI,		ATI_215GT,	"Mach64 GT (Rage II)"),
 	DEVICE( ATI,		ATI_210888GX,   "210888GX"),
+	DEVICE( ATI,		ATI_264VT,	"Mach64 VT"),
 	DEVICE( VLSI,		VLSI_82C592,	"82C592-FC1"),
 	DEVICE( VLSI,		VLSI_82C593,	"82C593-FC1"),
 	DEVICE( VLSI,		VLSI_82C594,	"82C594-AFC2"),
@@ -76,6 +78,7 @@
 	DEVICE( DEC,		DEC_TULIP_FAST,	"DC21140"),
 	DEVICE( DEC,		DEC_FDDI,	"DEFPA"),
 	DEVICE( DEC,		DEC_TULIP_PLUS,	"DC21041"),
+	DEVICE( DEC,		DEC_21142,	"DC21142"),
 	DEVICE( DEC,		DEC_21052,	"DC21052"),
 	DEVICE( DEC,		DEC_21152,	"DC21152"),
 	DEVICE( CIRRUS,		CIRRUS_7548,	"GD 7548"),
@@ -83,10 +86,14 @@
 	DEVICE( CIRRUS,		CIRRUS_5434_4,	"GD 5434"),
 	DEVICE( CIRRUS,		CIRRUS_5434_8,	"GD 5434"),
 	DEVICE( CIRRUS,		CIRRUS_5436,	"GD 5436"),
+	DEVICE( CIRRUS,		CIRRUS_5446,	"GD 5446"),
+	DEVICE( CIRRUS,		CIRRUS_5464,	"GD 5464"),
 	DEVICE( CIRRUS,		CIRRUS_6729,	"CL 6729"),
 	DEVICE( CIRRUS,		CIRRUS_7542,	"CL 7542"),
 	DEVICE( CIRRUS,		CIRRUS_7543,	"CL 7543"),
+	DEVICE( CIRRUS,		CIRRUS_7541,	"CL 7541"),
 	DEVICE( IBM,		IBM_82G2675,	"82G2675"),
+	DEVICE( IBM,		IBM_82351,	"82351"),
 	DEVICE( WD,		WD_7197,	"WD 7197"),
 	DEVICE( AMD,		AMD_LANCE,	"79C970"),
 	DEVICE( AMD,		AMD_SCSI,	"53C974"),
@@ -101,6 +108,7 @@
 	DEVICE( CT,		CT_65545,	"65545"),
 	DEVICE( CT,		CT_65548,	"65548"),
 	DEVICE(	CT,		CT_65550,	"65550"),
+	DEVICE( CT,		CT_65554,	"65554"),
 	DEVICE( MIRO,		MIRO_36050,	"ZR36050"),
 	DEVICE( FD,		FD_36C70,	"TMC-18C30"),
 	DEVICE( SI,		SI_6201,	"6201"),
@@ -112,7 +120,10 @@
 	DEVICE( SI,		SI_601,		"85C601"),
 	DEVICE( SI,		SI_5511,		"85C5511"),
 	DEVICE( SI,		SI_5513,		"85C5513"),
+	DEVICE( SI,		SI_5571,	"5571"),
+	DEVICE( SI,		SI_7001,	"7001"),
 	DEVICE( HP,		HP_J2585A,	"J2585A"),
+	DEVICE( HP,		HP_J2585B,	"J2585B"),
 	DEVICE( PCTECH,		PCTECH_RZ1000,  "RZ1000 (buggy)"),
 	DEVICE( PCTECH,		PCTECH_RZ1001,  "RZ1001 (buggy?)"),
 	DEVICE( DPT,		DPT,		"SmartCache/Raid"),
@@ -128,6 +139,9 @@
 	DEVICE( BUSLOGIC,	BUSLOGIC_FLASHPOINT,     "FlashPoint"),
 	DEVICE( OAK,		OAK_OTI107,	"OTI107"),
 	DEVICE( WINBOND2,	WINBOND2_89C940,"NE2000-PCI"),
+	DEVICE( MOTOROLA,	MOTOROLA_MPC105,"MPC105 Eagle"),
+	DEVICE( MOTOROLA,	MOTOROLA_MPC106,"MPC106 Grackle"),
+	DEVICE( MOTOROLA,	MOTOROLA_RAVEN,	"Raven"),
 	DEVICE( PROMISE,	PROMISE_5300,	"DC5030"),
 	DEVICE( N9,		N9_I128,	"Imagine 128"),
 	DEVICE( N9,		N9_I128_2,	"Imagine 128v2"),
@@ -155,11 +169,13 @@
 	DEVICE( ACC,		ACC_2056,	"2056"),
 	DEVICE( WINBOND,	WINBOND_83769,	"W83769F"),
 	DEVICE( WINBOND,	WINBOND_82C105,	"SL82C105"),
+	DEVICE( WINBOND,	WINBOND_83C553,	"W83C553"),
 	DEVICE( 3COM,		3COM_3C590,	"3C590 10bT"),
 	DEVICE( 3COM,		3COM_3C595TX,	"3C595 100bTX"),
 	DEVICE( 3COM,		3COM_3C595T4,	"3C595 100bT4"),
 	DEVICE( 3COM,		3COM_3C595MII,	"3C595 100b-MII"),
 	DEVICE( 3COM,		3COM_3C900TPO,	"3C900 10bTPO"),
+	DEVICE( 3COM,		3COM_3C900COMBO,"3C900 10b Combo"),
 	DEVICE( 3COM,		3COM_3C905TX,	"3C905 100bTX"),
 	DEVICE( AL,		AL_M1445,	"M1445"),
 	DEVICE( AL,		AL_M1449,	"M1449"),
@@ -171,18 +187,24 @@
 	DEVICE( AL,		AL_M4803,	"M4803"),
 	DEVICE( NEOMAGIC,       NEOMAGIC_MAGICGRAPH_NM2070,     "Magicgraph NM2070"),
 	DEVICE( ASP,		ASP_ABP940,	"ABP940"),
+	DEVICE( ASP,		ASP_ABP940U,	"ABP940U"),
 	DEVICE( CERN,		CERN_SPSB_PMC,	"STAR/RD24 SCI-PCI (PMC)"),
 	DEVICE( CERN,		CERN_SPSB_PCI,	"STAR/RD24 SCI-PCI (PMC)"),
 	DEVICE( IMS,		IMS_8849,	"8849"),
 	DEVICE( TEKRAM2,	TEKRAM2_690c,	"DC690c"),
+	DEVICE( TUNDRA,		TUNDRA_CA91C042,"CA91C042 Universe"),
 	DEVICE( AMCC,		AMCC_MYRINET,	"Myrinet PCI (M2-PCI-32)"),
+	DEVICE( AMCC,		AMCC_S5933,	"S5933"),
 	DEVICE( INTERG,		INTERG_1680,	"IGA-1680"),
 	DEVICE( INTERG,         INTERG_1682,    "IGA-1682"),
 	DEVICE( REALTEK,	REALTEK_8029,	"8029"),
 	DEVICE( INIT,		INIT_320P,	"320 P"),
 	DEVICE( VIA,		VIA_82C505,	"VT 82C505"),
 	DEVICE( VIA,		VIA_82C561,	"VT 82C561"),
+	DEVICE( VIA,		VIA_82C586_1,	"VT 82C586 Apollo VP-1"),
 	DEVICE( VIA,		VIA_82C576,	"VT 82C576 3V"),
+	DEVICE( VIA,		VIA_82C585,	"VT 82C585VP Apollo VP-1"),
+	DEVICE( VIA,		VIA_82C586_0,	"VT 82C586 Apollo VP-1"),
 	DEVICE( VIA,		VIA_82C416,	"VT 82C416MV"),
 	DEVICE( VORTEX,		VORTEX_GDT60x0,	"GDT 60x0"),
 	DEVICE( VORTEX,		VORTEX_GDT6000B,"GDT 6000b"),
@@ -200,19 +222,22 @@
 	DEVICE( VORTEX,		VORTEX_GDT6555,	"GDT 6555"),
 	DEVICE( EF,		EF_ATM_FPGA,		"155P-MF1 (FPGA)"),
 	DEVICE( EF,		EF_ATM_ASIC,	"155P-MF1 (ASIC)"),
-	DEVICE( IMAGINGTECH,	IMAGINGTECH_ICPCI, "MVC IC-PCI"),
 	DEVICE( FORE,		FORE_PCA200PC, "PCA-200PC"),
 	DEVICE( FORE,		FORE_PCA200E,	 "PCA-200E"),
+	DEVICE( IMAGINGTECH,	IMAGINGTECH_ICPCI, "MVC IC-PCI"),
 	DEVICE( PLX,		PLX_9060,	"PCI9060 i960 bridge"),
 	DEVICE( ALLIANCE,	ALLIANCE_PROMOTIO, "Promotion-6410"),
 	DEVICE( ALLIANCE,	ALLIANCE_PROVIDEO, "Provideo"),
 	DEVICE( VMIC,		VMIC_VME,	"VMIVME-7587"),
  	DEVICE( DIGI,		DIGI_RIGHTSWITCH, "RightSwitch SE-6"),
 	DEVICE( MUTECH,		MUTECH_MV1000,	"MV-1000"),
+	DEVICE( TOSHIBA,	TOSHIBA_601,	"Laptop"),
 	DEVICE( ZEITNET,	ZEITNET_1221,	"1221"),
 	DEVICE( ZEITNET,	ZEITNET_1225,	"1225"),
+	DEVICE( OMEGA,		OMEGA_PCMCIA,	"PCMCIA"),
 	DEVICE( SPECIALIX,	SPECIALIX_XIO,	"XIO/SIO host"),
 	DEVICE( SPECIALIX,	SPECIALIX_RIO,	"RIO host"),
+	DEVICE( ZORAN,		ZORAN_36120,	"ZR36120"),
 	DEVICE( COMPEX,		COMPEX_RL2000,	"ReadyLink 2000"),
 	DEVICE( RP,             RP8OCTA,        "RocketPort 8 Oct"),
 	DEVICE( RP,             RP8INTF,        "RocketPort 8 Intf"),
@@ -222,6 +247,8 @@
 	DEVICE( CYCLADES,	CYCLOM_Y_Hi,	"Cyclom-Y above 1Mbyte"),
 	DEVICE( CYCLADES,	CYCLOM_Z_Lo,	"Cyclom-Z below 1Mbyte"),
 	DEVICE( CYCLADES,	CYCLOM_Z_Hi,	"Cyclom-Z above 1Mbyte"),
+	DEVICE( 3DFX,		3DFX_VOODOO,	"Voodoo"),
+	DEVICE( SIGMADES,	SIGMADES_6425,	"REALmagic64/GX"),
 	DEVICE( OPTIBASE,	OPTIBASE_FORGE,	"MPEG Forge"),
 	DEVICE( OPTIBASE,	OPTIBASE_FUSION,"MPEG Fusion"),
 	DEVICE( OPTIBASE,	OPTIBASE_VPLEX,	"VideoPlex"),
@@ -230,6 +257,9 @@
 	DEVICE( SYMPHONY,	SYMPHONY_101,	"82C101"),
 	DEVICE( TEKRAM,		TEKRAM_DC290,	"DC-290"),
 	DEVICE( 3DLABS,		3DLABS_300SX,	"GLINT 300SX"),
+	DEVICE( 3DLABS,		3DLABS_DELTA,	"GLINT Delta"),
+	DEVICE( 3DLABS,		3DLABS_PERMEDIA,"PERMEDIA"),
+	DEVICE( AVANCE,		AVANCE_ALG2064,	"ALG2064i"),
 	DEVICE( AVANCE,		AVANCE_2302,	"ALG-2302"),
 	DEVICE( S3,		S3_ViRGE,	"ViRGE"),
 	DEVICE( S3,		S3_TRIO,	"Trio32/Trio64"),
@@ -248,6 +278,8 @@
 	DEVICE( INTEL,		INTEL_82378,	"82378IB"),
 	DEVICE( INTEL,		INTEL_82430,	"82430ZX Aries"),
 	BRIDGE( INTEL,		INTEL_82434,	"82434LX Mercury/Neptune", 0x00),
+	DEVICE( INTEL,		INTEL_82092AA_0,"82092AA PCMCIA bridge"),
+	DEVICE( INTEL,		INTEL_82092AA_1,"82092AA EIDE"),
 	DEVICE( INTEL,		INTEL_7116,	"SAA7116"),
 	DEVICE( INTEL,		INTEL_82596,	"82596"),
 	DEVICE( INTEL,		INTEL_82865,	"82865"),
@@ -255,15 +287,19 @@
 	DEVICE( INTEL,		INTEL_82437,	"82437"),
 	DEVICE( INTEL,		INTEL_82371_0,	"82371 Triton PIIX"),
 	DEVICE( INTEL,		INTEL_82371_1,	"82371 Triton PIIX"),
-	DEVICE( INTEL,		INTEL_430MX_0,	"Triton I"),
-	DEVICE( INTEL,		INTEL_430MX_1,	"Triton I"),
+	DEVICE( INTEL,		INTEL_82371MX,	"430MX - 82371MX MPIIX"),
+	DEVICE( INTEL,		INTEL_82437MX,	"430MX - 82437MX MTSC"),
 	DEVICE( INTEL,		INTEL_82441,	"82441FX Natoma"),
 	DEVICE( INTEL,		INTEL_82439,	"82439HX Triton II"),
 	DEVICE(	INTEL,		INTEL_82371SB_0,"82371SB Natoma/Triton II PIIX3"),
 	DEVICE(	INTEL,		INTEL_82371SB_1,"82371SB Natoma/Triton II PIIX3"),
 	DEVICE( INTEL,		INTEL_82371SB_2,"82371SB Natoma/Triton II PIIX3"),
 	DEVICE( INTEL,		INTEL_82437VX,	"82437VX Triton II"),
+	DEVICE( INTEL,		INTEL_82439TX,	"82439TX"),
+	DEVICE( INTEL,		INTEL_82371AB_0,"82371AB PIIX4"),
 	DEVICE( INTEL,		INTEL_82371AB,	"82371AB 430TX PIIX4"),
+	DEVICE( INTEL,		INTEL_82371AB_2,"82371AB PIIX4"),
+	DEVICE( INTEL,		INTEL_82371AB_3,"82371AB PIIX4 Power Management"),
 	DEVICE( INTEL,		INTEL_P6,	"Orion P6"),
  	DEVICE( INTEL,		INTEL_P6_2,	"82450GX Orion P6"),
 	DEVICE(	KTI,		KTI_ET32P2,	"ET32P2"),
@@ -508,6 +544,7 @@
 	      case PCI_VENDOR_ID_BUSLOGIC:	return "BusLogic";
 	      case PCI_VENDOR_ID_OAK: 		return "OAK";
 	      case PCI_VENDOR_ID_WINBOND2:	return "Winbond";
+	      case PCI_VENDOR_ID_MOTOROLA:	return "Motorola";
 	      case PCI_VENDOR_ID_PROMISE:	return "Promise Technology";
 	      case PCI_VENDOR_ID_N9:		return "Number Nine";
 	      case PCI_VENDOR_ID_UMC:		return "UMC";
@@ -531,6 +568,7 @@
 	      case PCI_VENDOR_ID_CERN:		return "CERN";
 	      case PCI_VENDOR_ID_IMS:		return "IMS";
 	      case PCI_VENDOR_ID_TEKRAM2:	return "Tekram";
+	      case PCI_VENDOR_ID_TUNDRA:	return "Tundra";
 	      case PCI_VENDOR_ID_AMCC:		return "AMCC";
 	      case PCI_VENDOR_ID_INTERG:	return "Intergraphics";
 	      case PCI_VENDOR_ID_REALTEK:	return "Realtek";
@@ -547,10 +585,14 @@
 	      case PCI_VENDOR_ID_MUTECH:	return "Mutech";
 	      case PCI_VENDOR_ID_TOSHIBA:	return "Toshiba";
 	      case PCI_VENDOR_ID_ZEITNET:	return "ZeitNet";
+	      case PCI_VENDOR_ID_OMEGA:		return "Omega Micro";
 	      case PCI_VENDOR_ID_SPECIALIX:	return "Specialix";
+	      case PCI_VENDOR_ID_ZORAN:		return "Zoran";
 	      case PCI_VENDOR_ID_COMPEX:	return "Compex";
 	      case PCI_VENDOR_ID_RP:		return "Comtrol";
 	      case PCI_VENDOR_ID_CYCLADES:	return "Cyclades";
+	      case PCI_VENDOR_ID_3DFX:		return "3Dfx";
+	      case PCI_VENDOR_ID_SIGMADES:	return "Sigma Designs";
 	      case PCI_VENDOR_ID_OPTIBASE:	return "Optibase";
 	      case PCI_VENDOR_ID_SYMPHONY:	return "Symphony";
 	      case PCI_VENDOR_ID_TEKRAM:	return "Tekram";
diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/bwtwo.c linux/drivers/sbus/char/bwtwo.c
--- v2.1.42/linux/drivers/sbus/char/bwtwo.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/sbus/char/bwtwo.c	Thu Jun 12 16:22:07 1997
@@ -1,4 +1,4 @@
-/* $Id: bwtwo.c,v 1.13 1997/04/14 17:04:55 jj Exp $
+/* $Id: bwtwo.c,v 1.16 1997/06/04 08:27:26 davem Exp $
  * bwtwo.c: bwtwo console driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -15,9 +15,11 @@
 #include <asm/fbio.h>
 #include <asm/pgtable.h>
 
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
+
 #include "fb.h"
 #include "cg_common.h"
 
@@ -91,7 +93,7 @@
 				 vma->vm_page_prot, fb->space);
 	if (r) return -EAGAIN;
 	vma->vm_inode = inode;
-	inode->i_count++;
+	atomic_inc(&inode->i_count);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/cgfourteen.c linux/drivers/sbus/char/cgfourteen.c
--- v2.1.42/linux/drivers/sbus/char/cgfourteen.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/sbus/char/cgfourteen.c	Thu Jun 12 16:22:07 1997
@@ -1,4 +1,4 @@
-/* $Id: cgfourteen.c,v 1.19 1997/04/14 17:04:57 jj Exp $
+/* $Id: cgfourteen.c,v 1.22 1997/06/04 08:27:27 davem Exp $
  * cgfourteen.c: Sun SparcStation console support.
  *
  * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -23,9 +23,10 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 #include "fb.h"
 
 #define CG14_MCR_INTENABLE_SHIFT	7
@@ -272,7 +273,7 @@
 		page += map_size;
 	}
         vma->vm_inode = inode;
-        inode->i_count++;
+        atomic_inc(&inode->i_count);
         return 0;
 }
 
diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/cgsix.c linux/drivers/sbus/char/cgsix.c
--- v2.1.42/linux/drivers/sbus/char/cgsix.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/sbus/char/cgsix.c	Thu Jun 12 16:22:07 1997
@@ -1,4 +1,4 @@
-/* $Id: cgsix.c,v 1.27 1997/04/14 17:04:55 jj Exp $
+/* $Id: cgsix.c,v 1.30 1997/06/04 08:27:28 davem Exp $
  * cgsix.c: cgsix frame buffer driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -15,9 +15,10 @@
 #include <asm/fbio.h>
 #include <asm/pgtable.h>
 
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 #include "fb.h"
 #include "cg_common.h"
 
@@ -296,7 +297,7 @@
 		page += map_size;
 	}
         vma->vm_inode = inode;
-        inode->i_count++;
+        atomic_inc(&inode->i_count);
         return 0;
 }
 
diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/cgthree.c linux/drivers/sbus/char/cgthree.c
--- v2.1.42/linux/drivers/sbus/char/cgthree.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/sbus/char/cgthree.c	Thu Jun 12 16:22:07 1997
@@ -1,4 +1,4 @@
-/* $Id: cgthree.c,v 1.18 1997/04/16 17:51:09 jj Exp $
+/* $Id: cgthree.c,v 1.21 1997/06/04 08:27:29 davem Exp $
  * cgtree.c: cg3 frame buffer driver
  *
  * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -18,9 +18,10 @@
 #include <asm/fbio.h>
 #include <asm/pgtable.h>
 
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 #include "fb.h"
 #include "cg_common.h"
 
@@ -131,7 +132,7 @@
 		page += map_size;
 	}
         vma->vm_inode = inode;
-        inode->i_count++;
+        atomic_inc(&inode->i_count);
         return 0;
 }
 
diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/creator.c linux/drivers/sbus/char/creator.c
--- v2.1.42/linux/drivers/sbus/char/creator.c	Tue May 13 22:41:12 1997
+++ linux/drivers/sbus/char/creator.c	Thu Jun 12 16:22:07 1997
@@ -15,9 +15,10 @@
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
 
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 #include "fb.h"
 
 __initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned long creator, int creator_io))
diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/leo.c linux/drivers/sbus/char/leo.c
--- v2.1.42/linux/drivers/sbus/char/leo.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/sbus/char/leo.c	Thu Jun 12 16:22:07 1997
@@ -1,4 +1,4 @@
-/* $Id: leo.c,v 1.15 1997/04/14 17:04:54 jj Exp $
+/* $Id: leo.c,v 1.18 1997/06/04 08:27:30 davem Exp $
  * leo.c: SUNW,leo 24/8bit frame buffer driver
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -17,9 +17,10 @@
 #include <asm/delay.h>
 #include <asm/uaccess.h>
 
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 #include "fb.h"
 #include "cg_common.h"
 
@@ -221,7 +222,7 @@
 		page += map_size;
 	}
         vma->vm_inode = inode;
-        inode->i_count++;
+        atomic_inc(&inode->i_count);
         return 0;
 }
 
diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/suncons.c linux/drivers/sbus/char/suncons.c
--- v2.1.42/linux/drivers/sbus/char/suncons.c	Thu May 15 16:48:03 1997
+++ linux/drivers/sbus/char/suncons.c	Thu Jun 12 16:22:07 1997
@@ -1,4 +1,4 @@
-/* $Id: suncons.c,v 1.62 1997/05/02 22:32:32 davem Exp $
+/* $Id: suncons.c,v 1.63 1997/05/31 18:33:25 mj Exp $
  *
  * suncons.c: Sun SparcStation console support.
  *
@@ -76,11 +76,11 @@
 #include <asm/io.h>
 #include <asm/smp.h>
 
-#include "../../char/kbd_kern.h"
-#include "../../char/vt_kern.h"
-#include "../../char/consolemap.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 
 #include "fb.h"
 
diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/sunfb.c linux/drivers/sbus/char/sunfb.c
--- v2.1.42/linux/drivers/sbus/char/sunfb.c	Mon Apr 14 16:28:13 1997
+++ linux/drivers/sbus/char/sunfb.c	Thu Jun 12 16:22:07 1997
@@ -1,4 +1,4 @@
-/* $Id: sunfb.c,v 1.22 1997/04/03 08:47:56 davem Exp $
+/* $Id: sunfb.c,v 1.23 1997/05/31 18:33:26 mj Exp $
  * sunfb.c: Sun generic frame buffer support.
  *
  * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx)
@@ -33,11 +33,11 @@
 #include <asm/fbio.h>
 #include <asm/io.h>
 
-#include "../../char/kbd_kern.h"
-#include "../../char/vt_kern.h"
-#include "../../char/consolemap.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+#include <linux/kbd_kern.h>
+#include <linux/vt_kern.h>
+#include <linux/consolemap.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 
 #include "fb.h"
 
diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/sunkbd.c linux/drivers/sbus/char/sunkbd.c
--- v2.1.42/linux/drivers/sbus/char/sunkbd.c	Tue May 13 22:41:12 1997
+++ linux/drivers/sbus/char/sunkbd.c	Thu Jun 12 16:22:07 1997
@@ -25,9 +25,9 @@
 #include <asm/oplib.h>
 #include <asm/uaccess.h>
 
-#include "../../char/kbd_kern.h"
-#include "../../char/diacr.h"
-#include "../../char/vt_kern.h"
+#include <linux/kbd_kern.h>
+#include <linux/kbd_diacr.h>
+#include <linux/vt_kern.h>
 
 #define SIZE(x) (sizeof(x)/sizeof((x)[0]))
 
diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/tcx.c linux/drivers/sbus/char/tcx.c
--- v2.1.42/linux/drivers/sbus/char/tcx.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/sbus/char/tcx.c	Thu Jun 12 16:22:07 1997
@@ -1,4 +1,4 @@
-/* $Id: tcx.c,v 1.12 1997/04/14 17:04:51 jj Exp $
+/* $Id: tcx.c,v 1.15 1997/06/04 08:27:32 davem Exp $
  * tcx.c: SUNW,tcx 24/8bit frame buffer driver
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -16,9 +16,10 @@
 #include <asm/fbio.h>
 #include <asm/pgtable.h>
 
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 #include "fb.h"
 #include "cg_common.h"
 
@@ -171,7 +172,7 @@
 		page += map_size;
 	}
         vma->vm_inode = inode;
-        inode->i_count++;
+        atomic_inc(&inode->i_count);
         return 0;
 }
 
diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c
--- v2.1.42/linux/drivers/sbus/char/vfc_dev.c	Tue May 13 22:41:12 1997
+++ linux/drivers/sbus/char/vfc_dev.c	Thu Jun 12 16:22:07 1997
@@ -581,7 +581,7 @@
 				vma->vm_page_prot, dev->which_io);
 	if(ret) return -EAGAIN;
 	vma->vm_inode=inode;
-	inode->i_count++;
+	atomic_inc(&inode->i_count);
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.42/linux/drivers/sbus/char/weitek.c linux/drivers/sbus/char/weitek.c
--- v2.1.42/linux/drivers/sbus/char/weitek.c	Wed Apr 23 19:01:21 1997
+++ linux/drivers/sbus/char/weitek.c	Thu Jun 12 16:22:07 1997
@@ -1,4 +1,4 @@
-/* $Id: weitek.c,v 1.9 1997/04/14 17:04:57 jj Exp $
+/* $Id: weitek.c,v 1.12 1997/06/04 08:27:34 davem Exp $
  * weitek.c: Tadpole P9100/P9000 console driver
  *
  * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
@@ -15,9 +15,10 @@
 #include <asm/fbio.h>
 #include <asm/pgtable.h>
 
-#include "../../char/vt_kern.h"
-#include "../../char/selection.h"
-#include "../../char/console_struct.h"
+/* These must be included after asm/fbio.h */
+#include <linux/vt_kern.h>
+#include <linux/selection.h>
+#include <linux/console_struct.h>
 #include "fb.h"
 #include "cg_common.h"
 
@@ -82,7 +83,7 @@
 		page += map_size;
 	}
 	vma->vm_inode = inode;
-	inode->i_count++;
+	atomic_inc(&inode->i_count);
 	return 0;
 }
 #endif
diff -u --recursive --new-file v2.1.42/linux/drivers/scsi/amiga7xx.c linux/drivers/scsi/amiga7xx.c
--- v2.1.42/linux/drivers/scsi/amiga7xx.c	Sat May 24 09:10:24 1997
+++ linux/drivers/scsi/amiga7xx.c	Thu Jun 12 16:22:07 1997
@@ -50,20 +50,20 @@
 #ifdef CONFIG_WARPENGINE_SCSI
     if ((key = zorro_find(MANUF_MACROSYSTEMS, PROD_WARP_ENGINE, 0, 0)))
     {
-    	cd = zorro_get_board(key);
-    	address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
+	cd = zorro_get_board(key);
+	address = (unsigned long)kernel_map((unsigned long)cd->cd_BoardAddr,
 		cd->cd_BoardSize, KERNELMAP_NOCACHE_SER, NULL);
 
-    	options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+	options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
 
 	clock = 50000000;	/* 50MHz SCSI Clock */
 
-    	ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address + 0x40000),
-			0, IRQ_AMIGA_PORTS & ~IRQ_MACHSPEC, DMA_NONE, 
+	ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address + 0x40000),
+			0, IRQ_AMIGA_PORTS, DMA_NONE, 
 			options, clock);
 
-    	zorro_config_board(key, 0);
-    	num++;
+	zorro_config_board(key, 0);
+	num++;
     }
 #endif
 
@@ -94,7 +94,7 @@
 	clock = 50000000;	/* 50MHz SCSI Clock */
 
     	ncr53c7xx_init(tpnt, 0, 710, (u32)(unsigned char *)(address+0x800000),
-			0, IRQ_AMIGA_PORTS & ~IRQ_MACHSPEC, DMA_NONE, 
+			0, IRQ_AMIGA_PORTS, DMA_NONE, 
 			options, clock);
 
 	zorro_config_board(key, 0);
diff -u --recursive --new-file v2.1.42/linux/drivers/scsi/g_NCR5380.c linux/drivers/scsi/g_NCR5380.c
--- v2.1.42/linux/drivers/scsi/g_NCR5380.c	Thu May 29 21:53:08 1997
+++ linux/drivers/scsi/g_NCR5380.c	Thu Jun 12 16:22:07 1997
@@ -619,7 +619,10 @@
     struct Scsi_Host *scsi_ptr;
     Scsi_Cmnd *ptr;
     struct NCR5380_hostdata *hostdata;
-    
+#ifdef NCR5380_STATS
+    Scsi_Device *dev;
+    extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
+#endif    
     cli();
 
     for (scsi_ptr = first_instance; scsi_ptr; scsi_ptr=scsi_ptr->next)
diff -u --recursive --new-file v2.1.42/linux/drivers/scsi/script_asm.pl linux/drivers/scsi/script_asm.pl
--- v2.1.42/linux/drivers/scsi/script_asm.pl	Sat Nov  4 19:25:10 1995
+++ linux/drivers/scsi/script_asm.pl	Thu Jun 12 16:22:07 1997
@@ -1,4 +1,4 @@
-#! /usr/local/bin/perl
+#!/usr/bin/perl -s
 
 # NCR 53c810 script assembler
 # Sponsored by 
@@ -10,6 +10,9 @@
 #      drew@Colorado.EDU
 #      +1 (303) 786-7975 
 #
+#   Support for 53c710 (via -ncr7x0_family switch) added by Richard
+#   Hirst <richard@sleepie.demon.co.uk> - 15th March 1997
+#
 #   This program is free software; you can redistribute it and/or modify
 #   it under the terms of the GNU General Public License as published by
 #   the Free Software Foundation; either version 2 of the License, or
@@ -74,7 +77,15 @@
 # 	and = 0x04_00_00_00
 # 	add = 0x06_00_00_00
 
-%operators_810 = (
+if ($ncr7x0_family) {
+  %operators = (
+    '|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
+    '&', 0x04_00_00_00, 'AND', 0x04_00_00_00,
+    '+', 0x06_00_00_00
+  );
+}
+else {
+  %operators = (
     'SHL',  0x01_00_00_00, 
     '|', 0x02_00_00_00, 'OR', 0x02_00_00_00, 
     'XOR', 0x03_00_00_00, 
@@ -83,11 +94,33 @@
     # Note : low bit of the operator bit should be set for add with 
     # carry.
     '+', 0x06_00_00_00 
-);
-
+  );
+}
 
 # Table of register addresses
-%registers_810 = (
+
+if ($ncr7x0_family) {
+  %registers = (
+    'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
+    'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
+    'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11,
+    'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
+    'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
+    'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23,
+    'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27,
+    'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
+    'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34, 'LCRC', 35,
+    'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
+    'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
+    'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
+    'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
+    'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
+    'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
+    'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
+  );
+}
+else {
+  %registers = (
     'SCNTL0', 0, 'SCNTL1', 1, 'SCNTL2', 2, 'SCNTL3', 3,
     'SCID', 4, 'SXFER', 5, 'SDID', 6, 'GPREG', 7,
     'SFBR', 8, 'SOCL', 9, 'SSID', 10, 'SBCL', 11,
@@ -113,7 +146,8 @@
     'SODL', 84,
     'SBDL', 88,
     'SCRATCHB0', 92, 'SCRATCHB1', 93, 'SCRATCHB2', 94, 'SCRATCHB3', 95
-);
+  );
+}
 
 # Parsing regular expressions
 $identifier = '[A-Za-z_][A-Za-z_0-9]*';		
@@ -131,17 +165,22 @@
 
 $phase = join ('|', keys %scsi_phases);
 print STDERR "phase regex = $phase\n" if ($debug);
-$register = join ('|', keys %registers_810);
+$register = join ('|', keys %registers);
 
-# yucky - since %operators_810 includes meta-characters which must
+# yucky - since %operators includes meta-characters which must
 # be escaped, I can't use the join() trick I used for the register
 # regex
 
-$operator = '\||OR|AND|XOR|\&|\+';
+if ($ncr7x0_family) {
+  $operator = '\||OR|AND|\&|\+';
+}
+else {
+  $operator = '\||OR|AND|XOR|\&|\+';
+}
 
 # Global variables
 
-%symbol_values = (%registers_810) ;	# Traditional symbol table
+%symbol_values = (%registers) ;		# Traditional symbol table
 
 %symbol_references = () ;		# Table of symbol references, where
 					# the index is the symbol name, 
@@ -421,6 +460,7 @@
 	if ($1 =~ /^($identifier)\s*$/) {
 	    push (@entry, $1);
 	} else {
+	    die
 "$0 : syntax error in line $lineno : $_
 	expected ENTRY <identifier>
 ";
@@ -558,13 +598,13 @@
 	    # instruction.
 	    if (($src_reg eq undef) || ($src_reg eq $dst_reg)) {
 		$code[$address] |= 0x38_00_00_00 | 
-		    ($registers_810{$dst_reg} << 16);
+		    ($registers{$dst_reg} << 16);
 	    } elsif ($dst_reg =~ /SFBR/i) {
 		$code[$address] |= 0x30_00_00_00 |
-		    ($registers_810{$src_reg} << 16);
+		    ($registers{$src_reg} << 16);
 	    } elsif ($src_reg =~ /SFBR/i) {
 		$code[$address] |= 0x28_00_00_00 |
-		    ($registers_810{$dst_reg} << 16);
+		    ($registers{$dst_reg} << 16);
 	    } else {
 		die
 "$0 : Illegal combination of registers in line $lineno : $_
@@ -573,10 +613,10 @@
 ";
 	    }
 
-	    $code[$address] |= $operators_810{$op};
+	    $code[$address] |= $operators{$op};
 	    
 	    &parse_value ($data8, 0, 1, 1);
-	    $code[$address] |= $operators_810{$op};
+	    $code[$address] |= $operators{$op};
 	    $code[$address + 1] = 0x00_00_00_00;# Reserved
 	    $address += 2;
 	} else {
diff -u --recursive --new-file v2.1.42/linux/drivers/sound/dmabuf.c linux/drivers/sound/dmabuf.c
--- v2.1.42/linux/drivers/sound/dmabuf.c	Wed May 28 10:51:32 1997
+++ linux/drivers/sound/dmabuf.c	Mon Jun 16 14:23:51 1997
@@ -802,6 +802,8 @@
    */
 
   max = dmap->max_fragments;
+  if (max > dmap->nbufs)
+     max = dmap->nbufs;
   len = dmap->qlen;
 
   if (audio_devs[dev]->d->local_qlen)
diff -u --recursive --new-file v2.1.42/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- v2.1.42/linux/drivers/sound/soundcard.c	Wed May 28 10:51:33 1997
+++ linux/drivers/sound/soundcard.c	Thu Jun 12 16:22:07 1997
@@ -327,7 +327,7 @@
     return -EAGAIN;
 
   vma->vm_inode = inode;
-  inode->i_count++;
+  atomic_inc(&inode->i_count);
 
   dmap->mapping_flags |= DMA_MAP_MAPPED;
 
diff -u --recursive --new-file v2.1.42/linux/fs/Config.in linux/fs/Config.in
--- v2.1.42/linux/fs/Config.in	Sun Apr 13 10:18:21 1997
+++ linux/fs/Config.in	Thu Jun 12 16:22:07 1997
@@ -5,6 +5,27 @@
 comment 'Filesystems'
 
 bool	 'Quota support' CONFIG_QUOTA
+bool     'Preload dcache entries in readdir() [ALPHA, currently dangerous!]' CONFIG_DCACHE_PRELOAD
+bool     'Include support for omirr online mirror' CONFIG_OMIRR
+bool     'Translate filename suffixes' CONFIG_TRANS_NAMES
+if [ "$CONFIG_TRANS_NAMES" = "y" ]; then
+  bool '  Restrict translation to specific gid' CONFIG_TRANS_RESTRICT
+  if [ "$CONFIG_TRANS_RESTRICT" = "y" ]; then
+    int '    Enter gid to compile in' CONFIG_TRANS_GID 4
+  fi
+  bool '  Translate nodename' CONFIG_TR_NODENAME
+  bool '  Translate compiled-in kernelname' CONFIG_TR_KERNNAME
+  if [ "$CONFIG_TR_KERNNAME" = "y" ]; then
+    string '    Enter kernelname string to compile in' CONFIG_KERNNAME banana
+  fi
+  bool '  Translate compiled-in kerneltype' CONFIG_TR_KERNTYPE
+  if [ "$CONFIG_TR_KERNTYPE" = "y" ]; then
+    string '    Enter kerneltype string to compile in' CONFIG_KERNTYPE default
+  fi
+  bool '  Translate machine type' CONFIG_TR_MACHINE
+  bool '  Translate sysname' CONFIG_TR_SYSNAME
+fi
+
 tristate 'Minix fs support' CONFIG_MINIX_FS
 tristate 'Second extended fs support' CONFIG_EXT2_FS
 
diff -u --recursive --new-file v2.1.42/linux/fs/Makefile linux/fs/Makefile
--- v2.1.42/linux/fs/Makefile	Mon Apr  7 11:35:30 1997
+++ linux/fs/Makefile	Thu Jun 12 16:22:07 1997
@@ -10,10 +10,10 @@
 L_TARGET := filesystems.a
 L_OBJS    = $(join $(SUB_DIRS),$(SUB_DIRS:%=/%.o))
 O_TARGET := fs.o
-O_OBJS    = open.o read_write.o inode.o devices.o file_table.o buffer.o \
+O_OBJS    = open.o read_write.o devices.o file_table.o buffer.o \
 		super.o  block_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
 		ioctl.o readdir.o select.o fifo.o locks.o filesystems.o \
-		dcache.o $(BINFMTS) 
+		inode.o dcache.o attr.o $(BINFMTS) 
 
 MOD_LIST_NAME := FS_MODULES
 ALL_SUB_DIRS = minix ext2 fat msdos vfat proc isofs nfs umsdos \
@@ -25,6 +25,10 @@
 O_OBJS += noquot.o
 endif
 
+ifeq ($(CONFIG_TRANS_NAMES),y)
+O_OBJS += nametrans.o
+endif
+
 ifeq ($(CONFIG_MINIX_FS),y)
 SUB_DIRS += minix
 else
@@ -210,6 +214,14 @@
   endif
 endif
 
+
+ifeq ($(CONFIG_BINFMT_MISC),y)
+BINFMTS += binfmt_misc.o
+else
+  ifeq ($(CONFIG_BINFMT_MISC),m)
+  M_OBJS += binfmt_misc.o
+  endif
+endif
 
 # binfmt_script is always there
 BINFMTS += binfmt_script.o
diff -u --recursive --new-file v2.1.42/linux/fs/affs/dir.c linux/fs/affs/dir.c
--- v2.1.42/linux/fs/affs/dir.c	Tue May 13 22:41:13 1997
+++ linux/fs/affs/dir.c	Thu Jun 12 16:22:08 1997
@@ -55,7 +55,6 @@
 	NULL,			/* mknod */
 	affs_rename,		/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/affs/file.c linux/fs/affs/file.c
--- v2.1.42/linux/fs/affs/file.c	Tue May 13 22:41:13 1997
+++ linux/fs/affs/file.c	Thu Jun 12 16:22:08 1997
@@ -71,7 +71,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	affs_bmap,		/* bmap */
@@ -105,7 +104,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- v2.1.42/linux/fs/affs/inode.c	Tue May 13 22:41:14 1997
+++ linux/fs/affs/inode.c	Thu Jun 12 16:22:08 1997
@@ -899,7 +899,7 @@
 		return NULL;
 	}
 
-	inode->i_count   = 1;
+	atomic_set(&inode->i_count, 1);
 	inode->i_nlink   = 1;
 	inode->i_dev     = sb->s_dev;
 	inode->i_uid     = current->fsuid;
@@ -1031,9 +1031,9 @@
 }
 
 static struct file_system_type affs_fs_type = {
-	affs_read_super,
 	"affs",
-	1,
+	FS_REQUIRES_DEV,
+	affs_read_super,
 	NULL
 };
 
diff -u --recursive --new-file v2.1.42/linux/fs/affs/namei.c linux/fs/affs/namei.c
--- v2.1.42/linux/fs/affs/namei.c	Tue May 13 22:41:14 1997
+++ linux/fs/affs/namei.c	Thu Jun 12 16:22:08 1997
@@ -343,7 +343,7 @@
 		retval = -ENOTEMPTY;
 		goto rmdir_done;
 	}
-	if (inode->i_count > 1) {
+	if (atomic_read(&inode->i_count) > 1) {
 		retval = -EBUSY;
 		goto rmdir_done;
 	}
@@ -512,7 +512,7 @@
     int ino;
     int result;
 
-    new_inode->i_count++;
+    atomic_inc(&new_inode->i_count);
     result = 0;
     for (;;) {
         if (new_inode == old_inode) {
@@ -535,8 +535,7 @@
 
 int
 affs_rename(struct inode *old_dir, const char *old_name, int old_len,
-	    struct inode *new_dir, const char *new_name, int new_len,
-	    int must_be_dir)
+	    struct inode *new_dir, const char *new_name, int new_len)
 {
 	struct inode		*old_inode;
 	struct inode		*new_inode;
@@ -570,8 +569,6 @@
 	old_inode = __iget(old_dir->i_sb,old_ino,0);
 	if (!old_inode)
 		goto end_rename;
-	if (must_be_dir && !S_ISDIR(old_inode->i_mode))
-		goto end_rename;
 	new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino);
 	if (new_bh) {
 		new_inode = __iget(new_dir->i_sb,new_ino,0);
@@ -595,7 +592,7 @@
 		if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
 			goto end_rename;
 		retval = -EBUSY;
-		if (new_inode->i_count > 1)
+		if (atomic_read(&new_inode->i_count) > 1)
 			goto end_rename;
 	}
 	if (S_ISDIR(old_inode->i_mode)) {
diff -u --recursive --new-file v2.1.42/linux/fs/affs/symlink.c linux/fs/affs/symlink.c
--- v2.1.42/linux/fs/affs/symlink.c	Tue May 13 22:41:14 1997
+++ linux/fs/affs/symlink.c	Thu Jun 12 16:22:08 1997
@@ -20,7 +20,6 @@
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
 
 static int affs_readlink(struct inode *, char *, int);
-static int affs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
 
 struct inode_operations affs_symlink_inode_operations = {
 	NULL,			/* no file-operations */
@@ -34,92 +33,12 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	affs_readlink,		/* readlink */
-	affs_follow_link,	/* follow_link */
 	NULL,			/* bmap */
 	NULL,			/* truncate */
 	NULL			/* permission */
 };
 
 static int
-affs_follow_link(struct inode *dir, struct inode *inode, int flag, int mode,
-		 struct inode **res_inode)
-{
-	struct buffer_head	*bh;
-	struct slink_front	*lf;
-	char			*buffer;
-	int			 error;
-	int			 i, j;
-	char			 c;
-	char			 lc;
-
-	pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino);
-
-	*res_inode = NULL;
-	if (!dir) {
-		dir = current->fs->root;
-		dir->i_count++;
-	}
-	if (!inode) {
-		iput(dir);
-		return -ENOENT;
-	}
-	if (!S_ISLNK(inode->i_mode)) {
-		iput(dir);
-		*res_inode = inode;
-		return 0;
-	}
-	if (current->link_count > 5) {
-		iput(inode);
-		iput(dir);
-		return -ELOOP;
-	}
-	if (!(buffer = kmalloc(1024,GFP_KERNEL))) {
-		iput(inode);
-		iput(dir);
-		return -ENOSPC;
-	}
-	bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
-	i  = 0;
-	j  = 0;
-	if (!bh) {
-		affs_error(inode->i_sb,"follow_link","Cannot read block %lu\n",inode->i_ino);
-		kfree(buffer);
-		iput(inode);
-		iput(dir);
-		return -EIO;
-	}
-	lf = (struct slink_front *)bh->b_data;
-	lc = 0;
-	if (strchr(lf->symname,':')) {		/* Handle assign or volume name */
-		while (i < 1023 && (c = inode->i_sb->u.affs_sb.s_prefix[i]))
-			buffer[i++] = c;
-		while (i < 1023 && lf->symname[j] != ':')
-			buffer[i++] = lf->symname[j++];
-		if (i < 1023)
-			 buffer[i++] = '/';
-		j++;
-		lc = '/';
-	}
-	while (i < 1023 && (c = lf->symname[j])) {
-		if (c == '/' && lc == '/' && i < 1020) {	/* parent dir */
-			buffer[i++] = '.';
-			buffer[i++] = '.';
-		}
-		buffer[i++] = c;
-		lc = c;
-		j++;
-	}
-	buffer[i] = '\0';
-	affs_brelse(bh);
-	iput(inode);
-	current->link_count++;
-	error = open_namei(buffer,flag,mode,res_inode,dir);
-	current->link_count--;
-	kfree(buffer);
-	return error;
-}
-
-static int
 affs_readlink(struct inode *inode, char *buffer, int buflen)
 {
 	struct buffer_head	*bh;
@@ -130,10 +49,6 @@
 
 	pr_debug("AFFS: readlink(ino=%lu,buflen=%d)\n",inode->i_ino,buflen);
 
-	if (!S_ISLNK(inode->i_mode)) {
-		iput(inode);
-		return -EINVAL;
-	}
 	bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
 	i  = 0;
 	j  = 0;
diff -u --recursive --new-file v2.1.42/linux/fs/attr.c linux/fs/attr.c
--- v2.1.42/linux/fs/attr.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/attr.c	Thu Jun 12 16:22:08 1997
@@ -0,0 +1,99 @@
+/*
+ *  linux/fs/attr.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  changes by Thomas Schoebel-Theuer
+ */
+
+#include <linux/stat.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <asm/system.h>
+
+/* Taken over from the old code... */
+
+/* POSIX UID/GID verification for setting inode attributes. */
+int inode_change_ok(struct inode *inode, struct iattr *attr)
+{
+	/* If force is set do it anyway. */
+	if (attr->ia_valid & ATTR_FORCE)
+		return 0;
+
+	/* Make sure a caller can chown. */
+	if ((attr->ia_valid & ATTR_UID) &&
+	    (current->fsuid != inode->i_uid ||
+	     attr->ia_uid != inode->i_uid) && !fsuser())
+		return -EPERM;
+
+	/* Make sure caller can chgrp. */
+	if ((attr->ia_valid & ATTR_GID) &&
+	    (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid) &&
+	    !fsuser())
+		return -EPERM;
+
+	/* Make sure a caller can chmod. */
+	if (attr->ia_valid & ATTR_MODE) {
+		if ((current->fsuid != inode->i_uid) && !fsuser())
+			return -EPERM;
+		/* Also check the setgid bit! */
+		if (!fsuser() && !in_group_p((attr->ia_valid & ATTR_GID) ? attr->ia_gid :
+					     inode->i_gid))
+			attr->ia_mode &= ~S_ISGID;
+	}
+
+	/* Check for setting the inode time. */
+	if ((attr->ia_valid & ATTR_ATIME_SET) &&
+	    ((current->fsuid != inode->i_uid) && !fsuser()))
+		return -EPERM;
+	if ((attr->ia_valid & ATTR_MTIME_SET) &&
+	    ((current->fsuid != inode->i_uid) && !fsuser()))
+		return -EPERM;
+	return 0;
+}
+
+void inode_setattr(struct inode * inode, struct iattr * attr)
+{
+	if(attr->ia_valid &
+	   (ATTR_UID|ATTR_GID|ATTR_SIZE|ATTR_ATIME|ATTR_MTIME|ATTR_CTIME|ATTR_MODE)) {
+		if (attr->ia_valid & ATTR_UID)
+			inode->i_uid = attr->ia_uid;
+		if (attr->ia_valid & ATTR_GID)
+			inode->i_gid = attr->ia_gid;
+		if (attr->ia_valid & ATTR_SIZE)
+			inode->i_size = attr->ia_size;
+		if (attr->ia_valid & ATTR_ATIME)
+			inode->i_atime = attr->ia_atime;
+		if (attr->ia_valid & ATTR_MTIME)
+			inode->i_mtime = attr->ia_mtime;
+		if (attr->ia_valid & ATTR_CTIME)
+			inode->i_ctime = attr->ia_ctime;
+		if (attr->ia_valid & ATTR_MODE) {
+			inode->i_mode = attr->ia_mode;
+			if (!fsuser() && !in_group_p(inode->i_gid))
+				inode->i_mode &= ~S_ISGID;
+		}
+		inode->i_dirt = 1;
+	}
+}
+
+int notify_change(struct inode * inode, struct iattr * attr)
+{
+	int error;
+	time_t now = CURRENT_TIME;
+
+	attr->ia_ctime = now;
+	if ((attr->ia_valid & (ATTR_ATIME | ATTR_ATIME_SET)) == ATTR_ATIME)
+		attr->ia_atime = now;
+	if ((attr->ia_valid & (ATTR_MTIME | ATTR_MTIME_SET)) == ATTR_MTIME)
+		attr->ia_mtime = now;
+	attr->ia_valid &= ~(ATTR_CTIME);
+	if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->notify_change) 
+		return inode->i_sb->s_op->notify_change(inode, attr);
+	error = inode_change_ok(inode, attr);
+	if(!error)
+		inode_setattr(inode, attr);
+	return error;
+}
+
diff -u --recursive --new-file v2.1.42/linux/fs/autofs/dir.c linux/fs/autofs/dir.c
--- v2.1.42/linux/fs/autofs/dir.c	Tue May 13 22:41:14 1997
+++ linux/fs/autofs/dir.c	Thu Jun 12 16:22:08 1997
@@ -80,7 +80,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* read_page */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/autofs/init.c linux/fs/autofs/init.c
--- v2.1.42/linux/fs/autofs/init.c	Thu May 15 16:48:03 1997
+++ linux/fs/autofs/init.c	Thu Jun 12 16:22:08 1997
@@ -20,7 +20,10 @@
 #endif
 
 static struct file_system_type autofs_fs_type = {
-	autofs_read_super, "autofs", 0, NULL
+	"autofs",
+	FS_NO_DCACHE,
+	autofs_read_super,
+	NULL
 };
 
 #ifdef MODULE
diff -u --recursive --new-file v2.1.42/linux/fs/autofs/root.c linux/fs/autofs/root.c
--- v2.1.42/linux/fs/autofs/root.c	Wed May 28 10:51:33 1997
+++ linux/fs/autofs/root.c	Thu Jun 12 16:22:08 1997
@@ -48,7 +48,6 @@
         NULL,                   /* mknod */
         NULL,                   /* rename */
         NULL,                   /* readlink */
-        NULL,                   /* follow_link */
         NULL,                   /* readpage */
         NULL,                   /* writepage */
         NULL,                   /* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/autofs/symlink.c linux/fs/autofs/symlink.c
--- v2.1.42/linux/fs/autofs/symlink.c	Tue May 13 22:41:14 1997
+++ linux/fs/autofs/symlink.c	Thu Jun 12 16:22:08 1997
@@ -14,39 +14,6 @@
 #include <linux/sched.h>
 #include "autofs_i.h"
 
-static int autofs_follow_link(struct inode *dir, struct inode *inode,
-			      int flag, int mode, struct inode **res_inode)
-{
-	int error;
-	char *link;
-
-	*res_inode = NULL;
-	if (!dir) {
-		dir = current->fs->root;
-		dir->i_count++;
-	}
-	if (!inode) {
-		iput(dir);
-		return -ENOENT;
-	}
-	if (!S_ISLNK(inode->i_mode)) {
-		iput(dir);
-		*res_inode = inode;
-		return 0;
-	}
-	if (current->link_count > 5) {
-		iput(dir);
-		iput(inode);
-		return -ELOOP;
-	}
-	link = ((struct autofs_symlink *)inode->u.generic_ip)->data;
-	current->link_count++;
-	error = open_namei(link,flag,mode,res_inode,dir);
-	current->link_count--;
-	iput(inode);
-	return error;
-}
-
 static int autofs_readlink(struct inode *inode, char *buffer, int buflen)
 {
 	struct autofs_symlink *sl;
@@ -76,7 +43,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	autofs_readlink,	/* readlink */
-	autofs_follow_link,	/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- v2.1.42/linux/fs/binfmt_aout.c	Wed Apr 23 19:01:22 1997
+++ linux/fs/binfmt_aout.c	Thu Jun 12 16:22:08 1997
@@ -214,6 +214,7 @@
 /* Finally dump the task struct.  Not be used by gdb, but could be useful */
 	set_fs(KERNEL_DS);
 	DUMP_WRITE(current,sizeof(*current));
+	inode->i_status |= ST_MODIFIED;
 close_coredump:
 	if (file.f_op->release)
 		file.f_op->release(inode,&file);
diff -u --recursive --new-file v2.1.42/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- v2.1.42/linux/fs/binfmt_elf.c	Sat May 24 09:10:24 1997
+++ linux/fs/binfmt_elf.c	Thu Jun 12 16:22:08 1997
@@ -681,7 +681,7 @@
 
 #ifndef VM_STACK_FLAGS
 	current->executable = bprm->inode;
-	bprm->inode->i_count++;
+	atomic_inc(&bprm->inode->i_count);
 #endif
 #ifdef LOW_ELF_STACK
 	current->start_stack = bprm->p = elf_stack - 4;
@@ -887,6 +887,7 @@
  */
 static int dump_write(struct file *file, const void *addr, int nr)
 {
+	file->f_inode->i_status |= ST_MODIFIED;
 	return file->f_op->write(file->f_inode, file, addr, nr) == nr;
 }
 
diff -u --recursive --new-file v2.1.42/linux/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- v2.1.42/linux/fs/binfmt_misc.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/binfmt_misc.c	Thu Jun 12 16:22:08 1997
@@ -0,0 +1,505 @@
+/*
+ *  binfmt_misc.c
+ *
+ *  Copyright (C) 1997 Richard Günther
+ *
+ *  binfmt_misc detects binaries via a magic or filename extension and invokes
+ *  a specified wrapper. This should obsolete binfmt_java, binfmt_em86 and
+ *  binfmt_mz.
+ *
+ *  25.4.97 first version
+ *    [...]
+ *  19.5.97 cleanup
+ */
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/malloc.h>
+#include <linux/binfmts.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <asm/uaccess.h>
+#include <asm/spinlock.h>
+
+
+#define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
+
+#ifndef MIN
+#define MIN(x,y) (((x)<(y))?(x):(y))
+#endif
+
+struct binfmt_entry {
+	struct binfmt_entry *next;
+	int id;
+	int flags;			/* type, status, etc. */
+	int offset;			/* offset of magic */
+	int size;			/* size of magic/mask */
+	char *magic;			/* magic or filename extension */
+	char *mask;			/* mask, NULL for exact match */
+	char *interpreter;		/* filename of interpreter */
+	char *proc_name;
+	struct proc_dir_entry *proc_dir;
+};
+
+#define ENTRY_ENABLED 1		/* the old binfmt_entry.enabled */
+#define	ENTRY_MAGIC 8		/* not filename detection */
+#define ENTRY_STRIP_EXT 32	/* strip of last filename extension */
+
+static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
+static void entry_proc_cleanup(struct binfmt_entry *e);
+static int entry_proc_setup(struct binfmt_entry *e);
+
+static struct linux_binfmt misc_format = {
+#ifndef MODULE
+	NULL, 0, load_misc_binary, NULL, NULL
+#else
+	NULL, &__this_module, load_misc_binary, NULL, NULL
+#endif
+};
+
+static struct proc_dir_entry *bm_dir = NULL;
+
+static struct binfmt_entry *entries = NULL;
+static int free_id = 1;
+static int enabled = 1;
+static rwlock_t entries_lock = RW_LOCK_UNLOCKED;
+
+
+/*
+ * Unregister one entry
+ */
+static void clear_entry(int id)
+{
+	struct binfmt_entry **ep, *e;
+
+	write_lock(&entries_lock);
+	ep = &entries;
+	while (*ep && ((*ep)->id != id))
+		ep = &((*ep)->next);
+	if ((e = *ep)) {
+		*ep = e->next;
+		entry_proc_cleanup(e);
+		kfree(e);
+		MOD_DEC_USE_COUNT;
+	}
+	write_unlock(&entries_lock);
+}
+
+/*
+ * Clear all registered binary formats
+ */
+static void clear_entries(void)
+{
+	struct binfmt_entry *e;
+
+	write_lock(&entries_lock);
+	while ((e = entries)) {
+		entries = entries->next;
+		entry_proc_cleanup(e);
+		kfree(e);
+		MOD_DEC_USE_COUNT;
+	}
+	write_unlock(&entries_lock);
+}
+
+/*
+ * Find entry through id - caller has to do locking
+ */
+static struct binfmt_entry *get_entry(int id)
+{
+	struct binfmt_entry *e = entries;
+
+	while (e && (e->id != id))
+		e = e->next;
+	return e;
+}
+
+
+/* 
+ * Check if we support the binfmt
+ * if we do, return the binfmt_entry, else NULL
+ * locking is done in load_misc_binary
+ */
+static struct binfmt_entry *check_file(struct linux_binprm *bprm)
+{
+	struct binfmt_entry *e = entries;
+	char *p = strrchr(bprm->filename, '.');
+	int j;
+
+	while (e) {
+		if (e->flags & ENTRY_ENABLED) {
+			if (!(e->flags & ENTRY_MAGIC)) {
+				if (p && !strcmp(e->magic, p + 1))
+					return e;
+			} else {
+				j = 0;
+				while ((j < e->size) &&
+				  !((bprm->buf[e->offset + j] ^ e->magic[j])
+				   & (e->mask ? e->mask[j] : 0xff)))
+					j++;
+				if (j == e->size)
+					return e;
+			}
+		}
+		e = e->next;
+	};
+	return NULL;
+}
+
+/*
+ * the loader itself
+ */
+static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
+{
+	struct binfmt_entry *fmt;
+	char iname[128];
+	char *iname_addr = iname, *p;
+	int retval, fmt_flags = 0;
+
+	MOD_INC_USE_COUNT;
+	if (!enabled) {
+		retval = -ENOEXEC;
+		goto _ret;
+	}
+
+	/* to keep locking time low, we copy the interpreter string */
+	read_lock(&entries_lock);
+	if ((fmt = check_file(bprm))) {
+		strncpy(iname, fmt->interpreter, 127);
+		iname[127] = '\0';
+		fmt_flags = fmt->flags;
+	}
+	read_unlock(&entries_lock);
+	if (!fmt) {
+		retval = -ENOEXEC;
+		goto _ret;
+	}
+
+	iput(bprm->inode);
+	bprm->dont_iput = 1;
+
+	/* Build args for interpreter */
+	if ((fmt_flags & ENTRY_STRIP_EXT) &&
+	    (p = strrchr(bprm->filename, '.'))) {
+		*p = '\0';
+		remove_arg_zero(bprm);
+		bprm->p = copy_strings(1, &bprm->filename, bprm->page, bprm->p, 2);
+		bprm->argc++;
+	}
+	bprm->p = copy_strings(1, &iname_addr, bprm->page, bprm->p, 2);
+	bprm->argc++;
+	if (!bprm->p) {
+		retval = -E2BIG;
+		goto _ret;
+	}
+	bprm->filename = iname;	/* for binfmt_script */
+
+	if ((retval = open_namei(iname, 0, 0, &bprm->inode, NULL)))
+		goto _ret;
+	bprm->dont_iput = 0;
+
+	if ((retval = prepare_binprm(bprm)) >= 0)
+		retval = search_binary_handler(bprm, regs);
+_ret:
+	MOD_DEC_USE_COUNT;
+	return retval;
+}
+
+
+
+/*
+ * /proc handling routines
+ */
+
+/*
+ * parses and copies one argument enclosed in del from *sp to *dp,
+ * recognising the \x special.
+ * returns pointer to the copied argument or NULL in case of an
+ * error (and sets err) or null argument length.
+ */
+static char *copyarg(char **dp, const char **sp, int *count,
+		     char del, int special, int *err)
+{
+	char c, *res = *dp;
+
+	while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) {
+		switch (c) {
+		case '\\':
+			if (special && (**sp == 'x')) {
+				if (!isxdigit(c = toupper(*(++*sp))))
+					*err = -EINVAL;
+				**dp = (c - (isdigit(c) ? '0' : 'A' - 10)) * 16;
+				if (!isxdigit(c = toupper(*(++*sp))))
+					*err = -EINVAL;
+				*((*dp)++) += c - (isdigit(c) ? '0' : 'A' - 10);
+				++*sp;
+				*count -= 3;
+				break;
+			}
+		default:
+			*((*dp)++) = c;
+		}
+	}
+	if (*err || (c != del) || (res == *dp))
+		res = NULL;
+	else if (!special)
+		*((*dp)++) = '\0';
+	return res;
+}
+
+/*
+ * This registers a new binary format, it recognises the syntax
+ * ':name:type:offset:magic:mask:interpreter:'
+ * where the ':' is the IFS, that can be chosen with the first char
+ */
+static int proc_write_register(struct file *file, const char *buffer,
+			       unsigned long count, void *data)
+{
+	const char *sp;
+	char del, *dp;
+	struct binfmt_entry *e;
+	int memsize, cnt = count - 1, err = 0;
+
+	MOD_INC_USE_COUNT;
+	/* some sanity checks */
+	if ((count < 11) || (count > 256)) {
+		err = -EINVAL;
+		goto _err;
+	}
+
+	memsize = sizeof(struct binfmt_entry) + count;
+	if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER))) {
+		err = -ENOMEM;
+		goto _err;
+	}
+
+	sp = buffer + 1;
+	del = buffer[0];
+	dp = (char *)e + sizeof(struct binfmt_entry);
+
+	e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err);
+
+	/* we can use bit 3 and 5 of type for ext/magic and ext-strip
+	   flag due to the nice encoding of E, M, e and m */
+	if ((*sp & 0x92) || (sp[1] != del))
+		err = -EINVAL;
+	else
+		e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_STRIP_EXT))
+			    | ENTRY_ENABLED;
+	cnt -= 2; sp++;
+
+	e->offset = 0;
+	while (cnt-- && isdigit(*sp))
+		e->offset = e->offset * 10 + *sp++ - '0';
+	if (*sp++ != del)
+		err = -EINVAL;
+
+	e->magic = copyarg(&dp, &sp, &cnt, del, (e->flags & ENTRY_MAGIC), &err);
+	e->size = dp - e->magic;
+	e->mask = copyarg(&dp, &sp, &cnt, del, 1, &err);
+	if (e->mask && ((dp - e->mask) != e->size))
+		err = -EINVAL;
+	e->interpreter = copyarg(&dp, &sp, &cnt, del, 0, &err);
+	e->id = free_id++;
+
+	/* more sanity checks */
+	if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) ||
+	    (e->size < 1) || ((e->size + e->offset) > 127) ||
+	    !(e->proc_name) || !(e->interpreter) ||
+	    entry_proc_setup(e)) {
+		kfree(e);
+		err = -EINVAL;
+		goto _err;
+	}
+
+	write_lock(&entries_lock);
+	e->next = entries;
+	entries = e;
+	write_unlock(&entries_lock);
+
+	return count;
+_err:
+	MOD_DEC_USE_COUNT;
+	return err;
+}
+
+/*
+ * Get status of entry/binfmt_misc
+ * FIXME? should an entry be marked disabled if binfmt_misc is disabled though
+ *        entry is enabled?
+ */
+static int proc_read_status(char *page, char **start, off_t off,
+			    int count, int *eof, void *data)
+{
+	struct binfmt_entry *e;
+	char *dp;
+	int elen, i;
+
+	MOD_INC_USE_COUNT;
+#ifndef VERBOSE_STATUS
+	if (data) {
+		read_lock(&entries_lock);
+		if (!(e = get_entry((int) data)))
+			i = 0;
+		else
+			i = e->flags & ENTRY_ENABLED;
+		read_unlock(&entries_lock);
+	} else {
+		i = enabled;
+	} 
+	sprintf(page, "%s\n", (i ? "enabled" : "disabled"));
+#else
+	if (!data)
+		sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
+	else {
+		read_lock(&entries_lock);
+		if (!(e = get_entry((int) data))) {
+			*page = '\0';
+			goto _out;
+		}
+		sprintf(page, "%s\ninterpreter %s\n",
+		        (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"),
+			e->interpreter);
+		dp = page + strlen(page);
+		if (!(e->flags & ENTRY_MAGIC)) {
+			sprintf(dp, "extension .%s\n", e->magic);
+			dp = page + strlen(page);
+		} else {
+			sprintf(dp, "offset %i\nmagic ", e->offset);
+			dp = page + strlen(page);
+			for (i = 0; i < e->size; i++) {
+				sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
+				dp += 2;
+			}
+			if (e->mask) {
+				sprintf(dp, "\nmask ");
+				dp += 6;
+				for (i = 0; i < e->size; i++) {
+					sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
+					dp += 2;
+				}
+			}
+			*dp++ = '\n';
+			*dp = '\0';
+		}
+		if (e->flags & ENTRY_STRIP_EXT)
+			sprintf(dp, "extension stripped\n");
+_out:
+		read_unlock(&entries_lock);
+	}
+#endif
+
+	elen = strlen(page) - off;
+	if (elen < 0)
+		elen = 0;
+	*eof = (elen <= count) ? 1 : 0;
+	*start = page + off;
+
+	MOD_DEC_USE_COUNT;
+	return elen;
+}
+
+/*
+ * Set status of entry/binfmt_misc:
+ * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
+ */
+static int proc_write_status(struct file *file, const char *buffer,
+			     unsigned long count, void *data)
+{
+	struct binfmt_entry *e;
+	int res = count;
+
+	MOD_INC_USE_COUNT;
+	if (((buffer[0] == '1') || (buffer[0] == '0')) &&
+	    ((count == 1) || ((count == 2) && (buffer[1] == '\n')))) {
+		if (data) {
+			read_lock(&entries_lock);
+			if ((e = get_entry((int) data)))
+				e->flags = (e->flags & -2) | (int) (buffer[0] - '0');
+			read_unlock(&entries_lock);
+		} else {
+			enabled = buffer[0] - '0';
+		}
+	} else if ((buffer[0] == '-') && (buffer[1] == '1') &&
+	       ((count == 2) || ((count == 3) && (buffer[2] == '\n')))) {
+		if (data)
+			clear_entry((int) data);
+		else
+			clear_entries();
+	} else {
+		res = -EINVAL;
+	}
+	MOD_DEC_USE_COUNT;
+	return res;
+}
+
+/*
+ * Remove the /proc-dir entries of one binfmt
+ */
+static void entry_proc_cleanup(struct binfmt_entry *e)
+{
+	remove_proc_entry(e->proc_name, bm_dir);
+}
+
+/*
+ * Create the /proc-dir entry for binfmt
+ */
+static int entry_proc_setup(struct binfmt_entry *e)
+{
+	if (!(e->proc_dir = create_proc_entry(e->proc_name,
+			 	S_IFREG | S_IRUGO | S_IWUSR, bm_dir)))
+		return -ENOMEM;
+
+	e->proc_dir->data = (void *) (e->id);
+	e->proc_dir->read_proc = proc_read_status;
+	e->proc_dir->write_proc = proc_write_status;
+
+	return 0;
+}
+
+
+__initfunc(int init_misc_binfmt(void))
+{
+	struct proc_dir_entry *status = NULL, *reg;
+
+	if (!(bm_dir = create_proc_entry("sys/fs/binfmt_misc", S_IFDIR,
+					 NULL)) ||
+	    !(status = create_proc_entry("status", S_IFREG | S_IRUGO | S_IWUSR,
+					 bm_dir)) ||
+	    !(reg = create_proc_entry("register", S_IFREG | S_IWUSR,
+				      bm_dir))) {
+		if (status)
+			remove_proc_entry("status", bm_dir);
+		if (bm_dir)
+			remove_proc_entry("sys/fs/binfmt_misc", NULL);
+		return -ENOMEM;
+	}
+	status->read_proc = proc_read_status;
+	status->write_proc = proc_write_status;
+
+	reg->write_proc = proc_write_register;
+
+	return register_binfmt(&misc_format);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+int init_module(void)
+{
+	return init_misc_binfmt();
+}
+
+void cleanup_module(void)
+{
+	unregister_binfmt(&misc_format);
+	remove_proc_entry("register", bm_dir);
+	remove_proc_entry("status", bm_dir);
+	remove_proc_entry("sys/fs/binfmt_misc", NULL);
+}
+#endif
+#undef VERBOSE_STATUS
diff -u --recursive --new-file v2.1.42/linux/fs/buffer.c linux/fs/buffer.c
--- v2.1.42/linux/fs/buffer.c	Thu May 29 21:53:08 1997
+++ linux/fs/buffer.c	Mon Jun 16 08:46:23 1997
@@ -36,6 +36,7 @@
 #include <linux/smp_lock.h>
 #include <linux/vmalloc.h>
 #include <linux/blkdev.h>
+#include <linux/sysrq.h>
 
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -81,8 +82,6 @@
  * remove any of the parameters, make sure to update kernel/sysctl.c.
  */
 
-static void wakeup_bdflush(int);
-
 #define N_PARAM 9
 
 /* The dummy values in this structure are left in there for compatibility
@@ -113,6 +112,8 @@
 int bdflush_min[N_PARAM] = {  0,  10,    5,   25,  0,   100,   100, 1, 1};
 int bdflush_max[N_PARAM] = {100,5000, 2000, 2000,100, 60000, 60000, 2047, 5};
 
+void wakeup_bdflush(int);
+
 /*
  * Rewrote the wait-routines to use the "new" wait-queue functionality,
  * and getting rid of the cli-sti pairs. The wait-queue routines still
@@ -1109,10 +1110,10 @@
 {
 	if (test_and_clear_bit(PG_decr_after, &page->flags))
 		atomic_dec(&nr_async_pages);
+	if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
+		swap_after_unlock_page(page->pg_swap_entry);
 	if (test_and_clear_bit(PG_free_after, &page->flags))
 		__free_page(page);
-	if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
-		swap_after_unlock_page(page->swap_unlock_entry);
 }
 
 /*
@@ -1533,7 +1534,7 @@
 struct wait_queue * bdflush_done = NULL;
 struct task_struct *bdflush_tsk = 0;
 
-static void wakeup_bdflush(int wait)
+void wakeup_bdflush(int wait)
 {
 	if (current == bdflush_tsk)
 		return;
@@ -1707,7 +1708,9 @@
 #ifdef DEBUG
 		printk("bdflush() activated...");
 #endif
-		
+
+		CHECK_EMERGENCY_SYNC
+
 		ncount = 0;
 #ifdef DEBUG
 		for(nlist = 0; nlist < NR_LIST; nlist++)
diff -u --recursive --new-file v2.1.42/linux/fs/dcache.c linux/fs/dcache.c
--- v2.1.42/linux/fs/dcache.c	Tue May 13 22:41:14 1997
+++ linux/fs/dcache.c	Thu Jun 12 21:53:45 1997
@@ -1,283 +1,1039 @@
 /*
- *  linux/fs/dcache.c
+ * fs/dcache.c
  *
- *  (C) Copyright 1994 Linus Torvalds
+ * Complete reimplementation
+ * (C) 1997 Thomas Schoebel-Theuer
  */
 
-/* Speeded up searches a bit and threaded the mess. -DaveM */
+/* The new dcache is exclusively called from the VFS, not from
+ * the specific fs'es any more. Despite having the same name as in the
+ * old code, it has less to do with it.
+ *
+ * It serves many purposes:
+ *
+ *  1) Any inode that has been retrieved with lookup() and is in use
+ *     (i_count>0), has access to its full absolute path name, by going
+ *     to inode->i_dentry and then recursively following the entry->d_parent
+ *     chain. Use d_path() as predefined method for that.
+ *     You may find out the corresponding inode belonging to
+ *     a dentry by calling d_inode(). This can be used as an easy way for
+ *     determining .. and its absolute pathname, an old UNIX problem that
+ *     deserved a solution for a long time.
+ *     Note that hardlinked inodes may have multiple dentries assigned to
+ *     (via the d_next chain), reflecting multiple alias pathnames.
+ *
+ *  2) If not disabled by filesystem types specifying FS_NO_DCACHE,
+ *     the dentries of unused (aged) inodes are retained for speeding up
+ *     lookup()s, by allowing hashed inquiry starting from the dentry of
+ *     the parent directory.
+ *
+ *  3) It can remeber so-called "negative entries", that is dentries for
+ *     pathnames that are known to *not* exist, so unneccessary repeated
+ *     lookup()s for non-existant names can be saved.
+ *
+ *  4) It provides a means for keeping deleted files (inode->i_nlink==0)
+ *     accessible in the so-called *basket*. Inodes in the basket have been
+ *     removed with unlink() while being in use (i_count>0), so they would
+ *     normally use up space on the disk and be accessile through their
+ *     filedescriptor, but would not be accessible for lookup() any more.
+ *     The basket simply keeps such files in the dcache (for potential
+ *     dcache lookup) until they are either eventually removed completely,
+ *     or transferred to the second-level basket, the so-called *ibasket*.
+ *     The ibasket is implemented in the new inode code, on request of
+ *     filesystem types that have the flag FS_IBASKET set, and proliferates
+ *     the unlinked files when i_count has gone to zero, at least as long
+ *     as there is space on the disk and enough inodes remain available
+ *     and no umount() has started.
+ *
+ *  5) Preliminary dentries can be added by readdir(). While normal dentries
+ *     directly point to the inode via u.d_inode only the inode number is
+ *     known from readdir(), but not more. They can be converted to
+ *     normal dentries by using d_inode().
+ */
 
 /*
- * The directory cache is a "two-level" cache, each level doing LRU on
- * its entries.  Adding new entries puts them at the end of the LRU
- * queue on the first-level cache, while the second-level cache is
- * fed by any cache hits.
- *
- * The idea is that new additions (from readdir(), for example) will not
- * flush the cache of entries that have really been used.
+ * Notes on the allocation strategy:
  *
- * There is a global hash-table over both caches that hashes the entries
- * based on the directory inode number and device as well as on a
- * string-hash computed over the name. 
+ * The dcache is a full slave cache of the inodes. Whenever an inode
+ * is cleared, all the dentries associated with it will recursively
+ * disappear. dentries have no own reference counting; this has to
+ * be obeyed for SMP.
+ * If directories could go out of inode cache while
+ * successors are alive, this would interrupt the d_parent chain of
+ * the live successors. To prevent this without using zombies, all
+ * directories are thus prevented from __iput() as long as successors
+ * are alive.
  */
 
-#include <linux/fs.h>
+#include <linux/config.h>
 #include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/dalloc.h>
+#include <linux/dlists.h>
 
-#include <asm/unaligned.h>
-#include <asm/spinlock.h>
-
-spinlock_t dcache_lock = SPIN_LOCK_UNLOCKED;
+/* this should be removed after the beta phase */
+/* #define DEBUG */
+/*#undef DEBUG*/
+/* #define DEBUG_DDIR_COUNT */
+
+#define D_HASHSIZE   64
+
+/* local flags for d_flag */
+#define D_DIR          32
+#define D_HASHED       64
+#define D_ZOMBIE      128
+#define D_PRELIMINARY 256
+#define D_INC_DDIR    512
+
+/* local flags for d_del() */
+#define D_RECURSIVE 4
+#define D_NO_FREE   8
+
+/* adjust these constants if you know a probability distribution ... */
+#define D_SMALL 16
+#define D_MEDIUM 64
+#define D_LARGE 256
+#define D_HUGE D_MAXLEN
+
+#define BASE_DHEADER(x) (struct dheader*)((unsigned long)(x) & ~(PAGE_SIZE-1))
+#define BYTE_ADD(x,n) (void*)((char*)(x) + (n))
+#define BYTE_SUB(x,n) (void*)((char*)(x) - (n))
 
-/*
- * Don't bother caching long names.. They just take up space in the cache, and
- * for a name cache you just want to cache the "normal" names anyway which tend
- * to be short.
+/* This is for global allocation of dentries.  Remove this when
+ * converting to SLAB.
  */
-#define DCACHE_NAME_LEN	15
-#define DCACHE_SIZE 1024
-#define DCACHE_HASH_QUEUES 256	/* keep this a pow2 */
+struct dheader {
+	struct dentry * emptylist;
+	short free, maxfree;
+	struct dheader * next;
+	struct dheader * prev;
+};
 
-/*
- * The dir_cache_entry must be in this order: we do ugly things with the pointers
+struct anchors {
+	struct dheader * free; /* each contains at least 1 empty dentry */
+	struct dheader * full; /* all the used up ones */
+	struct dheader * dir_free; 
+	struct dheader * dir_full; 
+};
+
+/* This is only used for directory dentries. Think of it as an extension
+ * of the dentry.
+ * It is defined as separate struct, so it uses up space only
+ * where necessary.
  */
-struct dir_cache_entry {
-	struct dir_cache_entry *next;
-	struct dir_cache_entry **pprev;
-	kdev_t dc_dev;
-	unsigned long dir;
-	unsigned long version;
-	unsigned long ino;
-	unsigned char name_len;
-	char name[DCACHE_NAME_LEN];
-	struct dir_cache_entry ** lru_head;
-	struct dir_cache_entry * next_lru,  * prev_lru;
+struct ddir {
+	struct dentry * dd_hashtable[D_HASHSIZE];
+	struct dentry * dd_neglist;
+	struct dentry * dd_basketlist;
+	struct dentry * dd_zombielist;
+	unsigned short dd_alloced; /* # d_alloc()ed, but not yet d_add()ed */
+	unsigned short dd_hashed;  /* # of entries in hashtable */
+	unsigned short dd_true_hashed; /* # non-preliminaries in hashtable */
+	unsigned short dd_negs; /* # of negative entries */
 };
 
-#define dcache_offset(x) ((unsigned long)&((struct dir_cache_entry*)0)->x)
-#define dcache_datalen (dcache_offset(lru_head) - dcache_offset(dc_dev))
+DEF_INSERT(header,struct dheader,next,prev)
+DEF_REMOVE(header,struct dheader,next,prev)
 
-#define COPYDATA(de, newde) \
-memcpy((void *) &newde->dc_dev, (void *) &de->dc_dev, dcache_datalen)
+DEF_INSERT(alias,struct dentry,d_next,d_prev)
+DEF_REMOVE(alias,struct dentry,d_next,d_prev)
 
-static struct dir_cache_entry level1_cache[DCACHE_SIZE];
-static struct dir_cache_entry level2_cache[DCACHE_SIZE];
+DEF_INSERT(hash,struct dentry,d_hash_next,d_hash_prev)
+DEF_REMOVE(hash,struct dentry,d_hash_next,d_hash_prev)
 
-/*
- * The LRU-lists are doubly-linked circular lists, and do not change in size
- * so these pointers always have something to point to (after _init)
- */
-static struct dir_cache_entry * level1_head;
-static struct dir_cache_entry * level2_head;
+DEF_INSERT(basket,struct dentry,d_basket_next,d_basket_prev)
+DEF_REMOVE(basket,struct dentry,d_basket_next,d_basket_prev)
 
-/* The hash queues are layed out in a slightly different manner. */
-static struct dir_cache_entry *hash_table[DCACHE_HASH_QUEUES];
+static struct anchors anchors[4];
 
-#define hash_fn(dev,dir,namehash) \
-	((HASHDEV(dev) ^ (dir) ^ (namehash)) & (DCACHE_HASH_QUEUES - 1))
+struct dentry * the_root = NULL;
 
-/*
- * Stupid name"hash" algorithm. Write something better if you want to,
- * but I doubt it matters that much.
+unsigned long name_cache_init(unsigned long mem_start, unsigned long mem_end)
+{
+	memset(anchors, 0, sizeof(anchors));
+	return mem_start;
+}
+
+#ifdef DEBUG
+/* throw this away after the beta phase */
+/*************************************************************************/
+extern void xcheck(char * txt, struct inode * p);
+
+static int x_alloc = 0;
+static int x_freed = 0;
+static int x_free = 0;
+
+static void * tst[20000];
+static int cnt = 0;
+
+static void ins(void* ptr)
+{
+	extern int inodes_stat;
+	tst[cnt++] = ptr;
+        if(cnt % 1000 == 0)
+		printk("------%d allocated: %d: %d %d %d\n", inodes_stat, cnt,
+		       x_alloc, x_freed, x_free);
+	if(cnt>=20000) panic("stop");
+}
+
+#if 0
+static inline int search(void* ptr)
+{
+	int i;
+	for(i = cnt-1; i>=0; i--)
+		if(tst[i] == ptr)
+			return i;
+	return -1;
+}
+
+#define TST(n,x) if(search(x)<0) printk("%s bad ptr %p line %d\n", n, x, __LINE__)
+#else
+#define TST(n,x) /*nothing*/
+#endif
+
+void LOG(char * txt, struct dentry * entry)
+{
+	static int count = 0;
+	if(entry) {
+		TST(txt,entry);
+	}
+	if(count) {
+		count--;
+		printk("%s: entry=%p\n", txt, entry);
+	}
+}
+
+#ifdef DEBUG_DDIR_COUNT
+static struct ddir * d_dir(struct dentry * entry);
+void recursive_test(struct dentry * entry)
+{
+	int i;
+	struct ddir * ddir = d_dir(entry);
+	int sons = 0;
+
+	if(ddir->dd_zombielist)
+		sons++;
+	for(i=0; i < D_HASHSIZE; i++) {
+		struct dentry ** base = &ddir->dd_hashtable[i];
+		struct dentry * tmp = *base;
+		if(tmp) do {
+			TST("__clear",tmp);
+			if(!(tmp->d_flag & D_HASHED)) {
+				printk("VFS: dcache entry not hashed!\n");
+				printpath(*base); printk("\n");
+				printpath(tmp);
+			}
+			if(!(tmp->d_flag & D_PRELIMINARY))
+				sons++;
+			if(tmp->d_flag & D_DIR)
+				recursive_test(tmp);
+			tmp = tmp->d_hash_next;
+		} while(tmp && tmp != *base);
+	}
+	if(!sons && !(entry->d_flag & D_PRELIMINARY) && entry->u.d_inode) {
+		struct inode * inode = entry->u.d_inode;
+		if(!atomic_read(&inode->i_count)) {
+			if(!(inode->i_status & 1/*ST_AGED*/)) {
+				printpath(entry);
+				printk(" is not aged!\n");
+			}
+			if(inode->i_ddir_count) {
+				printpath(entry);
+				printk(" has ddir_count blockage!\n");
+			}
+		}
+	}
+}
+#else
+#define recursive_test(e) /*nothing*/
+#endif
+#else
+#define TST(n,x) /*nothing*/
+#define LOG(n,x) /*nothing*/
+#define xcheck(t,i) /*nothing*/
+#define recursive_test(e) /*nothing*/
+/*****************************************************************************/
+#endif
+
+void printpath(struct dentry * entry)
+{
+	if(!IS_ROOT(entry))
+		printpath(entry->d_parent);
+	printk("/%s", entry->d_name);
+}
+
+static inline long has_sons(struct ddir * ddir)
+{
+	return ((ddir->dd_alloced | ddir->dd_hashed)	||
+		ddir->dd_neglist			||
+		ddir->dd_basketlist			||
+		ddir->dd_zombielist);
+}
+
+static inline int has_true_sons(struct ddir * ddir)
+{
+	return (ddir->dd_alloced | ddir->dd_true_hashed);
+}
+
+/* Only hold the i_ddir_count pseudo refcount when neccessary (i.e. when
+ * they have true_sons), to prevent keeping too much dir inodes in use.
  */
-static unsigned long namehash(const char * name, int len)
+static inline void inc_ddir(struct dentry * entry, struct inode * inode)
 {
-	unsigned long hash = 0;
+	if(!(entry->d_flag & D_INC_DDIR)) {
+		entry->d_flag |= D_INC_DDIR;
+#ifdef DEBUG
+		if(inode->i_ddir_count) {
+			printpath(entry);
+			printk(" ddir_count=%d\n", inode->i_ddir_count);
+		}
+#endif
+		inode->i_ddir_count++;
+		_get_inode(inode);
+	}
+}
 
-	while ((len -= sizeof(unsigned long)) > 0) {
-		hash += get_unaligned((unsigned long *)name);
-		name += sizeof(unsigned long);
+static inline blocking void dec_ddir(struct dentry * entry, struct inode * inode)
+{
+	if(entry->d_flag & D_INC_DDIR) {
+		entry->d_flag &= ~D_INC_DDIR;
+		inode->i_ddir_count--;
+		if(!inode->i_ddir_count)
+			__iput(inode);
 	}
-	return hash +
-		(get_unaligned((unsigned long *)name) &
-		 ~(~0UL << ((len + sizeof(unsigned long)) << 3)));
 }
 
-static inline struct dir_cache_entry **get_hlist(struct inode *dir,
-						 const char *name, int len)
+/* Do not inline this many times. */
+static void d_panic(void)
 {
-	return hash_table + hash_fn(dir->i_dev, dir->i_ino, namehash(name, len));
+	panic("VFS: dcache directory corruption");
 }
 
-static inline void remove_lru(struct dir_cache_entry * de)
+static inline struct ddir * d_dir(struct dentry * entry)
 {
-	struct dir_cache_entry * next = de->next_lru;
-	struct dir_cache_entry * prev = de->prev_lru;
+	struct ddir * res = BYTE_SUB(entry, sizeof(struct ddir));
 
-	next->prev_lru = prev;
-	prev->next_lru = next;
+	if(!(entry->d_flag & D_DIR))
+		d_panic();
+#ifdef DEBUG
+	if(!entry)
+		panic("entry NULL!");
+	if(BASE_DHEADER(res) != BASE_DHEADER(entry))
+		printk("Scheisse!!!\n");
+#endif
+	return res;
 }
 
-static inline void add_lru(struct dir_cache_entry * de, struct dir_cache_entry *head)
+static /*inline*/ struct dheader * dinit(int isdir, int size)
 {
-	struct dir_cache_entry * prev = head->prev_lru;
+	struct dheader * res = (struct dheader*)__get_free_page(GFP_KERNEL);
+	int restlen = PAGE_SIZE - sizeof(struct dheader);
+	struct dentry * ptr = BYTE_ADD(res, sizeof(struct dheader));
+
+	if(!res)
+		return NULL;
+        memset(res, 0, sizeof(struct dheader));
+	if(isdir) {
+		ptr = BYTE_ADD(ptr, sizeof(struct ddir));
+		size += sizeof(struct ddir);
+	}
+	if(BASE_DHEADER(ptr) != res) 
+		panic("Bad kernel page alignment");
+	size += sizeof(struct dentry) - D_MAXLEN;
+	res->emptylist = NULL;
+	res->free = 0;
+	while(restlen >= size) {
+#ifdef DEBUG
+		ins(ptr);
+		if(BASE_DHEADER(ptr) != res)
+			panic("Wrong dinit!");
+#endif
+		ptr->d_next = res->emptylist;
+		res->emptylist = ptr;
+		ptr = BYTE_ADD(ptr, size);
+		res->free++;
+		restlen -= size;
+	}
+	res->maxfree = res->free;
+	return res;
+}
 
-	de->next_lru = head;
-	de->prev_lru = prev;
-	prev->next_lru = de;
-	head->prev_lru = de;
+static /*inline*/ struct dentry * __dalloc(struct anchors * anchor,
+					   struct dentry * parent, int isdir,
+					   int len, int size)
+{
+	struct dheader ** free = isdir ? &anchor->dir_free : &anchor->free;
+	struct dheader ** full = isdir ? &anchor->dir_full : &anchor->full;
+	struct dheader * base = *free;
+	struct dentry * res;
+
+	if(!base) {
+		base = dinit(isdir, size);
+		if(!base)
+			return NULL;
+		insert_header(free, base);
+	}
+	base->free--;
+	res = base->emptylist;
+	if(!(base->emptylist = res->d_next)) {
+		remove_header(free, base);
+		insert_header(full, base);
+	}
+	memset(res, 0, sizeof(struct dentry) - D_MAXLEN);
+	if(isdir) {
+		res->d_flag = D_DIR;
+		memset(d_dir(res), 0, sizeof(struct ddir));
+	}
+	res->d_len = len;
+	res->d_parent = parent;
+	if(parent) {
+		struct ddir * pdir = d_dir(parent);
+#ifdef DEBUG
+		if(pdir->dd_alloced > 1 && !IS_ROOT(parent)) {
+			printpath(parent);
+			printk(" dd_alloced=%d\n", pdir->dd_alloced);
+		}
+#endif
+		pdir->dd_alloced++;
+	}
+#ifdef DEBUG
+	x_alloc++;
+#endif
+	return res;
 }
 
-static inline void update_lru(struct dir_cache_entry * de)
+struct dentry * d_alloc(struct dentry * parent, int len, int isdir)
 {
-	if (de == *de->lru_head)
-		*de->lru_head = de->next_lru;
-	else {
-		remove_lru(de);
-		add_lru(de,*de->lru_head);
+	int i, size;
+
+#ifdef DEBUG
+        if(the_root)
+	        recursive_test(the_root);
+	LOG("d_alloc", parent);
+#endif
+	if(len >= D_MEDIUM) {
+		if(len >= D_LARGE) {
+			i = 3;
+			size = D_HUGE;
+		} else {
+			i = 2;
+			size = D_LARGE;
+		} 
+	} else if(len >= D_SMALL) {
+		i = 1;
+		size = D_MEDIUM;
+	} else {
+		i = 0;
+		size = D_SMALL;
 	}
+	return __dalloc(&anchors[i], parent, isdir, len, size);
 }
 
-/*
- * Hash queue manipulation. Look out for the casts..
- *
- * What casts? 8-) -DaveM
- */
-static inline void remove_hash(struct dir_cache_entry * de)
+extern blocking struct dentry * d_alloc_root(struct inode * root_inode)
 {
-	if(de->pprev) {
-		if(de->next)
-			de->next->pprev = de->pprev;
-		*de->pprev = de->next;
-		de->pprev = NULL;
+	struct dentry * res = the_root;
+
+	if(res) {
+		d_del(res, D_NO_CLEAR_INODE); /* invalidate everything beyond */
+	} else {
+		struct ddir * ddir;
+
+		the_root = res = d_alloc(NULL, 0, 1);
+		LOG("d_alloc_root", res);
+		res->d_parent = res;
+		res->d_name[0]='\0';
+		ddir = d_dir(res);
+		ddir->dd_alloced = 999; /* protect from deletion */
 	}
+	insert_alias(&root_inode->i_dentry, res);
+	root_inode->i_dent_count++;
+	root_inode->i_ddir_count++;
+	res->u.d_inode = root_inode;
+	return res;
 }
 
-static inline void add_hash(struct dir_cache_entry * de, struct dir_cache_entry ** hash)
+static inline unsigned long d_hash(char first, char last)
 {
-	if((de->next = *hash) != NULL)
-		(*hash)->pprev = &de->next;
-	*hash = de;
-	de->pprev = hash;
+	return ((unsigned long)first ^ ((unsigned long)last << 4)) & (D_HASHSIZE-1);
 }
 
-/*
- * Find a directory cache entry given all the necessary info.
- */
-static inline struct dir_cache_entry * find_entry(struct inode * dir, const char * name, unsigned char len, struct dir_cache_entry ** hash)
+static inline struct dentry ** d_base_entry(struct ddir * pdir, struct dentry * entry)
 {
-	struct dir_cache_entry *de;
+	return &pdir->dd_hashtable[d_hash(entry->d_name[0],
+					  entry->d_name[entry->d_len-1])];
+}
 
-	de = *hash;
-	goto inside;
-	for (;;) {
-		de = de->next;
-inside:
-		if (!de)
-			break;
-		if((de->name_len == (unsigned char) len)	&&
-		   (de->dc_dev == dir->i_dev)			&&
-		   (de->dir == dir->i_ino)			&&
-		   (de->version == dir->i_version)		&&
-		   (!memcmp(de->name, name, len)))
-			break;
+static inline struct dentry ** d_base_qstr(struct ddir * pdir,
+					   struct qstr * s1,
+					   struct qstr * s2)
+{
+	unsigned long hash;
+
+	if(s2 && s2->len) {
+		hash = d_hash(s1->name[0], s2->name[s2->len-1]);
+	} else {
+		hash = d_hash(s1->name[0], s1->name[s1->len-1]);
 	}
-	return de;
+	return &pdir->dd_hashtable[hash];
 }
 
-/*
- * Move a successfully used entry to level2. If already at level2,
- * move it to the end of the LRU queue..
+
+static /*inline*/ blocking void _d_remove_from_parent(struct dentry * entry,
+						      struct ddir * pdir,
+						      struct inode * inode,
+						      int flags)
+{
+	if(entry->d_flag & D_HASHED) {
+		struct dentry ** base = d_base_entry(pdir, entry);
+
+		remove_hash(base, entry);
+		entry->d_flag &= ~D_HASHED;
+		pdir->dd_hashed--;
+		if(!(entry->d_flag & D_PRELIMINARY)) {
+			pdir->dd_true_hashed--;
+			if(!inode) {
+#ifdef DEBUG
+				if(!entry->d_next || !entry->d_prev) {
+					printpath(entry);
+					printk(" flags=%x d_flag=%x negs=%d "
+					       "hashed=%d\n", flags, entry->d_flag,
+					       pdir->dd_negs, pdir->dd_hashed);
+				}
+#endif
+				remove_alias(&pdir->dd_neglist, entry);
+				pdir->dd_negs--;
+			}
+		}
+	} else if(!(entry->d_flag & D_ZOMBIE)) {
+#ifdef DEBUG
+		if(!pdir->dd_alloced) printk("dd_alloced is 0!\n");
+#endif
+		pdir->dd_alloced--;
+	}
+	if(entry->d_flag & D_BASKET) {
+		remove_basket(&pdir->dd_basketlist, entry);
+		entry->d_flag &= ~D_BASKET;
+	}
+}
+
+/* Theoretically, zombies should never or extremely seldom appear,
+ * so this code is nearly superfluous.
+ * A way to get zombies is while using inodes (i_count>0), unlink()
+ * them as well as rmdir() the parent dir => the parent dir becomes a zombie.
+ * Zombies are *not* in the hashtable, because somebody could re-creat()
+ * that filename in it's parent dir again.
+ * Besides coding errors during beta phase, when forcing an umount()
+ * (e.g. at shutdown time), inodes could be in use such that the parent
+ * dir is cleared, resulting also in zombies.
  */
-static inline void move_to_level2(struct dir_cache_entry * old_de, struct dir_cache_entry ** hash)
+static /*inline*/ void _d_handle_zombie(struct dentry * entry,
+					struct ddir * ddir,
+					struct ddir * pdir)
 {
-	struct dir_cache_entry * de;
+	if(entry->d_flag & D_DIR) {
+		if(entry->d_flag & D_ZOMBIE) {
+			if(!has_sons(ddir)) {
+				entry->d_flag &= ~D_ZOMBIE;
+				remove_hash(&pdir->dd_zombielist, entry);
+				if(!pdir->dd_zombielist &&
+				   (entry->d_parent->d_flag & D_ZOMBIE)) {
+					d_del(entry->d_parent, D_NORMAL);
+				}
+			}
+		} else if(has_sons(ddir)) {
+			entry->d_flag |= D_ZOMBIE;
+			insert_hash(&pdir->dd_zombielist, entry);
+
+			/* This condition is no longer a bug, with the removal
+			 * of recursive_clear() this happens naturally during
+			 * an unmount attempt of a filesystem which is busy.
+			 */
+#if 0
+			/* Not sure when this message should show up... */
+			if(!IS_ROOT(entry)) {
+				printk("VFS: clearing dcache directory "
+				       "with successors\n");
+#ifdef DEBUG
+				printpath(entry);
+				printk(" d_flag=%x alloced=%d negs=%d hashed=%d "
+				       "basket=%p zombies=%p\n",
+				       entry->d_flag, ddir->dd_alloced,
+				       ddir->dd_negs, ddir->dd_hashed,
+				       ddir->dd_basketlist, ddir->dd_zombielist);
+#endif
+			}
+#endif
+		}
+	}
+}
+
+static /*inline*/ blocking void _d_del(struct dentry * entry,
+				       struct anchors * anchor,
+				       int flags)
+{
+	struct dheader ** free;
+	struct dheader ** full;
+	struct dheader * base = BASE_DHEADER(entry);
+	struct ddir * ddir = NULL;
+	struct ddir * pdir;
+	struct inode * inode = entry->d_flag & D_PRELIMINARY ? NULL : entry->u.d_inode;
+
+#ifdef DEBUG
+	if(inode)
+		xcheck("_d_del", inode);
+#endif
+	if(!entry->d_parent) {
+		printk("VFS: dcache parent is NULL\n");
+		return;
+	}
+	if(entry->d_flag & D_DIR) {
+		free = &anchor->dir_free;
+		full = &anchor->dir_full;
+	} else {
+		free = &anchor->free;
+		full = &anchor->full;
+	}
+	pdir = d_dir(entry->d_parent);
+	if(!IS_ROOT(entry))
+		_d_remove_from_parent(entry, pdir, inode, flags);
 
-	if (old_de->lru_head == &level2_head) {
-		update_lru(old_de);
+	/* This may block, be careful! _d_remove_from_parent() is
+	 * thus called before.
+	 */
+	if(entry->d_flag & D_DIR)
+		ddir = d_dir(entry);
+	if(IS_ROOT(entry))
 		return;
-	}	
-	de = level2_head;
-	level2_head = de->next_lru;
-	remove_hash(de);
-	COPYDATA(old_de, de);
-	add_hash(de, hash);
+
+	if(flags & D_NO_FREE) {
+		/* Make it re-d_add()able */
+		pdir->dd_alloced++;
+		entry->d_flag &= D_DIR;
+	} else
+		_d_handle_zombie(entry, ddir, pdir);
+
+	/* This dec_ddir() must occur after zombie handling. */
+	if(!has_true_sons(pdir))
+		dec_ddir(entry->d_parent, entry->d_parent->u.d_inode);
+
+	entry->u.d_inode = NULL;
+	if(inode) {
+		remove_alias(&inode->i_dentry, entry);
+		inode->i_dent_count--;
+		if (entry->d_flag & D_DIR)
+			dec_ddir(entry, inode);
+
+		if(!(flags & D_NO_CLEAR_INODE) &&
+		   !(atomic_read(&inode->i_count) +
+		     inode->i_ddir_count +
+		     inode->i_dent_count)) {
+#ifdef DEBUG
+			printk("#");
+#endif
+			/* This may block also. */
+			_clear_inode(inode, 0, 0);
+		}
+	}
+	if(!(flags & D_NO_FREE) && !(entry->d_flag & D_ZOMBIE)) {
+		base->free++;
+		if(base->free == base->maxfree) {
+#ifndef DEBUG
+			remove_header(free, base);
+			free_page((unsigned long)base);
+			goto done;
+#endif
+		}
+		entry->d_next = base->emptylist;
+		base->emptylist = entry;
+		if(!entry->d_next) {
+			remove_header(full, base);
+			insert_header(free, base);
+		}
+#ifdef DEBUG
+		x_freed++;
+#endif
+	}
+#ifndef DEBUG
+done:
+#else
+	x_free++;
+#endif
 }
 
-int dcache_lookup(struct inode * dir, const char * name, int len, unsigned long * ino)
+blocking void d_del(struct dentry * entry, int flags)
 {
-	int ret = 0;
+	int i;
+
+	if(!entry)
+		return;
+	LOG("d_clear", entry);
+	if(entry->d_len >= D_MEDIUM) {
+		if(entry->d_len >= D_LARGE) {
+			i = 3;
+		} else {
+			i = 2;
+		} 
+	} else if(entry->d_len >= D_SMALL) {
+		i = 1;
+	} else {
+		i = 0;
+	}
+	_d_del(entry, &anchors[i], flags);
+}
+
+static inline struct dentry * __dlookup(struct dentry ** base,
+					struct qstr * name,
+					struct qstr * appendix)
+{
+	struct dentry * tmp = *base;
+
+	if(tmp && name->len) {
+		int totallen = name->len;
+
+		if(appendix)
+			totallen += appendix->len;
+		do {
+			if(tmp->d_len == totallen			&&
+			   !(tmp->d_flag & D_DUPLICATE)			&&
+			   !strncmp(tmp->d_name, name->name, name->len)	&&
+			   (!appendix || !strncmp(tmp->d_name+name->len,
+						  appendix->name, appendix->len)))
+				return tmp;
+			tmp = tmp->d_hash_next;
+		} while(tmp != *base);
+	}
+	return NULL;
+}
+
+struct dentry * d_lookup(struct inode * dir,
+			 struct qstr * name,
+			 struct qstr * appendix)
+{
+	if(dir->i_dentry) {
+		struct ddir * ddir = d_dir(dir->i_dentry);
+		struct dentry ** base = d_base_qstr(ddir, name, appendix);
+
+		return __dlookup(base, name, appendix);
+	}
+	return NULL;
+}
+
+static /*inline*/ blocking void _d_insert_to_parent(struct dentry * entry,
+						    struct ddir * pdir,
+						    struct inode * inode,
+						    struct qstr * ininame,
+						    int flags)
+{
+	struct dentry ** base;
+	struct dentry * parent = entry->d_parent;
+
+#ifdef DEBUG
+	if(!pdir->dd_alloced)
+		printk("dd_alloced is 0!\n");
+#endif
+	base = d_base_qstr(pdir, ininame, NULL);
+	if(!(flags & (D_NOCHECKDUP|D_DUPLICATE)) &&
+	   __dlookup(base, ininame, NULL)) {
+		d_del(entry, D_NO_CLEAR_INODE);
+		return;
+	}
+	if(entry->d_flag & D_HASHED) {
+		printk("VFS: dcache entry is already hashed\n");
+		return;
+	}
+	if(!(flags & D_PRELIMINARY))
+		pdir->dd_true_hashed++;
+	pdir->dd_hashed++;
+	insert_hash(base, entry);
+	entry->d_flag |= D_HASHED;
+	pdir->dd_alloced--;
+	if(flags & D_BASKET)
+		insert_basket(&pdir->dd_basketlist, entry);
+
+#ifdef DEBUG
+	if(inode && inode->i_dentry && (entry->d_flag & D_DIR)) {
+		struct dentry * tmp = inode->i_dentry;
+		printk("Auweia inode=%p entry=%p (%p %p %s)\n",
+		       inode, entry, parent->u.d_inode, parent, parent->d_name);
+		printk("entry path="); printpath(entry); printk("\n");
+		do {
+			TST("auweia",tmp);
+			printk("alias path="); printpath(tmp); printk("\n");
+			tmp = tmp->d_next;
+		} while(tmp != inode->i_dentry);
+		printk("\n");
+	}
+#endif
+	if(has_true_sons(pdir))
+		inc_ddir(parent, parent->u.d_inode);
+	if(!inode && !(flags & D_PRELIMINARY)) {
+		insert_alias(&pdir->dd_neglist, entry);
+		pdir->dd_negs++;
+
+		/* Don't allow the negative list to grow too much ... */
+		while(pdir->dd_negs > (pdir->dd_true_hashed >> 1) + 5)
+			d_del(pdir->dd_neglist->d_prev, D_REMOVE);
+	}
+}
 
-	if(len <= DCACHE_NAME_LEN) {
-		struct dir_cache_entry **hash = get_hlist(dir, name, len);
-		struct dir_cache_entry *de;
+blocking void d_add(struct dentry * entry, struct inode * inode,
+		    struct qstr * ininame, int flags)
+{
+	struct dentry * parent = entry->d_parent;
+	struct qstr dummy;
+	struct ddir * pdir;
+
+#ifdef DEBUG
+	if(inode)
+		xcheck("d_add", inode);
+	if(IS_ROOT(entry)) {
+		printk("VFS: d_add for root dentry ");
+		printpath(entry);
+		printk(" -> ");
+		if(ininame)
+			printk("%s", ininame->name);
+		printk("\n");
+		return;
+	}
+	if(!parent)
+		panic("d_add with parent==NULL");
+	LOG("d_add", entry);
+#endif
+	if(ininame) {
+		if(ininame->len != entry->d_len) {
+			printk("VFS: d_add with wrong string length");
+			entry->d_len = ininame->len; /* kludge */
+		}
+		memcpy(entry->d_name, ininame->name, ininame->len);
+		entry->d_name[ininame->len] = '\0';
+	} else {
+		dummy.name = entry->d_name;
+		dummy.len = entry->d_len;
+		ininame = &dummy;
+	}
+        if(entry->d_flag & D_HASHED)
+		printk("VFS: d_add of already added dcache entry\n");
 
-		spin_lock(&dcache_lock);
-		de = find_entry(dir, name, (unsigned char) len, hash);
-		if(de) {
-			*ino = de->ino;
-			move_to_level2(de, hash);
-			ret = 1;
+	pdir = d_dir(parent);
+	_d_insert_to_parent(entry, pdir, inode, ininame, flags);
+	entry->d_flag |= flags;
+	if(inode && !(flags & D_PRELIMINARY)) {
+		if(entry->d_flag & D_DIR) {
+			if(inode->i_dentry) {
+				printk("VFS: creating dcache directory alias\n");
+				return;
+			}
 		}
-		spin_unlock(&dcache_lock);
+		insert_alias(&inode->i_dentry, entry);
+		inode->i_dent_count++;
 	}
-	return ret;
+	entry->u.d_inode = inode;
 }
 
-void dcache_add(struct inode * dir, const char * name, int len, unsigned long ino)
+blocking struct dentry * d_entry(struct dentry * parent,
+				 struct qstr * name,
+				 struct inode * inode)
 {
-	if (len <= DCACHE_NAME_LEN) {
-		struct dir_cache_entry **hash = get_hlist(dir, name, len);
-		struct dir_cache_entry *de;
+	struct ddir * pdir = d_dir(parent);
+	struct dentry ** base = d_base_qstr(pdir, name, NULL);
+	struct dentry * found = __dlookup(base, name, NULL);
+
+	if(!found) {
+		int isdir = (inode && S_ISDIR(inode->i_mode));
+
+		found = d_alloc(parent, name->len, isdir);
+		if(found) {
+			d_add(found, inode, name,
+			      isdir ? (D_DIR|D_NOCHECKDUP) : D_NOCHECKDUP);
+		} else
+			printk("VFS: problem with d_alloc\n");
+	}
+	return found;
+}
 
-		spin_lock(&dcache_lock);
-		de = find_entry(dir, name, (unsigned char) len, hash);
-		if (de) {
-			de->ino = ino;
-			update_lru(de);
-		} else {
-			de = level1_head;
-			level1_head = de->next_lru;
-			remove_hash(de);
-			de->dc_dev = dir->i_dev;
-			de->dir = dir->i_ino;
-			de->version = dir->i_version;
-			de->ino = ino;
-			de->name_len = len;
-			memcpy(de->name, name, len);
-			add_hash(de, hash);
+blocking void d_entry_preliminary(struct dentry * parent,
+				  struct qstr * name,
+				  unsigned long ino)
+{
+	struct ddir * pdir = d_dir(parent);
+	struct dentry ** base = d_base_qstr(pdir, name, NULL);
+	struct dentry * found = __dlookup(base, name, NULL);
+
+	if(!found && ino) {
+		struct dentry * new = d_alloc(parent, name->len, 0);
+
+		if(new) {
+			d_add(new, NULL, name, D_PRELIMINARY|D_NOCHECKDUP);
+			new->u.d_ino = ino;
+		} else
+			printk("VFS: problem with d_alloc\n");
+	}
+}
+
+blocking void d_move(struct dentry * entry, struct inode * newdir, 
+		     struct qstr * newname, struct qstr * newapp)
+{
+	struct ddir tmp;
+	struct dentry * new;
+	struct inode * inode;
+	int len;
+	int flags;
+
+	if(!entry)
+		return;
+	inode = entry->u.d_inode;
+	flags = entry->d_flag;
+	if((flags & D_PRELIMINARY) || !inode) {
+		if(!(flags & D_PRELIMINARY))
+			printk("VFS: trying to move negative dcache entry\n");
+		d_del(entry, D_NO_CLEAR_INODE);
+		return;
+	}
+#if 0
+printk("d_move %p '%s' -> '%s%s' dent_count=%d\n", inode, entry->d_name,
+       newname->name, newapp ? newapp->name : "", inode->i_dent_count);
+#endif
+	if(flags & D_ZOMBIE) {
+		printk("VFS: moving zombie entry\n");
+	}
+	if(flags & D_DIR) {
+		struct ddir * ddir = d_dir(entry);
+
+		memcpy(&tmp, ddir, sizeof(struct ddir));
+
+                /* Simulate empty dir for d_del(). */
+		memset(ddir, 0, sizeof(struct ddir));
+	}
+	len = newname->len;
+	if(newapp) {
+		len += newapp->len;
+		flags |= D_BASKET;
+	} else
+		flags &= ~D_BASKET;
+	new = d_alloc(newdir->i_dentry, len, flags & D_DIR);
+	memcpy(new->d_name, newname->name, newname->len);
+	if(newapp)
+		memcpy(new->d_name+newname->len, newapp->name, newapp->len);
+	new->d_name[len] = '\0';
+	d_del(entry, D_NO_CLEAR_INODE);
+	d_add(new, inode, NULL, flags & (D_DIR|D_BASKET));
+	if(flags & D_DIR) {
+		struct ddir * ddir = d_dir(new);
+
+		memcpy(ddir, &tmp, sizeof(struct ddir));
+       	}
+}
+
+int d_path(struct dentry * entry, struct inode * chroot, char * buf)
+{
+	if(IS_ROOT(entry) || (chroot && entry->u.d_inode == chroot &&
+			      !(entry->d_flag & D_PRELIMINARY))) {
+		*buf = '/';
+		return 1;
+	} else {
+		int len = d_path(entry->d_parent, chroot, buf);
+
+		buf += len;
+		if(len > 1) {
+			*buf++ = '/';
+			len++;
 		}
-		spin_unlock(&dcache_lock);
+		memcpy(buf, entry->d_name, entry->d_len);
+		return len + entry->d_len;
 	}
 }
 
-unsigned long name_cache_init(unsigned long mem_start, unsigned long mem_end)
+struct dentry * d_basket(struct dentry * dir_entry)
 {
-	int i;
-	struct dir_cache_entry * p;
+	if(dir_entry && (dir_entry->d_flag & D_DIR)) {
+		struct ddir * ddir = d_dir(dir_entry);
 
-	/*
-	 * Init level1 LRU lists..
-	 */
-	p = level1_cache;
-	do {
-		p[1].prev_lru = p;
-		p[0].next_lru = p+1;
-		p[0].lru_head = &level1_head;
-	} while (++p < level1_cache + DCACHE_SIZE-1);
-	level1_cache[0].prev_lru = p;
-	p[0].next_lru = &level1_cache[0];
-	p[0].lru_head = &level1_head;
-	level1_head = level1_cache;
+		return ddir->dd_basketlist;
+	} else
+		return NULL;
+}
 
-	/*
-	 * Init level2 LRU lists..
-	 */
-	p = level2_cache;
-	do {
-		p[1].prev_lru = p;
-		p[0].next_lru = p+1;
-		p[0].lru_head = &level2_head;
-	} while (++p < level2_cache + DCACHE_SIZE-1);
-	level2_cache[0].prev_lru = p;
-	p[0].next_lru = &level2_cache[0];
-	p[0].lru_head = &level2_head;
-	level2_head = level2_cache;
+int d_isbasket(struct dentry * entry)
+{
+	return entry->d_flag & D_BASKET;
+}
 
-	/*
-	 * Empty hash queues..
-	 */
-	for (i = 0 ; i < DCACHE_HASH_QUEUES ; i++)
-		hash_table[i] = NULL;
+blocking struct inode * d_inode(struct dentry ** changing_entry)
+{
+	struct dentry * entry = *changing_entry;
+	struct inode * inode;
 
-	return mem_start;
+#ifdef CONFIG_DCACHE_PRELOAD
+	if(entry->d_flag & D_PRELIMINARY) {
+		struct qstr name = { entry->d_name, entry->d_len };
+		struct ddir * pdir = d_dir(entry->d_parent);
+		struct dentry ** base = d_base_qstr(pdir, &name, NULL);
+		struct dentry * found;
+		unsigned long ino;
+		struct inode * dir = entry->d_parent->u.d_inode;
+		TST("d_inode",entry);
+		ino = entry->u.d_ino;
+		if(!dir)
+			d_panic();
+
+		/* Prevent concurrent d_lookup()s or d_inode()s before
+		 * giving up vfs_lock. This just removes from the parent,
+		 * but does not deallocate it.
+		 */
+
+		/* !!!!!!! Aiee, here is an unresolved race if somebody
+		 * unlink()s the inode during the iget(). The problem is
+		 * that we need to synchronize externally. Proposed solution:
+		 * put a rw_lock (read-mode) on the parent dir for each
+		 * iget(), lookup() and so on, and a write-mode lock for
+		 * everything that changes the dir (e.g. unlink()), and do
+		 * this consistently everywhere in the generic VFS (not in
+		 * the concrete filesystems). This should kill similar
+		 * races everywhere, with a single clean concept.
+		 * Later, the synchronization stuff can be cleaned out
+		 * of the concrete fs'es.
+		 */
+		d_del(entry, D_NO_CLEAR_INODE|D_NO_FREE);
+		vfs_unlock();
+
+		/* This circumvents the normal lookup() of pathnames.
+		 * Therefore,  preliminary entries must not be used
+		 * (see FS_NO_DCACHE and FS_NO_PRELIM) if the fs does not
+		 * permit fetching *valid* inodes with plain iget().
+		 */
+		inode = __iget(dir->i_sb, ino, 0);
+		vfs_lock();
+		if(!inode) {
+			printk("VFS: preliminary dcache entry was invalid\n");
+			*changing_entry = NULL;
+			return NULL;
+		}
+		xcheck("d_inode iget()", inode);
+		if((found = __dlookup(base, &name, NULL))) {
+			d_del(entry, D_NO_CLEAR_INODE);
+			*changing_entry = found;
+		} else if(S_ISDIR(inode->i_mode)) {
+			struct dentry * new = d_alloc(entry->d_parent, entry->d_len, 1);
+			if(new)
+				d_add(new, inode, &name, D_DIR);
+			*changing_entry = new;
+
+			/* Finally deallocate old entry. */
+			d_del(entry, D_NO_CLEAR_INODE);
+		} else {
+			/* Re-insert to the parent, but now as normal dentry. */
+			d_add(entry, inode, NULL, 0);
+		}
+		return inode;
+	}
+#endif
+	inode = entry->u.d_inode;
+	if(inode) {
+#ifdef DEBUG
+		xcheck("d_inode", inode);
+#endif
+		iinc_zero(inode);
+	}
+	return inode;
 }
diff -u --recursive --new-file v2.1.42/linux/fs/devices.c linux/fs/devices.c
--- v2.1.42/linux/fs/devices.c	Fri Apr  4 08:52:24 1997
+++ linux/fs/devices.c	Thu Jun 12 16:22:08 1997
@@ -273,7 +273,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -326,7 +325,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/dquot.c linux/fs/dquot.c
--- v2.1.42/linux/fs/dquot.c	Tue May 13 22:41:14 1997
+++ linux/fs/dquot.c	Thu Jun 12 16:22:08 1997
@@ -237,9 +237,12 @@
 		filp->f_pos = dqoff(dquot->dq_id);
 	fs = get_fs();
 	set_fs(KERNEL_DS);
+
 	if (filp->f_op->write(filp->f_inode, filp,
 	   (char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk))
 		dquot->dq_flags &= ~DQ_MOD;
+	/* inode->i_status |= ST_MODIFIED is willingly *not* done here */
+
 	up(&dquot->dq_mnt->mnt_sem);
 	set_fs(fs);
 	unlock_dquot(dquot);
@@ -1035,7 +1038,8 @@
 	if (special == (char *)NULL && (cmds == Q_SYNC || cmds == Q_GETSTATS))
 		dev = 0;
 	else {
-		if (namei(special, &ino))
+		int error = namei(NAM_FOLLOW_LINK, special, &ino);
+		if(error)
 			goto out;
 		dev = ino->i_rdev;
 		ret = -ENOTBLK;
diff -u --recursive --new-file v2.1.42/linux/fs/exec.c linux/fs/exec.c
--- v2.1.42/linux/fs/exec.c	Thu May 15 16:48:04 1997
+++ linux/fs/exec.c	Thu Jun 12 16:22:08 1997
@@ -68,6 +68,10 @@
 
 __initfunc(void binfmt_setup(void))
 {
+#ifdef CONFIG_BINFMT_MISC
+	init_misc_binfmt();
+#endif
+
 #ifdef CONFIG_BINFMT_ELF
 	init_elf_binfmt();
 #endif
@@ -154,7 +158,7 @@
 			}
 		}
 		current->files->fd[fd] = f;
-		inode->i_count++;
+		atomic_inc(&inode->i_count);
 	}
 	return fd;
 }
diff -u --recursive --new-file v2.1.42/linux/fs/ext2/balloc.c linux/fs/ext2/balloc.c
--- v2.1.42/linux/fs/ext2/balloc.c	Tue May 13 22:41:14 1997
+++ linux/fs/ext2/balloc.c	Thu Jun 12 16:22:08 1997
@@ -291,6 +291,7 @@
 		printk ("ext2_new_block: nonexistent device");
 		return 0;
 	}
+retry:
 	lock_super (sb);
 	es = sb->u.ext2_sb.s_es;
 	if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) &&
@@ -298,6 +299,8 @@
 	     (sb->u.ext2_sb.s_resgid == 0 ||
 	      !in_group_p (sb->u.ext2_sb.s_resgid)))) {
 		unlock_super (sb);
+		if(sb->s_ibasket && free_ibasket(sb))
+			goto retry;
 		return 0;
 	}
 
@@ -389,6 +392,8 @@
 	}
 	if (k >= sb->u.ext2_sb.s_groups_count) {
 		unlock_super (sb);
+		if(sb->s_ibasket && free_ibasket(sb))
+			goto retry;
 		return 0;
 	}
 	bitmap_nr = load_block_bitmap (sb, i);
diff -u --recursive --new-file v2.1.42/linux/fs/ext2/dir.c linux/fs/ext2/dir.c
--- v2.1.42/linux/fs/ext2/dir.c	Sun Jan 26 02:07:43 1997
+++ linux/fs/ext2/dir.c	Thu Jun 12 16:22:08 1997
@@ -65,7 +65,6 @@
 	ext2_mknod,		/* mknod */
 	ext2_rename,		/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -194,12 +193,13 @@
 				 * currently swapped out.  So, use a
 				 * version stamp to detect whether or
 				 * not the directory has been modified
-				 * during the copy operation. */
-				unsigned long version;
-				dcache_add(inode, de->name, le16_to_cpu(de->name_len),
-					   le32_to_cpu(de->inode));
-				version = inode->i_version;
-				error = filldir(dirent, de->name, le16_to_cpu(de->name_len), filp->f_pos, le32_to_cpu(de->inode));
+				 * during the copy operation.
+				 */
+				unsigned long version = inode->i_version;
+
+				error = filldir(dirent, de->name,
+						le16_to_cpu(de->name_len),
+						filp->f_pos, le32_to_cpu(de->inode));
 				if (error)
 					break;
 				if (version != inode->i_version)
diff -u --recursive --new-file v2.1.42/linux/fs/ext2/file.c linux/fs/ext2/file.c
--- v2.1.42/linux/fs/ext2/file.c	Fri Apr  4 08:52:24 1997
+++ linux/fs/ext2/file.c	Thu Jun 12 16:22:08 1997
@@ -72,7 +72,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	ext2_bmap,		/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- v2.1.42/linux/fs/ext2/ialloc.c	Sat Nov 30 02:24:01 1996
+++ linux/fs/ext2/ialloc.c	Thu Jun 12 16:22:08 1997
@@ -171,9 +171,9 @@
 		printk ("ext2_free_inode: inode has no device\n");
 		return;
 	}
-	if (inode->i_count > 1) {
+	if (atomic_read(&inode->i_count) > 1) {
 		printk ("ext2_free_inode: inode has count=%d\n",
-			inode->i_count);
+			atomic_read(&inode->i_count));
 		return;
 	}
 	if (inode->i_nlink) {
@@ -404,7 +404,7 @@
 	sb->s_dirt = 1;
 	inode->i_mode = mode;
 	inode->i_sb = sb;
-	inode->i_count = 1;
+	atomic_set(&inode->i_count, 1);
 	inode->i_nlink = 1;
 	inode->i_dev = sb->s_dev;
 	inode->i_uid = current->fsuid;
diff -u --recursive --new-file v2.1.42/linux/fs/ext2/namei.c linux/fs/ext2/namei.c
--- v2.1.42/linux/fs/ext2/namei.c	Tue May 13 22:41:14 1997
+++ linux/fs/ext2/namei.c	Thu Jun 12 16:22:08 1997
@@ -172,27 +172,12 @@
 		iput (dir);
 		return -ENAMETOOLONG;
 	}
-	if (dcache_lookup(dir, name, len, &ino)) {
-		if (!ino) {
-			iput(dir);
-			return -ENOENT;
-		}
-		if (!(*result = iget (dir->i_sb, ino))) {
-			iput (dir);
-			return -EACCES;
-		}
-		iput (dir);
-		return 0;
-	}
 	ino = dir->i_version;
 	if (!(bh = ext2_find_entry (dir, name, len, &de))) {
-		if (ino == dir->i_version)
-			dcache_add(dir, name, len, 0);
 		iput (dir);
 		return -ENOENT;
 	}
 	ino = le32_to_cpu(de->inode);
-	dcache_add(dir, name, len, ino);
 	brelse (bh);
 	if (!(*result = iget (dir->i_sb, ino))) {
 		iput (dir);
@@ -391,7 +376,6 @@
 	}
 	de->inode = cpu_to_le32(inode->i_ino);
 	dir->i_version = ++event;
-	dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -460,7 +444,6 @@
 	}
 	de->inode = cpu_to_le32(inode->i_ino);
 	dir->i_version = ++event;
-	dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -538,7 +521,6 @@
 	}
 	de->inode = cpu_to_le32(inode->i_ino);
 	dir->i_version = ++event;
-	dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -662,7 +644,7 @@
 	else if (le32_to_cpu(de->inode) != inode->i_ino)
 		retval = -ENOENT;
 	else {
-		if (inode->i_count > 1) {
+		if (atomic_read(&inode->i_count) > 1) {
 		/*
 		 * Are we deleting the last instance of a busy directory?
 		 * Better clean up if so.
@@ -836,7 +818,6 @@
 	}
 	de->inode = cpu_to_le32(inode->i_ino);
 	dir->i_version = ++event;
-	dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -885,7 +866,6 @@
 	}
 	de->inode = cpu_to_le32(oldinode->i_ino);
 	dir->i_version = ++event;
-	dcache_add(dir, de->name, le16_to_cpu(de->name_len), le32_to_cpu(de->inode));
 	mark_buffer_dirty(bh, 1);
 	if (IS_SYNC(dir)) {
 		ll_rw_block (WRITE, 1, &bh);
@@ -905,7 +885,7 @@
 	int ino;
 	int result;
 
-	new_inode->i_count++;
+	atomic_inc(&new_inode->i_count);
 	result = 0;
 	for (;;) {
 		if (new_inode == old_inode) {
@@ -945,8 +925,7 @@
  */
 static int do_ext2_rename (struct inode * old_dir, const char * old_name,
 			   int old_len, struct inode * new_dir,
-			   const char * new_name, int new_len,
-			   int must_be_dir)
+			   const char * new_name, int new_len)
 {
 	struct inode * old_inode, * new_inode;
 	struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -981,8 +960,6 @@
 	old_inode = __iget (old_dir->i_sb, le32_to_cpu(old_de->inode), 0); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
-	if (must_be_dir && !S_ISDIR(old_inode->i_mode))
-		goto end_rename;
 	retval = -EPERM;
 	if ((old_dir->i_mode & S_ISVTX) && 
 	    current->fsuid != old_inode->i_uid &&
@@ -1016,7 +993,7 @@
 		if (!empty_dir (new_inode))
 			goto end_rename;
 		retval = -EBUSY;
-		if (new_inode->i_count > 1)
+		if (atomic_read(&new_inode->i_count) > 1)
 			goto end_rename;
 	}
 	retval = -EPERM;
@@ -1059,7 +1036,6 @@
 	 * ok, that's it
 	 */
 	new_de->inode = le32_to_cpu(old_inode->i_ino);
-	dcache_add(new_dir, new_de->name, le16_to_cpu(new_de->name_len), le32_to_cpu(new_de->inode));
 	retval = ext2_delete_entry (old_de, old_bh);
 	if (retval == -ENOENT)
 		goto try_again;
@@ -1075,7 +1051,6 @@
 	old_dir->i_dirt = 1;
 	if (dir_bh) {
 		PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
-		dcache_add(old_inode, "..", 2, new_dir->i_ino);
 		mark_buffer_dirty(dir_bh, 1);
 		old_dir->i_nlink--;
 		old_dir->i_dirt = 1;
@@ -1123,8 +1098,7 @@
  * on the same file system
  */
 int ext2_rename (struct inode * old_dir, const char * old_name, int old_len,
-		 struct inode * new_dir, const char * new_name, int new_len,
-		 int must_be_dir)
+		 struct inode * new_dir, const char * new_name, int new_len)
 {
 	int result;
 
@@ -1132,7 +1106,7 @@
 		sleep_on (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
 	old_dir->i_sb->u.ext2_sb.s_rename_lock = 1;
 	result = do_ext2_rename (old_dir, old_name, old_len, new_dir,
-				 new_name, new_len, must_be_dir);
+				 new_name, new_len);
 	old_dir->i_sb->u.ext2_sb.s_rename_lock = 0;
 	wake_up (&old_dir->i_sb->u.ext2_sb.s_rename_wait);
 	return result;
diff -u --recursive --new-file v2.1.42/linux/fs/ext2/super.c linux/fs/ext2/super.c
--- v2.1.42/linux/fs/ext2/super.c	Tue May 13 22:41:14 1997
+++ linux/fs/ext2/super.c	Thu Jun 12 16:22:08 1997
@@ -319,6 +319,13 @@
 			ext2_check_inodes_bitmap (sb);
 		}
 	}
+#if 0 /* ibasket's still have unresolved bugs... -DaveM */
+
+	/* [T. Schoebel-Theuer] This limit should be maintained on disk.
+	 * This is just provisionary.
+	 */
+	sb->s_ibasket_max = 100;
+#endif
 }
 
 static int ext2_check_descriptors (struct super_block * sb)
@@ -728,7 +735,10 @@
 }
 
 static struct file_system_type ext2_fs_type = {
-        ext2_read_super, "ext2", 1, NULL
+	"ext2", 
+	FS_REQUIRES_DEV /* | FS_IBASKET */,	/* ibaskets have unresolved bugs */
+        ext2_read_super, 
+	NULL
 };
 
 __initfunc(int init_ext2_fs(void))
diff -u --recursive --new-file v2.1.42/linux/fs/ext2/symlink.c linux/fs/ext2/symlink.c
--- v2.1.42/linux/fs/ext2/symlink.c	Sat Jan 25 03:02:44 1997
+++ linux/fs/ext2/symlink.c	Thu Jun 12 16:22:08 1997
@@ -25,8 +25,6 @@
 #include <linux/stat.h>
 
 static int ext2_readlink (struct inode *, char *, int);
-static int ext2_follow_link (struct inode *, struct inode *, int, int,
-			       struct inode **);
 
 /*
  * symlinks can't do much...
@@ -43,7 +41,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	ext2_readlink,		/* readlink */
-	ext2_follow_link,	/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -52,70 +49,20 @@
 	NULL			/* smap */
 };
 
-static int ext2_follow_link(struct inode * dir, struct inode * inode,
-			    int flag, int mode, struct inode ** res_inode)
-{
-	int error;
-	struct buffer_head * bh = NULL;
-	char * link;
-
-	*res_inode = NULL;
-	if (!dir) {
-		dir = current->fs->root;
-		dir->i_count++;
-	}
-	if (!inode) {
-		iput (dir);
-		return -ENOENT;
-	}
-	if (!S_ISLNK(inode->i_mode)) {
-		iput (dir);
-		*res_inode = inode;
-		return 0;
-	}
-	if (current->link_count > 5) {
-		iput (dir);
-		iput (inode);
-		return -ELOOP;
-	}
-	if (inode->i_blocks) {
-		if (!(bh = ext2_bread (inode, 0, 0, &error))) {
-			iput (dir);
-			iput (inode);
-			return -EIO;
-		}
-		link = bh->b_data;
-	} else
-		link = (char *) inode->u.ext2_i.i_data;
-	if (DO_UPDATE_ATIME(inode)) {
-		inode->i_atime = CURRENT_TIME;
-		inode->i_dirt = 1;
-	}
-	current->link_count++;
-	error = open_namei (link, flag, mode, res_inode, dir);
-	current->link_count--;
-	iput (inode);
-	if (bh)
-		brelse (bh);
-	return error;
-}
-
 static int ext2_readlink (struct inode * inode, char * buffer, int buflen)
 {
 	struct buffer_head * bh = NULL;
 	char * link;
 	int i, err;
 
-	if (!S_ISLNK(inode->i_mode)) {
-		iput (inode);
-		return -EINVAL;
-	}
 	if (buflen > inode->i_sb->s_blocksize - 1)
 		buflen = inode->i_sb->s_blocksize - 1;
 	if (inode->i_blocks) {
 		bh = ext2_bread (inode, 0, 0, &err);
 		if (!bh) {
 			iput (inode);
+			if(err < 0) /* indicate type of error */
+				return err;
 			return 0;
 		}
 		link = bh->b_data;
diff -u --recursive --new-file v2.1.42/linux/fs/fat/dir.c linux/fs/fat/dir.c
--- v2.1.42/linux/fs/fat/dir.c	Sun Jan 26 02:07:43 1997
+++ linux/fs/fat/dir.c	Thu Jun 12 16:22:08 1997
@@ -260,10 +260,8 @@
 					ino = fat_parent_ino(inode,0);
 
 				if (shortnames || !is_long) {
-					dcache_add(inode, bufname, i+dotoffset, ino);
-					if (both) {
+					if (both)
 						bufname[i+dotoffset] = '\0';
-					}
 					spos = oldpos;
 					if (is_long) {
 						spos = filp->f_pos - sizeof(struct msdos_dir_entry);
@@ -276,7 +274,6 @@
 					}
 				}
 				if (is_long && longnames) {
-					dcache_add(inode, longname, long_len, ino);
 					if (both) {
 						memcpy(&longname[long_len+1], bufname, i+dotoffset);
 						long_len += i+dotoffset;
diff -u --recursive --new-file v2.1.42/linux/fs/fat/file.c linux/fs/fat/file.c
--- v2.1.42/linux/fs/fat/file.c	Sun Jan 26 02:07:44 1997
+++ linux/fs/fat/file.c	Thu Jun 12 16:22:08 1997
@@ -52,7 +52,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	fat_bmap,		/* bmap */
@@ -100,7 +99,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/fat/mmap.c linux/fs/fat/mmap.c
--- v2.1.42/linux/fs/fat/mmap.c	Mon Oct 28 04:29:25 1996
+++ linux/fs/fat/mmap.c	Thu Jun 12 16:22:08 1997
@@ -105,7 +105,7 @@
 	}
 
 	vma->vm_inode = inode;
-	inode->i_count++;
+	atomic_inc(&inode->i_count);
 	vma->vm_ops = &fat_file_mmap;
 	return 0;
 }
diff -u --recursive --new-file v2.1.42/linux/fs/fifo.c linux/fs/fifo.c
--- v2.1.42/linux/fs/fifo.c	Mon Mar 11 01:23:22 1996
+++ linux/fs/fifo.c	Thu Jun 12 16:22:08 1997
@@ -143,7 +143,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/filesystems.c linux/fs/filesystems.c
--- v2.1.42/linux/fs/filesystems.c	Thu May 29 21:53:08 1997
+++ linux/fs/filesystems.c	Thu Jun 12 16:22:08 1997
@@ -8,6 +8,7 @@
 
 #include <linux/config.h>
 #include <linux/fs.h>
+#include <linux/nametrans.h>
 
 #include <linux/minix_fs.h>
 #include <linux/ext2_fs.h>
@@ -43,6 +44,10 @@
 	device_setup();
 
 	binfmt_setup();
+
+#ifdef CONFIG_TRANS_NAMES
+	init_nametrans();
+#endif
 
 #ifdef CONFIG_EXT2_FS
 	init_ext2_fs();
diff -u --recursive --new-file v2.1.42/linux/fs/hpfs/hpfs_fs.c linux/fs/hpfs/hpfs_fs.c
--- v2.1.42/linux/fs/hpfs/hpfs_fs.c	Wed Apr 23 19:01:23 1997
+++ linux/fs/hpfs/hpfs_fs.c	Thu Jun 12 16:22:08 1997
@@ -175,7 +175,6 @@
 	NULL,				/* mknod */
 	NULL,				/* rename */
 	NULL,				/* readlink */
-	NULL,				/* follow_link */
 	generic_readpage,		/* readpage */
 	NULL,				/* writepage */
 	(int (*)(struct inode *, int))
@@ -219,7 +218,6 @@
 	NULL,				/* mknod */
 	NULL,				/* rename */
 	NULL,				/* readlink */
-	NULL,				/* follow_link */
 	NULL,				/* readpage */
 	NULL,				/* writepage */
 	NULL,				/* bmap */
@@ -1746,7 +1744,10 @@
 }
 
 static struct file_system_type hpfs_fs_type = {
-        hpfs_read_super, "hpfs", 1, NULL
+	"hpfs", 
+	FS_REQUIRES_DEV,
+        hpfs_read_super,
+	NULL
 };
 
 __initfunc(int init_hpfs_fs(void))
diff -u --recursive --new-file v2.1.42/linux/fs/inode.c linux/fs/inode.c
--- v2.1.42/linux/fs/inode.c	Thu May 15 16:48:04 1997
+++ linux/fs/inode.c	Thu Jun 12 21:53:45 1997
@@ -1,657 +1,708 @@
 /*
- * linux/fs/inode.c: Keeping track of inodes.
+ * fs/inode.c
  *
- * Copyright (C) 1991, 1992  Linus Torvalds
- * Copyright (C) 1997 David S. Miller
+ * Complete reimplementation
+ * (C) 1997 Thomas Schoebel-Theuer
  */
 
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
+/* Everything here is intended to be MP-safe. However, other parts
+ * of the kernel are not yet MP-safe, in particular the inode->i_count++
+ * that are spread over everywhere. These should be replaced by
+ * iinc() as soon as possible. Since I have no MP machine, I could
+ * not test it.
+ */
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
 #include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/kernel.h>
+#include <linux/dlists.h>
+#include <linux/dalloc.h>
+#include <linux/omirr.h>
+
+/* #define DEBUG */
+
+#define HASH_SIZE 1024 /* must be a power of 2 */
+#define NR_LEVELS 4
+
+#define ST_AGED      1
+#define ST_HASHED    2
+#define ST_EMPTY     4
+#define ST_TO_READ   8
+#define ST_TO_WRITE 16
+#define ST_TO_PUT   32
+#define ST_TO_DROP  64
+#define ST_IO       (ST_TO_READ|ST_TO_WRITE|ST_TO_PUT|ST_TO_DROP)
+#define ST_WAITING 128
+#define ST_FREEING 256
+#define ST_IBASKET 512
+
+/* The idea is to keep empty inodes in a separate list, so no search
+ * is required as long as empty inodes exit.
+ * All reusable inodes occurring in the hash table with i_count==0
+ * are also registered in the ringlist aged_i[level], but in LRU order.
+ * Used inodes with i_count>0 are kept solely in the hashtable and in
+ * all_i, but in no other list.
+ * The level is used for multilevel aging to avoid thrashing; each
+ * time i_count decreases to 0, the inode is inserted into the next level
+ * ringlist. Cache reusage is simply by taking the _last_ element from the
+ * lowest-level ringlist that contains inodes.
+ * In contrast to the old code, there isn't any O(n) search overhead now
+ * in iget/iput (if you make HASH_SIZE large enough).
+ */
+static struct inode * hashtable[HASH_SIZE];/* linked with i_hash_{next,prev} */
+static struct inode * all_i = NULL;        /* linked with i_{next,prev} */
+static struct inode * empty_i = NULL;      /* linked with i_{next,prev} */
+static struct inode * aged_i[NR_LEVELS+1]; /* linked with i_lru_{next,prev} */
+static int aged_reused[NR_LEVELS+1];       /* # removals from aged_i[level] */
+static int age_table[NR_LEVELS+1] = { /* You may tune this. */
+	1, 4, 10, 100, 1000
+}; /* after which # of uses to increase to the next level */
+
+/* This is for kernel/sysctl.c */
+
+/* Just aligning plain ints and arrays thereof doesn't work reliably.. */
+struct {
+	int nr_inodes;
+	int nr_free_inodes;
+	int aged_count[NR_LEVELS+1];        /* # in each level */
+} inodes_stat;
 
-int nr_inodes = 0, nr_free_inodes = 0;
 int max_inodes = NR_INODE;
+unsigned long last_inode = 0;
 
-#define INODE_HASHSZ	1024
-
-static struct inode *inode_hash[INODE_HASHSZ];
-
-/* All the details of hashing and lookup. */
-#define hashfn(dev, i) ((HASHDEV(dev) + ((i) ^ ((i) >> 10))) & (INODE_HASHSZ - 1))
-
-__inline__ void insert_inode_hash(struct inode *inode)
-{
-	struct inode **htable = &inode_hash[hashfn(inode->i_dev, inode->i_ino)];
-	if((inode->i_hash_next = *htable) != NULL)
-		(*htable)->i_hash_pprev = &inode->i_hash_next;
-	*htable = inode;
-	inode->i_hash_pprev = htable;
-}
-
-#define hash_inode(inode) insert_inode_hash(inode)
-
-static inline void unhash_inode(struct inode *inode)
-{
-	if(inode->i_hash_pprev) {
-		if(inode->i_hash_next)
-			inode->i_hash_next->i_hash_pprev = inode->i_hash_pprev;
-		*(inode->i_hash_pprev) = inode->i_hash_next;
-		inode->i_hash_pprev = NULL;
-	}
-}
-
-static inline struct inode *find_inode(unsigned int hashent,
-				       kdev_t dev, unsigned long ino)
+void inode_init(void)
 {
-	struct inode *inode;
-
-	for(inode = inode_hash[hashent]; inode; inode = inode->i_hash_next)
-		if(inode->i_dev == dev && inode->i_ino == ino)
-			break;
-	return inode;
+	memset(hashtable, 0, sizeof(hashtable));
+	memset(aged_i, 0, sizeof(aged_i));
+	memset(aged_reused, 0, sizeof(aged_reused));
+	memset(&inodes_stat, 0, sizeof(inodes_stat));
 }
 
-/* Free list queue and management. */
-static struct free_inode_queue {
-	struct inode *head;
-	struct inode **last;
-} free_inodes = { NULL, &free_inodes.head };
-
-static inline void put_inode_head(struct inode *inode)
-{
-	if((inode->i_next = free_inodes.head) != NULL)
-		free_inodes.head->i_pprev = &inode->i_next;
-	else
-		free_inodes.last = &inode->i_next;
-	free_inodes.head = inode;
-	inode->i_pprev = &free_inodes.head;
-	nr_free_inodes++;
-}
+/* Intended for short locks of the above global data structures.
+ * Could be replaced with spinlocks completely, since there is
+ * no blocking during manipulation of the static data; however the
+ * lock in invalidate_inodes() may last relatively long.
+ */
+#ifdef __SMP__
+struct semaphore vfs_sem = MUTEX;
+#endif
+
+DEF_INSERT(all,struct inode,i_next,i_prev)
+DEF_REMOVE(all,struct inode,i_next,i_prev)
+	
+DEF_INSERT(lru,struct inode,i_lru_next,i_lru_prev)
+DEF_REMOVE(lru,struct inode,i_lru_next,i_lru_prev)
+
+DEF_INSERT(hash,struct inode,i_hash_next,i_hash_prev)
+DEF_REMOVE(hash,struct inode,i_hash_next,i_hash_prev)
+
+DEF_INSERT(ibasket,struct inode,i_basket_next,i_basket_prev)
+DEF_REMOVE(ibasket,struct inode,i_basket_next,i_basket_prev)
+
+#ifdef DEBUG
+extern void printpath(struct dentry * entry);
+struct inode * xtst[15000];
+int xcnt = 0;
 
-static inline void put_inode_last(struct inode *inode)
+void xcheck(char * txt, struct inode * p)
 {
-	inode->i_next = NULL;
-	inode->i_pprev = free_inodes.last;
-	*free_inodes.last = inode;
-	free_inodes.last = &inode->i_next;
-	nr_free_inodes++;
+	int i;
+	for(i=xcnt-1; i>=0; i--)
+		if(xtst[i] == p)
+			return;
+	printk("Bogus inode %p in %s\n", p, txt);
 }
+#else
+#define xcheck(t,p) /*nothing*/
+#endif
 
-static inline void remove_free_inode(struct inode *inode)
+static inline struct inode * grow_inodes(void)
 {
-	if(inode->i_pprev) {
-		if(inode->i_next)
-			inode->i_next->i_pprev = inode->i_pprev;
-		else
-			free_inodes.last = inode->i_pprev;
-		*inode->i_pprev = inode->i_next;
-		inode->i_pprev = NULL;
-		nr_free_inodes--;
+	struct inode * res;
+	struct inode * inode = res = (struct inode*)__get_free_page(GFP_KERNEL);
+	int size = PAGE_SIZE;
+	if(!inode)
+		return NULL;
+	
+	size -= sizeof(struct inode);
+	inode++;
+	inodes_stat.nr_inodes++;
+#ifdef DEBUG
+xtst[xcnt++]=res;
+#endif
+	while(size >= sizeof(struct inode)) {
+#ifdef DEBUG
+xtst[xcnt++]=inode;
+#endif
+		inodes_stat.nr_inodes++;
+		inodes_stat.nr_free_inodes++;
+		insert_all(&empty_i, inode);
+		inode->i_status = ST_EMPTY;
+		inode++;
+		size -= sizeof(struct inode);
 	}
+	return res;
 }
 
-/* This is the in-use queue, if i_count > 0 (as far as we can tell)
- * the sucker is here.
- */
-static struct inode *inuse_list = NULL;
-
-static inline void put_inuse(struct inode *inode)
+static inline int hash(dev_t i_dev, unsigned long i_ino)
 {
-	if((inode->i_next = inuse_list) != NULL)
-		inuse_list->i_pprev = &inode->i_next;
-	inuse_list = inode;
-	inode->i_pprev = &inuse_list;
+	return ((int)i_ino ^ ((int)i_dev << 6)) & (HASH_SIZE-1);
 }
 
-static inline void remove_inuse(struct inode *inode)
+static inline blocking void wait_io(struct inode * inode, unsigned short flags)
 {
-	if(inode->i_pprev) {
-		if(inode->i_next)
-			inode->i_next->i_pprev = inode->i_pprev;
-		*inode->i_pprev = inode->i_next;
-		inode->i_pprev = NULL;
+	while(inode->i_status & flags) {
+		struct wait_queue wait = {current, NULL};
+		inode->i_status |= ST_WAITING;
+		vfs_unlock();
+		add_wait_queue(&inode->i_wait, &wait);
+		sleep_on(&inode->i_wait);
+		remove_wait_queue(&inode->i_wait, &wait);
+		vfs_lock();
 	}
 }
 
-/* Locking and unlocking inodes, plus waiting for locks to clear. */
-static void __wait_on_inode(struct inode *);
-
-static inline void wait_on_inode(struct inode *inode)
+static inline blocking void set_io(struct inode * inode,
+				   unsigned short waitflags,
+				   unsigned short setflags)
 {
-	if(inode->i_lock)
-		__wait_on_inode(inode);
+	wait_io(inode, waitflags);
+	inode->i_status |= setflags;
+	vfs_unlock();
 }
 
-static inline void lock_inode(struct inode *inode)
+static inline blocking int release_io(struct inode * inode, unsigned short flags)
 {
-	if(inode->i_lock)
-		__wait_on_inode(inode);
-	inode->i_lock = 1;
-}
-
-static inline void unlock_inode(struct inode *inode)
-{
-	inode->i_lock = 0;
-	wake_up(&inode->i_wait);
+	int res = 0; 
+	vfs_lock();
+	inode->i_status &= ~flags;
+	if(inode->i_status & ST_WAITING) {
+		inode->i_status &= ~ST_WAITING;
+		vfs_unlock();
+		wake_up(&inode->i_wait);
+		res = 1;
+	}
+	return res;
 }
 
-static void __wait_on_inode(struct inode * inode)
+static inline blocking void _io(void (*op)(struct inode*), struct inode * inode,
+				unsigned short waitflags, unsigned short setflags)
 {
-	struct wait_queue wait = { current, NULL };
-
-	add_wait_queue(&inode->i_wait, &wait);
-repeat:
-	current->state = TASK_UNINTERRUPTIBLE;
-	if (inode->i_lock) {
-		schedule();
-		goto repeat;
+	/* Do nothing if the same op is already in progress. */
+	if(op && !(inode->i_status & setflags)) {
+		set_io(inode, waitflags, setflags);
+		op(inode);
+		if(release_io(inode, setflags)) {
+			/* Somebody grabbed my inode from under me. */
+#ifdef DEBUG
+			printk("_io grab!\n");
+#endif
+                        vfs_lock();
+		}
 	}
-	remove_wait_queue(&inode->i_wait, &wait);
-	current->state = TASK_RUNNING;
 }
 
-/* Clear an inode of all it's identity, this is exported to the world. */
-void clear_inode(struct inode *inode)
+blocking int _free_ibasket(struct super_block * sb)
 {
-	struct wait_queue *wait;
-
-	/* So we don't disappear. */
-	inode->i_count++;
-
-	truncate_inode_pages(inode, 0);
-	wait_on_inode(inode);
-	if(IS_WRITABLE(inode) && inode->i_sb && inode->i_sb->dq_op)
-		inode->i_sb->dq_op->drop(inode);
-
-	if(--inode->i_count > 0)
-		remove_inuse(inode);
-	else
-		remove_free_inode(inode);
-	unhash_inode(inode);
-	wait = inode->i_wait;
-	memset(inode, 0, sizeof(*inode)); barrier();
-	inode->i_wait = wait;
-	put_inode_head(inode);	/* Pages zapped, put at the front. */
+	if(sb->s_ibasket) {
+		struct inode * delinquish = sb->s_ibasket->i_basket_prev;
+#if 0
+printpath(delinquish->i_dentry);
+printk(" delinquish\n");
+#endif
+		_clear_inode(delinquish, 0, 1);
+		return 1;
+	}
+	return 0;
 }
 
-/* These check the validity of a mount/umount type operation, we essentially
- * check if there are any inodes hanging around which prevent this operation
- * from occurring.  We also clear out clean inodes referencing this device.
- */
-int fs_may_mount(kdev_t dev)
+static /*inline*/ void _put_ibasket(struct inode * inode)
 {
-	struct inode *inode;
-	int pass = 0;
-
-	inode = free_inodes.head;
-repeat:
-	while(inode) {
-		struct inode *next = inode->i_next;
-		if(inode->i_dev != dev)
-			goto next;
-		if(inode->i_count || inode->i_dirt || inode->i_lock)
-			return 0;
-		clear_inode(inode);
-	next:
-		inode = next;
+	struct super_block * sb = inode->i_sb;
+	if(!(inode->i_status & ST_IBASKET)) {
+		inode->i_status |= ST_IBASKET;
+		insert_ibasket(&sb->s_ibasket, inode);
+		sb->s_ibasket_count++;
+		if(sb->s_ibasket_count > sb->s_ibasket_max)
+			(void)_free_ibasket(sb);
 	}
-	if(pass == 0) {
-		inode = inuse_list;
-		pass = 1;
-		goto repeat;
-	}
-	return 1; /* Tis' cool bro. */
 }
 
-int fs_may_umount(kdev_t dev, struct inode *iroot)
-{
-	struct inode *inode;
-	int pass = 0;
-
-	inode = free_inodes.head;
-repeat:
-	for(; inode; inode = inode->i_next) {
-		if(inode->i_dev != dev || !inode->i_count)
-			continue;
-		if(inode == iroot &&
-		   (inode->i_count == (inode->i_mount == inode ? 2 : 1)))
-			continue;
-		return 0;
-	}
-	if(pass == 0) {
-		inode = inuse_list;
-		pass = 1;
-		goto repeat;
+blocking void _clear_inode(struct inode * inode, int external, int verbose)
+{
+xcheck("_clear_inode",inode);
+	if(inode->i_status & ST_IBASKET) {
+		struct super_block * sb = inode->i_sb;
+		remove_ibasket(&sb->s_ibasket, inode);
+		sb->s_ibasket_count--;
+		inode->i_status &= ~ST_IBASKET;
+#if 0
+printpath(inode->i_dentry);
+printk(" put_inode\n");
+#endif
+		_io(sb->s_op->put_inode, inode, ST_TO_PUT|ST_TO_WRITE, ST_TO_PUT);
+		if(inode->i_status & ST_EMPTY)
+			return;
 	}
-	return 1; /* Tis' cool bro. */
+	if(inode->i_status & ST_HASHED)
+		remove_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode);
+	if(inode->i_status & ST_AGED) {
+		/* "cannot happen" when called from an fs because at least
+		 * the caller must use it. Can happen when called from
+		 * invalidate_inodes(). */
+		if(verbose)
+			printk("VFS: clearing aged inode\n");
+		if(atomic_read(&inode->i_count))
+			printk("VFS: aged inode is in use\n");
+		remove_lru(&aged_i[inode->i_level], inode);
+		inodes_stat.aged_count[inode->i_level]--;
+	}
+	if(!external && inode->i_status & ST_IO) {
+		printk("VFS: clearing inode during IO operation\n");
+	}
+	if(!(inode->i_status & ST_EMPTY)) {
+		remove_all(&all_i, inode);
+		inode->i_status = ST_EMPTY;
+		while(inode->i_dentry) {
+			d_del(inode->i_dentry, D_NO_CLEAR_INODE);
+		}
+		if(inode->i_pages) {
+			vfs_unlock(); /* may block, can that be revised? */
+			truncate_inode_pages(inode, 0);
+			vfs_lock();
+		}
+		insert_all(&empty_i, inode);
+		inodes_stat.nr_free_inodes++;
+	} else if(external)
+		printk("VFS: empty inode is unnecessarily cleared multiple "
+		       "times by an fs\n");
+        else
+		printk("VFS: clearing empty inode\n");
+	inode->i_status = ST_EMPTY;
+	/* The inode is not really cleared any more here, but only once
+	 * when taken from empty_i. This saves instructions and processor
+	 * cache pollution.
+	 */
+}
+
+void insert_inode_hash(struct inode * inode)
+{
+xcheck("insert_inode_hash",inode);
+	vfs_lock();
+	if(!(inode->i_status & ST_HASHED)) {
+		insert_hash(&hashtable[hash(inode->i_dev, inode->i_ino)], inode);
+		inode->i_status |= ST_HASHED;
+	} else
+		printk("VFS: trying to hash an inode again\n");
+	vfs_unlock();
 }
 
-/* This belongs in file_table.c, not here... */
-int fs_may_remount_ro(kdev_t dev)
+blocking struct inode * _get_empty_inode(void)
 {
-	struct file * file;
+	struct inode * inode;
+	int retry = 0;
 
-	/* Check that no files are currently opened for writing. */
-	for (file = inuse_filps; file; file = file->f_next) {
-		if (!file->f_inode || file->f_inode->i_dev != dev)
-			continue;
-		if (S_ISREG(file->f_inode->i_mode) && (file->f_mode & 2))
-			return 0;
-	}
-	return 1; /* Tis' cool bro. */
-}
-
-/* Reading/writing inodes. */
-static void write_inode(struct inode *inode)
-{
-	if(inode->i_dirt) {
-		wait_on_inode(inode);
-		if(inode->i_dirt) {
-			if(inode->i_sb		&&
-			   inode->i_sb->s_op	&&
-			   inode->i_sb->s_op->write_inode) {
-				inode->i_lock = 1;
-				inode->i_sb->s_op->write_inode(inode);
-				unlock_inode(inode);
-			} else {
-				inode->i_dirt = 0;
+retry:
+	inode = empty_i;
+	if(inode) {
+		remove_all(&empty_i, inode);
+		inodes_stat.nr_free_inodes--;
+	} else if(inodes_stat.nr_inodes < max_inodes || retry > 2) {
+		inode = grow_inodes();
+	}
+	if(!inode) {
+		int level;
+		int usable = 0;
+		for(level = 0; level <= NR_LEVELS; level++)
+			if(aged_i[level]) {
+				inode = aged_i[level]->i_lru_prev;
+				/* Here is the picking strategy, tune this */
+				if(aged_reused[level] < (usable++ ?
+							 inodes_stat.aged_count[level] :
+							 2))
+					break;
+				aged_reused[level] = 0;
 			}
+		if(inode) {
+			if(!(inode->i_status & ST_AGED))
+				printk("VFS: inode aging inconsistency\n");
+			if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+				printk("VFS: i_count of aged inode is not zero\n");
+			if(inode->i_dirt)
+				printk("VFS: Hey, somebody made my aged inode dirty\n");
+			_clear_inode(inode, 0, 0);
+			goto retry;
 		}
 	}
+	if(!inode) {
+		vfs_unlock();
+		schedule();
+		if(retry > 10)
+			panic("VFS: cannot repair inode shortage");
+		if(retry > 2)
+			printk("VFS: no free inodes\n");
+		retry++;
+		vfs_lock();
+		goto retry;
+	}
+xcheck("get_empty_inode",inode);
+	memset(inode, 0, sizeof(struct inode));
+	atomic_set(&inode->i_count, 1);
+	inode->i_nlink = 1;
+	sema_init(&inode->i_sem, 1);
+	inode->i_ino = ++last_inode;
+	inode->i_version = ++event;
+	insert_all(&all_i, inode);
+	return inode;
 }
 
-static inline void read_inode(struct inode *inode)
+static inline blocking struct inode * _get_empty_inode_hashed(dev_t i_dev,
+							      unsigned long i_ino)
 {
-	if(inode->i_sb		&&
-	   inode->i_sb->s_op	&&
-	   inode->i_sb->s_op->read_inode) {
-		lock_inode(inode);
-		inode->i_sb->s_op->read_inode(inode);
-		unlock_inode(inode);
-	}
-}
-
-int inode_change_ok(struct inode *inode, struct iattr *attr)
-{
-	if(!(attr->ia_valid & ATTR_FORCE)) {
-		unsigned short fsuid = current->fsuid;
-		uid_t iuid = inode->i_uid;
-		int not_fsuser = !fsuser();
-
-		if(((attr->ia_valid & ATTR_UID) &&
-		    ((fsuid != iuid) ||
-		     (attr->ia_uid != iuid)) && not_fsuser)	||
-
-		   ((attr->ia_valid & ATTR_GID) &&
-		    (!in_group_p(attr->ia_gid) &&
-		     (attr->ia_gid != inode->i_gid)) && not_fsuser)	||
-
-		   ((attr->ia_valid & (ATTR_ATIME_SET | ATTR_MTIME_SET)) &&
-		    (fsuid != iuid) && not_fsuser))
-			return -EPERM;
-
-		if(attr->ia_valid & ATTR_MODE) {
-			gid_t grp;
-			if(fsuid != iuid && not_fsuser)
-				return -EPERM;
-			grp = attr->ia_valid & ATTR_GID ? attr->ia_gid : inode->i_gid;
-			if(not_fsuser && !in_group_p(grp))
-				attr->ia_mode &= ~S_ISGID;
-		}
-	}
-	return 0;
+	struct inode ** base = &hashtable[hash(i_dev, i_ino)];
+	struct inode * inode = *base;
+	if(inode) do {
+		if(inode->i_ino == i_ino && inode->i_dev == i_dev) {
+			atomic_inc(&inode->i_count);
+			printk("VFS: inode %lx is already in use\n", i_ino);
+			return inode;
+		}
+		inode = inode->i_hash_next;
+	} while(inode != *base);
+	inode = _get_empty_inode();
+	inode->i_dev = i_dev;
+	inode->i_ino = i_ino;
+	insert_hash(base, inode);
+	inode->i_status |= ST_HASHED;
+	return inode;
 }
 
-void inode_setattr(struct inode *inode, struct iattr *attr)
+blocking struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino)
 {
-	if (attr->ia_valid & ATTR_UID)
-		inode->i_uid = attr->ia_uid;
-	if (attr->ia_valid & ATTR_GID)
-		inode->i_gid = attr->ia_gid;
-	if (attr->ia_valid & ATTR_SIZE)
-		inode->i_size = attr->ia_size;
-	if (attr->ia_valid & ATTR_ATIME)
-		inode->i_atime = attr->ia_atime;
-	if (attr->ia_valid & ATTR_MTIME)
-		inode->i_mtime = attr->ia_mtime;
-	if (attr->ia_valid & ATTR_CTIME)
-		inode->i_ctime = attr->ia_ctime;
-	if (attr->ia_valid & ATTR_MODE) {
-		inode->i_mode = attr->ia_mode;
-		if (!fsuser() && !in_group_p(inode->i_gid))
-			inode->i_mode &= ~S_ISGID;
-	}
-	if (attr->ia_valid & ATTR_ATTR_FLAG)
-		inode->i_attr_flags = attr->ia_attr_flags;
-	inode->i_dirt = 1;
-}
-
-int notify_change(struct inode *inode, struct iattr *attr)
-{
-	attr->ia_ctime = CURRENT_TIME;
-	if (attr->ia_valid & (ATTR_ATIME | ATTR_MTIME)) {
-		if (!(attr->ia_valid & ATTR_ATIME_SET))
-			attr->ia_atime = attr->ia_ctime;
-		if (!(attr->ia_valid & ATTR_MTIME_SET))
-			attr->ia_mtime = attr->ia_ctime;
-	}
-
-	if (inode->i_sb		&&
-	    inode->i_sb->s_op	&&
-	    inode->i_sb->s_op->notify_change) 
-		return inode->i_sb->s_op->notify_change(inode, attr);
+	struct inode * inode;
 
-	if(inode_change_ok(inode, attr) != 0)
-		return -EPERM;
-
-	inode_setattr(inode, attr);
-	return 0;
-}
-
-int bmap(struct inode *inode, int block)
-{
-	if(inode->i_op && inode->i_op->bmap)
-		return inode->i_op->bmap(inode, block);
-	return 0;
+	vfs_lock();
+	inode = _get_empty_inode_hashed(i_dev, i_ino);
+	vfs_unlock();
+	return inode;
 }
 
-void invalidate_inodes(kdev_t dev)
+void _get_inode(struct inode * inode)
 {
-	struct inode *inode;
-	int pass = 0;
-
-	inode = free_inodes.head;
-repeat:
-	while(inode) {
-		struct inode *next = inode->i_next;
-		if(inode->i_dev != dev)
-			goto next;
-		clear_inode(inode);
-	next:
-		inode = next;
-	}
-	if(pass == 0) {
-		inode = inuse_list;
-		pass = 1;
-		goto repeat;
-	}
-}
-
-void sync_inodes(kdev_t dev)
-{
-	struct inode *inode;
-	int pass = 0;
-
-	inode = free_inodes.head;
-repeat:
-	while(inode) {
-		struct inode *next = inode->i_next;
-		if(dev && inode->i_dev != dev)
-			goto next;
-		wait_on_inode(inode);
-		write_inode(inode);
-	next:
-		inode = next;
-	}
-	if(pass == 0) {
-		inode = inuse_list;
-		pass = 1;
-		goto repeat;
+	if(inode->i_status & ST_IBASKET) {
+		inode->i_status &= ~ST_IBASKET;
+		remove_ibasket(&inode->i_sb->s_ibasket, inode);
+		inode->i_sb->s_ibasket_count--;
+	}
+	if(inode->i_status & ST_AGED) {
+		inode->i_status &= ~ST_AGED;
+		remove_lru(&aged_i[inode->i_level], inode);
+		inodes_stat.aged_count[inode->i_level]--;
+		aged_reused[inode->i_level]++;
+		if(S_ISDIR(inode->i_mode))
+			/* make dirs less thrashable */
+			inode->i_level = NR_LEVELS-1;
+		else if(inode->i_nlink > 1)
+			/* keep hardlinks totally separate */
+			inode->i_level = NR_LEVELS;
+		else if(++inode->i_reuse_count >= age_table[inode->i_level]
+			&& inode->i_level < NR_LEVELS-1)
+			inode->i_level++;
+		if(atomic_read(&inode->i_count) != 1)
+			printk("VFS: inode count was not zero\n");
+	} else if(inode->i_status & ST_EMPTY)
+		printk("VFS: invalid reuse of empty inode\n");
+}
+
+blocking struct inode * __iget(struct super_block * sb,
+			       unsigned long i_ino,
+			       int crossmntp)
+{
+	struct inode ** base;
+	struct inode * inode;
+	dev_t i_dev;
+	
+	if(!sb)
+		panic("VFS: iget with sb == NULL");
+	i_dev = sb->s_dev;
+	if(!i_dev)
+		panic("VFS: sb->s_dev is NULL\n");
+	base = &hashtable[hash(i_dev, i_ino)];
+	vfs_lock();
+	inode = *base;
+	if(inode) do {
+		if(inode->i_ino == i_ino && inode->i_dev == i_dev) {
+			atomic_inc(&inode->i_count);
+			_get_inode(inode);
+
+			 /* Allow concurrent writes/puts. This is in particular
+			  * useful e.g. when syncing large chunks.
+			  * I hope the i_dirty flag is everywhere set as soon
+			  * as _any_ modifcation is made and _before_
+			  * giving up control, so no harm should occur if data
+			  * is modified during writes, because it will be
+			  * rewritten again (does a short inconsistency on the
+			  * disk harm?)
+			  */
+			wait_io(inode, ST_TO_READ);
+			vfs_unlock();
+			goto done;
+		}
+		inode = inode->i_hash_next;
+	} while(inode != *base);
+	inode = _get_empty_inode_hashed(i_dev, i_ino);
+	inode->i_sb = sb;
+	inode->i_flags = sb->s_flags;
+	if(sb->s_op && sb->s_op->read_inode) {
+		set_io(inode, 0, ST_TO_READ); /* do not wait at all */
+		sb->s_op->read_inode(inode);
+		if(release_io(inode, ST_TO_READ))
+			goto done;
+	}
+	vfs_unlock();
+done:
+	while(crossmntp && inode->i_mount) {
+		struct inode * tmp = inode->i_mount;
+		iinc(tmp);
+		iput(inode);
+		inode = tmp;
 	}
+xcheck("_iget",inode);
+	return inode;
 }
 
-static struct wait_queue *inode_wait, *update_wait;
-
-void iput(struct inode *inode)
+blocking void __iput(struct inode * inode)
 {
-	if(!inode)
-		return;
-	wait_on_inode(inode);
-	if(!inode->i_count) {
-		printk("VFS: Freeing free inode, tell DaveM\n");
+	struct super_block * sb;
+xcheck("_iput",inode);
+	if(atomic_read(&inode->i_count) + inode->i_ddir_count < 0)
+		printk("VFS: i_count is negative\n");
+	if((atomic_read(&inode->i_count) + inode->i_ddir_count) ||
+	   (inode->i_status & ST_FREEING)) {
 		return;
 	}
-	if(inode->i_pipe)
-		wake_up_interruptible(&PIPE_WAIT(*inode));
-we_slept:
-	if(inode->i_count > 1) {
-		inode->i_count--;
-	} else {
-		wake_up(&inode_wait);
-		if(inode->i_pipe) {
-			free_page((unsigned long)PIPE_BASE(*inode));
-			PIPE_BASE(*inode) = NULL;
-		}
-		if(inode->i_sb		&&
-		   inode->i_sb->s_op	&&
-		   inode->i_sb->s_op->put_inode) {
-			inode->i_sb->s_op->put_inode(inode);
-			if(!inode->i_nlink)
-				return;
-		}
-		if(inode->i_dirt) {
-			write_inode(inode);
-			wait_on_inode(inode);
-			goto we_slept;
-		}
-		if(IS_WRITABLE(inode)		&&
-		   inode->i_sb			&&
-		   inode->i_sb->dq_op) {
-			inode->i_lock = 1;
-			inode->i_sb->dq_op->drop(inode);
-			unlock_inode(inode);
-			goto we_slept;
-		}
-		/* There is a serious race leading to here, watch out. */
-		if(--inode->i_count == 0) {
-			remove_inuse(inode);
-			put_inode_last(inode);	/* Place at end of LRU free queue */
+	inode->i_status |= ST_FREEING;
+#ifdef CONFIG_OMIRR
+	if(inode->i_status & ST_MODIFIED) {
+		inode->i_status &= ~ST_MODIFIED;
+		omirr_printall(inode, " W %ld ", CURRENT_TIME);
+	}
+#endif
+	if(inode->i_pipe) {
+		free_page((unsigned long)PIPE_BASE(*inode));
+		PIPE_BASE(*inode)= NULL;
+	}
+	if((sb = inode->i_sb)) {
+		if(sb->s_type && (sb->s_type->fs_flags & FS_NO_DCACHE)) {
+			while(inode->i_dentry)
+				d_del(inode->i_dentry, D_NO_CLEAR_INODE);
+			if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+				goto done;
+		}
+		if(sb->s_op) {
+			if(inode->i_nlink <= 0 && inode->i_dent_count &&
+			   !(inode->i_status & (ST_EMPTY|ST_IBASKET)) &&
+			   (sb->s_type->fs_flags & FS_IBASKET)) {
+				_put_ibasket(inode);
+				goto done;
+			}
+			if(!inode->i_dent_count ||
+			   (sb->s_type->fs_flags & FS_NO_DCACHE)) {
+				_io(sb->s_op->put_inode, inode, 
+				    ST_TO_PUT|ST_TO_WRITE, ST_TO_PUT);
+				if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+					goto done;
+				if(inode->i_nlink <= 0) {
+					if(!(inode->i_status & ST_EMPTY)) {
+						_clear_inode(inode, 0, 1);
+					}
+					goto done;
+				}
+			}
+			if(inode->i_dirt) {
+				inode->i_dirt = 0;
+				_io(sb->s_op->write_inode, inode,
+				    ST_TO_PUT|ST_TO_WRITE, ST_TO_WRITE);
+				if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+					goto done;
+			}
 		}
-	}
-}
-
-static kmem_cache_t *inode_cachep;
-
-static void grow_inodes(void)
-{
-	int i = 16;
-
-	while(i--) {
-		struct inode *inode;
-		
-		inode = kmem_cache_alloc(inode_cachep, SLAB_KERNEL);
-		if(!inode)
-			return;
-		memset(inode, 0, sizeof(*inode));
-		put_inode_head(inode);
-		nr_inodes++;
-	}
-}
-
-/* We have to be really careful, it's really easy to run yourself into
- * inefficient sequences of events.  The first problem is that when you
- * steal a non-referenced inode you run the risk of zaping a considerable
- * number of page cache entries, which might get refernced once again.
- * But if you are growing the inode set to quickly, you suck up ram
- * and cause other problems.
- *
- * We approach the problem in the following way, we take two things into
- * consideration.  Firstly we take a look at how much we have "committed"
- * to this inode already (i_nrpages), this accounts for the cost of getting
- * those pages back if someone should reference that inode soon.  We also
- * attempt to factor in i_blocks, which says "how much of a problem could
- * this potentially be".  It still needs some tuning though.  -DaveM
- */
-#define BLOCK_FACTOR_SHIFT	5	/* It is not factored in as much. */
-static struct inode *find_best_candidate_weighted(struct inode *inode)
-{
-	struct inode *best = NULL;
+		if(IS_WRITABLE(inode) && sb->dq_op) {
+			/* can operate in parallel to other ops ? */
+			_io(sb->dq_op->drop, inode, 0, ST_TO_DROP);
+			if(atomic_read(&inode->i_count) + inode->i_ddir_count)
+				goto done;
+		}
+	}
+	if(inode->i_mmap)
+		printk("VFS: inode has mappings\n");
+	if(inode->i_status & ST_AGED) {
+		printk("VFS: reaging inode\n");
+#if defined(DEBUG)
+printpath(inode->i_dentry);
+printk("\n");
+#endif
+		goto done;
+	}
+	if(!(inode->i_status & (ST_HASHED|ST_EMPTY))) {
+		_clear_inode(inode, 0, 1);
+		goto done;
+	}
+	if(inode->i_status & ST_EMPTY) {
+		printk("VFS: aging an empty inode\n");
+		goto done;
+	}
+	insert_lru(&aged_i[inode->i_level], inode);
+	inodes_stat.aged_count[inode->i_level]++;
+	inode->i_status |= ST_AGED;
+done:
+	inode->i_status &= ~ST_FREEING;
+}
+
+blocking void _iput(struct inode * inode)
+{
+	vfs_lock();
+	__iput(inode);
+	vfs_unlock();
+}
+
+blocking void sync_inodes(kdev_t dev)
+{
+	struct inode * inode;
+	vfs_lock();
+	inode = all_i;
+	if(inode) do {
+xcheck("sync_inodes",inode);
+		if(inode->i_dirt && (inode->i_dev == dev || !dev)) {
+			if(inode->i_sb && inode->i_sb->s_op &&
+			   !(inode->i_status & ST_FREEING)) {
+				inode->i_dirt = 0; 
+				_io(inode->i_sb->s_op->write_inode, inode,
+				    ST_IO, ST_TO_WRITE);
+			}
+		}
+		inode = inode->i_next;
+	} while(inode != all_i);
+	vfs_unlock();
+}
+
+blocking int _check_inodes(kdev_t dev, int complain)
+{
+	struct inode * inode;
+	int bad = 0;
+
+	vfs_lock();
+startover:
+	inode = all_i;
+	if(inode) do {
+		struct inode * next;
+xcheck("_check_inodes",inode);
+		next = inode->i_next;
+		if(inode->i_dev == dev) {
+			if(inode->i_dirt || atomic_read(&inode->i_count)) {
+				bad++;
+			} else {
+				_clear_inode(inode, 0, 0);
 
-	if(inode) {
-		unsigned long bestscore = 1000;
-		int limit = nr_free_inodes >> 2;
-		do {
-			if(!(inode->i_lock | inode->i_dirt)) {
-				int myscore = inode->i_nrpages;
-
-				myscore += (inode->i_blocks >> BLOCK_FACTOR_SHIFT);
-				if(myscore < bestscore) {
-					bestscore = myscore;
-					best = inode;
-				}
+				/* _clear_inode() may recursively clear other
+				 * inodes, probably also the next one.
+				 */
+				if(next->i_status & ST_EMPTY)
+					goto startover;
 			}
-			inode = inode->i_next;
-		} while(inode && --limit);
-	}
-	return best;
+		}
+		inode = next;
+	} while(inode != all_i);
+	vfs_unlock();
+	if(complain && bad)
+		printk("VFS: %d inode(s) busy on removed device `%s'\n",
+		       bad, kdevname(dev));
+	return (bad == 0);
 }
 
-static inline struct inode *find_best_free(struct inode *inode)
+/*inline*/ void invalidate_inodes(kdev_t dev)
 {
-	if(inode) {
-		int limit = nr_free_inodes >> 5;
-		do {
-			if(!inode->i_nrpages)
-				return inode;
-			inode = inode->i_next;
-		} while(inode && --limit);
-	}
-	return NULL;
+	/* Requires two passes, because of the new dcache holding
+	 * directories with i_count > 1.
+	 */
+	(void)_check_inodes(dev, 0);
+	(void)_check_inodes(dev, 1);
 }
 
-struct inode *get_empty_inode(void)
+/*inline*/ int fs_may_mount(kdev_t dev)
 {
-	static int ino = 0;
-	struct inode *inode;
-
-repeat:
-	inode = find_best_free(free_inodes.head);
-	if(!inode)
-		goto pressure;
-got_it:
-	inode->i_count++;
-	truncate_inode_pages(inode, 0);
-	wait_on_inode(inode);
-	if(IS_WRITABLE(inode) && inode->i_sb && inode->i_sb->dq_op)
-		inode->i_sb->dq_op->drop(inode);
-	unhash_inode(inode);
-	remove_free_inode(inode);
-
-	memset(inode, 0, sizeof(*inode));
-	inode->i_count = 1;
-	inode->i_nlink = 1;
-	inode->i_version = ++event;
-	sema_init(&inode->i_sem, 1);
-	inode->i_ino = ++ino;
-	inode->i_dev = 0;
-	put_inuse(inode);
-	return inode;
-pressure:
-	if(nr_inodes < max_inodes) {
-		grow_inodes();
-		goto repeat;
-	}
-	inode = find_best_candidate_weighted(free_inodes.head);
-	if(!inode) {
-		printk("VFS: No free inodes, contact DaveM\n");
-		sleep_on(&inode_wait);
-		goto repeat;
-	}
-	if(inode->i_lock) {
-		wait_on_inode(inode);
-		goto repeat;
-	} else if(inode->i_dirt) {
-		write_inode(inode);
-		goto repeat;
-	}
-	goto got_it;
+	return _check_inodes(dev, 0);
 }
 
-struct inode *get_pipe_inode(void)
+int fs_may_remount_ro(kdev_t dev)
 {
-	extern struct inode_operations pipe_inode_operations;
-	struct inode *inode = get_empty_inode();
-
-	if(inode) {
-		unsigned long page = __get_free_page(GFP_USER);
-		if(!page) {
-			iput(inode);
-			inode = NULL;
-		} else {
-			PIPE_BASE(*inode) = (char *) page;
-			inode->i_op = &pipe_inode_operations;
-			inode->i_count = 2;
-			PIPE_WAIT(*inode) = NULL;
-			PIPE_START(*inode) = PIPE_LEN(*inode) = 0;
-			PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0;
-			PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
-			PIPE_LOCK(*inode) = 0;
-			inode->i_pipe = 1;
-			inode->i_mode |= S_IFIFO | S_IRUSR | S_IWUSR;
-			inode->i_uid = current->fsuid;
-			inode->i_gid = current->fsgid;
-			inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-			inode->i_blksize = PAGE_SIZE;
-		}
-	}
-	return inode;
+	(void)dev;
+	return 1; /* not checked any more */
 }
 
-static int inode_updating[INODE_HASHSZ];
-
-struct inode *__iget(struct super_block *sb, int nr, int crossmntp)
+int fs_may_umount(kdev_t dev, struct inode * mount_root)
 {
-	unsigned int hashent = hashfn(sb->s_dev, nr);
-	struct inode *inode, *empty = NULL;
-
-we_slept:
-	if((inode = find_inode(hashent, sb->s_dev, nr)) == NULL) {
-		if(empty == NULL) {
-			inode_updating[hashent]++;
-			empty = get_empty_inode();
-			if(!--inode_updating[hashent])
-				wake_up(&update_wait);
-			goto we_slept;
-		}
-		inode = empty;
-		inode->i_sb = sb;
-		inode->i_dev = sb->s_dev;
-		inode->i_ino = nr;
-		inode->i_flags = sb->s_flags;
-		hash_inode(inode);
-		read_inode(inode);
-	} else {
-		if(!inode->i_count++) {
-			remove_free_inode(inode);
-			put_inuse(inode);
-		}
-		wait_on_inode(inode);
-		if(crossmntp && inode->i_mount) {
-			struct inode *mp = inode->i_mount;
-			mp->i_count++;
-			iput(inode);
-			wait_on_inode(inode = mp);
-		}
-		if(empty)
-			iput(empty);
+	struct inode * inode;
+	vfs_lock();
+	inode = all_i;
+	if(inode) do {
+xcheck("fs_may_umount",inode);
+		if(inode->i_dev == dev && atomic_read(&inode->i_count))
+			if(inode != mount_root || atomic_read(&inode->i_count) > 
+			   (inode->i_mount == inode ? 2 : 1)) {
+				vfs_unlock();
+				return 0;
+			}
+		inode = inode->i_next;
+	} while(inode != all_i);
+	vfs_unlock();
+	return 1;
+}
+
+extern struct inode_operations pipe_inode_operations;
+
+blocking struct inode * get_pipe_inode(void)
+{
+	struct inode * inode = get_empty_inode();
+
+	PIPE_BASE(*inode) = (char*)__get_free_page(GFP_USER);
+	if(!(PIPE_BASE(*inode))) {
+		iput(inode);
+		return NULL;
+	}
+	inode->i_blksize = PAGE_SIZE;
+	inode->i_pipe = 1;
+	inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR;
+	atomic_inc(&inode->i_count);
+	inode->i_uid = current->fsuid;
+	inode->i_gid = current->fsgid;
+	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->i_op = &pipe_inode_operations;
+	PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1;
+
+	/* I hope this does not introduce security problems.
+	 * Please check and give me response.
+	 */
+	{
+		char dummyname[32];
+		struct qstr dummy = { dummyname, 0 };
+		struct dentry * new;
+		sprintf(dummyname, ".anonymous-pipe-%06lud", inode->i_ino);
+		dummy.len = strlen(dummyname);
+		vfs_lock();
+		new = d_alloc(the_root, dummy.len, 0);
+		if(new)
+			d_add(new, inode, &dummy, D_BASKET);
+		vfs_unlock();
 	}
-	while(inode_updating[hashent])
-		sleep_on(&update_wait);
 	return inode;
 }
 
-void inode_init(void)
+int bmap(struct inode * inode, int block)
 {
-	int i;
-
-	inode_cachep = kmem_cache_create("inode", sizeof(struct inode),
-					 0,
-					 SLAB_HWCACHE_ALIGN, NULL, NULL);
-	if(!inode_cachep)
-		panic("Cannot create inode SLAB cache\n");
-
-	for(i = 0; i < INODE_HASHSZ; i++)
-		inode_hash[i] = NULL;
+	if (inode->i_op && inode->i_op->bmap)
+		return inode->i_op->bmap(inode, block);
+	return 0;
 }
diff -u --recursive --new-file v2.1.42/linux/fs/isofs/dir.c linux/fs/isofs/dir.c
--- v2.1.42/linux/fs/isofs/dir.c	Mon May 19 12:57:39 1997
+++ linux/fs/isofs/dir.c	Thu Jun 12 16:22:08 1997
@@ -54,7 +54,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	isofs_bmap,		/* bmap */
@@ -226,7 +225,6 @@
 			/* rrflag == 1 means that we have a new name (kmalloced) */
 			if (rrflag == 1) {
 				rrflag = filldir(dirent, name, len, filp->f_pos, inode_number);
-				dcache_add(inode, name, len, inode_number);
 				kfree(name); /* this was allocated in get_r_r_filename.. */
 				if (rrflag < 0)
 					break;
@@ -239,7 +237,6 @@
 			len = isofs_name_translate(name, len, tmpname);
 			if (filldir(dirent, tmpname, len, filp->f_pos, inode_number) < 0)
 				break;
-			dcache_add(inode, tmpname, len, inode_number);
 			filp->f_pos += de_len;
 			continue;
 		}
@@ -247,7 +244,6 @@
 		if (filldir(dirent, name, len, filp->f_pos, inode_number) < 0)
 			break;
 
-		dcache_add(inode, name, len, inode_number);
 		filp->f_pos += de_len;
 		continue;
 	}
diff -u --recursive --new-file v2.1.42/linux/fs/isofs/file.c linux/fs/isofs/file.c
--- v2.1.42/linux/fs/isofs/file.c	Sun Jan 26 02:07:44 1997
+++ linux/fs/isofs/file.c	Thu Jun 12 16:22:08 1997
@@ -47,7 +47,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	isofs_bmap,		/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/isofs/inode.c linux/fs/isofs/inode.c
--- v2.1.42/linux/fs/isofs/inode.c	Tue May 13 22:41:14 1997
+++ linux/fs/isofs/inode.c	Thu Jun 12 16:22:08 1997
@@ -912,7 +912,10 @@
 #endif
 
 static struct file_system_type iso9660_fs_type = {
-	isofs_read_super, "iso9660", 1, NULL
+	"iso9660",
+	FS_REQUIRES_DEV,
+	isofs_read_super, 
+	NULL
 };
 
 __initfunc(int init_iso9660_fs(void))
diff -u --recursive --new-file v2.1.42/linux/fs/isofs/namei.c linux/fs/isofs/namei.c
--- v2.1.42/linux/fs/isofs/namei.c	Mon May 19 12:57:39 1997
+++ linux/fs/isofs/namei.c	Thu Jun 12 16:22:08 1997
@@ -206,6 +206,7 @@
 {
 	unsigned long ino, ino_back;
 	struct buffer_head * bh;
+	char *lcname;
 
 #ifdef DEBUG
 	printk("lookup: %x %d\n",dir->i_ino, len);
@@ -219,38 +220,29 @@
 		return -ENOENT;
 	}
 
-	ino = 0;
-
-	if (dcache_lookup(dir, name, len, &ino)) ino_back = dir->i_ino;
-
-	if (!ino) {
-		char *lcname;
-
-		/* If mounted with check=relaxed (and most likely norock),
-		   then first convert this name to lower case. */
-		if (dir->i_sb->u.isofs_sb.s_name_check == 'r'
-		    && (lcname = kmalloc(len, GFP_KERNEL)) != NULL) {
-			int i;
-			char c;
-
-			for (i=0; i<len; i++) {
-				c = name[i];
-				if (c >= 'A' && c <= 'Z') c |= 0x20;
-				lcname[i] = c;
-			}
-			bh = isofs_find_entry(dir,lcname,len, &ino, &ino_back);
-			kfree(lcname);
-		} else
-			bh = isofs_find_entry(dir,name,len, &ino, &ino_back);
-
-		if (!bh) {
-			iput(dir);
-	  		return -ENOENT;
+	/* If mounted with check=relaxed (and most likely norock),
+	 * then first convert this name to lower case.
+	 */
+	if (dir->i_sb->u.isofs_sb.s_name_check == 'r' &&
+	    (lcname = kmalloc(len, GFP_KERNEL)) != NULL) {
+		int i;
+		char c;
+
+		for (i=0; i<len; i++) {
+			c = name[i];
+			if (c >= 'A' && c <= 'Z') c |= 0x20;
+			lcname[i] = c;
 		}
-		if (ino_back == dir->i_ino)
-			dcache_add(dir, name, len, ino);
-		brelse(bh);
+		bh = isofs_find_entry(dir,lcname,len, &ino, &ino_back);
+		kfree(lcname);
+	} else
+		bh = isofs_find_entry(dir,name,len, &ino, &ino_back);
+
+	if (!bh) {
+		iput(dir);
+		return -ENOENT;
 	}
+	brelse(bh);
 
 	if (!(*result = iget(dir->i_sb,ino))) {
 		iput(dir);
@@ -258,14 +250,12 @@
 	}
 
 	/* We need this backlink for the ".." entry unless the name that we
-	   are looking up traversed a mount point (in which case the inode
-	   may not even be on an iso9660 filesystem, and writing to
-	   u.isofs_i would only cause memory corruption).
-	*/
-	
-	if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) {
-	  (*result)->u.isofs_i.i_backlink = ino_back; 
-	}
+	 * are looking up traversed a mount point (in which case the inode
+	 * may not even be on an iso9660 filesystem, and writing to
+	 * u.isofs_i would only cause memory corruption).
+	 */
+	if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb)
+		(*result)->u.isofs_i.i_backlink = ino_back; 
 	
 	iput(dir);
 	return 0;
diff -u --recursive --new-file v2.1.42/linux/fs/isofs/symlink.c linux/fs/isofs/symlink.c
--- v2.1.42/linux/fs/isofs/symlink.c	Wed Jan  1 06:56:07 1997
+++ linux/fs/isofs/symlink.c	Thu Jun 12 16:22:08 1997
@@ -19,7 +19,6 @@
 #include <asm/uaccess.h>
 
 static int isofs_readlink(struct inode *, char *, int);
-static int isofs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
 
 /*
  * symlinks can't do much...
@@ -36,7 +35,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	isofs_readlink,		/* readlink */
-	isofs_follow_link,	/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -44,50 +42,10 @@
 	NULL			/* permission */
 };
 
-static int isofs_follow_link(struct inode * dir, struct inode * inode,
-	int flag, int mode, struct inode ** res_inode)
-{
-	int error;
-	char * pnt;
-
-	if (!dir) {
-		dir = current->fs->root;
-		dir->i_count++;
-	}
-	if (!inode) {
-		iput(dir);
-		*res_inode = NULL;
-		return -ENOENT;
-	}
-	if (!S_ISLNK(inode->i_mode)) {
-		iput(dir);
-		*res_inode = inode;
-		return 0;
-	}
-	if ((current->link_count > 5) ||
-	   !(pnt = get_rock_ridge_symlink(inode))) {
-		iput(dir);
-		iput(inode);
-		*res_inode = NULL;
-		return -ELOOP;
-	}
-	iput(inode);
-	current->link_count++;
-	error = open_namei(pnt,flag,mode,res_inode,dir);
-	current->link_count--;
-	kfree(pnt);
-	return error;
-}
-
 static int isofs_readlink(struct inode * inode, char * buffer, int buflen)
 {
         char * pnt;
 	int i;
-
-	if (!S_ISLNK(inode->i_mode)) {
-		iput(inode);
-		return -EINVAL;
-	}
 
 	if (buflen > 1023)
 		buflen = 1023;
diff -u --recursive --new-file v2.1.42/linux/fs/minix/bitmap.c linux/fs/minix/bitmap.c
--- v2.1.42/linux/fs/minix/bitmap.c	Fri Dec 20 01:24:38 1996
+++ linux/fs/minix/bitmap.c	Thu Jun 12 16:22:08 1997
@@ -191,8 +191,8 @@
 		printk("free_inode: inode has no device\n");
 		return;
 	}
-	if (inode->i_count != 1) {
-		printk("free_inode: inode has count=%d\n",inode->i_count);
+	if (atomic_read(&inode->i_count) != 1) {
+		printk("free_inode: inode has count=%d\n",atomic_read(&inode->i_count));
 		return;
 	}
 	if (inode->i_nlink) {
@@ -251,7 +251,7 @@
 		iput(inode);
 		return NULL;
 	}
-	inode->i_count = 1;
+	atomic_set(&inode->i_count, 1);
 	inode->i_nlink = 1;
 	inode->i_dev = sb->s_dev;
 	inode->i_uid = current->fsuid;
diff -u --recursive --new-file v2.1.42/linux/fs/minix/dir.c linux/fs/minix/dir.c
--- v2.1.42/linux/fs/minix/dir.c	Sun Jan 26 02:07:44 1997
+++ linux/fs/minix/dir.c	Thu Jun 12 16:22:08 1997
@@ -50,7 +50,6 @@
 	minix_mknod,		/* mknod */
 	minix_rename,		/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/minix/file.c linux/fs/minix/file.c
--- v2.1.42/linux/fs/minix/file.c	Sun Jan 26 02:07:44 1997
+++ linux/fs/minix/file.c	Thu Jun 12 16:22:08 1997
@@ -58,7 +58,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	minix_bmap,		/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/minix/inode.c linux/fs/minix/inode.c
--- v2.1.42/linux/fs/minix/inode.c	Wed Apr 23 19:01:26 1997
+++ linux/fs/minix/inode.c	Thu Jun 12 16:22:08 1997
@@ -944,7 +944,10 @@
 }
 
 static struct file_system_type minix_fs_type = {
-	minix_read_super, "minix", 1, NULL
+	"minix",
+	FS_REQUIRES_DEV,
+	minix_read_super,
+	NULL
 };
 
 __initfunc(int init_minix_fs(void))
diff -u --recursive --new-file v2.1.42/linux/fs/minix/namei.c linux/fs/minix/namei.c
--- v2.1.42/linux/fs/minix/namei.c	Sat Nov 30 02:24:01 1996
+++ linux/fs/minix/namei.c	Thu Jun 12 16:22:08 1997
@@ -462,7 +462,7 @@
 		retval = -ENOENT;
 		goto end_rmdir;
 	}
-	if (inode->i_count > 1) {
+	if (atomic_read(&inode->i_count) > 1) {
 		retval = -EBUSY;
 		goto end_rmdir;
 	}
@@ -639,7 +639,7 @@
 	int ino;
 	int result;
 
-	new_inode->i_count++;
+	atomic_inc(&new_inode->i_count);
 	result = 0;
 	for (;;) {
 		if (new_inode == old_inode) {
@@ -672,7 +672,7 @@
  * higher-level routines.
  */
 static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len, int must_be_dir)
+			   struct inode * new_dir, const char * new_name, int new_len)
 {
 	struct inode * old_inode, * new_inode;
 	struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -700,8 +700,6 @@
 	old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
-	if (must_be_dir && !S_ISDIR(old_inode->i_mode))
-		goto end_rename;
 	retval = -EPERM;
 	if ((old_dir->i_mode & S_ISVTX) && 
 	    current->fsuid != old_inode->i_uid &&
@@ -730,7 +728,7 @@
 		if (!empty_dir(new_inode))
 			goto end_rename;
 		retval = -EBUSY;
-		if (new_inode->i_count > 1)
+		if (atomic_read(&new_inode->i_count) > 1)
 			goto end_rename;
 	}
 	retval = -EPERM;
@@ -818,8 +816,7 @@
  * as they are on different partitions.
  */
 int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len,
-	int must_be_dir)
+		 struct inode * new_dir, const char * new_name, int new_len)
 {
 	static struct wait_queue * wait = NULL;
 	static int lock = 0;
@@ -829,7 +826,7 @@
 		sleep_on(&wait);
 	lock = 1;
 	result = do_minix_rename(old_dir, old_name, old_len,
-		new_dir, new_name, new_len, must_be_dir);
+				 new_dir, new_name, new_len);
 	lock = 0;
 	wake_up(&wait);
 	return result;
diff -u --recursive --new-file v2.1.42/linux/fs/minix/symlink.c linux/fs/minix/symlink.c
--- v2.1.42/linux/fs/minix/symlink.c	Mon Oct 28 04:29:26 1996
+++ linux/fs/minix/symlink.c	Thu Jun 12 16:22:08 1997
@@ -15,7 +15,6 @@
 #include <asm/uaccess.h>
 
 static int minix_readlink(struct inode *, char *, int);
-static int minix_follow_link(struct inode *, struct inode *, int, int, struct inode **);
 
 /*
  * symlinks can't do much...
@@ -32,7 +31,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	minix_readlink,		/* readlink */
-	minix_follow_link,	/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -40,54 +38,12 @@
 	NULL			/* permission */
 };
 
-static int minix_follow_link(struct inode * dir, struct inode * inode,
-	int flag, int mode, struct inode ** res_inode)
-{
-	int error;
-	struct buffer_head * bh;
-
-	*res_inode = NULL;
-	if (!dir) {
-		dir = current->fs->root;
-		dir->i_count++;
-	}
-	if (!inode) {
-		iput(dir);
-		return -ENOENT;
-	}
-	if (!S_ISLNK(inode->i_mode)) {
-		iput(dir);
-		*res_inode = inode;
-		return 0;
-	}
-	if (current->link_count > 5) {
-		iput(inode);
-		iput(dir);
-		return -ELOOP;
-	}
-	if (!(bh = minix_bread(inode, 0, 0))) {
-		iput(inode);
-		iput(dir);
-		return -EIO;
-	}
-	iput(inode);
-	current->link_count++;
-	error = open_namei(bh->b_data,flag,mode,res_inode,dir);
-	current->link_count--;
-	brelse(bh);
-	return error;
-}
-
 static int minix_readlink(struct inode * inode, char * buffer, int buflen)
 {
 	struct buffer_head * bh;
 	int i;
 	char c;
 
-	if (!S_ISLNK(inode->i_mode)) {
-		iput(inode);
-		return -EINVAL;
-	}
 	if (buflen > 1023)
 		buflen = 1023;
 	bh = minix_bread(inode, 0, 0);
diff -u --recursive --new-file v2.1.42/linux/fs/msdos/msdosfs_syms.c linux/fs/msdos/msdosfs_syms.c
--- v2.1.42/linux/fs/msdos/msdosfs_syms.c	Tue May 13 22:41:14 1997
+++ linux/fs/msdos/msdosfs_syms.c	Thu Jun 12 16:22:08 1997
@@ -31,7 +31,10 @@
 
 
 struct file_system_type msdos_fs_type = {
-	msdos_read_super, "msdos", 1, NULL
+	"msdos",
+	FS_REQUIRES_DEV,
+	msdos_read_super, 
+	NULL
 };
 
 __initfunc(int init_msdos_fs(void))
diff -u --recursive --new-file v2.1.42/linux/fs/msdos/namei.c linux/fs/msdos/namei.c
--- v2.1.42/linux/fs/msdos/namei.c	Sat Dec 21 04:24:02 1996
+++ linux/fs/msdos/namei.c	Thu Jun 12 16:22:08 1997
@@ -219,14 +219,6 @@
 		if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
 		return 0;
 	}
-#if 0
-	if (dcache_lookup(dir, name, len, (unsigned long *) &ino)) {
-		iput(dir);
-		if (!(*result = iget(dir->i_sb, ino)))
-			return -EACCES;
-		return 0;
-	}
-#endif
 	PRINTK (("msdos_lookup 3\n"));
 	if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) {
 		iput(dir);
@@ -304,7 +296,6 @@
 	(*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime =
 	    CURRENT_TIME;
 	(*result)->i_dirt = 1;
-	dcache_add(dir, name, len, ino);
 	return 0;
 }
 
@@ -378,7 +369,7 @@
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 
-	if (dir->i_count > 1)
+	if (atomic_read(&dir->i_count) > 1)
 		return -EBUSY;
 	if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
 		pos = 0;
@@ -596,7 +587,6 @@
 		new_inode->i_dirt = 1;
 		new_de->name[0] = DELETED_FLAG;
 		fat_mark_buffer_dirty(sb, new_bh, 1);
-		dcache_add(new_dir, new_name, new_len, new_ino);
 		iput(new_inode);
 		fat_brelse(sb, new_bh);
 	}
@@ -721,10 +711,9 @@
 		MSDOS_I(new_inode)->i_depend = free_inode;
 		MSDOS_I(free_inode)->i_old = new_inode;
 		/* Two references now exist to free_inode so increase count */
-		free_inode->i_count++;
+		atomic_inc(&free_inode->i_count);
 		/* free_inode is put after putting new_inode and old_inode */
 		iput(new_inode);
-		dcache_add(new_dir, new_name, new_len, new_ino);
 		fat_brelse(sb, new_bh);
 	}
 	if (S_ISDIR(old_inode->i_mode)) {
@@ -755,8 +744,7 @@
 
 /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
 int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
-	struct inode *new_dir,const char *new_name,int new_len,
-	int must_be_dir)
+		 struct inode *new_dir,const char *new_name,int new_len)
 {
 	struct super_block *sb = old_dir->i_sb;
 	char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
@@ -805,7 +793,6 @@
 	NULL,			/* mknod */
 	msdos_rename,		/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	fat_bmap,		/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/namei.c linux/fs/namei.c
--- v2.1.42/linux/fs/namei.c	Tue May 13 22:41:14 1997
+++ linux/fs/namei.c	Sun Jun 15 15:09:10 1997
@@ -8,6 +8,11 @@
  * Some corrections by tytso.
  */
 
+/* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname
+ * lookup logic.
+ */
+
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -15,18 +20,114 @@
 #include <linux/fcntl.h>
 #include <linux/stat.h>
 #include <linux/mm.h>
+#include <linux/dalloc.h>
+#include <linux/nametrans.h>
+#include <linux/proc_fs.h>
+#include <linux/omirr.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
+#include <asm/semaphore.h>
 #include <asm/namei.h>
 
+/* This can be removed after the beta phase. */
+#define CACHE_SUPERVISE	/* debug the correctness of dcache entries */
+#undef DEBUG		/* some other debugging */
+
+
+/* local flags for __namei() */
+#define NAM_SEMLOCK        8 /* set a semlock on the last dir */
+#define NAM_TRANSCREATE   16 /* last component may be created, try "=CREATE#" suffix*/
+#define NAM_NO_TRAILSLASH 32 /* disallow trailing slashes by returning EISDIR */
 #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
 
+/* [Feb-1997 T. Schoebel-Theuer]
+ * Fundamental changes in the pathname lookup mechanisms (namei)
+ * were necessary because of omirr.  The reason is that omirr needs
+ * to know the _real_ pathname, not the user-supplied one, in case
+ * of symlinks (and also when transname replacements occur).
+ *
+ * The new code replaces the old recursive symlink resolution with
+ * an iterative one (in case of non-nested symlink chains).  It does
+ * this by looking up the symlink name from the particular filesystem,
+ * and then follows this name as if it were a user-supplied one.  This
+ * is done solely in the VFS level, such that <fs>_follow_link() is not
+ * used any more and could be removed in future.  As a side effect,
+ * dir_namei(), _namei() and follow_link() are now replaced with a single
+ * function __namei() that can handle all the special cases of the former
+ * code.
+ *
+ * With the new dcache, the pathname is stored at each inode, at least as
+ * long as the refcount of the inode is positive.  As a side effect, the
+ * size of the dcache depends on the inode cache and thus is dynamic.
+ */
 
-/*
- * In order to reduce some races, while at the same time doing additional
+/* [24-Feb-97 T. Schoebel-Theuer] Side effects caused by new implementation:
+ * New symlink semantics: when open() is called with flags O_CREAT | O_EXCL
+ * and the name already exists in form of a symlink, try to create the new
+ * name indicated by the symlink. The old code always complained that the
+ * name already exists, due to not following the symlink even if its target
+ * is non-existant.  The new semantics affects also mknod() and link() when
+ * the name is a symlink pointing to a non-existant name.
+ *
+ * I don't know which semantics is the right one, since I have no access
+ * to standards. But I found by trial that HP-UX 9.0 has the full "new"
+ * semantics implemented, while SunOS 4.1.1 and Solaris (SunOS 5.4) have the
+ * "old" one. Personally, I think the new semantics is much more logical.
+ * Note that "ln old new" where "new" is a symlink pointing to a non-existing
+ * file does succeed in both HP-UX and SunOs, but not in Solaris
+ * and in the old Linux semantics.
+ */
+
+static char * quicklist = NULL;
+static int quickcount = 0;
+struct semaphore quicklock = MUTEX;
+
+/* Tuning: increase locality by reusing same pages again...
+ * if quicklist becomes too long on low memory machines, either a limit
+ * should be added or after a number of cycles some pages should
+ * be released again ...
+ */
+static inline char * get_page(void)
+{
+	char * res;
+	down(&quicklock);
+	res = quicklist;
+	if(res) {
+#ifdef DEBUG
+		char * tmp = res;
+		int i;
+		for(i=0; i<quickcount; i++)
+			tmp = *(char**)tmp;
+		if(tmp)
+			printk("bad quicklist %x\n", (int)tmp);
+#endif
+		quicklist = *(char**)res;
+		quickcount--;
+	}
+	else
+		res = (char*)__get_free_page(GFP_KERNEL);
+	up(&quicklock);
+	return res;
+}
+
+inline void putname(char * name)
+{
+	if(name) {
+		down(&quicklock);
+		*(char**)name = quicklist;
+		quicklist = name;
+		quickcount++;
+		up(&quicklock);
+	}
+	/* if a quicklist limit is necessary to introduce, call
+	 * 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..
  *
@@ -53,44 +154,22 @@
 	return retval;
 }
 
-/*
- * This is a single page for faster getname.
- *   If the page is available when entering getname, use it.
- *   If the page is not available, call __get_free_page instead.
- * This works even though do_getname can block (think about it).
- * -- Michael Chastain, based on idea of Linus Torvalds, 1 Dec 1996.
- */
-static unsigned long name_page_cache = 0;
-
 int getname(const char * filename, char **result)
 {
-	unsigned long page;
+	char *tmp;
 	int retval;
 
-	page = name_page_cache;
-	name_page_cache = 0;
-	if (!page) {
-		page = __get_free_page(GFP_KERNEL);
-		if (!page)
-			return -ENOMEM;
-	}
-
-	retval = do_getname(filename, (char *) page);
+	tmp = get_page();
+	if(!tmp)
+		return -ENOMEM;
+	retval = do_getname(filename, tmp);
 	if (retval < 0)
-		putname( (char *) page );
+		putname(tmp);
 	else
-		*result = (char *) page;
+		*result = tmp;
 	return retval;
 }
 
-void putname(char * name)
-{
-	if (name_page_cache == 0)
-		name_page_cache = (unsigned long) name;
-	else
-		free_page((unsigned long) name);
-}
-
 /*
  *	permission()
  *
@@ -143,155 +222,416 @@
 	inode->i_writecount--;
 }
 
-/*
- * lookup() looks up one part of a pathname, using the fs-dependent
- * routines (currently minix_lookup) for it. It also checks for
- * fathers (pseudo-roots, mount-points)
+static /*inline */ int concat(struct qstr * name, struct qstr * appendix, char * buf)
+{
+	int totallen = name->len;
+	if(name->len > MAX_TRANS_FILELEN ||
+	   appendix->len > MAX_TRANS_SUFFIX) {
+		return -ENAMETOOLONG;
+	}
+	memcpy(buf, name->name, name->len);
+	memcpy(buf + name->len, appendix->name, appendix->len);
+	totallen += appendix->len;
+	buf[totallen] = '\0';
+	return totallen;
+}
+
+/* Internal lookup() using the new generic dcache.
+ * buf must only be supplied if appendix!=NULL.
  */
-int lookup(struct inode * dir,const char * name, int len,
-           struct inode ** result)
+static int cached_lookup(struct inode * dir, struct qstr * name,
+			 struct qstr * appendix, char * buf,
+			 struct qstr * res_name, struct dentry ** res_entry,
+			 struct inode ** result)
 {
-	struct super_block * sb;
-	int perm;
+	struct qstr tmp = { name->name, name->len };
+	int error;
+	struct dentry * cached;
 
 	*result = NULL;
-	if (!dir)
-		return -ENOENT;
-/* check permissions before traversing mount-points */
-	perm = permission(dir,MAY_EXEC);
-	if (len==2 && get_unaligned((u16 *) name) == 0x2e2e) {
-		if (dir == current->fs->root) {
-			*result = dir;
-			return 0;
-		} else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) {
-			iput(dir);
-			dir = sb->s_covered;
-			if (!dir)
-				return -ENOENT;
-			dir->i_count++;
-		}
-	}
-	if (!dir->i_op || !dir->i_op->lookup) {
-		iput(dir);
-		return -ENOTDIR;
-	}
- 	if (perm != 0) {
-		iput(dir);
-		return perm;
-	}
-	if (!len) {
-		*result = dir;
-		return 0;
+	if(name->len >= D_MAXLEN)
+		return -ENAMETOOLONG;
+	vfs_lock();
+	cached = d_lookup(dir, name, appendix);
+	if(cached) {
+		struct inode *inode = NULL;
+
+		if(cached->u.d_inode && (inode = d_inode(&cached))) {
+			error = 0;
+			if(appendix && res_name) {
+				tmp.len = error = concat(name, appendix, buf);
+				tmp.name = buf;
+				if(error > 0)
+					error = 0;
+			}
+		} else {
+			error = -ENOENT;
+		}
+		vfs_unlock();
+		if(res_entry)
+			*res_entry = cached;
+
+		/* Since we are bypassing the iget() mechanism, we have to
+		 * fabricate the act of crossing any mount points.
+		 */
+		if(!error && inode && inode->i_mount) {
+			do {
+				struct inode *mnti = inode->i_mount;
+				iinc(mnti);
+				iput(inode);
+				inode = mnti;
+			} while(inode->i_mount);
+		}
+		*result = inode;
+		goto done;
+	} else
+		vfs_unlock();
+
+	if(appendix) {
+		tmp.len = error = concat(name, appendix, buf);
+		tmp.name = buf;
+		if(error < 0)
+			goto done;
+	}
+	atomic_inc(&dir->i_count);
+	error = dir->i_op->lookup(dir, tmp.name, tmp.len, result);
+	if(dir->i_dentry && tmp.len &&
+	   (!error || (error == -ENOENT && (!dir->i_sb || !dir->i_sb->s_type ||
+	    !(dir->i_sb->s_type->fs_flags & FS_NO_DCACHE))))) {
+		struct dentry * res;
+		vfs_lock();
+		res = d_entry(dir->i_dentry, &tmp, error ? NULL : *result);
+		vfs_unlock();
+		if(res_entry)
+			*res_entry = res;
+	}
+done:
+	if(res_name) {
+                if(error) {
+		        res_name->name = name->name;
+		        res_name->len = name->len;
+                } else {
+		        res_name->name = tmp.name;
+		        res_name->len = tmp.len;
+                }
 	}
-	return dir->i_op->lookup(dir, name, len, result);
+	return error;
 }
 
-int follow_link(struct inode * dir, struct inode * inode,
-	int flag, int mode, struct inode ** res_inode)
-{
-	if (!dir || !inode) {
-		iput(dir);
-		iput(inode);
-		*res_inode = NULL;
-		return -ENOENT;
+#ifdef CONFIG_TRANS_NAMES
+/* If a normal filename is seen, try to determine whether a
+ * "#keyword=context#" file exists and return the new filename.
+ * If the name is to be created (create_mode), check whether a
+ * "#keyword=CREATE" name exists and optionally return the corresponding
+ * context name even if it didn't exist before.
+ */
+static int check_suffixes(struct inode * dir, struct qstr * name,
+			  int create_mode, char * buf,
+			  struct qstr * res_name, struct dentry ** res_entry,
+			  struct inode ** result)
+{
+	struct translations * trans;
+	char * env;
+	struct qstr * suffixes;
+	int i;
+	int error = -ENOENT;
+
+	if(!buf)
+		panic("buf==NULL");
+	env = env_transl();
+#ifdef CONFIG_TRANS_RESTRICT
+	if(!env && dir->i_gid != CONFIG_TRANS_GID) {
+		return error;
+        }
+#endif
+	trans = get_translations(env);
+	suffixes = create_mode ? trans->c_name : trans->name;
+	for(i = 0; i < trans->count; i++) {
+		error = cached_lookup(dir, name, &suffixes[i],
+				      buf, res_name, res_entry, result);
+		if(!error) {
+			if(res_name && create_mode) {
+				/* buf == res_name->name, but is writable */
+				memcpy(buf + name->len,
+				       trans->name[i].name,
+				       trans->name[i].len);
+				res_name->len = name->len + trans->name[i].len;
+                                buf[res_name->len] = '\0';
+			}
+			break;
+		}
 	}
-	if (!inode->i_op || !inode->i_op->follow_link) {
-		iput(dir);
-		*res_inode = inode;
-		return 0;
+	if(env)
+		free_page((unsigned long)trans);
+	return error;
+}
+
+#endif
+
+/* Any operations involving reserved names at the VFS level should go here. */
+static /*inline*/ int reserved_lookup(struct inode * dir, struct qstr * name,
+				      int create_mode, char * buf,
+				      struct inode ** result)
+{
+	int error = -ENOENT;
+	if(name->name[0] == '.') {
+		if(name->len == 1) {
+			*result = dir;
+			error = 0;
+		} else if (name->len==2 && name->name[1] == '.') {
+			if (dir == current->fs->root) {
+				*result = dir;
+				error = 0;
+			}
+			else if(dir->i_dentry) {
+				error = 0;
+				*result = dir->i_dentry->d_parent->u.d_inode;
+				if(!*result) {
+					printk("dcache parent directory is lost");
+					error = -ESTALE;	/* random error */
+				}
+			}
+		}
+		if(!error)
+			atomic_inc(&(*result)->i_count);
 	}
-	return inode->i_op->follow_link(dir,inode,flag,mode,res_inode);
+	return error;
 }
 
-/*
- *	dir_namei()
- *
- * dir_namei() returns the inode of the directory of the
- * specified name, and the name within that directory.
+/* In difference to the former version, lookup() no longer eats the dir. */
+static /*inline*/ int lookup(struct inode * dir, struct qstr * name, int create_mode,
+			     char * buf, struct qstr * res_name,
+			     struct dentry ** res_entry, struct inode ** result)
+{
+	int perm;
+
+	*result = NULL;
+	perm = -ENOENT;
+ 	if (!dir)
+		goto done;
+
+	/* Check permissions before traversing mount-points. */
+	perm = permission(dir,MAY_EXEC);
+ 	if (perm)
+		goto done;
+	perm = reserved_lookup(dir, name, create_mode, buf, result);
+	if(!perm) {
+		if(res_name) {
+			res_name->name = name->name;
+			res_name->len = name->len;
+		}
+		goto done;
+	}
+	perm = -ENOTDIR;
+	if (!dir->i_op || !dir->i_op->lookup)
+		goto done;
+#ifdef CONFIG_TRANS_NAMES /* try suffixes */
+	perm = check_suffixes(dir, name, 0, buf, res_name, res_entry, result);
+	if(perm) /* try original name */
+#endif
+		perm = cached_lookup(dir, name, NULL, buf, res_name, res_entry, result);
+#ifdef CONFIG_TRANS_NAMES
+	if(perm == -ENOENT && create_mode) { /* try the =CREATE# suffix */
+		struct inode * dummy;
+		if(!check_suffixes(dir, name, 1, buf, res_name, NULL, &dummy)) {
+			iput(dummy);
+		}
+	}
+#endif
+done:
+	return perm;
+}
+
+/* [8-Feb-97 T. Schoebel-Theuer] follow_link() modified for generic operation
+ * on the VFS layer: first call <fs>_readlink() and then open_namei().
+ * All <fs>_follow_link() are not used any more and may be eliminated
+ * (by Linus; I refrained in order to not break other patches).
+ * Single exeption is procfs, where proc_follow_link() is used
+ * internally (and perhaps should be rewritten).
+ * Note: [partly obsolete] I removed parameters flag and mode, since now
+ * __namei() is called instead of open_namei(). In the old semantics,
+ * the _last_ instance of open_namei() did the real create() if O_CREAT was
+ * set and the name existed already in form of a symlink. This has been
+ * simplified now, and also the semantics when combined with O_EXCL has changed.
+ ****************************************************************************
+ * [13-Feb-97] Complete rewrite -> functionality of reading symlinks factored
+ * out into _read_link(). The above notes remain valid in principle.
  */
-static int dir_namei(const char *pathname, int *namelen, const char **name,
-                     struct inode * base, struct inode **res_inode)
+static /*inline*/ int _read_link(struct inode * inode, char ** linkname, int loopcount)
 {
-	unsigned char c;
-	const char * thisname;
-	int len,error;
-	struct inode * inode;
+	unsigned long old_fs;
+	int error;
 
-	*res_inode = NULL;
-	if (!base) {
-		base = current->fs->pwd;
-		base->i_count++;
+	error = -ENOSYS;
+	if (!inode->i_op || !inode->i_op->readlink)
+		goto done;
+	error = -ELOOP;
+	if (current->link_count + loopcount > 10)
+		goto done;
+	error = -ENOMEM;
+	if(!*linkname && !(*linkname = get_page()))
+		goto done;
+	if (DO_UPDATE_ATIME(inode)) {
+		inode->i_atime = CURRENT_TIME;
+		inode->i_dirt = 1;
+	}
+	atomic_inc(&inode->i_count);
+	old_fs = get_fs();
+	set_fs(KERNEL_DS);
+	error = inode->i_op->readlink(inode, *linkname, PAGE_SIZE);
+	set_fs(old_fs);
+	if(!error) {
+		error = -ENOENT; /* ? or other error code ? */
+	} else if(error > 0) {
+		(*linkname)[error] = '\0';
+		error = 0;
 	}
-	if ((c = *pathname) == '/') {
-		iput(base);
+done:
+	iput(inode);
+	return error;
+}
+
+/* [13-Feb-97 T. Schoebel-Theuer] complete rewrite:
+ * merged dir_name(), _namei() and follow_link() into one new routine
+ * that obeys all the special cases hidden in the old routines in a
+ * (hopefully) systematic way:
+ * parameter retrieve_mode is bitwise or'ed of the ST_* flags.
+ * if res_inode is a NULL pointer, dont try to retrieve the last component
+ * at all. Parameters with prefix last_ are used only if res_inode is
+ * non-NULL and refer to the last component of the path only.
+ */
+int __namei(int retrieve_mode, const char * name, struct inode * base,
+	    char * buf, struct inode ** res_dir, struct inode ** res_inode,
+	    struct qstr * last_name, struct dentry ** last_entry,
+	    int * last_error)
+{
+	char c;
+	struct qstr this;
+	char * linkname = NULL;
+	char * oldlinkname = NULL;
+	int trail_flag = 0;
+	int loopcount = 0;
+	int error;
+#ifdef DEBUG
+	if(last_name) {
+		last_name->name = "(Uninitialized)";
+		last_name->len = 15;
+	}
+#endif
+again:
+	error = -ENOENT;
+	this.name = name;
+	if (this.name[0] == '/') {
+		if(base)
+			iput(base);
+		if (__prefix_namei(retrieve_mode, this.name, base, buf,
+				   res_dir, res_inode,
+				   last_name, last_entry, last_error) == 0)
+			return 0;
 		base = current->fs->root;
-		pathname++;
-		base->i_count++;
+		atomic_inc(&base->i_count);
+		this.name++;
+	} else if (!base) {
+		base = current->fs->pwd;
+		atomic_inc(&base->i_count);
 	}
-	while (1) {
-		thisname = pathname;
-		for(len=0;(c = *(pathname++))&&(c != '/');len++)
-			/* nothing */ ;
-		if (!c)
+	for(;;) {
+		struct inode * inode;
+		const char * tmp = this.name;
+		int len;
+
+		for(len = 0; (c = *tmp++) && (c != '/'); len++) ;
+		this.len = len;
+		if(!c)
 			break;
-		base->i_count++;
-		error = lookup(base, thisname, len, &inode);
-		if (error) {
-			iput(base);
-			return error;
+		while((c = *tmp) == '/') /* remove embedded/trailing slashes */
+			tmp++;
+		if(!c) {
+			trail_flag = 1;
+			if(retrieve_mode & NAM_NO_TRAILSLASH) {
+				error = -EISDIR;
+				goto alldone;
+			}
+			break;		
 		}
-		error = follow_link(base,inode,0,0,&base);
+#if 0
+		if(atomic_read(&base->i_count) == 0)
+			printk("vor lookup this=%s tmp=%s\n", this.name, tmp);
+#endif
+		error = lookup(base, &this, 0, buf, NULL, NULL, &inode);
+#if 0
+		if(atomic_read(&base->i_count) == 0)
+			printk("nach lookup this=%s tmp=%s\n", this.name, tmp);
+#endif
 		if (error)
-			return error;
-	}
-	if (!base->i_op || !base->i_op->lookup) {
+			goto alldone;
+		if(S_ISLNK(inode->i_mode)) {
+			error = _read_link(inode, &linkname, loopcount);
+			if(error)
+				goto alldone;
+			current->link_count++;
+			error = __namei((retrieve_mode & 
+					 ~(NAM_SEMLOCK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH))
+					| NAM_FOLLOW_LINK,
+					linkname, base, buf,
+					&base, &inode, NULL, NULL, NULL);
+			current->link_count--;
+			if(error)
+				goto alldone;
+		}
+#if 0
+		if(atomic_read(&base->i_count) == 0)
+			printk("this=%s tmp=%s\n", this.name, tmp);
+#endif
+		this.name = tmp;
 		iput(base);
-		return -ENOTDIR;
+		base = inode;
 	}
-	*name = thisname;
-	*namelen = len;
-	*res_inode = base;
-	return 0;
-}
-
-static int _namei(const char * pathname, struct inode * base,
-                  int follow_links, struct inode ** res_inode)
-{
-	const char *basename;
-	int namelen,error;
-	struct inode * inode;
-
-	translate_namei(pathname, base, follow_links, res_inode);
-	*res_inode = NULL;
-	error = dir_namei(pathname, &namelen, &basename, base, &base);
-	if (error)
-		return error;
-	base->i_count++;	/* lookup uses up base */
-	error = lookup(base, basename, namelen, &inode);
-	if (error) {
-		iput(base);
-		return error;
+	if(res_inode) {
+		if(retrieve_mode & NAM_SEMLOCK)
+			down(&base->i_sem);
+		error = lookup(base, &this, retrieve_mode & NAM_TRANSCREATE,
+			       buf, last_name, last_entry, res_inode);
+		if(!error && S_ISLNK((*res_inode)->i_mode) &&
+		   ((retrieve_mode & NAM_FOLLOW_LINK) ||
+		    (trail_flag && (retrieve_mode & NAM_FOLLOW_TRAILSLASH)))) {
+			char * tmp;
+
+			error = _read_link(*res_inode, &linkname, loopcount);
+			if(error)
+				goto lastdone;
+			if(retrieve_mode & NAM_SEMLOCK)
+				up(&base->i_sem);
+			/* exchange pages */
+			name = tmp = linkname;
+			linkname = oldlinkname; oldlinkname = tmp;
+			loopcount++;
+			goto again; /* Tail recursion elimination "by hand",
+				     * uses less dynamic memory.
+				     */
+
+			/* Note that trail_flag is not reset, so it
+			 * does not matter in a symlink chain where a
+			 * trailing slash indicates a directory endpoint.
+			 */
+		}
+		if(!error && trail_flag && !S_ISDIR((*res_inode)->i_mode)) {
+			iput(*res_inode);
+			error = -ENOTDIR;
+		}
+	lastdone:
+		if(last_error) {
+			*last_error = error;
+			error = 0;
+		}
 	}
-	if (follow_links) {
-		error = follow_link(base, inode, 0, 0, &inode);
-		if (error)
-			return error;
-	} else
+alldone:
+	if(!error && res_dir)
+		*res_dir = base;
+	else
 		iput(base);
-	*res_inode = inode;
-	return 0;
-}
-
-int lnamei(const char *pathname, struct inode **res_inode)
-{
-	int error;
-	char * tmp;
-
-	error = getname(pathname, &tmp);
-	if (!error) {
-		error = _namei(tmp, NULL, 0, res_inode);
-		putname(tmp);
-	}
+	putname(linkname);
+	putname(oldlinkname);
 	return error;
 }
 
@@ -302,14 +642,20 @@
  * Open, link etc use their own routines, but this is enough for things
  * like 'chmod' etc.
  */
-int namei(const char *pathname, struct inode **res_inode)
+
+/* [Feb 1997 T.Schoebel-Theuer] lnamei() completely removed; can be
+ * simulated when calling with retrieve_mode==NAM_FOLLOW_TRAILSLASH.
+ */
+int namei(int retrieve_mode, const char *pathname, struct inode **res_inode)
 {
 	int error;
 	char * tmp;
 
 	error = getname(pathname, &tmp);
 	if (!error) {
-		error = _namei(tmp, NULL, 1, res_inode);
+		char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+		error = __namei(retrieve_mode, tmp, NULL,
+				buf, NULL, res_inode, NULL, NULL, NULL);
 		putname(tmp);
 	}
 	return error;
@@ -328,40 +674,30 @@
  * which is a lot more logical, and also allows the "no perm" needed
  * for symlinks (where the permissions are checked later).
  */
-int
-open_namei(const char * pathname, int flag, int mode,
+int open_namei(const char * pathname, int flag, int mode,
                struct inode ** res_inode, struct inode * base)
 {
-	const char * basename;
-	int namelen,error;
-	struct inode * dir, *inode;
+	char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+	struct qstr last;
+	int error;
+	int lasterror;
+	struct inode * dir, * inode;
+	int namei_mode;
 
-	translate_open_namei(pathname, flag, mode, res_inode, base);
 	mode &= S_IALLUGO & ~current->fs->umask;
 	mode |= S_IFREG;
-	error = dir_namei(pathname, &namelen, &basename, base, &dir);
+
+	namei_mode = NAM_FOLLOW_LINK;
+	if(flag & O_CREAT)
+		namei_mode |= NAM_SEMLOCK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH;
+	error = __namei(namei_mode, pathname, base, buf,
+			&dir, &inode, &last, NULL, &lasterror);
 	if (error)
-		return error;
-	if (!namelen) {			/* special case: '/usr/' etc */
-		if (flag & 2) {
-			iput(dir);
-			return -EISDIR;
-		}
-		/* thanks to Paul Pluzhnikov for noticing this was missing.. */
-		if ((error = permission(dir,ACC_MODE(flag))) != 0) {
-			iput(dir);
-			return error;
-		}
-		*res_inode=dir;
-		return 0;
-	}
-	dir->i_count++;		/* lookup eats the dir */
+		goto exit;
+	error = lasterror;
 	if (flag & O_CREAT) {
-		down(&dir->i_sem);
-		error = lookup(dir, basename, namelen, &inode);
 		if (!error) {
 			if (flag & O_EXCL) {
-				iput(inode);
 				error = -EEXIST;
 			}
 		} else if (IS_RDONLY(dir))
@@ -371,31 +707,31 @@
 		else if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
 			;	/* error is already set! */
 		else {
-			dir->i_count++;		/* create eats the dir */
+			d_del(d_lookup(dir, &last, NULL), D_REMOVE);
+			atomic_inc(&dir->i_count);	/* create eats the dir */
 			if (dir->i_sb && dir->i_sb->dq_op)
 				dir->i_sb->dq_op->initialize(dir, -1);
-			error = dir->i_op->create(dir, basename, namelen, mode, res_inode);
+			error = dir->i_op->create(dir, last.name, last.len,
+						  mode, res_inode);
+#ifdef CONFIG_OMIRR
+			if(!error)
+				omirr_print(dir->i_dentry, NULL, &last,
+					    " c %ld %d ", CURRENT_TIME, mode);
+#endif
 			up(&dir->i_sem);
-			iput(dir);
-			return error;
+			goto exit_dir;
 		}
 		up(&dir->i_sem);
-	} else
-		error = lookup(dir, basename, namelen, &inode);
-	if (error) {
-		iput(dir);
-		return error;
 	}
-	error = follow_link(dir,inode,flag,mode,&inode);
 	if (error)
-		return error;
+		goto exit_inode;
+
 	if (S_ISDIR(inode->i_mode) && (flag & 2)) {
-		iput(inode);
-		return -EISDIR;
+		error = -EISDIR;
+		goto exit_inode;
 	}
 	if ((error = permission(inode,ACC_MODE(flag))) != 0) {
-		iput(inode);
-		return error;
+		goto exit_inode;
 	}
 	if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
 		/*
@@ -410,86 +746,102 @@
 	}
 	else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
 		if (IS_NODEV(inode)) {
-			iput(inode);
-			return -EACCES;
+			error = -EACCES;
+			goto exit_inode;
 		}
 		flag &= ~O_TRUNC;
 	} else {
 		if (IS_RDONLY(inode) && (flag & 2)) {
-			iput(inode);
-			return -EROFS;
+			error = -EROFS;
+			goto exit_inode;
 		}
 	}
 	/*
-	 * An append-only file must be opened in append mode for writing
+	 * An append-only file must be opened in append mode for writing.
 	 */
 	if (IS_APPEND(inode) && ((flag & FMODE_WRITE) && !(flag & O_APPEND))) {
-		iput(inode);
-		return -EPERM;
+		error = -EPERM;
+		goto exit_inode;
 	}
 	if (flag & O_TRUNC) {
-		if ((error = get_write_access(inode))) {
-			iput(inode);
-			return error;
-		}
+		if ((error = get_write_access(inode)))
+			goto exit_inode;
 		/*
-		 * Refuse to truncate files with mandatory locks held on them
+		 * Refuse to truncate files with mandatory locks held on them.
 		 */
 		error = locks_verify_locked(inode);
-		if (error) {
-			iput(inode);
-			return error;
-		}
+		if (error)
+			goto exit_inode;
 		if (inode->i_sb && inode->i_sb->dq_op)
 			inode->i_sb->dq_op->initialize(inode, -1);
 			
 		error = do_truncate(inode, 0);
 		put_write_access(inode);
-		if (error) {
-			iput(inode);
-			return error;
-		}
 	} else
 		if (flag & FMODE_WRITE)
 			if (inode->i_sb && inode->i_sb->dq_op)
 				inode->i_sb->dq_op->initialize(inode, -1);
-	*res_inode = inode;
-	return 0;
+exit_inode:
+	if(error) {
+		if(!lasterror)
+			iput(inode);
+	} else
+		*res_inode = inode;
+exit_dir:
+	iput(dir);
+exit:
+	return error;
 }
 
 int do_mknod(const char * filename, int mode, dev_t dev)
 {
-	const char * basename;
-	int namelen, error;
+	char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+	struct qstr last;
+	int error, lasterror;
 	struct inode * dir;
+	struct inode * inode;
 
 	mode &= ~current->fs->umask;
-	error = dir_namei(filename, &namelen, &basename, NULL, &dir);
+	error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE|NAM_NO_TRAILSLASH,
+			filename, NULL, buf,
+			&dir, &inode, &last, NULL, &lasterror);
 	if (error)
-		return error;
-	if (!namelen) {
-		iput(dir);
-		return -ENOENT;
+		goto exit;
+	if(!lasterror) {
+		error = -EEXIST;
+		goto exit_inode;
+	}
+	if (!last.len) {
+		error = -ENOENT;
+		goto exit_inode;
 	}
 	if (IS_RDONLY(dir)) {
-		iput(dir);
-		return -EROFS;
-	}
-	if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
-		iput(dir);
-		return error;
+		error = -EROFS;
+		goto exit_inode;
 	}
+	if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
+		goto exit_inode;
 	if (!dir->i_op || !dir->i_op->mknod) {
-		iput(dir);
-		return -EPERM;
+		error = -ENOSYS; /* instead of EPERM, what does Posix say? */
+		goto exit_inode;
 	}
-	dir->i_count++;
+	atomic_inc(&dir->i_count);
 	if (dir->i_sb && dir->i_sb->dq_op)
 		dir->i_sb->dq_op->initialize(dir, -1);
 	down(&dir->i_sem);
-	error = dir->i_op->mknod(dir,basename,namelen,mode,dev);
+	d_del(d_lookup(dir, &last, NULL), D_REMOVE);
+	error = dir->i_op->mknod(dir, last.name, last.len, mode, dev);
+#ifdef CONFIG_OMIRR
+	if(!error)
+		omirr_print(dir->i_dentry, NULL, &last, " n %ld %d %d ",
+			    CURRENT_TIME, mode, dev);
+#endif
 	up(&dir->i_sem);
+exit_inode:
+	if(!lasterror)
+		iput(inode);
 	iput(dir);
+exit:
 	return error;
 }
 
@@ -522,75 +874,59 @@
 	return error;
 }
 
-/*
- * Some operations need to remove trailing slashes for POSIX.1
- * conformance. For rename we also need to change the behaviour
- * depending on whether we had a trailing slash or not.. (we
- * cannot rename normal files with trailing slashes, only dirs)
- *
- * "dummy" is used to make sure we don't do "/" -> "".
+/* [Feb-97 T. Schoebel-Theuer] remove_trailing_slashes() is now obsolete,
+ * its functionality is handled by observing trailing slashes in __namei().
  */
-static int remove_trailing_slashes(char * name)
+static inline int do_mkdir(const char * pathname, int mode)
 {
-	int result;
-	char dummy[1];
-	char *remove = dummy+1;
-
-	for (;;) {
-		char c = *name;
-		name++;
-		if (!c)
-			break;
-		if (c != '/') {
-			remove = NULL;
-			continue;
-		}
-		if (remove)
-			continue;
-		remove = name;
-	}
-
-	result = 0;
-	if (remove) {
-		remove[-1] = 0;
-		result = 1;
-	}
-
-	return result;
-}
-
-static int do_mkdir(const char * pathname, int mode)
-{
-	const char * basename;
-	int namelen, error;
+	char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+	struct qstr last;
+	int error, lasterror;
 	struct inode * dir;
+	struct inode * inode;
 
-	error = dir_namei(pathname, &namelen, &basename, NULL, &dir);
+	mode &= 0777 & ~current->fs->umask;
+
+	error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, pathname, NULL, buf,
+			&dir, &inode, &last, NULL, &lasterror);
 	if (error)
-		return error;
-	if (!namelen) {
-		iput(dir);
-		return -ENOENT;
+		goto exit;
+	if(!lasterror) {
+		error = -EEXIST;
+		goto exit_inode;
+	}
+	if (!last.len) {
+		error = -ENOENT;
+		goto exit_inode;
 	}
 	if (IS_RDONLY(dir)) {
-		iput(dir);
-		return -EROFS;
-	}
-	if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
-		iput(dir);
-		return error;
+		error = -EROFS;
+		goto exit_inode;
 	}
+	if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
+		goto exit_inode;
 	if (!dir->i_op || !dir->i_op->mkdir) {
-		iput(dir);
-		return -EPERM;
+		error = -ENOSYS; /* instead of EPERM, what does Posix say? */
+		goto exit_inode;
 	}
-	dir->i_count++;
+	atomic_inc(&dir->i_count);
 	if (dir->i_sb && dir->i_sb->dq_op)
 		dir->i_sb->dq_op->initialize(dir, -1);
 	down(&dir->i_sem);
-	error = dir->i_op->mkdir(dir, basename, namelen, mode & 01777 & ~current->fs->umask);
+	d_del(d_lookup(dir, &last, NULL), D_REMOVE);
+	mode &= 01777 & ~current->fs->umask;
+	error = dir->i_op->mkdir(dir, last.name, last.len, mode);
+#ifdef CONFIG_OMIRR
+	if(!error)
+		omirr_print(dir->i_dentry, NULL, &last, " d %ld %d ",
+			    CURRENT_TIME, mode);
+#endif
 	up(&dir->i_sem);
+exit_inode:
+	if(!lasterror)
+		iput(inode);
 	iput(dir);
+exit:
 	return error;
 }
 
@@ -602,7 +938,6 @@
 	lock_kernel();
 	error = getname(pathname,&tmp);
 	if (!error) {
-		remove_trailing_slashes(tmp);
 		error = do_mkdir(tmp,mode);
 		putname(tmp);
 	}
@@ -610,43 +945,125 @@
 	return error;
 }
 
-static int do_rmdir(const char * name)
-{
-	const char * basename;
-	int namelen, error;
+#if 0 /* We need a "deletefs", someone please write it.  -DaveM */
+/* Perhaps this could be moved out into a new file. */
+static void basket_name(struct inode * dir, struct dentry * entry)
+{
+	char prefix[32];
+	struct qstr prename = { prefix, 14 };
+	struct qstr entname = { entry->d_name, entry->d_len };
+	struct inode * inode;
+	struct dentry * old = entry; /* dummy */
+	int i;
+	if(!entry || !(inode = d_inode(&entry)))
+		return;
+#if 0
+	if(atomic_read(&inode->i_count) > 2) {
+		extern void printpath(struct dentry *entry);
+
+		printk("Caution: in use ");
+		if(inode->i_dentry)
+			printpath(inode->i_dentry);
+		printk(" i_nlink=%d i_count=%d i_ddir_count=%d i_dent_count=%d\n",
+		       inode->i_nlink, atomic_read(&inode->i_count),
+		       inode->i_ddir_count, inode->i_dent_count);
+	}
+#endif
+        vfs_lock();
+	for(i = 1; old; i++) {
+		sprintf(prefix, ".deleted-%04d.", i);
+		old = d_lookup(dir, &prename, &entname);
+	}
+	d_move(entry, dir, &prename, &entname);
+        vfs_unlock();
+	iput(inode);
+}
+#endif
+
+static inline int do_rmdir(const char * name)
+{
+	char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+	struct qstr last;
+	struct dentry * lastent = NULL;
+	int error;
 	struct inode * dir;
+	struct inode * inode;
 
-	error = dir_namei(name, &namelen, &basename, NULL, &dir);
+	/* [T.Schoebel-Theuer] I'm not sure which flags to use here.
+	 *  Try the following on different platforms:
+	 * [0] rm -rf test test2
+	 * [1] ln -s test2 test
+	 * [2] mkdir test  || mkdir test2
+	 * [3] rmdir test  && mkdir test2
+	 * [4] rmdir test/
+	 * Now the rusults:
+	 * cmd  |   HP-UX   |  SunOS   |  Solaris | Old Linux | New Linux |
+	 * ----------------------------------------------------------------
+	 * [2]  |   (OK)    |  EEXIST  |  EEXIST  |  EEXIST   |  (OK)
+	 * [3]  |  ENOTDIR  |  ENOTDIR |  ENOTDIR |  ENOTDIR  |  ENOTDIR
+	 * [4]  |   (OK)    |  EINVAL  |  ENOTDIR |  ENOTDIR  |  (OK)
+	 * So I implemented the HP-UX semantics. If this is not right
+	 * for Posix compliancy, change the flags accordingly. If Posix
+	 * let the question open, I'd suggest to stay at the new semantics.
+	 * I'd even make case [3] work by adding 2 to the flags parameter
+	 * if Posix tolerates that.
+	 */
+	error = __namei(NAM_FOLLOW_TRAILSLASH, name, NULL, buf,
+			&dir, &inode, &last, &lastent, NULL);
 	if (error)
-		return error;
-	if (!namelen) {
-		iput(dir);
-		return -ENOENT;
-	}
+		goto exit;
 	if (IS_RDONLY(dir)) {
-		iput(dir);
-		return -EROFS;
-	}
-	if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
-		iput(dir);
-		return error;
+		error = -EROFS;
+		goto exit_dir;
 	}
+	if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
+		goto exit_dir;
 	/*
-	 * A subdirectory cannot be removed from an append-only directory
+	 * A subdirectory cannot be removed from an append-only directory.
 	 */
 	if (IS_APPEND(dir)) {
-		iput(dir);
-		return -EPERM;
+		error = -EPERM;
+		goto exit_dir;
 	}
 	if (!dir->i_op || !dir->i_op->rmdir) {
-		iput(dir);
-		return -EPERM;
+		error = -ENOSYS; /* was EPERM */
+		goto exit_dir;
+	}
+	/* Disallow removals of mountpoints. */
+	if(inode->i_mount) {
+		error = -EBUSY;
+		goto exit_dir;
 	}
 	if (dir->i_sb && dir->i_sb->dq_op)
 		dir->i_sb->dq_op->initialize(dir, -1);
-	down(&dir->i_sem);
-	error = dir->i_op->rmdir(dir,basename,namelen);
-	up(&dir->i_sem);
+
+        down(&dir->i_sem);
+#if 0
+	if(lastent && d_isbasket(lastent)) {
+		d_del(lastent, D_REMOVE);
+		error = 0;
+		goto exit_lock;
+	}
+#endif
+	atomic_inc(&dir->i_count);
+	error = dir->i_op->rmdir(dir, last.name, last.len);
+#ifdef CONFIG_OMIRR
+	if(!error)
+		omirr_print(lastent, NULL, NULL, " r %ld ", CURRENT_TIME);
+#endif
+#if 0
+	if(!error && lastent)
+		basket_name(dir, lastent);
+exit_lock:
+#else
+	if(!error && lastent)
+		d_del(lastent, D_REMOVE);
+#endif
+        up(&dir->i_sem);
+exit_dir:
+	iput(inode);
+	iput(dir);
+exit:
 	return error;
 }
 
@@ -658,7 +1075,6 @@
 	lock_kernel();
 	error = getname(pathname,&tmp);
 	if (!error) {
-		remove_trailing_slashes(tmp);
 		error = do_rmdir(tmp);
 		putname(tmp);
 	}
@@ -666,43 +1082,93 @@
 	return error;
 }
 
-static int do_unlink(const char * name)
+static inline int do_unlink(const char * name)
 {
-	const char * basename;
-	int namelen, error;
+	char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+	struct qstr last;
+	struct dentry * lastent = NULL;
+	int error;
 	struct inode * dir;
+	struct inode * inode;
 
-	error = dir_namei(name, &namelen, &basename, NULL, &dir);
+	/* HP-UX shows a strange behaviour:
+	 * touch y; ln -s y x; rm x/
+	 * this succeeds and removes the file y, not the symlink x!
+	 * Solaris and old Linux remove the symlink instead, and
+	 * old SunOS complains ENOTDIR.
+	 * I chose the SunOS behaviour (by not using NAM_FOLLOW_TRAILSLASH),
+	 * but I'm not shure whether I should.
+	 * The current code generally prohibits using trailing slashes with
+	 * non-directories if the name already exists, but not if
+	 * it is to be newly created. 
+	 * Perhaps this should be further strengthened (by introducing
+	 * an additional flag bit indicating whether trailing slashes are
+	 * allowed) to get it as consistant as possible, but I don't know
+	 * what Posix says.
+	 */
+	error = __namei(NAM_NO_TRAILSLASH, name, NULL, buf,
+			&dir, &inode, &last, &lastent, NULL);
 	if (error)
-		return error;
-	if (!namelen) {
-		iput(dir);
-		return -EPERM;
-	}
+		goto exit;
 	if (IS_RDONLY(dir)) {
-		iput(dir);
-		return -EROFS;
-	}
-	if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
-		iput(dir);
-		return error;
+		error = -EROFS;
+		goto exit_dir;
 	}
+	if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
+		goto exit_dir;
 	/*
-	 * A file cannot be removed from an append-only directory
+	 * A file cannot be removed from an append-only directory.
 	 */
 	if (IS_APPEND(dir)) {
-		iput(dir);
-		return -EPERM;
+		error = -EPERM;
+		goto exit_dir;
 	}
 	if (!dir->i_op || !dir->i_op->unlink) {
-		iput(dir);
-		return -EPERM;
+		error = -ENOSYS; /* was EPERM */
+		goto exit_dir;
 	}
 	if (dir->i_sb && dir->i_sb->dq_op)
 		dir->i_sb->dq_op->initialize(dir, -1);
-	down(&dir->i_sem);
-	error = dir->i_op->unlink(dir,basename,namelen);
-	up(&dir->i_sem);
+
+        down(&dir->i_sem);
+#if 0
+	if(atomic_read(&inode->i_count) > 1) {
+		extern void printpath(struct dentry *entry);
+
+		printk("Fire ");
+		if(lastent)
+			printpath(lastent);
+		printk(" i_nlink=%d i_count=%d i_ddir_count=%d i_dent_count=%d\n",
+		       inode->i_nlink, atomic_read(&inode->i_count),
+		       inode->i_ddir_count, inode->i_dent_count);
+	}
+#endif
+#if 0
+	if(lastent && d_isbasket(lastent)) {
+		d_del(lastent, D_REMOVE);
+		error = 0;
+		goto exit_lock;
+	}
+#endif
+	atomic_inc(&dir->i_count);
+	error = dir->i_op->unlink(dir, last.name, last.len);
+#ifdef CONFIG_OMIRR
+	if(!error)
+		omirr_print(lastent, NULL, NULL, " u %ld ", CURRENT_TIME);
+#endif
+#if 0
+	if(!error && lastent)
+		basket_name(dir, lastent);
+exit_lock:
+#else
+	if(!error && lastent)
+		d_del(lastent, D_REMOVE);
+#endif
+        up(&dir->i_sem);
+exit_dir:
+	iput(inode);
+	iput(dir);
+exit:
 	return error;
 }
 
@@ -721,38 +1187,65 @@
 	return error;
 }
 
-static int do_symlink(const char * oldname, const char * newname)
+static inline int do_symlink(const char * oldname, const char * newname)
 {
+	char buf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+	struct qstr last;
+	int error, lasterror;
 	struct inode * dir;
-	const char * basename;
-	int namelen, error;
+	struct inode * inode;
 
-	error = dir_namei(newname, &namelen, &basename, NULL, &dir);
+	/* The following works on HP-UX and Solaris, by producing
+	 * a symlink chain:
+	 * rm -rf ? ; mkdir z ; ln -s z y ; ln -s y x/
+	 * Under old SunOS, the following occurs:
+	 * ln: x/: No such file or directory
+	 * Under old Linux, very strange things occur:
+	 * ln: cannot create symbolic link `x//y' to `y': No such file or directory
+	 * This is very probably a bug, but may be caused by the ln program
+	 * when checking for a directory target.
+	 *
+	 * I'm not shure whether to add NAM_NO_TRAILSLASH to inhibit trailing
+	 * slashes in the target generally.
+	 */
+	error = __namei(NAM_TRANSCREATE, newname, NULL, buf,
+			&dir, &inode, &last, NULL, &lasterror);
 	if (error)
-		return error;
-	if (!namelen) {
-		iput(dir);
-		return -ENOENT;
+		goto exit;
+	if(!lasterror) {
+		iput(inode);
+		error = -EEXIST;
+		goto exit_dir;
 	}
-	if (IS_RDONLY(dir)) {
-		iput(dir);
-		return -EROFS;
+	if (!last.len) {
+		error = -ENOENT;
+		goto exit_dir;
 	}
-	if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
-		iput(dir);
-		return error;
+	if (IS_RDONLY(dir)) {
+		error = -EROFS;
+		goto exit_dir;
 	}
+	if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0)
+		goto exit_dir;
 	if (!dir->i_op || !dir->i_op->symlink) {
-		iput(dir);
-		return -EPERM;
+		error = -ENOSYS; /* was EPERM */
+		goto exit_dir;
 	}
-	dir->i_count++;
+	atomic_inc(&dir->i_count);
 	if (dir->i_sb && dir->i_sb->dq_op)
 		dir->i_sb->dq_op->initialize(dir, -1);
 	down(&dir->i_sem);
-	error = dir->i_op->symlink(dir,basename,namelen,oldname);
+	d_del(d_lookup(dir, &last, NULL), D_REMOVE);
+	error = dir->i_op->symlink(dir, last.name, last.len, oldname);
+#ifdef CONFIG_OMIRR
+	if(!error)
+		omirr_print(dir->i_dentry, NULL, &last,
+			    " s %ld %s\0", CURRENT_TIME, oldname);
+#endif
 	up(&dir->i_sem);
+exit_dir:
 	iput(dir);
+exit:
 	return error;
 }
 
@@ -775,149 +1268,198 @@
 	return error;
 }
 
-static int do_link(struct inode * oldinode, const char * newname)
+static inline int do_link(const char * oldname, const char * newname)
 {
-	struct inode * dir;
-	const char * basename;
-	int namelen, error;
+	char oldbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+	char newbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+	struct qstr oldlast;
+	struct qstr newlast;
+	struct dentry * oldent = NULL;
+	struct inode * oldinode;
+	struct inode * newinode;
+	struct inode * newdir;
+	int error, lasterror;
+
+	error = __namei(NAM_FOLLOW_LINK|NAM_NO_TRAILSLASH,
+			oldname, NULL, oldbuf,
+			NULL, &oldinode, &oldlast, &oldent, NULL);
+	if (error)
+		goto exit;
 
-	error = dir_namei(newname, &namelen, &basename, NULL, &dir);
-	if (error) {
-		iput(oldinode);
-		return error;
-	}
-	if (!namelen) {
-		iput(oldinode);
-		iput(dir);
-		return -EPERM;
-	}
-	if (IS_RDONLY(dir)) {
-		iput(oldinode);
-		iput(dir);
-		return -EROFS;
-	}
-	if (dir->i_dev != oldinode->i_dev) {
-		iput(dir);
-		iput(oldinode);
-		return -EXDEV;
-	}
-	if ((error = permission(dir,MAY_WRITE | MAY_EXEC)) != 0) {
-		iput(dir);
-		iput(oldinode);
-		return error;
+	error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, newname, NULL, newbuf,
+			&newdir, &newinode, &newlast, NULL, &lasterror);
+	if (error)
+		goto old_exit;
+	if(!lasterror) {
+		iput(newinode);
+		error = -EEXIST;
+		goto new_exit;
+	}
+	if (!newlast.len) {
+		error = -EPERM;
+		goto new_exit;
+	}
+	if (IS_RDONLY(newdir)) {
+		error = -EROFS;
+		goto new_exit;
+	}
+	if (newdir->i_dev != oldinode->i_dev) {
+		error = -EXDEV;
+		goto new_exit;
 	}
+	if ((error = permission(newdir,MAY_WRITE | MAY_EXEC)) != 0)
+		goto new_exit;
 	/*
-	 * A link to an append-only or immutable file cannot be created
+	 * A link to an append-only or immutable file cannot be created.
 	 */
 	if (IS_APPEND(oldinode) || IS_IMMUTABLE(oldinode)) {
-		iput(dir);
-		iput(oldinode);
-		return -EPERM;
-	}
-	if (!dir->i_op || !dir->i_op->link) {
-		iput(dir);
-		iput(oldinode);
-		return -EPERM;
+		error = -EPERM;
+		goto new_exit;
 	}
-	dir->i_count++;
-	if (dir->i_sb && dir->i_sb->dq_op)
-		dir->i_sb->dq_op->initialize(dir, -1);
-	down(&dir->i_sem);
-	error = dir->i_op->link(oldinode, dir, basename, namelen);
-	up(&dir->i_sem);
-	iput(dir);
+	if (!newdir->i_op || !newdir->i_op->link) {
+		error = -ENOSYS; /* was EPERM */
+		goto new_exit;
+	}
+	atomic_inc(&oldinode->i_count);
+	atomic_inc(&newdir->i_count);
+	if (newdir->i_sb && newdir->i_sb->dq_op)
+		newdir->i_sb->dq_op->initialize(newdir, -1);
+	down(&newdir->i_sem);
+	d_del(d_lookup(newdir, &newlast, NULL), D_REMOVE);
+	error = newdir->i_op->link(oldinode, newdir, newlast.name, newlast.len);
+#ifdef CONFIG_OMIRR
+	if(!error)
+		omirr_print(oldent, newdir->i_dentry, &newlast,
+			    " l %ld ", CURRENT_TIME);
+#endif
+	up(&newdir->i_sem);
+new_exit:
+	iput(newdir);
+old_exit:
+	iput(oldinode);
+exit:
 	return error;
 }
 
 asmlinkage int sys_link(const char * oldname, const char * newname)
 {
 	int error;
-	char * to;
-	struct inode * oldinode;
+	char * from, * to;
 
 	lock_kernel();
-	error = lnamei(oldname, &oldinode);
-	if (error)
-		goto out;
-	error = getname(newname,&to);
-	if (error) {
-		iput(oldinode);
-		goto out;
+	error = getname(oldname,&from);
+	if (!error) {
+		error = getname(newname,&to);
+		if (!error) {
+			error = do_link(from,to);
+			putname(to);
+		}
+		putname(from);
 	}
-	error = do_link(oldinode,to);
-	putname(to);
-out:
 	unlock_kernel();
 	return error;
 }
 
-static int do_rename(const char * oldname, const char * newname, int must_be_dir)
+static inline int do_rename(const char * oldname, const char * newname)
 {
-	struct inode * old_dir, * new_dir;
-	const char * old_base, * new_base;
-	int old_len, new_len, error;
+	char oldbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+	struct qstr oldlast;
+	char newbuf[MAX_TRANS_FILELEN+MAX_TRANS_SUFFIX+2];
+	struct qstr newlast;
+	struct dentry * oldent = NULL;
+	struct inode * olddir, * newdir;
+	struct inode * oldinode, * newinode;
+	int error, newlasterror;
 
-	error = dir_namei(oldname, &old_len, &old_base, NULL, &old_dir);
+	error = __namei(NAM_FOLLOW_TRAILSLASH, oldname, NULL, oldbuf,
+			&olddir, &oldinode, &oldlast, &oldent, NULL);
 	if (error)
-		return error;
-	if ((error = permission(old_dir,MAY_WRITE | MAY_EXEC)) != 0) {
-		iput(old_dir);
-		return error;
+		goto exit;
+	if ((error = permission(olddir,MAY_WRITE | MAY_EXEC)) != 0)
+		goto old_exit;
+	if (!oldlast.len || (oldlast.name[0] == '.' &&
+	    (oldlast.len == 1 || (oldlast.name[1] == '.' &&
+	     oldlast.len == 2)))) {
+		error = -EPERM;
+		goto old_exit;
+	}
+	/* Disallow moves of mountpoints. */
+	if(oldinode->i_mount) {
+		error = -EBUSY;
+		goto old_exit;
 	}
-	if (!old_len || (old_base[0] == '.' &&
-	    (old_len == 1 || (old_base[1] == '.' &&
-	     old_len == 2)))) {
-		iput(old_dir);
-		return -EPERM;
-	}
-	error = dir_namei(newname, &new_len, &new_base, NULL, &new_dir);
-	if (error) {
-		iput(old_dir);
-		return error;
-	}
-	if ((error = permission(new_dir,MAY_WRITE | MAY_EXEC)) != 0){
-		iput(old_dir);
-		iput(new_dir);
-		return error;
-	}
-	if (!new_len || (new_base[0] == '.' &&
-	    (new_len == 1 || (new_base[1] == '.' &&
-	     new_len == 2)))) {
-		iput(old_dir);
-		iput(new_dir);
-		return -EPERM;
-	}
-	if (new_dir->i_dev != old_dir->i_dev) {
-		iput(old_dir);
-		iput(new_dir);
-		return -EXDEV;
-	}
-	if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) {
-		iput(old_dir);
-		iput(new_dir);
-		return -EROFS;
+
+	error = __namei(NAM_FOLLOW_LINK|NAM_TRANSCREATE, newname, NULL, newbuf,
+			&newdir, &newinode, &newlast, NULL, &newlasterror);
+	if (error)
+		goto old_exit;
+	if ((error = permission(newdir,MAY_WRITE | MAY_EXEC)) != 0)
+		goto new_exit;
+	if (!newlast.len || (newlast.name[0] == '.' &&
+	    (newlast.len == 1 || (newlast.name[1] == '.' &&
+	     newlast.len == 2)))) {
+		error = -EPERM;
+		goto new_exit;
+	}
+	if (newdir->i_dev != olddir->i_dev) {
+		error = -EXDEV;
+		goto new_exit;
+	}
+	if (IS_RDONLY(newdir) || IS_RDONLY(olddir)) {
+		error = -EROFS;
+		goto new_exit;
 	}
 	/*
-	 * A file cannot be removed from an append-only directory
+	 * A file cannot be removed from an append-only directory.
+	 */
+	if (IS_APPEND(olddir)) {
+		error = -EPERM;
+		goto new_exit;
+	}
+	if (!olddir->i_op || !olddir->i_op->rename) {
+		error = -ENOSYS; /* was EPERM */
+		goto new_exit;
+	}
+#ifdef CONFIG_TRANS_NAMES
+	/* if oldname has been translated, but newname not (and
+	 * has not already a suffix), take over the suffix from oldname.
 	 */
-	if (IS_APPEND(old_dir)) {
-		iput(old_dir);
-		iput(new_dir);
-		return -EPERM;
-	}
-	if (!old_dir->i_op || !old_dir->i_op->rename) {
-		iput(old_dir);
-		iput(new_dir);
-		return -EPERM;
-	}
-	new_dir->i_count++;
-	if (new_dir->i_sb && new_dir->i_sb->dq_op)
-		new_dir->i_sb->dq_op->initialize(new_dir, -1);
-	down(&new_dir->i_sem);
-	error = old_dir->i_op->rename(old_dir, old_base, old_len, 
-		new_dir, new_base, new_len, must_be_dir);
-	up(&new_dir->i_sem);
-	iput(new_dir);
+	if(oldlast.name == oldbuf && newlast.name != newbuf &&
+	   newlast.name[newlast.len-1] != '#') {
+		int i = oldlast.len - 2;
+		while (i > 0 && oldlast.name[i] != '#')
+			i--;
+		memcpy(newbuf, newlast.name, newlast.len);
+		memcpy(newbuf+newlast.len, oldlast.name+i, oldlast.len - i);
+		newlast.len += oldlast.len - i;
+		newlast.name = newbuf;
+	}
+#endif
+	atomic_inc(&olddir->i_count);
+	atomic_inc(&newdir->i_count);
+	if (newdir->i_sb && newdir->i_sb->dq_op)
+		newdir->i_sb->dq_op->initialize(newdir, -1);
+	down(&newdir->i_sem);
+	error = olddir->i_op->rename(olddir, oldlast.name, oldlast.len, 
+		newdir, newlast.name, newlast.len);
+#ifdef CONFIG_OMIRR
+	if(!error)
+		omirr_print(oldent, newdir->i_dentry, &newlast,
+			    " m %ld ", CURRENT_TIME);
+#endif
+	if(!error) {
+		d_del(d_lookup(newdir, &newlast, NULL), D_REMOVE);
+		d_move(d_lookup(olddir, &oldlast, NULL), newdir, &newlast, NULL);
+	}
+	up(&newdir->i_sem);
+new_exit:
+	if(!newlasterror)
+		iput(newinode);
+	iput(newdir);
+old_exit:
+	iput(oldinode);
+	iput(olddir);
+exit:
 	return error;
 }
 
@@ -931,9 +1473,7 @@
 	if (!error) {
 		error = getname(newname,&to);
 		if (!error) {
-			error = do_rename(from,to,
-				remove_trailing_slashes(from) |
-				remove_trailing_slashes(to));
+			error = do_rename(from,to);
 			putname(to);
 		}
 		putname(from);
diff -u --recursive --new-file v2.1.42/linux/fs/nametrans.c linux/fs/nametrans.c
--- v2.1.42/linux/fs/nametrans.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/nametrans.c	Thu Jun 12 16:22:08 1997
@@ -0,0 +1,310 @@
+/*
+ * $Id: nametrans.c,v 1.2 1997/06/04 23:45:44 davem Exp $
+ *
+ * linux/fs/nametrans.c - context-dependend filename suffixes.
+ * Copyright (C) 1997, Thomas Schoebel-Theuer,
+ * <schoebel@informatik.uni-stuttgart.de>.
+ *
+ * translates names of the form "filename#host=myhost#" to "filename"
+ * as if both names were hardlinked to the same file.
+ * benefit: diskless clients can mount the / filesystem of the
+ * server if /etc/fstab (and other config files) are organized using
+ * context suffixes.
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/uaccess.h>
+#include <linux/nametrans.h>
+
+char  nametrans_txt[MAX_DEFAULT_TRANSLEN] = "";
+static struct translations * global_trans = NULL;
+static int default_trans = 1;
+static const char version[] = "revision: 2.3 <schoebel@informatik.uni-stuttgart.de>";
+int translations_dirty = 1;
+static char * transl_names[] = {
+#ifdef CONFIG_TR_NODENAME
+  "host=",        system_utsname.nodename,
+#endif
+#ifdef CONFIG_TR_KERNNAME
+  "kname=",  CONFIG_KERNNAME,
+#endif
+#ifdef CONFIG_TR_KERNTYPE
+  "ktype=",  CONFIG_KERNTYPE,
+#endif
+#ifdef CONFIG_TR_MACHINE
+  "machine=",     system_utsname.machine,
+#endif
+#ifdef CONFIG_TR_SYSNAME
+  "system=",      system_utsname.sysname,
+#endif
+  0, 0
+};
+
+/* Convert and do syntax checking. */
+static void convert(char * txt, struct translations * res)
+{
+	char * tmp = txt;
+	char * space = (char*)res + sizeof(struct translations);
+
+	res->count = 0;
+	while(*tmp) {
+		struct qstr * name = &res->name[res->count];
+		struct qstr * c_name = &res->c_name[res->count];
+		int len;
+		char * p = tmp;
+
+		if(*p++ != '#')
+			goto next;
+		while(*p && *p != '=' && *p != ':')
+			p++;
+		if(*p != '=')
+			goto next;
+		p++;
+		len = (unsigned long)p - (unsigned long)tmp;
+		c_name->name = space;
+		memcpy(space, tmp, len);
+		memcpy(space + len, "CREATE#", 8);
+		c_name->len = len + 7;
+		if(c_name->len >= MAX_TRANS_SUFFIX)
+			goto next;
+		while(*p && *p != '#' && *p != ':')
+			p++;
+		if(*p != '#')
+			goto next;
+		p++;
+		if(*p != ':' && *p)
+			goto next;
+		space += len + 8;
+		name->len = len = (unsigned long)p - (unsigned long)tmp;
+		if(len >= MAX_TRANS_SUFFIX)
+			goto next;
+		name->name = space;
+		memcpy(space, tmp, len);
+		space[len] = '\0';
+		space += len + 1;
+		res->count++;
+		if(res->count >= MAX_TRANSLATIONS ||
+		   (unsigned long)space - (unsigned long)res >= PAGE_SIZE-2*MAX_TRANS_SUFFIX)
+			return;
+	next:
+		while(*p && *p++ != ':') ;
+		tmp = p;
+	}
+}
+
+static inline void trans_to_string(struct translations * trans, char * buf, int maxlen)
+{
+	int i;
+
+	for(i = 0; i < trans->count; i++) {
+		int len = trans->name[i].len;
+		if(len < maxlen) {
+			memcpy(buf, trans->name[i].name, len);
+			buf += len;
+			maxlen -= len;
+			*buf++ = ':';
+			maxlen--;
+		}
+	}
+	buf--;
+	*buf = '\0';
+}
+
+static inline void default_nametrans(char * buf)
+{
+	char * res = buf;
+	char ** entry;
+	char * ptr;
+
+	for (entry = transl_names; *entry; entry++) {
+		*res++ = '#';
+		for(ptr = *entry; *ptr; ptr++)
+			*res++ = *ptr;
+		entry++;
+		for(ptr = *entry; *ptr; ptr++)
+			*res++ = *ptr;
+		*res++ = '#';
+		*res++ = ':';
+	}
+	res--;
+	*res = '\0';
+}
+
+void nametrans_setup(char * line)
+{
+	if(line) {
+		default_trans = (!line[0]);
+		if(!global_trans) {
+			/* This can happen at boot time, and there is no chance
+			 * to allocate memory at this early stage.
+			 */
+			strncpy(nametrans_txt, line, MAX_DEFAULT_TRANSLEN);
+		} else {
+			if(default_trans) {
+				default_nametrans(nametrans_txt);
+				line = nametrans_txt;
+			}
+			convert(line, global_trans);
+
+			/* Show what really was recognized after parsing... */
+			trans_to_string(global_trans, nametrans_txt, MAX_DEFAULT_TRANSLEN);
+		}
+	}
+}
+
+/* If the _first_ environment variable is "NAMETRANS", return
+ * a pointer to the list of appendices.
+ * You can set the first environment variable using
+ * 'env - NAMETRANS=... "`env`" command ...'
+ */
+char* env_transl(void)
+{
+	char* env;
+	int i;
+
+	if(current && current->mm && (env = (char*)current->mm->env_start)
+	   && get_ds() != get_fs()
+	   && current->mm->env_end>=current->mm->env_start+10
+	   && !verify_area(VERIFY_READ,env,10)) {
+		for(i=0; i<10; i++) {
+			char c;
+
+			get_user(c, env++);
+			if(c != "NAMETRANS="[i])
+				return 0;
+		}
+		return env;
+	}
+	return 0;
+}
+
+/* If name has the correct suffix "#keyword=correct_context#",
+ * return position of the suffix, else 0.
+ */
+char *testname(int restricted, char* name)
+{
+	char * ptr = name;
+	char * cut;
+	char * env;
+	struct translations * trans;
+	int i, len;
+	char c, tmp;
+	
+	env = env_transl();
+#ifdef CONFIG_TRANS_RESTRICT
+	if(!env && restricted)
+		goto done;
+#else
+	(void)restricted; /* inhibit parameter usage warning */
+#endif
+	if(get_user(c, ptr))
+		goto done;
+	while(c && c != '#') {
+		ptr++;
+		__get_user(c, ptr);
+	}
+	if(!c)
+		goto done;
+	cut = ptr++;
+	if(get_user(c, ptr))
+		goto done;
+	while (c && c != '#') {
+		ptr++;
+		get_user(c, ptr);
+	}
+	if(!c)
+		goto done;
+	get_user(tmp, ptr);
+	if(tmp)
+		goto done;
+	trans = get_translations(env);
+	len = (unsigned long)ptr - (unsigned long)cut;
+	for(i = 0; i < trans->count; i++)
+		if(trans->name[i].len == len) {
+			const char * p1 = cut;
+			const char * p2 = trans->name[i].name;
+			get_user(c, p1);
+			while(c && c == *p2++) {
+				p1++;
+				get_user(c, p1);
+			}
+			if(!c)
+				return cut;
+		}
+done:
+	return NULL;
+}
+
+static inline void check_dirty(void)
+{
+	if(translations_dirty && default_trans) {
+		nametrans_setup("");
+		translations_dirty = 0;
+	}
+}
+
+struct translations * get_translations(char * env)
+{
+	struct translations * res;
+
+	if(env) {
+		char * env_txt = (char*)__get_free_page(GFP_KERNEL);
+
+		strncpy_from_user(env_txt, env, PAGE_SIZE);
+		res = (struct translations *)__get_free_page(GFP_KERNEL);
+		convert(env_txt, res);
+		free_page((unsigned long)env_txt);
+	} else {
+		check_dirty();
+		res = global_trans;
+	}
+	return res;
+}
+
+int nametrans_dostring(ctl_table * table, int write, struct file * filp,
+		       void * buffer, size_t * lenp)
+{
+	int res;
+	check_dirty();
+	res = proc_dostring(table, write, filp, buffer, lenp);
+	if(!res && write)
+		nametrans_setup(nametrans_txt);
+
+	return res;
+}
+
+int nametrans_string(ctl_table * table, int * name, int nlen,
+		     void * oldval, size_t * oldlenp,
+		     void * newval, size_t newlen, void ** context)
+{
+	int res;
+	check_dirty();
+	res = sysctl_string(table, name, nlen, oldval, oldlenp, newval, newlen, context);
+	if(!res && newval && newlen)
+		nametrans_setup(nametrans_txt);
+
+	return res;
+}
+
+void init_nametrans(void)
+{
+	if(!global_trans)
+		global_trans = (struct translations*)__get_free_page(GFP_KERNEL);
+	if(!global_trans) {
+		printk("NAMETRANS: No free memory\n");
+		return;
+	}
+	nametrans_setup(nametrans_txt);
+
+	/* Notify user for the default/supplied translations.
+	 * Extremely useful for finding translation problems.
+	 */
+	printk("Nametrans %s\nNametrans %s: %s\n", version,
+	       default_trans ? "default translations" : "external parameter",
+	       nametrans_txt);
+}
diff -u --recursive --new-file v2.1.42/linux/fs/ncpfs/dir.c linux/fs/ncpfs/dir.c
--- v2.1.42/linux/fs/ncpfs/dir.c	Fri Apr  4 08:52:24 1997
+++ linux/fs/ncpfs/dir.c	Thu Jun 12 16:22:08 1997
@@ -67,8 +67,7 @@
 
 static int
  ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
-	    struct inode *new_dir, const char *new_name, int new_len,
-	    int must_be_dir);
+	    struct inode *new_dir, const char *new_name, int new_len);
 
 static inline void str_upper(char *name)
 {
@@ -129,7 +128,6 @@
 	NULL,			/* mknod */
 	ncp_rename,		/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* bmap */
 	NULL,			/* truncate */
 	NULL,			/* permission */
@@ -965,8 +963,7 @@
 }
 
 static int ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
-		struct inode *new_dir, const char *new_name, int new_len,
-		      int must_be_dir)
+		      struct inode *new_dir, const char *new_name, int new_len)
 {
 	int res;
 	char _old_name[old_len + 1];
diff -u --recursive --new-file v2.1.42/linux/fs/ncpfs/file.c linux/fs/ncpfs/file.c
--- v2.1.42/linux/fs/ncpfs/file.c	Fri Apr  4 08:52:24 1997
+++ linux/fs/ncpfs/file.c	Thu Jun 12 16:22:08 1997
@@ -232,7 +232,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* bmap */
 	NULL			/* truncate */
 };
diff -u --recursive --new-file v2.1.42/linux/fs/ncpfs/inode.c linux/fs/ncpfs/inode.c
--- v2.1.42/linux/fs/ncpfs/inode.c	Tue May 13 22:41:15 1997
+++ linux/fs/ncpfs/inode.c	Thu Jun 12 16:22:08 1997
@@ -406,9 +406,11 @@
 int ncp_current_malloced;
 #endif
 
-static struct file_system_type ncp_fs_type =
-{
-	ncp_read_super, "ncpfs", 0, NULL
+static struct file_system_type ncp_fs_type = {
+	"ncpfs",
+	FS_NO_DCACHE,
+        ncp_read_super,
+	NULL
 };
 
 __initfunc(int init_ncp_fs(void))
diff -u --recursive --new-file v2.1.42/linux/fs/ncpfs/mmap.c linux/fs/ncpfs/mmap.c
--- v2.1.42/linux/fs/ncpfs/mmap.c	Fri Apr  4 08:52:24 1997
+++ linux/fs/ncpfs/mmap.c	Thu Jun 12 16:22:08 1997
@@ -133,7 +133,7 @@
 		inode->i_dirt = 1;
 	}
 	vma->vm_inode = inode;
-	inode->i_count++;
+	atomic_inc(&inode->i_count);
 	vma->vm_ops = &ncp_file_mmap;
 	return 0;
 }
diff -u --recursive --new-file v2.1.42/linux/fs/nfs/dir.c linux/fs/nfs/dir.c
--- v2.1.42/linux/fs/nfs/dir.c	Wed Apr 23 19:01:26 1997
+++ linux/fs/nfs/dir.c	Thu Jun 12 16:22:08 1997
@@ -51,7 +51,7 @@
 static int nfs_link(struct inode *, struct inode *, const char *, int);
 static int nfs_mknod(struct inode *, const char *, int, int, int);
 static int nfs_rename(struct inode *, const char *, int,
-		      struct inode *, const char *, int, int);
+		      struct inode *, const char *, int);
 
 static struct file_operations nfs_dir_operations = {
 	NULL,			/* lseek - default */
@@ -78,7 +78,6 @@
 	nfs_mknod,		/* mknod */
 	nfs_rename,		/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -351,7 +350,7 @@
 	char		filename[NFS_MAXNAMLEN + 1];
 	struct nfs_fh	fhandle;
 	struct nfs_fattr fattr;
-	int		expiration_date;
+	unsigned long	expiration_date;
 } nfs_lookup_cache[NFS_LOOKUP_CACHE_SIZE];
 
 static struct nfs_lookup_cache_entry *nfs_lookup_cache_index(struct inode *dir,
@@ -492,7 +491,7 @@
 	}
 	memcpy(name,__name,len);
 	name[len] = '\0';
-	if (len == 1 && name[0] == '.') { /* cheat for "." */
+	if (len == 0 || (len == 1 && name[0] == '.')) { /* cheat for "" and "." */
 		*result = dir;
 		return 0;
 	}
@@ -649,11 +648,11 @@
 	char		silly[16];
 	int		slen, ret;
 
-	dir->i_count++;
+	atomic_inc(&dir->i_count);
 	if (nfs_lookup(dir, name, len, &inode) < 0)
 		return -EIO;		/* arbitrary */
 
-	if (inode->i_count == 1) {
+	if (atomic_read(&inode->i_count) == 1) {
 		iput(inode);
 		return -EIO;
 	}
@@ -679,7 +678,7 @@
 		nfs_lookup_cache_remove(dir, NULL, name);
 		nfs_lookup_cache_remove(dir, NULL, silly);
 		NFS_RENAMED_DIR(inode) = dir;
-		dir->i_count++;
+		atomic_inc(&dir->i_count);
 	}
 	nfs_invalidate_dircache(dir);
 	iput(inode);
@@ -823,8 +822,7 @@
  * file in old_dir will go away when the last process iput()s the inode.
  */
 static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len,
-		      struct inode *new_dir, const char *new_name, int new_len,
-		      int must_be_dir)
+		      struct inode *new_dir, const char *new_name, int new_len)
 {
 	int error;
 
@@ -850,10 +848,6 @@
 		return -ENAMETOOLONG;
 	}
 
-	/* We don't do rename() with trailing slashes over NFS now. Hmm. */
-	if (must_be_dir)
-		return -EINVAL;
-
 	error = nfs_proc_rename(NFS_SERVER(old_dir),
 		NFS_FH(old_dir), old_name,
 		NFS_FH(new_dir), new_name);
@@ -879,7 +873,8 @@
 	int was_empty;
 
 	dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
-				inode->i_dev, inode->i_ino, inode->i_count);
+		 inode->i_dev, inode->i_ino,
+		 atomic_read(&inode->i_count));
 
 	if (!inode || !fattr) {
 		printk("nfs_refresh_inode: inode or fattr is NULL\n");
diff -u --recursive --new-file v2.1.42/linux/fs/nfs/file.c linux/fs/nfs/file.c
--- v2.1.42/linux/fs/nfs/file.c	Mon Apr  7 11:35:30 1997
+++ linux/fs/nfs/file.c	Thu Jun 12 16:22:08 1997
@@ -69,7 +69,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	nfs_readpage,		/* readpage */
 	nfs_writepage,		/* writepage */
 	NULL,			/* bmap */
@@ -143,7 +142,7 @@
 	int	result;
 
 	dfprintk(VFS, "nfs: write(%x/%ld (%d), %lu@%lu)\n",
-			inode->i_dev, inode->i_ino, inode->i_count,
+			inode->i_dev, inode->i_ino, atomic_read(&inode->i_count),
 			count, (unsigned long) file->f_pos);
 
 	if (!inode) {
diff -u --recursive --new-file v2.1.42/linux/fs/nfs/inode.c linux/fs/nfs/inode.c
--- v2.1.42/linux/fs/nfs/inode.c	Mon Apr 14 16:28:17 1997
+++ linux/fs/nfs/inode.c	Thu Jun 12 16:22:08 1997
@@ -316,7 +316,8 @@
 		nfs_refresh_inode(inode, fattr);
 	}
 	dprintk("NFS: fhget(%x/%ld ct=%d)\n",
-				inode->i_dev, inode->i_ino, inode->i_count);
+		inode->i_dev, inode->i_ino,
+		atomic_read(&inode->i_count));
 
 	return inode;
 }
@@ -433,7 +434,10 @@
  * File system information
  */
 static struct file_system_type nfs_fs_type = {
-	nfs_read_super, "nfs", 0, NULL
+	"nfs",
+	FS_NO_DCACHE,
+	nfs_read_super,
+	NULL
 };
 
 /*
diff -u --recursive --new-file v2.1.42/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c
--- v2.1.42/linux/fs/nfs/nfsroot.c	Thu May 29 21:53:08 1997
+++ linux/fs/nfs/nfsroot.c	Thu Jun 12 16:22:08 1997
@@ -1,5 +1,5 @@
 /*
- *  $Id: nfsroot.c,v 1.36 1997/05/27 15:57:47 mj Exp $
+ *  $Id: nfsroot.c,v 1.37 1997/06/04 08:28:10 davem Exp $
  *
  *  Copyright (C) 1995, 1996  Gero Kuhlmann <gero@gkminix.han.de>
  *
@@ -78,6 +78,7 @@
 
 #include <asm/param.h>
 #include <linux/utsname.h>
+#include <linux/nametrans.h>
 #include <linux/in.h>
 #include <linux/if.h>
 #include <linux/inet.h>
@@ -832,6 +833,9 @@
 			root_bootp_string(nfs_path, ext+1, *ext, NFS_MAXPATHLEN);
 			break;
 	}
+#ifdef CONFIG_TRANS_NAMES
+	translations_dirty = 1;
+#endif
 }
 
 
@@ -1254,6 +1258,9 @@
 	system_utsname.domainname[0] = '\0';
 	user_dev_name[0] = '\0';
 	bootp_flag = rarp_flag = 1;
+#ifdef CONFIG_TRANS_NAMES
+	translations_dirty = 1;
+#endif
 
 	/* The following is just a shortcut for automatic IP configuration */
 	if (!strcmp(addrs, "bootp")) {
@@ -1299,6 +1306,9 @@
 				}
 				strncpy(system_utsname.nodename, ip, __NEW_UTS_LEN);
 				system_utsname.nodename[__NEW_UTS_LEN] = '\0';
+#ifdef CONFIG_TRANS_NAMES
+				translations_dirty = 1;
+#endif
 				break;
 			case 5:
 				strncpy(user_dev_name, ip, IFNAMSIZ);
@@ -1332,6 +1342,9 @@
 	if (!system_utsname.nodename[0]) {
 		strncpy(system_utsname.nodename, in_ntoa(myaddr), __NEW_UTS_LEN);
 		system_utsname.nodename[__NEW_UTS_LEN] = '\0';
+#ifdef CONFIG_TRANS_NAMES
+		translations_dirty = 1;
+#endif
 	}
 
 	/* Set the correct netmask */
diff -u --recursive --new-file v2.1.42/linux/fs/nfs/proc.c linux/fs/nfs/proc.c
--- v2.1.42/linux/fs/nfs/proc.c	Mon Apr  7 11:35:31 1997
+++ linux/fs/nfs/proc.c	Thu Jun 12 16:22:08 1997
@@ -177,8 +177,8 @@
 
 int
 nfs_proc_rename(struct nfs_server *server,
-			struct nfs_fh *old_dir, const char *old_name,
-			struct nfs_fh *new_dir, const char *new_name)
+		struct nfs_fh *old_dir, const char *old_name,
+		struct nfs_fh *new_dir, const char *new_name)
 {
 	struct nfs_renameargs	arg = { old_dir, old_name, new_dir, new_name };
 	int			status;
diff -u --recursive --new-file v2.1.42/linux/fs/nfs/read.c linux/fs/nfs/read.c
--- v2.1.42/linux/fs/nfs/read.c	Mon Apr 14 16:28:17 1997
+++ linux/fs/nfs/read.c	Thu Jun 12 16:22:08 1997
@@ -188,7 +188,7 @@
 				nfs_readpage_result, req);
 
 	if (result >= 0) {
-		inode->i_count++;
+		atomic_inc(&inode->i_count);
 		atomic_inc(&page->count);
 		return 0;
 	}
diff -u --recursive --new-file v2.1.42/linux/fs/nfs/symlink.c linux/fs/nfs/symlink.c
--- v2.1.42/linux/fs/nfs/symlink.c	Mon Apr  7 11:35:31 1997
+++ linux/fs/nfs/symlink.c	Thu Jun 12 16:22:08 1997
@@ -19,8 +19,6 @@
 #include <asm/uaccess.h>
 
 static int nfs_readlink(struct inode *, char *, int);
-static int nfs_follow_link(struct inode *, struct inode *, int, int,
-			   struct inode **);
 
 /*
  * symlinks can't do much...
@@ -37,7 +35,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	nfs_readlink,		/* readlink */
-	nfs_follow_link,	/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -45,55 +42,6 @@
 	NULL			/* permission */
 };
 
-static int nfs_follow_link(struct inode *dir, struct inode *inode,
-			   int flag, int mode, struct inode **res_inode)
-{
-	int error;
-	unsigned int len;
-	char *res, *res2;
-	void *mem;
-
-	*res_inode = NULL;
-	if (!dir) {
-		dir = current->fs->root;
-		dir->i_count++;
-	}
-	if (!inode) {
-		iput(dir);
-		return -ENOENT;
-	}
-	if (!S_ISLNK(inode->i_mode)) {
-		iput(dir);
-		*res_inode = inode;
-		return 0;
-	}
-	if (current->link_count > 5) {
-		iput(inode);
-		iput(dir);
-		return -ELOOP;
-	}
-	error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem,
-		&res, &len, NFS_MAXPATHLEN);
-	if (error) {
-		iput(inode);
-		iput(dir);
-		kfree(mem);
-		return error;
-	}
-	while ((res2 = (char *) kmalloc(NFS_MAXPATHLEN + 1, GFP_NFS)) == NULL) {
-		schedule();
-	}
-	memcpy(res2, res, len);
-	res2[len] = '\0';
-	kfree(mem);
-	iput(inode);
-	current->link_count++;
-	error = open_namei(res2, flag, mode, res_inode, dir);
-	current->link_count--;
-	kfree_s(res2, NFS_MAXPATHLEN + 1);
-	return error;
-}
-
 static int nfs_readlink(struct inode *inode, char *buffer, int buflen)
 {
 	int error;
@@ -103,10 +51,6 @@
 
 	dfprintk(VFS, "nfs: readlink(%x/%ld)\n", inode->i_dev, inode->i_ino);
 
-	if (!S_ISLNK(inode->i_mode)) {
-		iput(inode);
-		return -EINVAL;
-	}
 	if (buflen > NFS_MAXPATHLEN)
 		buflen = NFS_MAXPATHLEN;
 	error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), &mem,
diff -u --recursive --new-file v2.1.42/linux/fs/nfs/write.c linux/fs/nfs/write.c
--- v2.1.42/linux/fs/nfs/write.c	Wed May 28 10:51:33 1997
+++ linux/fs/nfs/write.c	Mon Jun 16 08:46:24 1997
@@ -133,7 +133,7 @@
 	if (test_and_clear_bit(PG_decr_after, &page->flags))
 		atomic_dec(&page->count);
 	if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
-		swap_after_unlock_page(page->swap_unlock_entry);
+		swap_after_unlock_page(page->pg_swap_entry);
 #endif
 }
 
@@ -338,7 +338,7 @@
 	wreq->wb_page   = page;
 	wreq->wb_offset = offset;
 	wreq->wb_bytes  = bytes;
-	inode->i_count++;
+	atomic_inc(&inode->i_count);
 	atomic_inc(&page->count);
 
 	append_write_request(&NFS_WRITEBACK(inode), wreq);
@@ -788,7 +788,7 @@
 			dprintk("NFS: %4d saving write failure code\n",
 						task->tk_pid);
 			append_write_request(&nfs_failed_requests, req);
-			inode->i_count++;
+			atomic_inc(&inode->i_count);
 		}
 		clear_bit(PG_uptodate, &page->flags);
 	} else if (!WB_CANCELLED(req)) {
diff -u --recursive --new-file v2.1.42/linux/fs/nfsd/export.c linux/fs/nfsd/export.c
--- v2.1.42/linux/fs/nfsd/export.c	Mon Apr  7 11:35:31 1997
+++ linux/fs/nfsd/export.c	Thu Jun 12 16:22:09 1997
@@ -331,7 +331,7 @@
 
 	if (!(exp = exp_get(clp, dev, ino)))
 		return -EPERM;
-	exp->ex_inode->i_count++;
+	atomic_inc(&exp->ex_inode->i_count);
 	fh_compose(&fh, exp, exp->ex_inode);
 	memcpy(f, &fh.fh_handle, sizeof(struct knfs_fh));
 	fh_put(&fh);
diff -u --recursive --new-file v2.1.42/linux/fs/nfsd/nfsctl.c linux/fs/nfsd/nfsctl.c
--- v2.1.42/linux/fs/nfsd/nfsctl.c	Wed Apr 23 19:01:27 1997
+++ linux/fs/nfsd/nfsctl.c	Thu Jun 12 16:22:09 1997
@@ -35,8 +35,8 @@
 # define copy_to_user		memcpy_tofs
 # define access_ok		!verify_area
 #endif
-#include <asm/smp.h>
-#include <asm/smp_lock.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
 extern long sys_call_table[];
 
@@ -213,8 +213,6 @@
 EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR("Olaf Kirch <okir@monad.swb.de>");
 #endif
-
-static unsigned long	old_syscallvec;
 
 extern int (*do_nfsservctl)(int, void *, void *);
 
diff -u --recursive --new-file v2.1.42/linux/fs/nfsd/vfs.c linux/fs/nfsd/vfs.c
--- v2.1.42/linux/fs/nfsd/vfs.c	Tue May 13 22:41:15 1997
+++ linux/fs/nfsd/vfs.c	Thu Jun 12 16:22:09 1997
@@ -39,9 +39,6 @@
 
 #define NFSDDBG_FACILITY		NFSDDBG_FILEOP
 
-/* Symbol not exported */
-static struct super_block *get_super(dev_t dev);
-
 /* Open mode for nfsd_open */
 #define OPEN_READ	0
 #define OPEN_WRITE	1
@@ -123,13 +120,13 @@
 	dotdot = (len == 2 && name[0] == '.' && name[1] == '.');
 	if (dotdot) {
 		if (dirp == current->fs->root) {
-			dirp->i_count++;
+			atomic_inc(&dirp->i_count);
 			*resfh = *fhp;
 			return 0;
 		}
 
 		if (dirp->i_dev == exp->ex_dev && dirp->i_ino == exp->ex_ino) {
-			dirp->i_count++;
+			atomic_inc(&dirp->i_count);
 			*resfh = *fhp;
 			return 0;
 		}
@@ -147,12 +144,12 @@
  	if (perm != 0)
 		return perm;
 	if (!len) {
-		dirp->i_count++;
+		atomic_inc(&dirp->i_count);
 		*resfh = *fhp;
 		return 0;
 	}
 
-	dirp->i_count++;		/* lookup eats the dirp inode */
+	atomic_inc(&dirp->i_count);		/* lookup eats the dirp inode */
 	err = dirp->i_op->lookup(dirp, name, len, &inode);
 
 	if (err)
@@ -165,7 +162,7 @@
 	if (!dotdot && (sb = inode->i_sb) && (inode == sb->s_mounted)) {
 		iput(inode);
 		inode = sb->s_covered;
-		inode->i_count++;
+		atomic_inc(&inode->i_count);
 	}
 
 	fh_compose(resfh, exp, inode);
@@ -294,7 +291,7 @@
 		}
 	}
 
-	inode->i_count++;
+	atomic_inc(&inode->i_count);
 	return 0;
 }
 
@@ -307,7 +304,7 @@
 	struct inode	*inode;
 
 	inode = filp->f_inode;
-	if (!inode->i_count)
+	if (!atomic_read(&inode->i_count))
 		printk(KERN_WARNING "nfsd: inode count == 0!\n");
 	if (filp->f_op && filp->f_op->release)
 		filp->f_op->release(inode, filp);
@@ -536,7 +533,7 @@
 
 	fh_lock(fhp);			/* lock directory */
 	dirp = fhp->fh_inode;
-	dirp->i_count++;		/* dirop eats the inode */
+	atomic_inc(&dirp->i_count);	/* dirop eats the inode */
 
 	switch (type) {
 	case S_IFREG:
@@ -571,7 +568,7 @@
 	 * If the VFS call doesn't return the inode, look it up now.
 	 */
 	if (inode == NULL) {
-		dirp->i_count++;
+		atomic_inc(&dirp->i_count);
 		err = dirp->i_op->lookup(dirp, fname, flen, &inode);
 		if (err < 0)
 			return -nfserrno(err);	/* Huh?! */
@@ -646,7 +643,7 @@
 	if (!inode->i_op || !inode->i_op->readlink)
 		return nfserr_io;
 
-	inode->i_count++;
+	atomic_inc(&inode->i_count);
 	oldfs = get_fs(); set_fs(KERNEL_DS);
 	err = inode->i_op->readlink(inode, buf, *lenp);
 	set_fs(oldfs);
@@ -683,7 +680,7 @@
 		return nfserr_perm;
 
 	fh_lock(fhp);			/* lock inode */
-	dirp->i_count++;
+	atomic_inc(&dirp->i_count);
 	err = dirp->i_op->symlink(dirp, fname, flen, path);
 	fh_unlock(fhp);			/* unlock inode */
 
@@ -696,7 +693,7 @@
 	/*
 	 * Okay, now look up the inode of the new symlink.
 	 */
-	dirp->i_count++;		/* lookup eats the dirp inode */
+	atomic_inc(&dirp->i_count);	/* lookup eats the dirp inode */
 	err = dirp->i_op->lookup(dirp, fname, flen, &inode);
 	if (err)
 		return nfserrno(-err);
@@ -733,7 +730,7 @@
 		return nfserr_perm;
 
 	fh_lock(ffhp);			/* lock directory inode */
-	dirp->i_count++;
+	atomic_inc(&dirp->i_count);
 	err = dirp->i_op->link(dest, dirp, fname, len);
 	fh_unlock(ffhp);		/* unlock inode */
 
@@ -773,9 +770,9 @@
 		return nfserr_perm;
 
 	fh_lock(tfhp);			/* lock destination directory */
-	tdir->i_count++;
-	fdir->i_count++;
-	err = fdir->i_op->rename(fdir, fname, flen, tdir, tname, tlen, 0);
+	atomic_inc(&tdir->i_count);
+	atomic_inc(&fdir->i_count);
+	err = fdir->i_op->rename(fdir, fname, flen, tdir, tname, tlen);
 	fh_unlock(tfhp);		/* unlock inode */
 
 	if (!err && EX_ISSYNC(tfhp->fh_export)) {
@@ -808,12 +805,12 @@
 	if (type == S_IFDIR) {
 		if (!dirp->i_op || !dirp->i_op->rmdir)
 			return nfserr_notdir;
-		dirp->i_count++;
+		atomic_inc(&dirp->i_count);
 		err = dirp->i_op->rmdir(dirp, fname, flen);
 	} else {	/* other than S_IFDIR */
 		if (!dirp->i_op || !dirp->i_op->unlink)
 			return nfserr_perm;
-		dirp->i_count++;
+		atomic_inc(&dirp->i_count);
 		err = dirp->i_op->unlink(dirp, fname, flen);
 	}
 
@@ -1039,26 +1036,6 @@
 		return 0;
 	*devp = sb->s_covered->i_dev;
 	return 1;
-}
-
-/* Duplicated here from fs/super.c because it's not exported */
-static struct super_block *
-get_super(dev_t dev)
-{
-	struct super_block *s;
-
-	if (!dev)
-		return NULL;
-	s = 0 + super_blocks;
-	while (s < NR_SUPER + super_blocks)
-		if (s->s_dev == dev) {
-			wait_on_super(s);
-			if (s->s_dev == dev)
-				return s;
-			s = 0 + super_blocks;
-		} else
-			s++;
-	return NULL;
 }
 
 /*
diff -u --recursive --new-file v2.1.42/linux/fs/open.c linux/fs/open.c
--- v2.1.42/linux/fs/open.c	Tue May 13 22:41:15 1997
+++ linux/fs/open.c	Thu Jun 12 16:22:09 1997
@@ -4,6 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+#include <linux/config.h>
 #include <linux/vfs.h>
 #include <linux/types.h>
 #include <linux/utime.h>
@@ -20,6 +21,7 @@
 #include <linux/file.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <linux/omirr.h>
 
 #include <asm/uaccess.h>
 #include <asm/bitops.h>
@@ -33,7 +35,7 @@
 	error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs));
 	if (error)
 		goto out;
-	error = namei(path,&inode);
+	error = namei(NAM_FOLLOW_LINK, path, &inode);
 	if (error)
 		goto out;
 	error = -ENOSYS;
@@ -88,6 +90,7 @@
 		vmtruncate(inode, length);
 		if (inode->i_op && inode->i_op->truncate)
 			inode->i_op->truncate(inode);
+		inode->i_status |= ST_MODIFIED;
 	}
 	up(&inode->i_sem);
 	return error;
@@ -99,7 +102,7 @@
 	int error;
 
 	lock_kernel();
-	error = namei(path,&inode);
+	error = namei(NAM_FOLLOW_LINK, path, &inode);
 	if (error)
 		goto out;
 
@@ -185,33 +188,36 @@
 	struct iattr newattrs;
 
 	lock_kernel();
-	error = namei(filename,&inode);
+	/* Hmm, should I always follow symlinks or not ? */
+	error = namei(NAM_FOLLOW_LINK, filename, &inode);
 	if (error)
 		goto out;
 	error = -EROFS;
-	if (IS_RDONLY(inode)) {
-		iput(inode);
-		goto out;
-	}
+	if (IS_RDONLY(inode))
+		goto iput_and_out;
+
 	/* Don't worry, the checks are done in inode_change_ok() */
 	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
 	if (times) {
 		error = get_user(newattrs.ia_atime, &times->actime);
 		if (!error) 
 			error = get_user(newattrs.ia_mtime, &times->modtime);
-		if (error) {
-			iput(inode);
-			goto out;
-		}
+		if (error)
+			goto iput_and_out;
+
 		newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
 	} else {
 		if (current->fsuid != inode->i_uid &&
-		    (error = permission(inode,MAY_WRITE)) != 0) {
-			iput(inode);
-			goto out;
-		}
+		    (error = permission(inode,MAY_WRITE)) != 0)
+			goto iput_and_out;
 	}
 	error = notify_change(inode, &newattrs);
+#ifdef CONFIG_OMIRR
+	if(!error)
+		omirr_printall(inode, " U %ld %ld %ld ", CURRENT_TIME,
+				newattrs.ia_atime, newattrs.ia_mtime);
+#endif
+iput_and_out:
 	iput(inode);
 out:
 	unlock_kernel();
@@ -231,7 +237,7 @@
 	struct iattr newattrs;
 
 	lock_kernel();
-	error = namei(filename,&inode);
+	error = namei(NAM_FOLLOW_LINK, filename, &inode);
 	if (error)
 		goto out;
 	error = -EROFS;
@@ -252,6 +258,11 @@
 			goto iput_and_out;
 	}
 	error = notify_change(inode, &newattrs);
+#ifdef CONFIG_OMIRR
+	if(!error)
+		omirr_printall(inode, " U %ld %ld %ld ", CURRENT_TIME,
+				newattrs.ia_atime, newattrs.ia_mtime);
+#endif
 iput_and_out:
 	iput(inode);
 out:
@@ -276,7 +287,7 @@
 	old_fsgid = current->fsgid;
 	current->fsuid = current->uid;
 	current->fsgid = current->gid;
-	res = namei(filename,&inode);
+	res = namei(NAM_FOLLOW_LINK, filename, &inode);
 	if (!res) {
 		res = permission(inode, mode);
 		iput(inode);
@@ -291,24 +302,23 @@
 asmlinkage int sys_chdir(const char * filename)
 {
 	struct inode * inode;
+	struct inode * tmpi;
 	int error;
 
 	lock_kernel();
-	error = namei(filename,&inode);
+	error = namei(NAM_FOLLOW_LINK, filename, &inode);
 	if (error)
 		goto out;
 	error = -ENOTDIR;
-	if (!S_ISDIR(inode->i_mode)) {
-		iput(inode);
-		goto out;
-	}
-	if ((error = permission(inode,MAY_EXEC)) != 0) {
-		iput(inode);
-		goto out;
-	}
-	iput(current->fs->pwd);
-	current->fs->pwd = inode;
-	error = 0;
+	if (!S_ISDIR(inode->i_mode))
+		goto iput_and_out;
+	if ((error = permission(inode,MAY_EXEC)) != 0)
+		goto iput_and_out;
+
+	/* exchange inodes */
+	tmpi = current->fs->pwd; current->fs->pwd = inode; inode = tmpi;
+iput_and_out:
+	iput(inode);
 out:
 	unlock_kernel();
 	return error;
@@ -333,8 +343,7 @@
 		goto out;
 	iput(current->fs->pwd);
 	current->fs->pwd = inode;
-	inode->i_count++;
-	error = 0;
+	atomic_inc(&inode->i_count);
 out:
 	unlock_kernel();
 	return error;
@@ -343,25 +352,23 @@
 asmlinkage int sys_chroot(const char * filename)
 {
 	struct inode * inode;
+	struct inode * tmpi;
 	int error;
 
 	lock_kernel();
-	error = namei(filename,&inode);
+	error = namei(NAM_FOLLOW_LINK, filename, &inode);
 	if (error)
 		goto out;
 	error = -ENOTDIR;
-	if (!S_ISDIR(inode->i_mode)) {
-		iput(inode);
-		goto out;
-	}
+	if (!S_ISDIR(inode->i_mode))
+		goto iput_and_out;
 	error = -EPERM;
-	if (!fsuser()) {
-		iput(inode);
-		goto out;
-	}
-	iput(current->fs->root);
-	current->fs->root = inode;
+	if (!fsuser())
+		goto iput_and_out;
+	tmpi = current->fs->root; current->fs->root = inode; inode = tmpi;
 	error = 0;
+iput_and_out:
+	iput(inode);
 out:
 	unlock_kernel();
 	return error;
@@ -392,6 +399,10 @@
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
 	inode->i_dirt = 1;
 	err = notify_change(inode, &newattrs);
+#ifdef CONFIG_OMIRR
+	if(!err)
+		omirr_printall(inode, " M %ld %ld ", CURRENT_TIME, newattrs.ia_mode);
+#endif
 out:
 	unlock_kernel();
 	return err;
@@ -404,7 +415,11 @@
 	struct iattr newattrs;
 
 	lock_kernel();
-	error = namei(filename,&inode);
+	/* I'm not sure whether to use NAM_FOLLOW_TRAILSLASH instead,
+	 * because permissions on symlinks now can never be changed,
+	 * but on the other hand they are never needed.
+	 */
+	error = namei(NAM_FOLLOW_LINK, filename, &inode);
 	if (error)
 		goto out;
 	error = -EROFS;
@@ -419,6 +434,10 @@
 	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
 	inode->i_dirt = 1;
 	error = notify_change(inode, &newattrs);
+#ifdef CONFIG_OMIRR
+	if(!error)
+		omirr_printall(inode, " M %ld %ld ", CURRENT_TIME, newattrs.ia_mode);
+#endif
 iput_and_out:
 	iput(inode);
 out:
@@ -481,6 +500,11 @@
 			inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
 	} else
 		error = notify_change(inode, &newattrs);
+#ifdef CONFIG_OMIRR
+	if(!error)
+		omirr_printall(inode, " O %d %d ", CURRENT_TIME,
+				newattrs.ia_uid, newattrs.ia_gid);
+#endif
 out:
 	unlock_kernel();
 	return error;
@@ -493,7 +517,7 @@
 	struct iattr newattrs;
 
 	lock_kernel();
-	error = lnamei(filename,&inode);
+	error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode);
 	if (error)
 		goto out;
 	error = -EROFS;
@@ -532,12 +556,17 @@
 		inode->i_sb->dq_op->initialize(inode, -1);
 		error = -EDQUOT;
 		if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0))
-			goto out;
+			goto iput_and_out;
 		error = notify_change(inode, &newattrs);
 		if (error)
 			inode->i_sb->dq_op->transfer(inode, &newattrs, 1);
 	} else
 		error = notify_change(inode, &newattrs);
+#ifdef CONFIG_OMIRR
+	if(!error)
+		omirr_printall(inode, " O %d %d ", CURRENT_TIME,
+				newattrs.ia_uid, newattrs.ia_gid);
+#endif
 iput_and_out:
 	iput(inode);
 out:
diff -u --recursive --new-file v2.1.42/linux/fs/pipe.c linux/fs/pipe.c
--- v2.1.42/linux/fs/pipe.c	Tue May 13 22:41:15 1997
+++ linux/fs/pipe.c	Thu Jun 12 16:22:09 1997
@@ -385,7 +385,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -442,7 +441,7 @@
 close_f12_inode_i:
 	put_unused_fd(i);
 close_f12_inode:
-	inode->i_count--;
+	atomic_dec(&inode->i_count);
 	iput(inode);
 close_f12:
 	put_filp(f2);
diff -u --recursive --new-file v2.1.42/linux/fs/proc/Makefile linux/fs/proc/Makefile
--- v2.1.42/linux/fs/proc/Makefile	Mon Mar 17 14:54:30 1997
+++ linux/fs/proc/Makefile	Thu Jun 12 16:22:09 1997
@@ -8,8 +8,11 @@
 # Note 2! The CFLAGS definitions are now in the main makefile...
 
 O_TARGET := proc.o
-O_OBJS   := inode.o root.o base.o generic.o mem.o link.o fd.o array.o \
+O_OBJS   := inode.o root.o base.o generic.o mem.o link.o arbitrary.o fd.o array.o \
 		kmsg.o scsi.o proc_tty.o
+ifdef CONFIG_OMIRR
+O_OBJS   := $(O_OBJS) omirr.o
+endif
 OX_OBJS  := procfs_syms.o
 M_OBJS   := 
 
diff -u --recursive --new-file v2.1.42/linux/fs/proc/arbitrary.c linux/fs/proc/arbitrary.c
--- v2.1.42/linux/fs/proc/arbitrary.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/proc/arbitrary.c	Thu Jun 12 16:22:09 1997
@@ -0,0 +1,58 @@
+/*
+ * $Id: arbitrary.c,v 1.2 1997/06/05 01:27:47 davem Exp $
+ *
+ * linux/fs/proc/arbitrary.c - lookup() for arbitrary inodes.
+ * Copyright (C) 1997, Thomas Schoebel-Theuer,
+ * <schoebel@informatik.uni-stuttgart.de>.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/kdev_t.h>
+#include <linux/fs.h>
+
+/* Format of dev/inode pairs that can be used as file names:
+ * [<dev_number_in_hex]:<inode_number_in_decimal>
+ * (the same format that is already in use in /proc/<pid>/exe,
+ * /proc/<pid>/cwd and /proc/<pid>/root).
+ */
+/* Note that readdir does not supply such names, so they must be used
+ * either "blind" or must be queried another way, for example
+ * as result of a virtual symlink (see linux/proc/link.c).
+ */
+int proc_arbitrary_lookup(struct inode * dir, const char * name,
+			  int len, struct inode ** result)
+{
+	int dev, ino;
+	char * ptr = (char*)name;
+	kdev_t kdev;
+	int i;
+	int error = -EINVAL;
+	
+	if(*ptr++ != '[')
+		goto done;
+	dev = simple_strtoul(ptr, &ptr, 16);
+	if(*ptr++ != ']')
+		goto done;
+	if(*ptr++ != ':')
+		goto done;
+	ino = simple_strtoul(ptr, &ptr, 0);
+	if((long)ptr - (long)name != len)
+		goto done;
+
+	error = -ENOENT;
+	kdev = to_kdev_t(dev);
+	if(!kdev)
+		goto done;
+	for(i = 0; i < NR_SUPER; i++)
+		if(super_blocks[i].s_dev == kdev)
+			break;
+	if(i < NR_SUPER) {
+		*result = iget(&super_blocks[i], ino);
+		if(*result)
+			error = 0;
+	}
+done:
+	iput(dir);
+	return error;
+}
diff -u --recursive --new-file v2.1.42/linux/fs/proc/array.c linux/fs/proc/array.c
--- v2.1.42/linux/fs/proc/array.c	Wed May 28 10:51:33 1997
+++ linux/fs/proc/array.c	Thu Jun 12 16:22:09 1997
@@ -154,8 +154,6 @@
 	return read;
 }
 
-
-
 /*
  * Writing to /proc/profile resets the counters
  *
@@ -1021,6 +1019,9 @@
 #ifdef CONFIG_ZORRO
 extern int zorro_get_list(char *);
 #endif
+#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
+extern int get_hardware_list(char *);
+#endif
 
 static long get_root_array(char * page, int type, char **start,
 	off_t offset, unsigned long length)
@@ -1105,6 +1106,10 @@
 		case PROC_ZORRO:
 			return zorro_get_list(page);
 #endif
+#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
+		case PROC_HARDWARE:
+			return get_hardware_list(page);
+#endif
 	}
 	return -EBADF;
 }
@@ -1211,7 +1216,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -1257,7 +1261,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/proc/base.c linux/fs/proc/base.c
--- v2.1.42/linux/fs/proc/base.c	Tue May 13 22:41:15 1997
+++ linux/fs/proc/base.c	Thu Jun 12 16:22:09 1997
@@ -42,7 +42,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/proc/fd.c linux/fs/proc/fd.c
--- v2.1.42/linux/fs/proc/fd.c	Tue May 13 22:41:15 1997
+++ linux/fs/proc/fd.c	Thu Jun 12 16:22:09 1997
@@ -44,7 +44,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/proc/generic.c linux/fs/proc/generic.c
--- v2.1.42/linux/fs/proc/generic.c	Thu Mar 27 14:40:06 1997
+++ linux/fs/proc/generic.c	Thu Jun 12 16:22:09 1997
@@ -51,7 +51,6 @@
     NULL,	    /* mknod	   */
     NULL,	    /* rename	   */
     NULL,	    /* readlink	   */
-    NULL,	    /* follow_link */
     NULL,	    /* readpage	   */
     NULL,	    /* writepage   */
     NULL,	    /* bmap	   */
@@ -74,7 +73,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/proc/kmsg.c linux/fs/proc/kmsg.c
--- v2.1.42/linux/fs/proc/kmsg.c	Fri Apr  4 08:52:24 1997
+++ linux/fs/proc/kmsg.c	Thu Jun 12 16:22:09 1997
@@ -70,7 +70,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/proc/link.c linux/fs/proc/link.c
--- v2.1.42/linux/fs/proc/link.c	Tue May 13 22:41:15 1997
+++ linux/fs/proc/link.c	Thu Jun 12 16:22:09 1997
@@ -14,10 +14,9 @@
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
 #include <linux/stat.h>
+#include <linux/dalloc.h>
 
 static int proc_readlink(struct inode *, char *, int);
-static int proc_follow_link(struct inode *, struct inode *, int, int,
-			    struct inode **);
 
 /*
  * PLAN9_SEMANTICS won't work any more: it used an ugly hack that broke 
@@ -53,7 +52,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	proc_readlink,		/* readlink */
-	proc_follow_link,	/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -61,7 +59,11 @@
 	NULL			/* permission */
 };
 
-
+/* [Feb-1997 T. Schoebel-Theuer] This is no longer called from the
+ * VFS, but only from proc_readlink(). All the functionality
+ * should the moved there (without using temporary inodes any more)
+ * and then it could be eliminated.
+ */
 static int proc_follow_link(struct inode * dir, struct inode * inode,
 	int flag, int mode, struct inode ** res_inode)
 {
@@ -130,33 +132,35 @@
 	if (!new_inode)
 		return -ENOENT;
 	*res_inode = new_inode;
-	new_inode->i_count++;
+	atomic_inc(&new_inode->i_count);
 	return 0;
 }
 
 static int proc_readlink(struct inode * inode, char * buffer, int buflen)
 {
-	int i;
-	unsigned int dev,ino;
-	char buf[64];
+	int error = proc_follow_link(NULL, inode, 0, 0, &inode);
 
-	if (!S_ISLNK(inode->i_mode)) {
-		iput(inode);
-		return -EINVAL;
-	}
-	i = proc_follow_link(NULL, inode, 0, 0, &inode);
-	if (i)
-		return i;
+	if (error)
+		return error;
 	if (!inode)
 		return -EIO;
-	dev = kdev_t_to_nr(inode->i_dev);
-	ino = inode->i_ino;
+
+	/* This will return *one* of the alias names (which is not quite
+	 * correct). I have to rethink the problem, so this is only a
+	 * quick hack...
+	 */
+	if(inode->i_dentry) {
+		char * tmp = (char*)__get_free_page(GFP_KERNEL);
+		int len = d_path(inode->i_dentry, current->fs->root, tmp);
+		int min = buflen<PAGE_SIZE ? buflen : PAGE_SIZE;
+		if(len <= min)
+			min = len+1;
+		copy_to_user(buffer, tmp, min);
+		free_page((unsigned long)tmp);
+		error = len;
+	} else {
+		error= -ENOENT;
+	}
 	iput(inode);
-	i = sprintf(buf,"[%04x]:%u", dev, ino);
-	if (buflen > i)
-		buflen = i;
-	i = 0;
-	while (i < buflen)
-		put_user(buf[i++],buffer++);
-	return i;
+	return error;
 }
diff -u --recursive --new-file v2.1.42/linux/fs/proc/mem.c linux/fs/proc/mem.c
--- v2.1.42/linux/fs/proc/mem.c	Thu May 15 16:48:04 1997
+++ linux/fs/proc/mem.c	Thu Jun 12 16:22:09 1997
@@ -328,7 +328,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/proc/net.c linux/fs/proc/net.c
--- v2.1.42/linux/fs/proc/net.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/proc/net.c	Thu Jun 12 16:22:09 1997
@@ -111,7 +111,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/proc/omirr.c linux/fs/proc/omirr.c
--- v2.1.42/linux/fs/proc/omirr.c	Wed Dec 31 16:00:00 1969
+++ linux/fs/proc/omirr.c	Thu Jun 12 16:22:09 1997
@@ -0,0 +1,297 @@
+/*
+ * fs/proc/omirr.c  -  online mirror support
+ *
+ * (C) 1997 Thomas Schoebel-Theuer
+ */
+
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/dalloc.h>
+#include <linux/omirr.h>
+#include <asm/uaccess.h>
+
+static int nr_omirr_open = 0;
+static int cleared_flag = 0;
+
+static char * buffer = NULL;
+static int read_pos, write_pos;
+static int clip_pos, max_pos;
+static struct wait_queue * read_wait = NULL;
+static struct wait_queue * write_wait = NULL;
+
+static /*inline*/ int reserve_write_space(int len)
+{
+	int rest = max_pos - write_pos;
+
+	if(rest < len) {
+		clip_pos = write_pos;
+		write_pos = 0;
+		rest = max_pos;
+	}
+	while(read_pos > write_pos && read_pos <= write_pos+len) {
+		if(!nr_omirr_open)
+			return 0;
+		interruptible_sleep_on(&write_wait);
+	}
+	return 1;
+}
+
+static /*inline*/ void write_space(int len)
+{
+	write_pos += len;
+	wake_up_interruptible(&read_wait);
+}
+
+static /*inline*/ int reserve_read_space(int len)
+{
+	int rest = clip_pos - read_pos;
+
+	if(!rest) {
+		read_pos = 0;
+		rest = clip_pos;
+		clip_pos = max_pos;
+	}
+	if(len > rest)
+		len = rest;
+	while(read_pos == write_pos) {
+		interruptible_sleep_on(&read_wait);
+	}
+	rest = write_pos - read_pos;
+	if(rest > 0 && rest < len)
+		len = rest;
+	return len;
+}
+
+static /*inline*/ void read_space(int len)
+{
+	read_pos += len;
+	if(read_pos >= clip_pos) {
+		read_pos = 0;
+		clip_pos = max_pos;
+	}
+	wake_up_interruptible(&write_wait);
+}
+
+static /*inline*/ void init_buffer(char * initxt)
+{
+	int len = initxt ? strlen(initxt) : 0;
+
+	if(!buffer) {
+		buffer = (char*)__get_free_page(GFP_USER);
+		max_pos = clip_pos = PAGE_SIZE;
+	}
+	read_pos = write_pos = 0;
+	memcpy(buffer, initxt, len);
+	write_space(len);
+}
+
+static int omirr_open(struct inode * inode, struct file * file)
+{
+	if(nr_omirr_open)
+		return -EAGAIN;
+	nr_omirr_open++;
+	if(!buffer)
+		init_buffer(NULL);
+	return 0;
+}
+
+static int omirr_release(struct inode * inode, struct file * file)
+{
+	nr_omirr_open--;
+	read_space(0);
+	return 0;
+}
+
+static long omirr_read(struct inode * inode, struct file * file,
+		       char * buf, unsigned long count)
+{
+	char * tmp;
+	int len;
+	int error = 0;
+
+	if(!count)
+		goto done;
+	error = -EINVAL;
+	if(!buf || count < 0)
+		goto done;
+	
+	error = verify_area(VERIFY_WRITE, buf, count);
+	if(error)
+		goto done;
+	
+	error = -EAGAIN;
+	if((file->f_flags & O_NONBLOCK) && read_pos == write_pos)
+		goto done;
+
+	error = len = reserve_read_space(count);
+	tmp = buffer + read_pos;
+	while(len) {
+		put_user(*tmp++, buf++);
+		len--;
+	}
+	read_space(error);
+done:
+	return error;		
+}
+
+int compute_name(struct dentry * entry, char * buf)
+{
+	int len;
+
+	if(IS_ROOT(entry)) {
+		*buf = '/';
+		return 1;
+	}
+	len = compute_name(entry->d_parent, buf);
+	if(len > 1) {
+		buf[len++] = '/';
+	}
+	memcpy(buf+len, entry->d_name, entry->d_len);
+	return len + entry->d_len;
+}
+
+int _omirr_print(struct dentry * ent1, struct dentry * ent2, 
+		struct qstr * suffix, const char * fmt,
+		 va_list args1, va_list args2)
+{
+	int count = strlen(fmt) + 10; /* estimate */
+	const char * tmp = fmt;
+	char lenbuf[8];
+	int res;
+
+	if(!buffer)
+		init_buffer(NULL);
+	while(*tmp) {
+		while(*tmp && *tmp++ != '%') ;
+		if(*tmp) {
+			if(*tmp == 's') {
+				char * str = va_arg(args1, char*);
+				count += strlen(str);
+			} else {
+				(void)va_arg(args1, int);
+				count += 8; /* estimate */
+			}
+		}
+	}
+	if(ent1) {
+		struct dentry * dent = ent1;
+		while(dent && !IS_ROOT(dent)) {
+			count += dent->d_len + 1;
+			dent = dent->d_parent;
+		}
+		count++;
+		if(ent2) {
+			dent = ent2;
+			while(dent && !IS_ROOT(dent)) {
+				count += dent->d_len + 1;
+				dent = dent->d_parent;
+			}
+		count++;
+		}
+		if(suffix)
+			count += suffix->len + 1;
+	}
+	
+	if((nr_omirr_open | cleared_flag) && reserve_write_space(count)) {
+		cleared_flag = 0;
+		res = vsprintf(buffer+write_pos+4, fmt, args2) + 4;
+		if(res > count)
+			printk("omirr: format estimate was wrong\n");
+		if(ent1) {
+			res += compute_name(ent1, buffer+write_pos+res);
+			if(ent2) {
+				buffer[write_pos+res++] = '\0';
+				res += compute_name(ent2, buffer+write_pos+res);
+			}
+			if(suffix) {
+				buffer[write_pos+res++] = '/';
+				memcpy(buffer+write_pos+res,
+				       suffix->name, suffix->len);
+				res += suffix->len;
+			}
+			buffer[write_pos+res++] = '\0';
+			buffer[write_pos+res++] = '\n';
+		}
+		sprintf(lenbuf, "%04d", res);
+		memcpy(buffer+write_pos, lenbuf, 4);
+	} else {
+		if(!cleared_flag) {
+			cleared_flag = 1;
+			init_buffer("0007 Z\n");
+		}
+		res = 0;
+	}
+	write_space(res);
+	return res;
+}
+
+int omirr_print(struct dentry * ent1, struct dentry * ent2, 
+		struct qstr * suffix, const char * fmt, ...)
+{
+	va_list args1, args2;
+	int res;
+
+	/* I don't know whether I could make a simple copy of the va_list,
+	 * so for the safe way...
+	 */
+	va_start(args1, fmt);
+	va_start(args2, fmt);
+	res = _omirr_print(ent1, ent2, suffix, fmt, args1, args2);
+	va_end(args2);
+	va_end(args1);
+	return res;
+}
+
+int omirr_printall(struct inode * inode, const char * fmt, ...)
+{
+	int res = 0;
+	struct dentry * tmp = inode->i_dentry;
+
+	if(tmp) do {
+		va_list args1, args2;
+		va_start(args1, fmt);
+		va_start(args2, fmt);
+		res += _omirr_print(tmp, NULL, NULL, fmt, args1, args2);
+		va_end(args2);
+		va_end(args1);
+		tmp = tmp->d_next;
+	} while(tmp != inode->i_dentry);
+	return res;
+}
+
+static struct file_operations omirr_operations = {
+    NULL,	/* omirr_lseek */
+    omirr_read,
+    NULL,	/* omirr_write */
+    NULL,	/* omirr_readdir */
+    NULL,	/* omirr_select */
+    NULL,	/* omirr_ioctl */
+    NULL,	/* mmap */
+    omirr_open,
+    omirr_release,
+    NULL,	/* fsync */
+    NULL,       /* fasync */
+    NULL,       /* check_media_change */
+    NULL        /* revalidate */
+};
+
+struct inode_operations proc_omirr_inode_operations = {
+    &omirr_operations,
+    NULL, /* create */
+    NULL, /* lookup */
+    NULL, /* link */
+    NULL, /* unlink */
+    NULL, /* symlink */
+    NULL, /* mkdir */
+    NULL, /* rmdir */
+    NULL, /* mknod */
+    NULL, /* rename */
+    NULL, /* readlink */
+    NULL, /* readpage */
+    NULL, /* writepage */
+    NULL, /* bmap */
+    NULL, /* truncate */
+    NULL, /* permission */
+    NULL  /* smap */
+};
diff -u --recursive --new-file v2.1.42/linux/fs/proc/openpromfs.c linux/fs/proc/openpromfs.c
--- v2.1.42/linux/fs/proc/openpromfs.c	Mon Apr 14 16:28:18 1997
+++ linux/fs/proc/openpromfs.c	Thu Jun 12 16:22:09 1997
@@ -1,4 +1,4 @@
-/* $Id: openpromfs.c,v 1.13 1997/04/03 08:49:25 davem Exp $
+/* $Id: openpromfs.c,v 1.15 1997/06/05 01:28:11 davem Exp $
  * openpromfs.c: /proc/openprom handling routines
  *
  * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -484,7 +484,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -517,7 +516,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -550,7 +548,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -1015,7 +1012,7 @@
 	static int usec = 0;
 
 	if (inc) {
-		if (inode->i_count == 1)
+		if (atomic_read(&inode->i_count) == 1)
 			usec++;
 		else if (root_fresh && inode->i_ino == PROC_OPENPROM_FIRST) {
 			root_fresh = 0;
@@ -1028,10 +1025,10 @@
 			usec--;
 	}
 	printk ("openpromfs_use: %d %d %d %d\n",
-		inode->i_ino, inc, usec, inode->i_count);
+		inode->i_ino, inc, usec, atomic_read(&inode->i_count));
 #else
 	if (inc) {
-		if (inode->i_count == 1)
+		if (atomic_read(&inode->i_count) == 1)
 			MOD_INC_USE_COUNT;
 		else if (root_fresh && inode->i_ino == PROC_OPENPROM_FIRST) {
 			root_fresh = 0;
diff -u --recursive --new-file v2.1.42/linux/fs/proc/procfs_syms.c linux/fs/proc/procfs_syms.c
--- v2.1.42/linux/fs/proc/procfs_syms.c	Sun Apr 13 10:18:22 1997
+++ linux/fs/proc/procfs_syms.c	Thu Jun 12 16:22:09 1997
@@ -37,7 +37,10 @@
 #endif
 
 static struct file_system_type proc_fs_type = {
-	proc_read_super, "proc", 0, NULL
+	"proc", 
+	FS_NO_DCACHE,
+	proc_read_super, 
+	NULL
 };
 
 int init_proc_fs(void)
diff -u --recursive --new-file v2.1.42/linux/fs/proc/root.c linux/fs/proc/root.c
--- v2.1.42/linux/fs/proc/root.c	Tue May 13 22:41:15 1997
+++ linux/fs/proc/root.c	Thu Jun 12 16:22:09 1997
@@ -64,7 +64,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -105,7 +104,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -266,7 +264,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -348,17 +345,6 @@
 /*
  * /proc/self:
  */
-static int proc_self_followlink(struct inode * dir, struct inode * inode,
-			int flag, int mode, struct inode ** res_inode)
-{
-	iput(dir);
-	*res_inode = proc_get_inode(inode->i_sb, (current->pid << 16) + PROC_PID_INO, &proc_pid);
-	iput(inode);
-	if (!*res_inode)
-		return -ENOENT;
-	return 0;
-}
-
 static int proc_self_readlink(struct inode * inode, char * buffer, int buflen)
 {
 	int len;
@@ -384,7 +370,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	proc_self_readlink,	/* readlink */
-	proc_self_followlink,	/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -436,6 +421,13 @@
 	S_IFREG | S_IRUGO, 1, 0, 0,
 	0, &proc_array_inode_operations
 };
+#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
+static struct proc_dir_entry proc_root_hardware = {
+	PROC_HARDWARE, 8, "hardware",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+	0, &proc_array_inode_operations
+};
+#endif
 static struct proc_dir_entry proc_root_self = {
 	PROC_SELF, 4, "self",
 	S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, 1, 0, 0,
@@ -539,6 +531,13 @@
 	S_IFREG | S_IRUGO, 1, 0, 0,
 	0, &proc_array_inode_operations
 };
+#ifdef CONFIG_OMIRR
+static struct proc_dir_entry proc_root_omirr = {
+	PROC_OMIRR, 5, "omirr",
+	S_IFREG | S_IRUSR, 1, 0, 0,
+	0, &proc_omirr_inode_operations
+};
+#endif
 
 void proc_root_init(void)
 {
@@ -599,7 +598,9 @@
 #endif
 	proc_register(&proc_root, &proc_openprom);
 #endif
-		   
+#if defined (CONFIG_AMIGA) || defined (CONFIG_ATARI)
+	proc_register(&proc_root, &proc_root_hardware);
+#endif
 	proc_register(&proc_root, &proc_root_slab);
 
 	if (prof_shift) {
@@ -641,6 +642,16 @@
 		return -EINVAL;
 	}
 
+	/* Either remove this as soon as possible due to security problems,
+	 * or uncomment the root-only usage.
+	 */
+
+	/* Allow generic inode lookups everywhere.
+	 * No other name in /proc must begin with a '['.
+	 */
+	if(/*!current->uid &&*/ name[0] == '[')
+		return proc_arbitrary_lookup(dir,name,len,result);
+
 	/* Special case "." and "..": they aren't on the directory list */
 	*result = dir;
 	if (!len)
@@ -686,7 +697,7 @@
 	int ino, retval;
 	struct task_struct *p;
 
-	dir->i_count++;
+	atomic_inc(&dir->i_count);
 
 	if (dir->i_ino == PROC_ROOT_INO) { /* check for safety... */
 		dir->i_nlink = proc_root.nlink;
diff -u --recursive --new-file v2.1.42/linux/fs/proc/scsi.c linux/fs/proc/scsi.c
--- v2.1.42/linux/fs/proc/scsi.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/proc/scsi.c	Thu Jun 12 16:22:09 1997
@@ -69,7 +69,6 @@
     NULL,	    /* mknod	   */
     NULL,	    /* rename	   */
     NULL,	    /* readlink	   */
-    NULL,	    /* follow_link */
     NULL,	    /* readpage	   */
     NULL,	    /* writepage   */
     NULL,	    /* bmap	   */
diff -u --recursive --new-file v2.1.42/linux/fs/read_write.c linux/fs/read_write.c
--- v2.1.42/linux/fs/read_write.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/read_write.c	Thu Jun 12 16:22:09 1997
@@ -168,6 +168,7 @@
 		goto out;
 	down(&inode->i_sem);
 	error = write(inode,file,buf,count);
+	inode->i_status |= ST_MODIFIED;
 	up(&inode->i_sem);
 out:
 	fput(file, inode);
@@ -248,6 +249,10 @@
 		len = vector->iov_len;
 		vector++;
 		count--;
+
+		/* Any particular reason why we do not grab the inode semaphore
+		 * when doing writes here? -DaveM
+		 */
 		nr = fn(inode, file, base, len);
 		if (nr < 0) {
 			if (retval)
@@ -259,6 +264,8 @@
 		if (nr != len)
 			break;
 	}
+	if(fn == (IO_fn_t) file->f_op->write)
+		inode->i_status |= ST_MODIFIED;
 	if (iov != iovstack)
 		kfree(iov);
 	return retval;
diff -u --recursive --new-file v2.1.42/linux/fs/readdir.c linux/fs/readdir.c
--- v2.1.42/linux/fs/readdir.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/readdir.c	Thu Jun 12 16:22:09 1997
@@ -1,20 +1,35 @@
 /*
- *  linux/fs/readdir.c
+ *  fs/readdir.c
  *
  *  Copyright (C) 1995  Linus Torvalds
  */
 
+#include <linux/config.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/stat.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#ifdef CONFIG_TRANS_NAMES
+#include <linux/nametrans.h>
+#endif
+#include <linux/dalloc.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 
 #include <asm/uaccess.h>
 
+/* [T.Schoebel-Theuer] I am assuming that directories never get too large.
+ * The problem is that getdents() delivers d_offset's that can be used
+ * for lseek() by the user, so I must encode the status information for
+ * name translation and dcache baskets in the offset.
+ * Note that the linux man page getdents(2) does not mention that
+ * the d_offset is fs-specific and can be used for lseek().
+ */
+#define BASKET_BIT (1<<30) /* 31 is already used by affs */
+#define TRANS_BIT  (1<<29)
+
 /*
  * Traditional linux readdir() handling..
  *
@@ -35,6 +50,9 @@
 
 struct readdir_callback {
 	struct old_linux_dirent * dirent;
+	struct file * file;
+	int translate;
+	off_t oldoffset;
 	int count;
 };
 
@@ -47,11 +65,26 @@
 		return -EINVAL;
 	buf->count++;
 	dirent = buf->dirent;
+	copy_to_user(dirent->d_name, name, namlen);
+	put_user(0, dirent->d_name + namlen);
+#ifdef CONFIG_TRANS_NAMES
+	if(!buf->translate) {
+		char * cut;
+#ifdef CONFIG_TRANS_RESTRICT
+		struct inode * inode = buf->file->f_inode;
+		cut = testname(inode && inode->i_gid != CONFIG_TRANS_GID, dirent->d_name);
+#else
+		cut = testname(1, dirent->d_name);
+#endif
+		if(cut) {
+			put_user(0, cut);
+			buf->translate = 1;
+		}
+	}
+#endif
 	put_user(ino, &dirent->d_ino);
 	put_user(offset, &dirent->d_offset);
 	put_user(namlen, &dirent->d_namlen);
-	copy_to_user(dirent->d_name, name, namlen);
-	put_user(0, dirent->d_name + namlen);
 	return 0;
 }
 
@@ -60,6 +93,7 @@
 	int error = -EBADF;
 	struct file * file;
 	struct readdir_callback buf;
+	off_t oldpos;
 
 	lock_kernel();
 	if (fd >= NR_OPEN || !(file = current->files->fd[fd]))
@@ -70,11 +104,21 @@
 	error = verify_area(VERIFY_WRITE, dirent, sizeof(struct old_linux_dirent));
 	if (error)
 		goto out;
-	buf.count = 0;
+	oldpos = file->f_pos;
+	buf.file = file;
 	buf.dirent = dirent;
+	buf.count = 0;
+	buf.translate = 0;
+	if(file->f_pos & TRANS_BIT) {
+		file->f_pos &= ~TRANS_BIT;
+		buf.translate = 1;
+	}
 	error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir);
 	if (error < 0)
 		goto out;
+	if(buf.translate) {
+		file->f_pos = oldpos | TRANS_BIT;
+	}
 	error = buf.count;
 out:
 	unlock_kernel();
@@ -95,8 +139,11 @@
 struct getdents_callback {
 	struct linux_dirent * current_dir;
 	struct linux_dirent * previous;
+	struct file * file;
 	int count;
-	int error;
+        int error;
+        int restricted;
+	int do_preload;
 };
 
 static int filldir(void * __buf, const char * name, int namlen, off_t offset, ino_t ino)
@@ -105,18 +152,51 @@
 	struct getdents_callback * buf = (struct getdents_callback *) __buf;
 	int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
 
-	buf->error = -EINVAL;	/* only used if we fail.. */
+	/* Do not touch buf->error any more if everything is ok! */
 	if (reclen > buf->count)
-		return -EINVAL;
-	dirent = buf->previous;
-	if (dirent)
-		put_user(offset, &dirent->d_off);
+		return 	(buf->error = -EINVAL);
+#ifdef CONFIG_DCACHE_PRELOAD
+	if(buf->do_preload && (name[0] != '.' || namlen > 2)) {
+		struct qstr qname = { name, namlen };
+		struct inode * dir = buf->file->f_inode;
+		d_entry_preliminary(dir->i_dentry, &qname, ino);
+	}
+#endif
 	dirent = buf->current_dir;
-	buf->previous = dirent;
-	put_user(ino, &dirent->d_ino);
-	put_user(reclen, &dirent->d_reclen);
 	copy_to_user(dirent->d_name, name, namlen);
 	put_user(0, dirent->d_name + namlen);
+#ifdef CONFIG_TRANS_NAMES
+	{
+		char * cut;
+#ifdef CONFIG_TRANS_RESTRICT
+		cut = testname(buf->restricted, dirent->d_name);
+#else
+		cut = testname(1, dirent->d_name);
+#endif
+		if(cut) {
+			int newlen = (int)cut - (int)dirent->d_name;
+			int newreclen = ROUND_UP(NAME_OFFSET(dirent) + newlen + 1);
+			/* Either both must fit or none. This way we need
+			 * no status information in f_pos */
+			if (reclen+newlen > buf->count)
+				return -EINVAL;
+			put_user(0, cut);
+			put_user(ino, &dirent->d_ino);
+			put_user(newreclen, &dirent->d_reclen);
+			put_user(offset, &dirent->d_off);
+			((char *) dirent) += newreclen;
+			buf->count -= newreclen;
+			put_user(offset, &dirent->d_off);
+			copy_to_user(dirent->d_name, name, namlen);
+			put_user(0, dirent->d_name + namlen);
+		}
+	}
+#endif
+	put_user(ino, &dirent->d_ino);
+	put_user(reclen, &dirent->d_reclen);
+	if (buf->previous)
+		put_user(buf->file->f_pos, &buf->previous->d_off);
+	buf->previous = dirent;
 	((char *) dirent) += reclen;
 	buf->current_dir = dirent;
 	buf->count -= reclen;
@@ -126,7 +206,6 @@
 asmlinkage int sys_getdents(unsigned int fd, void * dirent, unsigned int count)
 {
 	struct file * file;
-	struct linux_dirent * lastdirent;
 	struct getdents_callback buf;
 	int error = -EBADF;
 
@@ -139,18 +218,72 @@
 	error = verify_area(VERIFY_WRITE, dirent, count);
 	if (error)
 		goto out;
+	buf.file = file;
 	buf.current_dir = (struct linux_dirent *) dirent;
 	buf.previous = NULL;
 	buf.count = count;
 	buf.error = 0;
-	error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
-	if (error < 0)
-		goto out;
-	lastdirent = buf.previous;
-	if (!lastdirent) {
+	buf.restricted = 0;
+#ifdef CONFIG_TRANS_RESTRICT
+	buf.restricted = file->f_inode && file->f_inode->i_gid != CONFIG_TRANS_GID;
+#endif
+	buf.do_preload = 0;
+#ifdef CONFIG_DCACHE_PRELOAD
+	if(file->f_inode && file->f_inode->i_dentry &&
+	   !(file->f_inode->i_sb->s_type->fs_flags & (FS_NO_DCACHE|FS_NO_PRELIM)) &&
+	   !(file->f_inode->i_dentry->d_flag & D_PRELOADED))
+		buf.do_preload = 1;
+#endif
+	
+	if(!(file->f_pos & BASKET_BIT)) {
+		int oldcount;
+		do {
+			oldcount = buf.count;
+			error = file->f_op->readdir(file->f_inode, file, &buf, filldir);
+			if (error < 0)
+				goto out;
+		} while(!buf.error && buf.count != oldcount);
+	}
+	if(!buf.error) {
+		int nr = 0;
+		struct dentry * list = file->f_inode ?
+			d_basket(file->f_inode->i_dentry) : NULL;
+		struct dentry * ptr = list;
+#ifdef CONFIG_DCACHE_PRELOAD
+		if(buf.do_preload) {
+			buf.do_preload = 0;
+			file->f_inode->i_dentry->d_flag |= D_PRELOADED;
+		}
+#endif
+		if(ptr) {
+			if(!(file->f_pos & BASKET_BIT))
+				file->f_pos = BASKET_BIT;
+			do {
+				struct dentry * next = ptr->d_basket_next;
+				struct inode * inode;
+				/* vfs_locks() are missing here */
+				inode = d_inode(&ptr);
+				if(inode) {
+					nr++;
+					if(nr > (file->f_pos & ~BASKET_BIT)) {
+						int err = filldir(&buf, ptr->d_name,
+								  ptr->d_len,
+								  file->f_pos,
+								  inode->i_ino);
+						if(err)
+							break;
+						file->f_pos++;
+					}
+					iput(inode);
+				}
+				ptr = next;
+			} while(ptr != list);
+		}
+	}
+	if (!buf.previous) {
 		error = buf.error;
 	} else {
-		put_user(file->f_pos, &lastdirent->d_off);
+		put_user(file->f_pos, &buf.previous->d_off);
 		error = count - buf.count;
 	}
 out:
diff -u --recursive --new-file v2.1.42/linux/fs/romfs/inode.c linux/fs/romfs/inode.c
--- v2.1.42/linux/fs/romfs/inode.c	Wed Apr 23 19:01:27 1997
+++ linux/fs/romfs/inode.c	Thu Jun 12 16:22:09 1997
@@ -417,59 +417,6 @@
 	return mylen;
 }
 
-static int
-romfs_follow_link(struct inode *dir, struct inode *inode,
-	int flag, int mode, struct inode **res_inode)
-{
-	int error, len;
-	char *buf;
-
-	*res_inode = NULL;
-	if (!dir) {
-		dir = current->fs->root;
-		dir->i_count++;
-	}
-
-	if (!inode) {
-		iput(dir);
-		return -ENOENT;
-	}
-	if (!S_ISLNK(inode->i_mode)) {
-		*res_inode = inode;
-		iput(dir);
-		return 0;
-	}
-	if (current->link_count > 5) {
-		iput(inode);
-		iput(dir);
-		return -ELOOP;
-	}
-
-	/* Eek. Short enough. */
-	len = inode->i_size;
-	if (!(buf = kmalloc(len+1, GFP_KERNEL))) {
-		iput(inode);
-		iput(dir);
-		/* correct?  spin? */
-		return -EAGAIN;
-	}
-	error = romfs_copyfrom(inode, buf, inode->u.romfs_i.i_dataoffset, len);
-	if (error != len) {
-		iput(inode);
-		iput(dir);
-		error = -EIO;
-	} else {
-		iput(inode);
-		buf[len] = 0;
-		current->link_count++;
-		error = open_namei(buf, flag, mode, res_inode, dir);
-		current->link_count--;
-	}
-
-	kfree(buf);
-	return error;
-}
-
 /* Mapping from our types to the kernel */
 
 static struct file_operations romfs_file_operations = {
@@ -500,7 +447,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	romfs_readpage,		/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap -- not really */
@@ -525,7 +471,7 @@
 	NULL			/* revalidate */
 };
 
-/* Merged dir/symlink op table.  readdir/lookup/readlink/follow_link
+/* Merged dir/symlink op table.  readdir/lookup/readlink
  * will protect from type mismatch.
  */
 
@@ -541,7 +487,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	romfs_readlink,		/* readlink */
-	romfs_follow_link,	/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -638,7 +583,10 @@
 };
 
 static struct file_system_type romfs_fs_type = {
-	romfs_read_super, "romfs", 1, NULL
+	"romfs",
+	(FS_REQUIRES_DEV | FS_NO_DCACHE),	/* Can dcache be used? */
+	romfs_read_super,
+	NULL
 };
 
 __initfunc(int init_romfs_fs(void))
diff -u --recursive --new-file v2.1.42/linux/fs/select.c linux/fs/select.c
--- v2.1.42/linux/fs/select.c	Thu Feb  6 02:51:45 1997
+++ linux/fs/select.c	Thu Jun 12 16:22:09 1997
@@ -208,17 +208,18 @@
  * We do a VERIFY_WRITE here even though we are only reading this time:
  * we'll write to it eventually..
  *
- * Use "int" accesses to let user-mode fd_set's be int-aligned.
+ * Use "unsigned long" accesses to let user-mode fd_set's be long-aligned.
  */
-static int __get_fd_set(unsigned long nr, int * fs_pointer, int * fdset)
+static int __get_fd_set(unsigned long nr, unsigned long * fs_pointer, unsigned long * fdset)
 {
-	/* round up nr to nearest "int" */
-	nr = (nr + 8*sizeof(int)-1) / (8*sizeof(int));
+	/* round up nr to nearest "unsigned long" */
+	nr = (nr + 8*sizeof(unsigned long)-1) / (8*sizeof(unsigned long));
 	if (fs_pointer) {
-		int error = verify_area(VERIFY_WRITE,fs_pointer,nr*sizeof(int));
+		int error = verify_area(VERIFY_WRITE,fs_pointer,
+					nr*sizeof(unsigned long));
 		if (!error) {
 			while (nr) {
-				get_user(*fdset, fs_pointer);
+				__get_user(*fdset, fs_pointer);
 				nr--;
 				fs_pointer++;
 				fdset++;
@@ -234,13 +235,13 @@
 	return 0;
 }
 
-static void __set_fd_set(long nr, int * fs_pointer, int * fdset)
+static void __set_fd_set(long nr, unsigned long * fs_pointer, unsigned long * fdset)
 {
 	if (!fs_pointer)
 		return;
 	while (nr >= 0) {
-		put_user(*fdset, fs_pointer);
-		nr -= 8 * sizeof(int);
+		__put_user(*fdset, fs_pointer);
+		nr -= 8 * sizeof(unsigned long);
 		fdset++;
 		fs_pointer++;
 	}
@@ -261,13 +262,16 @@
  * subtract by 1 on the nr of file descriptors. The former is better for
  * machines with long > int, and the latter allows us to test the bit count
  * against "zero or positive", which can mostly be just a sign bit test..
+ *
+ * Unfortunately this scheme falls apart on big endian machines where
+ * sizeof(long) > sizeof(int) (ie. V9 Sparc). -DaveM
  */
 
 #define get_fd_set(nr,fsp,fdp) \
-__get_fd_set(nr, (int *) (fsp), (int *) (fdp))
+__get_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp))
 
 #define set_fd_set(nr,fsp,fdp) \
-__set_fd_set((nr)-1, (int *) (fsp), (int *) (fdp))
+__set_fd_set((nr)-1, (unsigned long *) (fsp), (unsigned long *) (fdp))
 
 #define zero_fd_set(nr,fdp) \
 __zero_fd_set((nr)-1, (unsigned long *) (fdp))
@@ -302,11 +306,11 @@
 		error = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp));
 		if (error)
 			goto out;
-		get_user(timeout, &tvp->tv_usec);
+		__get_user(timeout, &tvp->tv_usec);
 		timeout = ROUND_UP(timeout,(1000000/HZ));
 		{
 			unsigned long tmp;
-			get_user(tmp, &tvp->tv_sec);
+			__get_user(tmp, &tvp->tv_sec);
 			timeout += tmp * (unsigned long) HZ;
 		}
 		if (timeout)
@@ -322,10 +326,10 @@
 	if ((long) timeout < 0)
 		timeout = 0;
 	if (tvp && !(current->personality & STICKY_TIMEOUTS)) {
-		put_user(timeout/HZ, &tvp->tv_sec);
+		__put_user(timeout/HZ, &tvp->tv_sec);
 		timeout %= HZ;
 		timeout *= (1000000/HZ);
-		put_user(timeout, &tvp->tv_usec);
+		__put_user(timeout, &tvp->tv_usec);
 	}
 	if (error < 0)
 		goto out;
diff -u --recursive --new-file v2.1.42/linux/fs/smbfs/dir.c linux/fs/smbfs/dir.c
--- v2.1.42/linux/fs/smbfs/dir.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/smbfs/dir.c	Thu Jun 12 16:22:09 1997
@@ -47,8 +47,7 @@
 
 static int
  smb_rename(struct inode *old_dir, const char *old_name, int old_len,
-	    struct inode *new_dir, const char *new_name, int new_len,
-	    int must_be_dir);
+	    struct inode *new_dir, const char *new_name, int new_len);
 
 static struct file_operations smb_dir_operations =
 {
@@ -77,7 +76,6 @@
 	NULL,			/* mknod */
 	smb_rename,		/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -798,8 +796,7 @@
 
 static int
 smb_rename(struct inode *old_dir, const char *old_name, int old_len,
-	   struct inode *new_dir, const char *new_name, int new_len,
-	   int must_be_dir)
+	   struct inode *new_dir, const char *new_name, int new_len)
 {
 	int res;
 
diff -u --recursive --new-file v2.1.42/linux/fs/smbfs/file.c linux/fs/smbfs/file.c
--- v2.1.42/linux/fs/smbfs/file.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/smbfs/file.c	Thu Jun 12 16:22:09 1997
@@ -236,7 +236,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/smbfs/inode.c linux/fs/smbfs/inode.c
--- v2.1.42/linux/fs/smbfs/inode.c	Tue May 13 22:41:15 1997
+++ linux/fs/smbfs/inode.c	Thu Jun 12 16:22:09 1997
@@ -429,9 +429,11 @@
 int smb_current_vmalloced;
 #endif
 
-static struct file_system_type smb_fs_type =
-{
-	smb_read_super, "smbfs", 0, NULL
+static struct file_system_type smb_fs_type = {
+	"smbfs",
+	FS_NO_DCACHE,
+	smb_read_super,
+	NULL
 };
 
 __initfunc(int init_smb_fs(void))
diff -u --recursive --new-file v2.1.42/linux/fs/smbfs/mmap.c linux/fs/smbfs/mmap.c
--- v2.1.42/linux/fs/smbfs/mmap.c	Sun Dec  1 08:26:22 1996
+++ linux/fs/smbfs/mmap.c	Thu Jun 12 16:22:09 1997
@@ -120,7 +120,7 @@
 		inode->i_dirt = 1;
 	}
 	vma->vm_inode = inode;
-	inode->i_count++;
+	atomic_inc(&inode->i_count);
 	vma->vm_ops = &smb_file_mmap;
 	return 0;
 }
diff -u --recursive --new-file v2.1.42/linux/fs/stat.c linux/fs/stat.c
--- v2.1.42/linux/fs/stat.c	Fri Apr  4 08:52:24 1997
+++ linux/fs/stat.c	Thu Jun 12 16:22:09 1997
@@ -127,7 +127,7 @@
 	int error;
 
 	lock_kernel();
-	error = namei(filename,&inode);
+	error = namei(NAM_FOLLOW_LINK, filename, &inode);
 	if (error)
 		goto out;
 	if ((error = do_revalidate(inode)) == 0)
@@ -145,7 +145,7 @@
 	int error;
 
 	lock_kernel();
-	error = namei(filename,&inode);
+	error = namei(NAM_FOLLOW_LINK, filename, &inode);
 	if (error)
 		goto out;
 	if ((error = do_revalidate(inode)) == 0)
@@ -168,7 +168,7 @@
 	int error;
 
 	lock_kernel();
-	error = lnamei(filename,&inode);
+	error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode);
 	if (error)
 		goto out;
 	if ((error = do_revalidate(inode)) == 0)
@@ -187,7 +187,7 @@
 	int error;
 
 	lock_kernel();
-	error = lnamei(filename,&inode);
+	error = namei(NAM_FOLLOW_TRAILSLASH, filename, &inode);
 	if (error)
 		goto out;
 	if ((error = do_revalidate(inode)) == 0)
@@ -249,14 +249,18 @@
 	error = verify_area(VERIFY_WRITE,buf,bufsiz);
 	if (error)
 		goto out;
-	error = lnamei(path,&inode);
+	error = namei(NAM_FOLLOW_TRAILSLASH, path, &inode);
 	if (error)
 		goto out;
 	error = -EINVAL;
-	if (!inode->i_op || !inode->i_op->readlink
-	 || (error = do_revalidate(inode)) < 0) {
+	if (!inode->i_op || !inode->i_op->readlink ||
+	    !S_ISLNK(inode->i_mode) || (error = do_revalidate(inode)) < 0) {
 		iput(inode);
 		goto out;
+	}
+	if (!IS_RDONLY(inode)) {
+		inode->i_atime = CURRENT_TIME;
+		inode->i_dirt = 1;
 	}
 	error = inode->i_op->readlink(inode,buf,bufsiz);
 out:
diff -u --recursive --new-file v2.1.42/linux/fs/super.c linux/fs/super.c
--- v2.1.42/linux/fs/super.c	Thu May 29 21:53:08 1997
+++ linux/fs/super.c	Thu Jun 12 16:22:09 1997
@@ -33,6 +33,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/fd.h>
+#include <linux/dalloc.h>
 #include <linux/init.h>
 
 #include <asm/system.h>
@@ -59,8 +60,8 @@
 
 struct super_block super_blocks[NR_SUPER];
 static struct file_system_type *file_systems = (struct file_system_type *) NULL;
-static struct vfsmount *vfsmntlist = (struct vfsmount *) NULL,
-                       *vfsmnttail = (struct vfsmount *) NULL,
+struct vfsmount *vfsmntlist = (struct vfsmount *) NULL;
+static struct vfsmount *vfsmnttail = (struct vfsmount *) NULL,
                        *mru_vfsmnt = (struct vfsmount *) NULL;
 
 /* 
@@ -376,7 +377,7 @@
 	tmp = file_systems;
 	while (tmp && len < PAGE_SIZE - 80) {
 		len += sprintf(buf+len, "%s\t%s\n",
-			tmp->requires_dev ? "" : "nodev",
+			(tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev",
 			tmp->name);
 		tmp = tmp->next;
 	}
@@ -435,7 +436,7 @@
 	}
 }
 
-static struct super_block * get_super(kdev_t dev)
+struct super_block * get_super(kdev_t dev)
 {
 	struct super_block * s;
 
@@ -601,6 +602,10 @@
 	if (!sb->s_covered->i_mount)
 		printk("VFS: umount(%s): mounted inode has i_mount=NULL\n",
 		       kdevname(dev));
+	while(sb->s_ibasket)
+		free_ibasket(sb);
+	if(sb->s_mounted->i_dentry)
+		d_del(sb->s_mounted->i_dentry, D_NO_CLEAR_INODE);
 	/*
 	 * Before checking if the filesystem is still busy make sure the kernel
 	 * doesn't hold any quotafiles open on that device. If the umount fails
@@ -636,15 +641,15 @@
 {
 	struct inode * inode;
 	kdev_t dev;
+	struct inode * dummy_inode = NULL;
 	int retval = -EPERM;
-	struct inode dummy_inode;
 
 	lock_kernel();
 	if (!suser())
 		goto out;
-	retval = namei(name, &inode);
+	retval = namei(NAM_FOLLOW_LINK, name, &inode);
 	if (retval) {
-		retval = lnamei(name, &inode);
+		retval = namei(NAM_FOLLOW_TRAILSLASH, name, &inode);
 		if (retval)
 			goto out;
 	}
@@ -663,9 +668,8 @@
 		}
 		dev = inode->i_sb->s_dev;
 		iput(inode);
-		memset(&dummy_inode, 0, sizeof(dummy_inode));
-		dummy_inode.i_rdev = dev;
-		inode = &dummy_inode;
+		inode = dummy_inode = get_empty_inode();
+		inode->i_rdev = dev;
 	}
 	retval = -ENXIO;
 	if (MAJOR(dev) >= MAX_BLKDEV) {
@@ -680,8 +684,7 @@
 			put_unnamed_dev(dev);
 		}
 	}
-	if (inode != &dummy_inode)
-		iput(inode);
+	iput(inode);
 	if (!retval)
 		fsync_dev(dev);
 out:
@@ -697,22 +700,42 @@
  * We cannot mount a filesystem if it has active, used, or dirty inodes.
  * We also have to flush all inode-data for this device, as the new mount
  * might need new info.
+ *
+ * [21-Mar-97] T.Schoebel-Theuer: Now this can be overridden when
+ * supplying a leading "!" before the dir_name, allowing "stacks" of
+ * mounted filesystems. The stacking will only influence any pathname lookups
+ * _after_ the mount, but open filedescriptors or working directories that
+ * are now covered remain valid. For example, when you overmount /home, any
+ * process with old cwd /home/joe will continue to use the old versions,
+ * as long as relative paths are used, but absolute paths like /home/joe/xxx
+ * will go to the new "top of stack" version. In general, crossing a
+ * mountpoint will always go to the top of stack element.
+ * Anyone using this new feature must know what he/she is doing.
  */
 
 int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data)
 {
-	struct inode * dir_i;
+	struct inode * dir_i = NULL;
 	struct super_block * sb;
 	struct vfsmount *vfsmnt;
 	int error;
+	int override = 0;
 
+	if(dir_name) {
+		char c;
+
+		get_user(c, dir_name);
+		override = (c == '!');
+	}
 	if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
 		return -EACCES;
 		/*flags |= MS_RDONLY;*/
-	error = namei(dir_name, &dir_i);
+	if(override)
+		dir_name++;
+	error = namei(NAM_FOLLOW_LINK, dir_name, &dir_i);
 	if (error)
 		return error;
-	if (dir_i->i_count != 1 || dir_i->i_mount) {
+	if (!override && (atomic_read(&dir_i->i_count) != 1 || dir_i->i_mount)) {
 		iput(dir_i);
 		return -EBUSY;
 	}
@@ -720,7 +743,7 @@
 		iput(dir_i);
 		return -ENOTDIR;
 	}
-	if (!fs_may_mount(dev)) {
+	if (!fs_may_mount(dev) && !override) {
 		iput(dir_i);
 		return -EBUSY;
 	}
@@ -738,6 +761,22 @@
 		vfsmnt->mnt_sb = sb;
 		vfsmnt->mnt_flags = flags;
 	}
+	{
+		struct dentry * old = dir_i->i_dentry;
+		struct dentry * new;
+		vfs_lock();
+		new = d_alloc(old->d_parent, old->d_len, 1);
+		if(new) {
+			struct qstr copy = { old->d_name, old->d_len };
+			d_add(new, sb->s_mounted, &copy, D_DUPLICATE);
+			vfs_unlock();
+		} else {
+			printk("VFS: cannot setup dentry for mount\n");
+			iput(dir_i);
+			return -ENOMEM;
+		}
+		vfs_unlock();
+	}
 	sb->s_covered = dir_i;
 	dir_i->i_mount = sb->s_mounted;
 	return 0;		/* we don't iput(dir_i) - see umount */
@@ -781,7 +820,7 @@
 	struct inode *dir_i;
 	int retval;
 
-	retval = namei(dir, &dir_i);
+	retval = namei(NAM_FOLLOW_LINK, dir, &dir_i);
 	if (retval)
 		return retval;
 	if (dir_i != dir_i->i_sb->s_mounted) {
@@ -872,8 +911,8 @@
 		goto out;
 	t = fstype->name;
 	fops = NULL;
-	if (fstype->requires_dev) {
-		retval = namei(dev_name, &inode);
+	if ((fstype->fs_flags & FS_REQUIRES_DEV)) {
+		retval = namei(NAM_FOLLOW_LINK, dev_name, &inode);
 		if (retval)
 			goto out;
 		retval = -ENOTBLK;
@@ -943,7 +982,7 @@
 	struct file_system_type * fs_type;
 	struct super_block * sb;
 	struct vfsmount *vfsmnt;
-	struct inode * inode, d_inode;
+	struct inode * inode, * d_inode = NULL;
 	struct file filp;
 	int retval;
   
@@ -963,13 +1002,14 @@
 			sb->s_flags = root_mountflags & ~MS_RDONLY;
 			if (nfs_root_mount(sb) >= 0) {
 				inode = sb->s_mounted;
-				inode->i_count += 3 ;
+				atomic_add(3, &inode->i_count);
 				sb->s_covered = inode;
 				sb->s_rd_only = 0;
 				sb->s_dirt = 0;
 				sb->s_type = fs_type;
 				current->fs->pwd = inode;
 				current->fs->root = inode;
+				(void)d_alloc_root(inode);
 				ROOT_DEV = sb->s_dev;
 				printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n");
 				vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");
@@ -1000,19 +1040,20 @@
 #endif
 
 	memset(&filp, 0, sizeof(filp));
-	memset(&d_inode, 0, sizeof(d_inode));
-	d_inode.i_rdev = ROOT_DEV;
-	filp.f_inode = &d_inode;
+	d_inode = get_empty_inode();
+	d_inode->i_rdev = ROOT_DEV;
+	filp.f_inode = d_inode;
 	if ( root_mountflags & MS_RDONLY)
 		filp.f_mode = 1; /* read only */
 	else
 		filp.f_mode = 3; /* read write */
-	retval = blkdev_open(&d_inode, &filp);
+	retval = blkdev_open(d_inode, &filp);
 	if (retval == -EROFS) {
 		root_mountflags |= MS_RDONLY;
 		filp.f_mode = 1;
-		retval = blkdev_open(&d_inode, &filp);
+		retval = blkdev_open(d_inode, &filp);
 	}
+	iput(d_inode);
 	if (retval)
 	        /*
 		 * Allow the user to distinguish between failed open
@@ -1021,16 +1062,19 @@
 		printk("VFS: Cannot open root device %s\n",
 		       kdevname(ROOT_DEV));
 	else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
-  		if (!fs_type->requires_dev)
+  		if (!(fs_type->fs_flags & FS_REQUIRES_DEV))
   			continue;
   		sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
 		if (sb) {
 			inode = sb->s_mounted;
-			inode->i_count += 3 ;	/* NOTE! it is logically used 4 times, not 1 */
+
+			/* NOTE! it is logically used 4 times, not 1 */
+			atomic_add(3, &inode->i_count);
 			sb->s_covered = inode;
 			sb->s_flags = root_mountflags;
 			current->fs->pwd = inode;
 			current->fs->root = inode;
+			(void)d_alloc_root(inode);
 			printk ("VFS: Mounted root (%s filesystem)%s.\n",
 				fs_type->name,
 				(sb->s_flags & MS_RDONLY) ? " readonly" : "");
@@ -1077,11 +1121,13 @@
 	do_mount_root();
 	old_fs = get_fs();
 	set_fs(get_ds());
-        error = namei(put_old,&inode);
+        error = namei(NAM_FOLLOW_LINK, put_old, &inode);
 	if (error) inode = NULL;
 	set_fs(old_fs);
-	if (!error && (inode->i_count != 1 || inode->i_mount)) error = -EBUSY;
-	if (!error && !S_ISDIR(inode->i_mode)) error = -ENOTDIR;
+	if (!error && (atomic_read(&inode->i_count) != 1 || inode->i_mount))
+		error = -EBUSY;
+	if (!error && !S_ISDIR(inode->i_mode))
+		error = -ENOTDIR;
 	iput(old_root); /* current->fs->root */
 	iput(old_pwd); /* current->fs->pwd */
 	if (error) {
diff -u --recursive --new-file v2.1.42/linux/fs/sysv/dir.c linux/fs/sysv/dir.c
--- v2.1.42/linux/fs/sysv/dir.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/sysv/dir.c	Thu Jun 12 16:22:09 1997
@@ -57,7 +57,6 @@
 	sysv_mknod,		/* mknod */
 	sysv_rename,		/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/sysv/file.c linux/fs/sysv/file.c
--- v2.1.42/linux/fs/sysv/file.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/sysv/file.c	Thu Jun 12 16:22:09 1997
@@ -64,7 +64,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	sysv_bmap,		/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c
--- v2.1.42/linux/fs/sysv/ialloc.c	Sat Nov 30 02:24:01 1996
+++ linux/fs/sysv/ialloc.c	Thu Jun 12 16:22:09 1997
@@ -62,8 +62,9 @@
 		printk("sysv_free_inode: inode has no device\n");
 		return;
 	}
-	if (inode->i_count != 1) {
-		printk("sysv_free_inode: inode has count=%d\n", inode->i_count);
+	if (atomic_read(&inode->i_count) != 1) {
+		printk("sysv_free_inode: inode has count=%d\n",
+		       atomic_read(&inode->i_count));
 		return;
 	}
 	if (inode->i_nlink) {
@@ -149,7 +150,7 @@
 	mark_buffer_dirty(sb->sv_bh1, 1); /* super-block has been modified */
 	if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2, 1);
 	sb->s_dirt = 1; /* and needs time stamp */
-	inode->i_count = 1;
+	atomic_set(&inode->i_count, 1);
 	inode->i_nlink = 1;
 	inode->i_dev = sb->s_dev;
 	inode->i_uid = current->fsuid;
diff -u --recursive --new-file v2.1.42/linux/fs/sysv/inode.c linux/fs/sysv/inode.c
--- v2.1.42/linux/fs/sysv/inode.c	Wed Apr 23 19:01:27 1997
+++ linux/fs/sysv/inode.c	Thu Jun 12 16:22:09 1997
@@ -975,9 +975,9 @@
 /* Every kernel module contains stuff like this. */
 
 static struct file_system_type sysv_fs_type[3] = {
-	{sysv_read_super, "xenix", 1, NULL},
-	{sysv_read_super, "sysv", 1, NULL},
-	{sysv_read_super, "coherent", 1, NULL}
+	{"xenix",    FS_REQUIRES_DEV, sysv_read_super, NULL},
+	{"sysv",     FS_REQUIRES_DEV, sysv_read_super, NULL},
+	{"coherent", FS_REQUIRES_DEV, sysv_read_super, NULL}
 };
 
 __initfunc(int init_sysv_fs(void))
diff -u --recursive --new-file v2.1.42/linux/fs/sysv/namei.c linux/fs/sysv/namei.c
--- v2.1.42/linux/fs/sysv/namei.c	Sat Nov 30 02:24:01 1996
+++ linux/fs/sysv/namei.c	Thu Jun 12 16:22:09 1997
@@ -454,7 +454,7 @@
 		retval = -ENOENT;
 		goto end_rmdir;
 	}
-	if (inode->i_count > 1) {
+	if (atomic_read(&inode->i_count) > 1) {
 		retval = -EBUSY;
 		goto end_rmdir;
 	}
@@ -635,7 +635,7 @@
 	int ino;
 	int result;
 
-	new_inode->i_count++;
+	atomic_inc(&new_inode->i_count);
 	result = 0;
 	for (;;) {
 		if (new_inode == old_inode) {
@@ -668,7 +668,7 @@
  * higher-level routines.
  */
 static int do_sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len, int must_be_dir)
+			  struct inode * new_dir, const char * new_name, int new_len)
 {
 	struct inode * old_inode, * new_inode;
 	struct buffer_head * old_bh, * new_bh, * dir_bh;
@@ -694,8 +694,6 @@
 	old_inode = __iget(old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */
 	if (!old_inode)
 		goto end_rename;
-	if (must_be_dir && !S_ISDIR(old_inode->i_mode))
-		goto end_rename;
 	retval = -EPERM;
 	if ((old_dir->i_mode & S_ISVTX) && 
 	    current->fsuid != old_inode->i_uid &&
@@ -724,7 +722,7 @@
 		if (!empty_dir(new_inode))
 			goto end_rename;
 		retval = -EBUSY;
-		if (new_inode->i_count > 1)
+		if (atomic_read(&new_inode->i_count) > 1)
 			goto end_rename;
 	}
 	retval = -EPERM;
@@ -810,8 +808,7 @@
  * as they are on different partitions.
  */
 int sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len,
-	int must_be_dir)
+		struct inode * new_dir, const char * new_name, int new_len)
 {
 	static struct wait_queue * wait = NULL;
 	static int lock = 0;
@@ -821,7 +818,7 @@
 		sleep_on(&wait);
 	lock = 1;
 	result = do_sysv_rename(old_dir, old_name, old_len,
-		new_dir, new_name, new_len, must_be_dir);
+				new_dir, new_name, new_len);
 	lock = 0;
 	wake_up(&wait);
 	return result;
diff -u --recursive --new-file v2.1.42/linux/fs/sysv/symlink.c linux/fs/sysv/symlink.c
--- v2.1.42/linux/fs/sysv/symlink.c	Mon Oct 28 04:29:27 1996
+++ linux/fs/sysv/symlink.c	Thu Jun 12 16:22:09 1997
@@ -21,7 +21,6 @@
 #include <asm/uaccess.h>
 
 static int sysv_readlink(struct inode *, char *, int);
-static int sysv_follow_link(struct inode *, struct inode *, int, int, struct inode **);
 
 /*
  * symlinks can't do much...
@@ -38,7 +37,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	sysv_readlink,		/* readlink */
-	sysv_follow_link,	/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -46,44 +44,6 @@
 	NULL			/* permission */
 };
 
-static int sysv_follow_link(struct inode * dir, struct inode * inode,
-	int flag, int mode, struct inode ** res_inode)
-{
-	int error;
-	struct buffer_head * bh;
-
-	*res_inode = NULL;
-	if (!dir) {
-		dir = current->fs->root;
-		dir->i_count++;
-	}
-	if (!inode) {
-		iput(dir);
-		return -ENOENT;
-	}
-	if (!S_ISLNK(inode->i_mode)) {
-		iput(dir);
-		*res_inode = inode;
-		return 0;
-	}
-	if (current->link_count > 5) {
-		iput(inode);
-		iput(dir);
-		return -ELOOP;
-	}
-	if (!(bh = sysv_file_bread(inode, 0, 0))) { /* is reading 1 block enough ?? */
-		iput(inode);
-		iput(dir);
-		return -EIO;
-	}
-	iput(inode);
-	current->link_count++;
-	error = open_namei(bh->b_data,flag,mode,res_inode,dir);
-	current->link_count--;
-	brelse(bh);
-	return error;
-}
-
 static int sysv_readlink(struct inode * inode, char * buffer, int buflen)
 {
 	struct buffer_head * bh;
@@ -91,10 +51,6 @@
 	int i;
 	char c;
 
-	if (!S_ISLNK(inode->i_mode)) {
-		iput(inode);
-		return -EINVAL;
-	}
 	if (buflen > inode->i_sb->sv_block_size_1)
 		buflen = inode->i_sb->sv_block_size_1;
 	bh = sysv_file_bread(inode, 0, 0);
diff -u --recursive --new-file v2.1.42/linux/fs/ufs/ufs_dir.c linux/fs/ufs/ufs_dir.c
--- v2.1.42/linux/fs/ufs/ufs_dir.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/ufs/ufs_dir.c	Thu Jun 12 16:22:09 1997
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_dir.c,v 1.8 1997/01/26 07:14:28 davem Exp $
+ * $Id: ufs_dir.c,v 1.10 1997/06/05 01:29:06 davem Exp $
  *
  */
 
@@ -108,11 +108,8 @@
 				 * version stamp to detect whether or
 				 * not the directory has been modified
 				 * during the copy operation. */
-				unsigned long version;
-				dcache_add(inode, de->d_name,
-					   ufs_swab16(de->d_namlen),
-	                                   ufs_swab32(de->d_ino));
-				version = inode->i_version;
+				unsigned long version = inode->i_version;
+
 	                        if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) {
 	                                printk("ufs_readdir: filldir(%s,%u)\n",
 	                                       de->d_name, ufs_swab32(de->d_ino));
@@ -166,7 +163,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -174,13 +170,3 @@
 	NULL,			/* permission */
 	NULL,			/* smap */
 };
-
-/*
- * Local Variables: ***
- * c-indent-level: 8 ***
- * c-continued-statement-offset: 8 ***
- * c-brace-offset: -8 ***
- * c-argdecl-indent: 0 ***
- * c-label-offset: -8 ***
- * End: ***
- */
diff -u --recursive --new-file v2.1.42/linux/fs/ufs/ufs_file.c linux/fs/ufs/ufs_file.c
--- v2.1.42/linux/fs/ufs/ufs_file.c	Sun Jan 26 02:07:45 1997
+++ linux/fs/ufs/ufs_file.c	Thu Jun 12 16:22:09 1997
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_file.c,v 1.7 1997/01/26 07:14:28 davem Exp $
+ * $Id: ufs_file.c,v 1.8 1997/06/05 01:29:09 davem Exp $
  *
  */
 
@@ -41,7 +41,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	ufs_bmap,		/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/ufs/ufs_inode.c linux/fs/ufs/ufs_inode.c
--- v2.1.42/linux/fs/ufs/ufs_inode.c	Sat Nov 30 03:22:19 1996
+++ linux/fs/ufs/ufs_inode.c	Thu Jun 12 16:22:09 1997
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_inode.c,v 1.7 1996/06/01 14:56:46 ecd Exp $
+ * $Id: ufs_inode.c,v 1.8 1997/06/04 08:28:28 davem Exp $
  *
  */
 
@@ -18,8 +18,9 @@
 {
 	printk("ino %lu  mode 0%6.6o  lk %d  uid %d  gid %d"
 	       "  sz %lu  blks %lu  cnt %u\n",
-		inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid,
-		inode->i_gid, inode->i_size, inode->i_blocks, inode->i_count);
+	       inode->i_ino, inode->i_mode, inode->i_nlink, inode->i_uid,
+	       inode->i_gid, inode->i_size, inode->i_blocks,
+	       atomic_read(&inode->i_count));
 	printk("  db <0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x"
 	       " 0x%x 0x%x 0x%x 0x%x>\n",
 		inode->u.ufs_i.i_data[0], inode->u.ufs_i.i_data[1],
diff -u --recursive --new-file v2.1.42/linux/fs/ufs/ufs_super.c linux/fs/ufs/ufs_super.c
--- v2.1.42/linux/fs/ufs/ufs_super.c	Wed Apr 23 19:01:27 1997
+++ linux/fs/ufs/ufs_super.c	Thu Jun 12 16:22:09 1997
@@ -8,7 +8,7 @@
  *
  * Copyright (C) 1996  Eddie C. Dost  (ecd@skynet.be)
  *
- * $Id: ufs_super.c,v 1.23 1997/04/16 04:53:39 tdyas Exp $
+ * $Id: ufs_super.c,v 1.24 1997/06/04 08:28:29 davem Exp $
  *
  */
 
@@ -49,7 +49,10 @@
 };
 
 static struct file_system_type ufs_fs_type = {
-	ufs_read_super, "ufs", 1, NULL
+	"ufs",
+	FS_REQUIRES_DEV,
+	ufs_read_super,
+	NULL
 };
 
 __initfunc(int init_ufs_fs(void))
diff -u --recursive --new-file v2.1.42/linux/fs/ufs/ufs_symlink.c linux/fs/ufs/ufs_symlink.c
--- v2.1.42/linux/fs/ufs/ufs_symlink.c	Sun Jan 26 02:07:46 1997
+++ linux/fs/ufs/ufs_symlink.c	Thu Jun 12 16:22:09 1997
@@ -6,7 +6,7 @@
  * Laboratory for Computer Science Research Computing Facility
  * Rutgers, The State University of New Jersey
  *
- * $Id: ufs_symlink.c,v 1.7 1997/01/26 07:14:29 davem Exp $
+ * $Id: ufs_symlink.c,v 1.9 1997/06/05 01:29:11 davem Exp $
  *
  */
 
@@ -30,10 +30,6 @@
 	               inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev));
 	}
 
-	if (!S_ISLNK(inode->i_mode)) {
-		iput (inode);
-		return -EINVAL;
-	}
 	if (buflen > inode->i_sb->s_blocksize - 1)
 		buflen = inode->i_sb->s_blocksize - 1;
 	if (inode->i_blocks) {
@@ -67,73 +63,6 @@
 	return i;
 }
 
-/*
- * XXX - blatantly stolen from ext2fs
- */
-static int
-ufs_follow_link(struct inode * dir, struct inode * inode,
-	        int flag, int mode, struct inode ** res_inode)
-{
-	unsigned long int block;
-	int error;
-	struct buffer_head * bh;
-	char * link;
-
-	bh = NULL;
-
-	if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) {
-	        printk("ufs_follow_link: called on ino %lu dev %u/%u\n",
-	               dir->i_ino, MAJOR(dir->i_dev), MINOR(dir->i_dev));
-	}
-
-	*res_inode = NULL;
-	if (!dir) {
-	        dir = current->fs->root;
-	        dir->i_count++;
-	}
-	if (!inode) {
-		iput (dir);
-		return -ENOENT;
-	}
-	if (!S_ISLNK(inode->i_mode)) {
-		iput (dir);
-		*res_inode = inode;
-		return 0;
-	}
-	if (current->link_count > 5) {
-		iput (dir);
-		iput (inode);
-		return -ELOOP;
-	}
-	if (inode->i_blocks) {
-	        /* read the link from disk */
-	        /* XXX - error checking */
-	        block = ufs_bmap(inode, 0);
-	        bh = bread(inode->i_dev, block, BLOCK_SIZE);
-	        if (bh == NULL) {
-	                printk("ufs_follow_link: can't read block 0 for ino %lu on dev %u/%u\n",
-	                       inode->i_ino, MAJOR(inode->i_dev),
-	                       MINOR(inode->i_dev));
-	                iput(dir);
-	                iput(inode);
-	                return(-EIO);
-	        }
-	        link = bh->b_data;
-	} else {
-	        /* fast symlink */
-	        link = (char *)&(inode->u.ufs_i.i_data[0]);
-	}
-	current->link_count++;
-	error = open_namei (link, flag, mode, res_inode, dir);
-	current->link_count--;
-	iput (inode);
-	if (bh) {
-		brelse (bh);
-	}
-	return(error);
-}
-
-
 static struct file_operations ufs_symlink_operations = {
 	NULL,			/* lseek */
 	NULL,			/* read */
@@ -161,8 +90,7 @@
 	NULL,			/* rmdir */
 	NULL,			/* mknod */
 	NULL,			/* rename */
-	&ufs_readlink,		/* readlink */
-	&ufs_follow_link,	/* follow_link */
+	ufs_readlink,		/* readlink */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/dir.c linux/fs/umsdos/dir.c
--- v2.1.42/linux/fs/umsdos/dir.c	Sun Jan 26 02:07:46 1997
+++ linux/fs/umsdos/dir.c	Thu Jun 12 16:22:09 1997
@@ -565,7 +565,7 @@
 				}
 			}
 		}else{
-			dir->i_count++;
+			atomic_inc(&dir->i_count);
 		}
 		if (ret == 0){
 			while (dir != dir->i_sb->s_mounted){
@@ -628,7 +628,7 @@
 	umsdos_startlookup(dir);	
 	if (len == 1 && name[0] == '.'){
 		*result = dir;
-		dir->i_count++;
+		atomic_inc(&dir->i_count);
 		ret = 0;
 	}else if (len == 2 && name[0] == '.' && name[1] == '.'){
 		if (pseudo_root != NULL && dir == pseudo_root->i_sb->s_mounted){
@@ -639,7 +639,7 @@
 			*/
 			ret = 0;
 			*result = pseudo_root;
-			pseudo_root->i_count++;
+			atomic_inc(&pseudo_root->i_count);
 		}else{
 			/* #Specification: locating .. / strategy
 				We use the msdos filesystem to locate the parent directory.
@@ -668,7 +668,7 @@
 			and return the inode of the real root.
 		*/
 		*result = dir->i_sb->s_mounted;
-		(*result)->i_count++;
+		atomic_inc(&((*result)->i_count));
 		ret = 0;
 	}else{
 		struct umsdos_info info;
@@ -757,7 +757,7 @@
 			dir = hlink->i_sb->s_mounted;
 			path[hlink->i_size] = '\0';
 			iput (hlink);
-			dir->i_count++;
+			atomic_inc(&dir->i_count);
 			while (1){
 				char *start = pt;
 				int len;
@@ -811,7 +811,6 @@
 	UMSDOS_mknod,		/* mknod */
 	UMSDOS_rename,		/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/emd.c linux/fs/umsdos/emd.c
--- v2.1.42/linux/fs/umsdos/emd.c	Thu Mar 27 14:40:06 1997
+++ linux/fs/umsdos/emd.c	Thu Jun 12 16:22:09 1997
@@ -137,7 +137,8 @@
 	if (dir->u.umsdos_i.i_emd_dir != 0){
 		ret = iget (dir->i_sb,dir->u.umsdos_i.i_emd_dir);
 		PRINTK (("deja trouve %d %x [%d] "
-			,dir->u.umsdos_i.i_emd_dir,ret,ret->i_count));
+			,dir->u.umsdos_i.i_emd_dir,ret,
+			 atomic_read(&ret->i_count)));
 	}else{
 		umsdos_real_lookup (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN,&ret);
 		PRINTK (("emd_dir_lookup "));
@@ -147,7 +148,7 @@
 		}else if (creat){
 			int code;
 			PRINTK (("avant create "));
-			dir->i_count++;
+			atomic_inc(&dir->i_count);
 			code = msdos_create (dir,UMSDOS_EMD_FILE,UMSDOS_EMD_NAMELEN
 				,S_IFREG|0777,&ret);
 			PRINTK (("Creat EMD code %d ret %x ",code,ret));
diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/file.c linux/fs/umsdos/file.c
--- v2.1.42/linux/fs/umsdos/file.c	Sun Jan 26 02:07:46 1997
+++ linux/fs/umsdos/file.c	Thu Jun 12 16:22:09 1997
@@ -86,7 +86,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	generic_readpage,	/* readpage */
 	NULL,			/* writepage */
 	fat_bmap,		/* bmap */
@@ -120,7 +119,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/inode.c linux/fs/umsdos/inode.c
--- v2.1.42/linux/fs/umsdos/inode.c	Wed Apr 23 19:01:27 1997
+++ linux/fs/umsdos/inode.c	Thu Jun 12 16:22:09 1997
@@ -73,7 +73,7 @@
 	struct inode **result)	/* Will hold inode of the file, if successful */
 {
 	int ret;
-	dir->i_count++;
+	atomic_inc(&dir->i_count);
 	ret = msdos_lookup (dir,name,len,result);
 	return ret;
 }
@@ -120,7 +120,7 @@
 #elif 0
 	return inode->i_atime != 0;
 #else
-	return inode->i_count > 1;
+	return atomic_read(&inode->i_count) > 1;
 #endif
 }
 /*
@@ -224,7 +224,7 @@
 {
 	PRINTK (("read inode %x ino = %d ",inode,inode->i_ino));
 	msdos_read_inode(inode);
-	PRINTK (("ino = %d %d\n",inode->i_ino,inode->i_count));
+	PRINTK (("ino = %d %d\n",inode->i_ino,atomic_read(&inode->i_count)));
 	if (S_ISDIR(inode->i_mode)
 		&& (inode->u.umsdos_i.u.dir_info.creating != 0
 			|| inode->u.umsdos_i.u.dir_info.looking != 0
@@ -480,7 +480,7 @@
 					umsdos_setup_dir_inode (pseudo);
 					Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME));
 					pseudo_root = pseudo;
-					pseudo->i_count++;
+					atomic_inc(&pseudo->i_count);
 					pseudo = NULL;
 				}
 				iput (sbin);
@@ -497,7 +497,10 @@
 
 
 static struct file_system_type umsdos_fs_type = {
-	UMSDOS_read_super, "umsdos", 1, NULL
+	"umsdos",
+	FS_REQUIRES_DEV,
+	UMSDOS_read_super,
+	NULL
 };
 
 __initfunc(int init_umsdos_fs(void))
diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/ioctl.c linux/fs/umsdos/ioctl.c
--- v2.1.42/linux/fs/umsdos/ioctl.c	Mon Oct 28 04:29:27 1996
+++ linux/fs/umsdos/ioctl.c	Thu Jun 12 16:22:09 1997
@@ -215,11 +215,11 @@
 					This ioctl allows umssync to rename a mangle file
 					name before syncing it back in the EMD.
 				*/
-				dir->i_count += 2;
+				atomic_add(2, &dir->i_count);
 				ret = msdos_rename (dir
 					,data.dos_dirent.d_name,data.dos_dirent.d_reclen
 					,dir
-					,data.umsdos_dirent.name,data.umsdos_dirent.name_len,0);
+					,data.umsdos_dirent.name,data.umsdos_dirent.name_len);
 			}else if (cmd == UMSDOS_UNLINK_EMD){
 				/* #Specification: ioctl / UMSDOS_UNLINK_EMD
 					The umsdos_dirent field of the struct umsdos_ioctl is used
@@ -246,7 +246,7 @@
 
 					Return 0 if success.
 				*/
-				dir->i_count++;
+				atomic_inc(&dir->i_count);
 				ret = msdos_unlink (dir,data.dos_dirent.d_name
 					,data.dos_dirent.d_reclen);
 			}else if (cmd == UMSDOS_RMDIR_DOS){
@@ -257,7 +257,7 @@
 
 					Return 0 if success.
 				*/
-				dir->i_count++;
+				atomic_inc(&dir->i_count);
 				ret = msdos_rmdir (dir,data.dos_dirent.d_name
 					,data.dos_dirent.d_reclen);
 			}else if (cmd == UMSDOS_STAT_DOS){
diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/namei.c linux/fs/umsdos/namei.c
--- v2.1.42/linux/fs/umsdos/namei.c	Tue May 13 22:41:15 1997
+++ linux/fs/umsdos/namei.c	Thu Jun 12 16:22:09 1997
@@ -225,13 +225,14 @@
 			umsdos_lockcreate(dir);
 			ret = umsdos_newentry (dir,&info);
 			if (ret == 0){
-				dir->i_count++;
+				atomic_inc(&dir->i_count);
 				ret = msdos_create (dir,info.fake.fname,info.fake.len
 					,S_IFREG|0777,result);
 				if (ret == 0){
 					struct inode *inode = *result;
 					umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
-					PRINTK (("inode %p[%d] ",inode,inode->i_count));
+					PRINTK (("inode %p[%d] ",inode,
+						 atomic_read(&inode->i_count)));
 					PRINTK (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino
 						,info.fake.fname,current->pid,info.f_pos));
 				}else{
@@ -351,13 +352,12 @@
 					PRINTK (("ret %d %d ",ret,new_info.fake.len));
 					if (ret == 0){
 						PRINTK (("msdos_rename "));
-						old_dir->i_count++;
-						new_dir->i_count++;	/* Both inode are needed later */
+						atomic_inc(&old_dir->i_count);
+						atomic_inc(&new_dir->i_count);	/* Both inode are needed later */
 						ret = msdos_rename (old_dir
 								    ,old_info.fake.fname,old_info.fake.len
 								    ,new_dir
-								    ,new_info.fake.fname,new_info.fake.len
-								    ,0);
+								    ,new_info.fake.fname,new_info.fake.len);
 chkstk();
 						PRINTK (("after m_rename ret %d ",ret));
 						if (ret != 0){
@@ -378,7 +378,7 @@
 								   Not very efficient ...
 								   */
 								struct inode *inode;
-								new_dir->i_count++;
+								atomic_inc(&new_dir->i_count);
 								PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
 								ret = UMSDOS_lookup (new_dir,new_name,new_len
 										     ,&inode);
@@ -441,7 +441,7 @@
 	*/
 	struct inode *inode;
 	int ret;
-	dir->i_count++;		/* We keep the inode in case we need it */
+	atomic_inc(&dir->i_count);/* We keep the inode in case we need it */
 						/* later */
 	ret = umsdos_create_any (dir,name,len,mode,0,flags,&inode);
 	PRINTK (("umsdos_symlink ret %d ",ret));
@@ -572,7 +572,8 @@
 		struct inode *olddir;
 		ret = umsdos_get_dirowner(oldinode,&olddir);
 		PRINTK (("umsdos_link dir_owner = %d -> %p [%d] "
-			,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count));
+			,oldinode->u.umsdos_i.i_dir_owner,olddir,
+			 atomic_read(&olddir->i_count)));
 		if (ret == 0){
 			struct umsdos_dirent entry;
 			umsdos_lockcreate2(dir,olddir);
@@ -596,8 +597,9 @@
 					struct umsdos_info info;
 					ret = umsdos_newhidden (olddir,&info);
 					if (ret == 0){
-						olddir->i_count+=2;
-						PRINTK (("olddir[%d] ",olddir->i_count));
+						atomic_add(2, &olddir->i_count);
+						PRINTK (("olddir[%d] ",
+							 atomic_read(&olddir->i_count)));
 						ret = umsdos_rename_f (olddir,entry.name
 							,entry.name_len
 							,olddir,info.entry.name,info.entry.name_len
@@ -607,17 +609,19 @@
 							if (path == NULL){
 								ret = -ENOMEM;
 							}else{
-								PRINTK (("olddir[%d] ",olddir->i_count));
+								PRINTK (("olddir[%d] ",
+									 atomic_read(&olddir->i_count)));
 								ret = umsdos_locate_path (oldinode,path);
-								PRINTK (("olddir[%d] ",olddir->i_count));
+								PRINTK (("olddir[%d] ",
+									 atomic_read(&olddir->i_count)));
 								if (ret == 0){
-									olddir->i_count++;
+									atomic_inc(&olddir->i_count);
 									ret = umsdos_symlink_x (olddir
 										,entry.name
 										,entry.name_len,path
 										,S_IFREG|0777,UMSDOS_HLINK);
 									if (ret == 0){
-										dir->i_count++;
+										atomic_inc(&dir->i_count);
 										ret = umsdos_symlink_x (dir,name,len
 											,path
 											,S_IFREG|0777,UMSDOS_HLINK);
@@ -634,7 +638,7 @@
 					}else{
 						ret = umsdos_locate_path (oldinode,path);
 						if (ret == 0){
-							dir->i_count++;
+							atomic_inc(&dir->i_count);
 							ret = umsdos_symlink_x (dir,name,len,path
 											,S_IFREG|0777,UMSDOS_HLINK);
 						}
@@ -703,7 +707,7 @@
 			ret = umsdos_newentry (dir,&info);
 			PRINTK (("newentry %d ",ret));
 			if (ret == 0){
-				dir->i_count++;
+				atomic_inc(&dir->i_count);
 				ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode);
 				if (ret != 0){
 					umsdos_delentry (dir,&info,1);
@@ -869,16 +873,17 @@
 	int ret = umsdos_nevercreat(dir,name,len,-EPERM);
 	if (ret == 0){
 		struct inode *sdir;
-		dir->i_count++;
+		atomic_inc(&dir->i_count);
 		ret = UMSDOS_lookup (dir,name,len,&sdir);
 		PRINTK (("rmdir lookup %d ",ret));
 		if (ret == 0){
 			int empty;
 			umsdos_lockcreate(dir);
-			if (sdir->i_count > 1){
+			if (atomic_read(&sdir->i_count) > 1){
 				ret = -EBUSY;
 			}else if ((empty = umsdos_isempty (sdir)) != 0){
-				PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
+				PRINTK (("isempty %d i_count %d ",empty,
+					 atomic_read(&sdir->i_count)));
 				/* check sticky bit */
 				if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
 				    current->fsuid == sdir->i_uid ||
@@ -895,7 +900,7 @@
 					PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
 					if (ret == 0){
 						struct umsdos_info info;
-						dir->i_count++;
+						atomic_inc(&dir->i_count);
 						umsdos_parse (name,len,&info);
 						/* The findentry is there only to complete */
 						/* the mangling */
@@ -960,7 +965,7 @@
 						   using the standard lookup function.
 						   */
 						struct inode *inode;
-						dir->i_count++;
+						atomic_inc(&dir->i_count);
 						ret = UMSDOS_lookup (dir,name,len,&inode);
 						if (ret == 0){
 							PRINTK (("unlink nlink = %d ",inode->i_nlink));
@@ -988,7 +993,7 @@
 						ret = umsdos_delentry (dir,&info,0);
 						if (ret == 0){
 							PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
-							dir->i_count++;
+							atomic_inc(&dir->i_count);
 							ret = msdos_unlink_umsdos (dir,info.fake.fname
 										   ,info.fake.len);
 							PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname
@@ -1018,8 +1023,7 @@
 	int old_len,
 	struct inode * new_dir,
 	const char * new_name,
-	int new_len,
-	int must_be_dir)
+	int new_len)
 {
 	/* #Specification: weakness / rename
 		There is a case where UMSDOS rename has a different behavior
@@ -1036,8 +1040,8 @@
 	int ret = umsdos_nevercreat(new_dir,new_name,new_len,-EEXIST);
 	if (ret == 0){
 		/* umsdos_rename_f eat the inode and we may need those later */
-		old_dir->i_count++;
-		new_dir->i_count++;
+		atomic_inc(&old_dir->i_count);
+		atomic_inc(&new_dir->i_count);
 		ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name
 			,new_len,0);
 		if (ret == -EEXIST){
@@ -1075,12 +1079,12 @@
 				is a problem at all.
 			*/
 			/* This is not super efficient but should work */
-			new_dir->i_count++;
+			atomic_inc(&new_dir->i_count);
 			ret = UMSDOS_unlink (new_dir,new_name,new_len);
 chkstk();
 			PRINTK (("rename unlink ret %d %d -- ",ret,new_len));
 			if (ret == -EISDIR){
-				new_dir->i_count++;
+				atomic_inc(&new_dir->i_count);
 				ret = UMSDOS_rmdir (new_dir,new_name,new_len);
 chkstk();
 				PRINTK (("rename rmdir ret %d -- ",ret));
diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/rdir.c linux/fs/umsdos/rdir.c
--- v2.1.42/linux/fs/umsdos/rdir.c	Sun Jan 26 02:07:46 1997
+++ linux/fs/umsdos/rdir.c	Thu Jun 12 16:22:09 1997
@@ -96,7 +96,7 @@
 		&& dir == dir->i_sb->s_mounted
 		&& dir == pseudo_root->i_sb->s_mounted){
 		*result = pseudo_root;
-		pseudo_root->i_count++;
+		atomic_inc(&pseudo_root->i_count);
 		ret = 0;
 		/* #Specification: pseudo root / DOS/..
 			In the real root directory (c:\), the directory ..
@@ -165,17 +165,18 @@
 		ret = -EPERM;
 	}else{
 		umsdos_lockcreate (dir);
-		dir->i_count++;
+		atomic_inc(&dir->i_count);
 		ret = msdos_rmdir (dir,name,len);
 		if (ret == -ENOTEMPTY){
 			struct inode *sdir;
-			dir->i_count++;
+			atomic_inc(&dir->i_count);
 			ret = UMSDOS_rlookup (dir,name,len,&sdir);
 			PRINTK (("rrmdir lookup %d ",ret));
 			if (ret == 0){
 				int empty;
 				if ((empty = umsdos_isempty (sdir)) != 0){
-					PRINTK (("isempty %d i_count %d ",empty,sdir->i_count));
+					PRINTK (("isempty %d i_count %d ",empty,
+						 atomic_read(&sdir->i_count)));
 					if (empty == 2){
 						/*
 							Not a Umsdos directory, so the previous msdos_rmdir
@@ -188,7 +189,7 @@
 							,UMSDOS_EMD_NAMELEN);
 						sdir = NULL;
 						if (ret == 0){
-							dir->i_count++;
+							atomic_inc(&dir->i_count);
 							ret = msdos_rmdir (dir,name,len);
 						}
 					}
@@ -260,7 +261,6 @@
 	NULL,				/* mknod */
 	msdos_rename,		/* rename */
 	NULL,				/* readlink */
-	NULL,				/* follow_link */
 	NULL,				/* readpage */
 	NULL,				/* writepage */
 	NULL,				/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/umsdos/symlink.c linux/fs/umsdos/symlink.c
--- v2.1.42/linux/fs/umsdos/symlink.c	Sun Jan 26 02:07:46 1997
+++ linux/fs/umsdos/symlink.c	Thu Jun 12 16:22:09 1997
@@ -42,69 +42,12 @@
 	}
 	return ret;
 }
-/*
-	Follow a symbolic link chain by calling open_namei recursively
-	until an inode is found.
-
-	Return 0 if ok, or a negative error code if not.
-*/
-static int UMSDOS_follow_link(
-	struct inode * dir,
-	struct inode * inode,
-	int flag,
-	int mode,
-	struct inode ** res_inode)
-{
-	int ret = -ELOOP;
-	*res_inode = NULL;
-	if (current->link_count < 5) {
-		char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
-		if (path == NULL){
-			ret = -ENOMEM;
-		}else{
-			if (!dir) {
-				dir = current->fs[1].root;
-				dir->i_count++;
-			}
-			if (!inode){
-				PRINTK (("symlink: inode = NULL\n"));
-				ret = -ENOENT;
-			}else if (!S_ISLNK(inode->i_mode)){
-				PRINTK (("symlink: Not ISLNK\n"));
-				*res_inode = inode;
-				inode = NULL;
-				ret = 0;
-			}else{
-				ret = umsdos_readlink_x (inode,path
-					,umsdos_file_read_kmem,PATH_MAX-1);
-				if (ret > 0){
-					path[ret] = '\0';
-					PRINTK (("follow :%s: %d ",path,ret));
-					iput(inode);
-					inode = NULL;
-					current->link_count++;
-					ret = open_namei(path,flag,mode,res_inode,dir);
-					current->link_count--;
-					dir = NULL;
-				}else{
-					ret = -EIO;
-				}
-			}
-			kfree (path);
-		}
-	}	
-	iput(inode);
-	iput(dir);
-	PRINTK (("follow_link ret %d\n",ret));
-	return ret;
-}
 
 static int UMSDOS_readlink(struct inode * inode, char * buffer, int buflen)
 {
-	int ret = -EINVAL;
-	if (S_ISLNK(inode->i_mode)) {
-		ret = umsdos_readlink_x (inode,buffer,fat_file_read,buflen);
-	}
+	int ret;
+
+	ret = umsdos_readlink_x (inode,buffer,fat_file_read,buflen);
 	PRINTK (("readlink %d %x bufsiz %d\n",ret,inode->i_mode,buflen));
 	iput(inode);
 	return ret;
@@ -136,7 +79,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	UMSDOS_readlink,	/* readlink */
-	UMSDOS_follow_link,	/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/fs/vfat/namei.c linux/fs/vfat/namei.c
--- v2.1.42/linux/fs/vfat/namei.c	Tue May 13 22:41:15 1997
+++ linux/fs/vfat/namei.c	Thu Jun 12 16:22:09 1997
@@ -937,12 +937,6 @@
 		if (!(*result = iget(dir->i_sb,ino))) return -EACCES;
 		return 0;
 	}
-	if (dcache_lookup(dir, name, len, (unsigned long *) &ino) && ino) {
-		iput(dir);
-		if (!(*result = iget(dir->i_sb, ino)))
-			return -EACCES;
-		return 0;
-	}
 	PRINTK (("vfat_lookup 3\n"));
 	if ((res = vfat_find(dir,name,len,1,0,0,&sinfo)) < 0) {
 		iput(dir);
@@ -1019,7 +1013,6 @@
 	(*result)->i_dirt = 1;
 	(*result)->i_version = ++event;
 	dir->i_version = event;
-	dcache_add(dir, name, len, ino);
 
 	return 0;
 }
@@ -1132,7 +1125,7 @@
 	struct buffer_head *bh;
 	struct msdos_dir_entry *de;
 
-	if (dir->i_count > 1)
+	if (atomic_read(&dir->i_count) > 1)
 		return -EBUSY;
 	if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */
 		pos = 0;
@@ -1356,7 +1349,7 @@
 
 
 int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
-	struct inode *new_dir,const char *new_name,int new_len,int must_be_dir)
+		struct inode *new_dir,const char *new_name,int new_len)
 {
 	struct super_block *sb = old_dir->i_sb;
 	struct buffer_head *old_bh,*new_bh,*dotdot_bh;
@@ -1391,8 +1384,6 @@
 	if (!(old_inode = iget(old_dir->i_sb,old_ino)))
 		goto rename_done;
 	is_dir = S_ISDIR(old_inode->i_mode);
-	if (must_be_dir && !is_dir)
-		goto rename_done;
 	if (is_dir) {
 		if ((old_dir->i_dev != new_dir->i_dev) ||
 		    (old_ino == new_dir->i_ino)) {
@@ -1504,7 +1495,6 @@
 	PRINTK(("vfat_rename 15b\n"));
 
 	fat_mark_buffer_dirty(sb, new_bh, 1);
-	dcache_add(new_dir, new_name, new_len, new_ino);
 
 	/* XXX: There is some code in the original MSDOS rename that
 	 * is not duplicated here and it might cause a problem in
@@ -1562,7 +1552,6 @@
 	NULL,			/* mknod */
 	vfat_rename,		/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	fat_bmap,		/* bmap */
@@ -1577,7 +1566,10 @@
 }
 
 static struct file_system_type vfat_fs_type = {
-	vfat_read_super, "vfat", 1, NULL
+	"vfat",
+	FS_REQUIRES_DEV,
+	vfat_read_super,
+	NULL
 };
 
 EXPORT_SYMBOL(vfat_create);
diff -u --recursive --new-file v2.1.42/linux/include/asm-alpha/byteorder.h linux/include/asm-alpha/byteorder.h
--- v2.1.42/linux/include/asm-alpha/byteorder.h	Thu Nov 14 05:36:13 1996
+++ linux/include/asm-alpha/byteorder.h	Thu Jun 12 16:22:09 1997
@@ -14,90 +14,65 @@
 #define __LITTLE_ENDIAN_BITFIELD
 #endif
 
-#ifdef __KERNEL__
-
-/*
- * In-kernel byte order macros to handle stuff like
- * byte-order-dependent filesystems etc.
- */
-#define cpu_to_le32(x) (x)
-#define le32_to_cpu(x) (x)
-#define cpu_to_le16(x) (x)
-#define le16_to_cpu(x) (x)
-
-#define cpu_to_be32(x) htonl((x))
-#define be32_to_cpu(x) ntohl((x))
-#define cpu_to_be16(x) htons((x))
-#define be16_to_cpu(x) ntohs((x))
-
-#endif /* __KERNEL__ */
-
-extern unsigned long int	ntohl(unsigned long int);
+extern unsigned int		ntohl(unsigned int);
 extern unsigned short int	ntohs(unsigned short int);
-extern unsigned long int	htonl(unsigned long int);
+extern unsigned int		htonl(unsigned int);
 extern unsigned short int	htons(unsigned short int);
 
-extern unsigned long int	__ntohl(unsigned long int);
+extern unsigned int		__ntohl(unsigned int);
 extern unsigned short int	__ntohs(unsigned short int);
 
 #ifdef __GNUC__
 
-extern unsigned long int	__constant_ntohl(unsigned long int);
+extern unsigned int		__constant_ntohl(unsigned int);
 extern unsigned short int	__constant_ntohs(unsigned short int);
 
-/*
- * The constant and non-constant versions here are the same.
- * Maybe I'll come up with an alpha-optimized routine for the
- * non-constant ones (the constant ones don't need it: gcc
- * will optimize it to the correct constant)
- */
-
-extern __inline__ unsigned long int
-__ntohl(unsigned long int x)
+extern __inline__ unsigned int
+__ntohl(unsigned int x)
 {
-	unsigned long int res, t1, t2;
+	unsigned int t1, t2, t3;
+
+	/* Break the final or's out of the block so that gcc can
+	   schedule them at will.  Further, use add not or so that
+	   we elide the sign extend gcc will put in because the
+	   return type is not a long.  */
 
 	__asm__(
-	"# bswap input: %0 (aabbccdd)\n\t"
-	"# output: %0, used %1 %2\n\t"
-	"extlh	%0,5,%1		# %1 = dd000000\n\t"
-	"zap	%0,0xfd,%2	# %2 = 0000cc00\n\t"
-	"sll	%2,5,%2		# %2 = 00198000\n\t"
-	"s8addq	%2,%1,%1	# %1 = ddcc0000\n\t"
-	"zap	%0,0xfb,%2	# %2 = 00bb0000\n\t"
-	"srl	%2,8,%2		# %2 = 0000bb00\n\t"
-	"extbl	%0,3,%0		# %0 = 000000aa\n\t"
-	"or	%1,%0,%0	# %0 = ddcc00aa\n\t"
-	"or	%2,%0,%0	# %0 = ddccbbaa\n"
-	: "r="(res), "r="(t1), "r="(t2)
-	: "0" (x & 0xffffffffUL));
-	return res;
+	"insbl	%3,3,%1		# %1 = dd000000\n\t"
+	"zapnot	%3,2,%2		# %2 = 0000cc00\n\t"
+	"sll	%2,8,%2		# %2 = 00cc0000\n\t"
+	"or	%2,%1,%1	# %1 = ddcc0000\n\t"
+	"zapnot	%3,4,%2		# %2 = 00bb0000\n\t"
+	"extbl	%3,3,%0		# %0 = 000000aa\n\t"
+	"srl	%2,8,%2		# %2 = 0000bb00"
+	: "=r"(t3), "=&r"(t1), "=&r"(t2)
+	: "r"(x));
+
+	return t3 + t2 + t1;
 }
 
 #define __constant_ntohl(x) \
-   ((unsigned long int)((((x) & 0x000000ffUL) << 24) | \
-			(((x) & 0x0000ff00UL) <<  8) | \
-			(((x) & 0x00ff0000UL) >>  8) | \
-			(((x) & 0xff000000UL) >> 24)))
+   ((unsigned int)((((x) & 0x000000ff) << 24) | \
+		   (((x) & 0x0000ff00) <<  8) | \
+		   (((x) & 0x00ff0000) >>  8) | \
+		   (((x) & 0xff000000) >> 24)))
 
 extern __inline__ unsigned short int
 __ntohs(unsigned short int x)
 {
-	unsigned long int res, t1;
+	unsigned short int t1, t2;
 	
 	__asm__(
-	"# v0 is result; swap in-place.\n\t"
-	"bis	%2,%2,%0	# v0 = aabb\n\t"
-	"extwh	%0,7,%1		# t1 = bb00\n\t"
-	"extbl	%0,1,%0		# v0 = 00aa\n\t"
-	"bis	%0,%1,%0	# v0 = bbaa\n"
-	: "r="(res), "r="(t1) : "r"(x));
-	return res;
+	"insbl	%2,1,%1		# %1 = bb00\n\t"
+	"extbl	%2,1,%0		# %0 = 00aa"
+	: "=r"(t1), "=&r"(t2) : "r"(x));
+
+	return t1 | t2;
 }
 
 #define __constant_ntohs(x) \
-((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
-		      (((unsigned short int)(x) & 0xff00) >> 8)))
+((unsigned short int)((((x) & 0x00ff) << 8) | \
+		      (((x) & 0xff00) >> 8)))
 
 #define __htonl(x) __ntohl(x)
 #define __htons(x) __ntohs(x)
@@ -124,5 +99,70 @@
 #endif /* __OPTIMIZE__ */
 
 #endif /* __GNUC__ */
+
+#ifdef __KERNEL__
+
+/*
+ * In-kernel byte order macros to handle stuff like
+ * byte-order-dependent filesystems etc.
+ */
+#define cpu_to_le32(x) (x)
+#define cpu_to_le16(x) (x)
+
+#define cpu_to_be32(x) htonl((x))
+#define cpu_to_be16(x) htons((x))
+
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
+{
+	return cpu_to_le16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
+{
+	return cpu_to_le32(*addr);
+}
+
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
+{
+	return cpu_to_be16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
+{
+	return cpu_to_be32(*addr);
+}
+
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+#define cpu_to_le16s(x) do { } while (0)
+#define cpu_to_le32s(x) do { } while (0)
+
+extern __inline__ void cpu_to_be16s(__u16 *addr)
+{
+	*addr = cpu_to_be16(*addr);
+}
+
+extern __inline__ void cpu_to_be32s(__u32 *addr)
+{
+	*addr = cpu_to_be32(*addr);
+}
+
+/* Convert from specified byte order, to CPU byte order. */
+#define le16_to_cpu(x)  cpu_to_le16(x)
+#define le32_to_cpu(x)  cpu_to_le32(x)
+#define be16_to_cpu(x)  cpu_to_be16(x)
+#define be32_to_cpu(x)  cpu_to_be32(x)
+
+#define le16_to_cpup(x) cpu_to_le16p(x)
+#define le32_to_cpup(x) cpu_to_le32p(x)
+#define be16_to_cpup(x) cpu_to_be16p(x)
+#define be32_to_cpup(x) cpu_to_be32p(x)
+
+#define le16_to_cpus(x) cpu_to_le16s(x)
+#define le32_to_cpus(x) cpu_to_le32s(x)
+#define be16_to_cpus(x) cpu_to_be16s(x)
+#define be32_to_cpus(x) cpu_to_be32s(x)
+
+#endif /* __KERNEL__ */
 
 #endif /* _ALPHA_BYTEORDER_H */
diff -u --recursive --new-file v2.1.42/linux/include/asm-alpha/fpu.h linux/include/asm-alpha/fpu.h
--- v2.1.42/linux/include/asm-alpha/fpu.h	Thu Dec 21 22:22:06 1995
+++ linux/include/asm-alpha/fpu.h	Thu Jun 12 16:22:09 1997
@@ -57,8 +57,28 @@
 				 IEEE_STATUS_OVF | IEEE_STATUS_UNF |	\
 				 IEEE_STATUS_INE)
 
+#define IEEE_SW_MASK		(IEEE_TRAP_ENABLE_MASK | IEEE_STATUS_MASK)
+
 #define IEEE_STATUS_TO_EXCSUM_SHIFT	16
 
 #define IEEE_INHERIT    (1UL<<63)	/* inherit on thread create? */
+
+/*
+ * Convert the spftware IEEE trap enable and status bits into the
+ * hardware fpcr format.
+ */
+
+static inline unsigned long
+ieee_swcr_to_fpcr(unsigned long sw)
+{
+	unsigned long fp;
+	fp = (sw & IEEE_STATUS_MASK) << 35;
+	fp |= sw & IEEE_STATUS_MASK ? FPCR_SUM : 0;
+	fp |= (~sw & (IEEE_TRAP_ENABLE_INV
+		      | IEEE_TRAP_ENABLE_DZE
+		      | IEEE_TRAP_ENABLE_OVF)) << 48;
+	fp |= (~sw & (IEEE_TRAP_ENABLE_UNF | IEEE_TRAP_ENABLE_INE)) << 57;
+	return fp;
+}
 
 #endif /* __ASM_ALPHA_FPU_H */
diff -u --recursive --new-file v2.1.42/linux/include/asm-alpha/keyboard.h linux/include/asm-alpha/keyboard.h
--- v2.1.42/linux/include/asm-alpha/keyboard.h	Sat May 24 09:10:24 1997
+++ linux/include/asm-alpha/keyboard.h	Thu Jun 12 16:22:09 1997
@@ -16,10 +16,6 @@
 #define KEYBOARD_IRQ			1
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 
-#define KBD_REPORT_ERR
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
-
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
 extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
diff -u --recursive --new-file v2.1.42/linux/include/asm-alpha/namei.h linux/include/asm-alpha/namei.h
--- v2.1.42/linux/include/asm-alpha/namei.h	Sun Jan 26 02:07:46 1997
+++ linux/include/asm-alpha/namei.h	Thu Jun 12 16:22:09 1997
@@ -7,15 +7,12 @@
 #ifndef __ALPHA_NAMEI_H
 #define __ALPHA_NAMEI_H
 
-/* These dummy routines maybe changed to something useful
+/* This dummy routine maybe changed to something useful
  * for /usr/gnemul/ emulation stuff.
  * Look at asm-sparc/namei.h for details.
  */
 
-#define translate_namei(pathname, base, follow_links, res_inode)	\
-	do { } while (0)
-
-#define translate_open_namei(pathname, flag, mode, res_inode, base) \
-	do { } while (0)
+#define __prefix_namei(retrieve_mode, name, base, buf, res_dir, res_inode, \
+		       last_name, last_entry, last_error) 1
 
 #endif /* __ALPHA_NAMEI_H */
diff -u --recursive --new-file v2.1.42/linux/include/asm-alpha/processor.h linux/include/asm-alpha/processor.h
--- v2.1.42/linux/include/asm-alpha/processor.h	Tue May 13 22:41:15 1997
+++ linux/include/asm-alpha/processor.h	Thu Jun 12 16:22:09 1997
@@ -43,6 +43,7 @@
 	/* the fields below are Linux-specific: */
 	/* bit 1..5: IEEE_TRAP_ENABLE bits (see fpu.h) */
 	/* bit 6..8: UAC bits (see sysinfo.h) */
+	/* bit 17..21: IEEE_STATUS_MASK bits (see fpu.h) */
 	unsigned long flags;
 	/* perform syscall argument validation (get/set_fs) */
 	unsigned long fs;
diff -u --recursive --new-file v2.1.42/linux/include/asm-i386/bugs.h linux/include/asm-i386/bugs.h
--- v2.1.42/linux/include/asm-i386/bugs.h	Thu Jun 12 15:28:33 1997
+++ linux/include/asm-i386/bugs.h	Sun Jun 15 15:12:29 1997
@@ -35,7 +35,7 @@
 	fpu_error = 1;
 	timer_table[COPRO_TIMER].expires = jiffies+100;
 	timer_active |= 1<<COPRO_TIMER;
-	printk("387 failed: trying to reset\n");
+	printk(KERN_ERR "387 failed: trying to reset\n");
 	send_sig(SIGFPE, last_task_used_math, 1);
 	outb_p(0,0xf1);
 	outb_p(0,0xf0);
@@ -49,8 +49,8 @@
 
 	if (!hard_math) {
 #ifndef CONFIG_MATH_EMULATION
-		printk("No coprocessor found and no math emulation present.\n");
-		printk("Giving up.\n");
+		printk(KERN_EMERG "No coprocessor found and no math emulation present.\n");
+		printk(KERN_EMERG "Giving up.\n");
 		for (;;) ;
 #endif
 		return;
@@ -64,7 +64,7 @@
 	 * So the irq13 will happen eventually, but the exception 16
 	 * should get there first..
 	 */
-	printk("Checking 386/387 coupling... ");
+	printk(KERN_INFO "Checking 386/387 coupling... ");
 	timer_table[COPRO_TIMER].expires = jiffies+50;
 	timer_table[COPRO_TIMER].fn = copro_timeout;
 	timer_active |= 1<<COPRO_TIMER;
@@ -101,7 +101,7 @@
 
 static void check_hlt(void)
 {
-	printk("Checking 'hlt' instruction... ");
+	printk(KERN_INFO "Checking 'hlt' instruction... ");
 	if (!hlt_works_ok) {
 		printk("disabled\n");
 		return;
@@ -118,7 +118,7 @@
 	 * They will fault when they hit an invlpg instruction.
 	 */
 	if (x86 == 3) {
-		printk("CPU is a 386 and this kernel was compiled for 486 or better.\n");
+		printk(KERN_EMERG "CPU is a 386 and this kernel was compiled for 486 or better.\n");
 		printk("Giving up.\n");
 		for (;;) ;
 	}
diff -u --recursive --new-file v2.1.42/linux/include/asm-i386/byteorder.h linux/include/asm-i386/byteorder.h
--- v2.1.42/linux/include/asm-i386/byteorder.h	Thu Jun 12 15:28:32 1997
+++ linux/include/asm-i386/byteorder.h	Sun Jun 15 15:12:29 1997
@@ -17,21 +17,6 @@
 /* For avoiding bswap on i386 */
 #ifdef __KERNEL__
 #include <linux/config.h>
-
-/*
- * In-kernel byte order macros to handle stuff like
- * byte-order-dependent filesystems etc.
- */
-#define cpu_to_le32(x) (x)
-#define le32_to_cpu(x) (x)
-#define cpu_to_le16(x) (x)
-#define le16_to_cpu(x) (x)
-
-#define cpu_to_be32(x) htonl((x))
-#define be32_to_cpu(x) ntohl((x))
-#define cpu_to_be16(x) htons((x))
-#define be16_to_cpu(x) ntohs((x))
-
 #endif
 
 extern unsigned long int	ntohl(unsigned long int);
@@ -101,5 +86,69 @@
  __constant_htons((x)) : \
  __htons((x)))
 #endif
+
+#ifdef __KERNEL__
+/*
+ * In-kernel byte order macros to handle stuff like
+ * byte-order-dependent filesystems etc.
+ */
+#define cpu_to_le32(x) (x)
+#define cpu_to_le16(x) (x)
+
+#define cpu_to_be32(x) htonl((x))
+#define cpu_to_be16(x) htons((x))
+
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
+{
+	return cpu_to_le16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
+{
+	return cpu_to_le32(*addr);
+}
+
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
+{
+	return cpu_to_be16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
+{
+	return cpu_to_be32(*addr);
+}
+
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+#define cpu_to_le16s(x) do { } while (0)
+#define cpu_to_le32s(x) do { } while (0)
+
+extern __inline__ void cpu_to_be16s(__u16 *addr)
+{
+	*addr = cpu_to_be16(*addr);
+}
+
+extern __inline__ void cpu_to_be32s(__u32 *addr)
+{
+	*addr = cpu_to_be32(*addr);
+}
+
+/* Convert from specified byte order, to CPU byte order. */
+#define le16_to_cpu(x)  cpu_to_le16(x)
+#define le32_to_cpu(x)  cpu_to_le32(x)
+#define be16_to_cpu(x)  cpu_to_be16(x)
+#define be32_to_cpu(x)  cpu_to_be32(x)
+
+#define le16_to_cpup(x) cpu_to_le16p(x)
+#define le32_to_cpup(x) cpu_to_le32p(x)
+#define be16_to_cpup(x) cpu_to_be16p(x)
+#define be32_to_cpup(x) cpu_to_be32p(x)
+
+#define le16_to_cpus(x) cpu_to_le16s(x)
+#define le32_to_cpus(x) cpu_to_le32s(x)
+#define be16_to_cpus(x) cpu_to_be16s(x)
+#define be32_to_cpus(x) cpu_to_be32s(x)
+
+#endif /* __KERNEL__ */
 
 #endif
diff -u --recursive --new-file v2.1.42/linux/include/asm-i386/keyboard.h linux/include/asm-i386/keyboard.h
--- v2.1.42/linux/include/asm-i386/keyboard.h	Sat May 24 09:10:24 1997
+++ linux/include/asm-i386/keyboard.h	Thu Jun 12 16:22:09 1997
@@ -16,10 +16,6 @@
 #define KEYBOARD_IRQ			1
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 
-#define KBD_REPORT_ERR
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
-
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
 extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
diff -u --recursive --new-file v2.1.42/linux/include/asm-i386/namei.h linux/include/asm-i386/namei.h
--- v2.1.42/linux/include/asm-i386/namei.h	Sun Jan 26 02:07:46 1997
+++ linux/include/asm-i386/namei.h	Thu Jun 12 16:22:09 1997
@@ -7,15 +7,12 @@
 #ifndef __I386_NAMEI_H
 #define __I386_NAMEI_H
 
-/* These dummy routines maybe changed to something useful
+/* This dummy routine maybe changed to something useful
  * for /usr/gnemul/ emulation stuff.
  * Look at asm-sparc/namei.h for details.
  */
 
-#define translate_namei(pathname, base, follow_links, res_inode)	\
-	do { } while (0)
-
-#define translate_open_namei(pathname, flag, mode, res_inode, base) \
-	do { } while (0)
+#define __prefix_namei(retrieve_mode, name, base, buf, res_dir, res_inode, \
+		       last_name, last_entry, last_error) 1
 
 #endif /* __I386_NAMEI_H */
diff -u --recursive --new-file v2.1.42/linux/include/asm-m68k/byteorder.h linux/include/asm-m68k/byteorder.h
--- v2.1.42/linux/include/asm-m68k/byteorder.h	Wed Apr 23 19:01:27 1997
+++ linux/include/asm-m68k/byteorder.h	Thu Jun 12 16:22:10 1997
@@ -17,13 +17,6 @@
  * byte-order-dependent filesystems etc.
  */
 
-#define le16_to_cpu(__val) __swab16(__val)
-#define cpu_to_le16(__val) __swab16(__val)
-#define le32_to_cpu(x) \
-(__builtin_constant_p(x) ? __constant_swab32(x) : __swab32(x))
-#define cpu_to_le32(x) \
-(__builtin_constant_p(x) ? __constant_swab32(x) : __swab32(x))
-
 extern __inline__ __u16 __swab16 (__u16 val)
 {
 	return (val << 8) | (val >> 8);
@@ -41,10 +34,63 @@
 	return val;
 }
 
-#define cpu_to_be32(x) (x)
-#define be32_to_cpu(x) (x)
-#define cpu_to_be16(x) (x)
-#define be16_to_cpu(x) (x)
+/* Convert from CPU byte order, to specified byte order. */
+#define cpu_to_le16(__val) __swab16(__val)
+#define cpu_to_le32(__val) \
+(__builtin_constant_p(__val) ? __constant_swab32(__val) : __swab32(__val))
+#define cpu_to_be16(x)  (x)
+#define cpu_to_be32(x)  (x)
+
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
+{
+	return cpu_to_le16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
+{
+	return cpu_to_le32(*addr);
+}
+
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
+{
+	return cpu_to_be16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
+{
+	return cpu_to_be32(*addr);
+}
+
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+extern __inline__ void cpu_to_le16s(__u16 *addr)
+{
+	*addr = cpu_to_le16(*addr);
+}
+
+extern __inline__ void cpu_to_le32s(__u32 *addr)
+{
+	*addr = cpu_to_le32(*addr);
+}
+
+#define cpu_to_be16s(x) do { } while (0)
+#define cpu_to_be32s(x) do { } while (0)
+
+/* Convert from specified byte order, to CPU byte order. */
+#define le16_to_cpu(x)  cpu_to_le16(x)
+#define le32_to_cpu(x)  cpu_to_le32(x)
+#define be16_to_cpu(x)  cpu_to_be16(x)
+#define be32_to_cpu(x)  cpu_to_be32(x)
+
+#define le16_to_cpup(x) cpu_to_le16p(x)
+#define le32_to_cpup(x) cpu_to_le32p(x)
+#define be16_to_cpup(x) cpu_to_be16p(x)
+#define be32_to_cpup(x) cpu_to_be32p(x)
+
+#define le16_to_cpus(x) cpu_to_le16s(x)
+#define le32_to_cpus(x) cpu_to_le32s(x)
+#define be16_to_cpus(x) cpu_to_be16s(x)
+#define be32_to_cpus(x) cpu_to_be32s(x)
 
 #endif
 
diff -u --recursive --new-file v2.1.42/linux/include/asm-m68k/entry.h linux/include/asm-m68k/entry.h
--- v2.1.42/linux/include/asm-m68k/entry.h	Wed Dec 31 16:00:00 1969
+++ linux/include/asm-m68k/entry.h	Thu Jun 12 16:22:10 1997
@@ -0,0 +1,176 @@
+#ifndef __M68K_ENTRY_H
+#define __M68K_ENTRY_H
+
+#include <linux/config.h>
+#include <asm/setup.h>
+#ifdef CONFIG_KGDB
+#include <asm/kgdb.h>
+#endif
+
+/*
+ * Stack layout in 'ret_from_exception':
+ *
+ *	This allows access to the syscall arguments in registers d1-d5
+ *
+ *	 0(sp) - d1
+ *	 4(sp) - d2
+ *	 8(sp) - d3
+ *	 C(sp) - d4
+ *	10(sp) - d5
+ *	14(sp) - a0
+ *	18(sp) - a1
+ *	1C(sp) - a2
+ *	20(sp) - d0
+ *	24(sp) - orig_d0
+ *	28(sp) - stack adjustment
+ *	2C(sp) - sr
+ *	2E(sp) - pc
+ *	32(sp) - format & vector
+ */
+
+/*
+ * 97/05/14 Andreas: Register %a2 is now set to the current task throughout
+ *		     the whole kernel.
+ */
+
+#ifdef __ASSEMBLY__
+
+#define curptr a2
+
+/*
+ * these are offsets into the task-struct
+ */
+LTASK_STATE	=  0
+LTASK_COUNTER	=  4
+LTASK_PRIORITY	=  8
+LTASK_SIGNAL	= 12
+LTASK_BLOCKED	= 16
+LTASK_FLAGS	= 20
+
+LTSS_KSP	= 0
+LTSS_USP	= 4
+LTSS_SR		= 8
+LTSS_FS		= 10
+LTSS_CRP	= 12
+LTSS_FPCTXT	= 24
+
+/* the following macro is used when enabling interrupts */
+#if defined(MACH_ATARI_ONLY)
+	/* block out HSYNC on the atari */
+#define ALLOWINT 0xfbff
+#define	MAX_NOINT_IPL	3
+#else
+	/* portable version */
+#define ALLOWINT 0xf8ff
+#define	MAX_NOINT_IPL	0
+#endif /* machine compilation types */ 
+
+LPT_OFF_D0	  = 0x20
+LPT_OFF_ORIG_D0	  = 0x24
+LPT_OFF_SR	  = 0x2C
+LPT_OFF_FORMATVEC = 0x32
+
+LFLUSH_I_AND_D = 0x00000808
+LENOSYS = 38
+LSIGTRAP = 5
+
+LPF_TRACESYS_OFF = 3
+LPF_TRACESYS_BIT = 5
+LPF_PTRACED_OFF = 3
+LPF_PTRACED_BIT = 4
+LPF_DTRACE_OFF = 1
+LPF_DTRACE_BIT = 5
+
+/*
+ * This defines the normal kernel pt-regs layout.
+ *
+ * regs a3-a6 and d6-d7 are preserved by C code
+ * the kernel doesn't mess with usp unless it needs to
+ */
+#ifndef CONFIG_KGDB
+/*
+ * a -1 in the orig_d0 field signifies
+ * that the stack frame is NOT for syscall
+ */
+#define SAVE_ALL_INT				\
+	clrl	%sp@-;		/* stk_adj */	\
+	pea	-1:w;		/* orig d0 */	\
+	movel	%d0,%sp@-;	/* d0 */	\
+	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-
+
+#define SAVE_ALL_SYS				\
+	clrl	%sp@-;		/* stk_adj */	\
+	movel	%d0,%sp@-;	/* orig d0 */	\
+	movel	%d0,%sp@-;	/* d0 */	\
+	moveml  %d1-%d5/%a0-%a1/%curptr,%sp@-
+#else
+/* Need to save the "missing" registers for kgdb...
+ */
+#define SAVE_ALL_INT					\
+	clrl	%sp@-;		/* stk_adj */		\
+	pea	-1:w;		/* orig d0 */		\
+	movel	%d0,%sp@-;	/* d0 */		\
+	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-;		\
+	moveml	%d6-%d7,kgdb_registers+GDBOFFA_D6;	\
+	moveml	%a3-%a6,kgdb_registers+GDBOFFA_A3
+
+#define SAVE_ALL_SYS					\
+	clrl	%sp@-;		/* stk_adj */		\
+	movel	%d0,%sp@-;	/* orig d0 */		\
+	movel	%d0,%sp@-;	/* d0 */		\
+	moveml	%d1-%d5/%a0-%a1/%curptr,%sp@-;		\
+	moveml	%d6-%d7,kgdb_registers+GDBOFFA_D6;	\
+	moveml	%a3-%a6,kgdb_registers+GDBOFFA_A3
+#endif
+
+#define RESTORE_ALL			\
+	moveml	%sp@+,%a0-%a1/%curptr/%d1-%d5;	\
+	movel	%sp@+,%d0;		\
+	addql	#4,%sp;	 /* orig d0 */	\
+	addl	%sp@+,%sp; /* stk adj */	\
+	rte
+
+#define SWITCH_STACK_SIZE (6*4+4)	/* includes return address */
+
+#define SAVE_SWITCH_STACK \
+	moveml	%a3-%a6/%d6-%d7,%sp@-
+
+#define RESTORE_SWITCH_STACK \
+	moveml	%sp@+,%a3-%a6/%d6-%d7
+
+#define GET_CURRENT(tmp) \
+	movel	%sp,tmp; \
+	andw	&-8192,tmp; \
+	movel	tmp,%curptr;
+
+#else /* C source */
+
+#define STR(X) STR1(X)
+#define STR1(X) #X
+
+#define PT_OFF_ORIG_D0	 0x24
+#define PT_OFF_FORMATVEC 0x32
+#define PT_OFF_SR	 0x2C
+#ifndef CONFIG_KGDB
+#define SAVE_ALL_INT				\
+	"clrl	%%sp@-;"    /* stk_adj */	\
+	"pea	-1:w;"	    /* orig d0 = -1 */	\
+	"movel	%%d0,%%sp@-;" /* d0 */		\
+	"moveml	%%d1-%%d5/%%a0-%%a2,%%sp@-"
+#else
+#define SAVE_ALL_INT				\
+	"clrl	%%sp@-\n\t" /* stk_adj */	\
+	"pea	-1:w\n\t"   /* orig d0 = -1 */	\
+	"movel	%%d0,%%sp@-\n\t" /* d0 */	\
+	"moveml	%%d1-%%d5/%%a0-%%a2,%%sp@-\n\t"	\
+	"moveml	%%d6-%%d7,kgdb_registers+"STR(GDBOFFA_D6)"\n\t" \
+	"moveml	%%a3-%%a6,kgdb_registers+"STR(GDBOFFA_A3)
+#endif
+#define GET_CURRENT(tmp) \
+	"movel	%%sp,"#tmp"\n\t" \
+	"andw	#-8192,"#tmp"\n\t" \
+	"movel	"#tmp",%%a2"
+
+#endif
+
+#endif /* __M68K_ENTRY_H */
diff -u --recursive --new-file v2.1.42/linux/include/asm-m68k/namei.h linux/include/asm-m68k/namei.h
--- v2.1.42/linux/include/asm-m68k/namei.h	Tue May 13 22:41:17 1997
+++ linux/include/asm-m68k/namei.h	Thu Jun 12 16:22:10 1997
@@ -7,15 +7,12 @@
 #ifndef __M68K_NAMEI_H
 #define __M68K_NAMEI_H
 
-/* These dummy routines maybe changed to something useful
+/* This dummy routine maybe changed to something useful
  * for /usr/gnemul/ emulation stuff.
  * Look at asm-sparc/namei.h for details.
  */
 
-#define translate_namei(pathname, base, follow_links, res_inode)	\
-	do { } while (0)
-
-#define translate_open_namei(pathname, flag, mode, res_inode, base) \
-	do { } while (0)
+#define __prefix_namei(retrieve_mode, name, base, buf, res_dir, res_inode, \
+		       last_name, last_entry, last_error) 1
 
 #endif
diff -u --recursive --new-file v2.1.42/linux/include/asm-m68k/semaphore.h linux/include/asm-m68k/semaphore.h
--- v2.1.42/linux/include/asm-m68k/semaphore.h	Sat May 24 09:10:24 1997
+++ linux/include/asm-m68k/semaphore.h	Thu Jun 12 16:22:10 1997
@@ -20,8 +20,8 @@
 	struct wait_queue * wait;
 };
 
-#define MUTEX ((struct semaphore) { { 1 }, { 0 }, NULL })
-#define MUTEX_LOCKED ((struct semaphore) { { 0 }, { 0 }, NULL })
+#define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL })
+#define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL })
 
 asmlinkage void __down_failed(void /* special register calling convention */);
 asmlinkage int  __down_failed_interruptible(void  /* params in registers */);
@@ -73,7 +73,7 @@
  * "down_failed" is a special asm handler that calls the C
  * routine that actually waits. See arch/m68k/lib/semaphore.S
  */
-extern inline void do_down(struct semaphore * sem, void (*failed)(void))
+extern inline void down(struct semaphore * sem)
 {
 	register struct semaphore *sem1 __asm__ ("%a1") = sem;
 	__asm__ __volatile__(
@@ -84,15 +84,34 @@
 		".section .text.lock,\"ax\"\n"
 		".even\n"
 		"2:\tpea 1b\n\t"
-		"jbra %1\n"
+		"jbra __down_failed\n"
 		".previous"
 		: /* no outputs */
-		: "a" (sem1), "m" (*(unsigned char *)failed)
+		: "a" (sem1)
 		: "memory");
 }
 
-#define down(sem) do_down((sem),__down_failed)
-#define down_interruptible(sem) do_down((sem),__down_failed_interruptible)
+extern inline int down_interruptible(struct semaphore * sem)
+{
+	register struct semaphore *sem1 __asm__ ("%a1") = sem;
+	register int result __asm__ ("%d0");
+
+	__asm__ __volatile__(
+		"| atomic interruptible down operation\n\t"
+		"subql #1,%1@\n\t"
+		"jmi 2f\n\t"
+		"clrl %0\n"
+		"1:\n"
+		".section .text.lock,\"ax\"\n"
+		".even\n"
+		"2:\tpea 1b\n\t"
+		"jbra __down_failed_interruptible\n"
+		".previous"
+		: "=d" (result)
+		: "a" (sem1)
+		: "%d0", "memory");
+	return result;
+}
 
 /*
  * Note! This is subtle. We jump to wake people up only if
@@ -111,10 +130,10 @@
 		".section .text.lock,\"ax\"\n"
 		".even\n"
 		"2:\tpea 1b\n\t"
-		"jbra %1\n"
+		"jbra __up_wakeup\n"
 		".previous"
 		: /* no outputs */
-		: "a" (sem1), "m" (*(unsigned char *)__up_wakeup)
+		: "a" (sem1)
 		: "memory");
 }
 
diff -u --recursive --new-file v2.1.42/linux/include/asm-mips/keyboard.h linux/include/asm-mips/keyboard.h
--- v2.1.42/linux/include/asm-mips/keyboard.h	Sat May 24 09:10:25 1997
+++ linux/include/asm-mips/keyboard.h	Thu Jun 12 16:22:10 1997
@@ -16,10 +16,6 @@
 #define KEYBOARD_IRQ			1
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 
-#define KBD_REPORT_ERR
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
-
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
 extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
diff -u --recursive --new-file v2.1.42/linux/include/asm-ppc/byteorder.h linux/include/asm-ppc/byteorder.h
--- v2.1.42/linux/include/asm-ppc/byteorder.h	Wed Dec 18 00:54:09 1996
+++ linux/include/asm-ppc/byteorder.h	Thu Jun 12 16:22:10 1997
@@ -19,38 +19,72 @@
 #define __constant_htonl(x) ntohl(x)
 #define __constant_htons(x) ntohs(x)
 
-/*
- * In-kernel byte order macros to handle stuff like
- * byte-order-dependent filesystems etc.
- */
+#ifdef __KERNEL__
 
-#define cpu_to_le32(x) le32_to_cpu((x))
-extern __inline__ unsigned long le32_to_cpu(unsigned long x)
+/* Convert from CPU byte order, to specified byte order. */
+extern __inline__ __u16 cpu_to_le16(__u16 value)
 {
-     	return (((x & 0x000000ffU) << 24) |
-		((x & 0x0000ff00U) <<  8) |
-		((x & 0x00ff0000U) >>  8) |
-		((x & 0xff000000U) >> 24));
+	return (value >> 8) | (value << 8);
 }
 
-
-#define cpu_to_le16(x) le16_to_cpu((x))
-extern __inline__ unsigned short le16_to_cpu(unsigned short x)
+extern __inline__ __u32 cpu_to_le32(__u32 value)
 {
-	return (((x & 0x00ff) << 8) |
-		((x & 0xff00) >> 8));
+	return((value>>24) | ((value>>8)&0xff00) |
+	       ((value<<8)&0xff0000) | (value<<24));
 }
+#define cpu_to_be16(x)  (x)
+#define cpu_to_be32(x)  (x)
 
-#define cpu_to_be32(x) (x)
-#define be32_to_cpu(x) (x)
-#define cpu_to_be16(x) (x)
-#define be16_to_cpu(x) (x)
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
+{
+	return cpu_to_le16(*addr);
+}
 
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
+{
+	return cpu_to_le32(*addr);
+}
 
-#endif /* !(_PPC_BYTEORDER_H) */
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
+{
+	return cpu_to_be16(*addr);
+}
 
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
+{
+	return cpu_to_be32(*addr);
+}
 
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+extern __inline__ void cpu_to_le16s(__u16 *addr)
+{
+	*addr = cpu_to_le16(*addr);
+}
 
+extern __inline__ void cpu_to_le32s(__u32 *addr)
+{
+	*addr = cpu_to_le32(*addr);
+}
 
+#define cpu_to_be16s(x) do { } while (0)
+#define cpu_to_be32s(x) do { } while (0)
 
+/* Convert from specified byte order, to CPU byte order. */
+#define le16_to_cpu(x)  cpu_to_le16(x)
+#define le32_to_cpu(x)  cpu_to_le32(x)
+#define be16_to_cpu(x)  cpu_to_be16(x)
+#define be32_to_cpu(x)  cpu_to_be32(x)
+
+#define le16_to_cpup(x) cpu_to_le16p(x)
+#define le32_to_cpup(x) cpu_to_le32p(x)
+#define be16_to_cpup(x) cpu_to_be16p(x)
+#define be32_to_cpup(x) cpu_to_be32p(x)
+
+#define le16_to_cpus(x) cpu_to_le16s(x)
+#define le32_to_cpus(x) cpu_to_le32s(x)
+#define be16_to_cpus(x) cpu_to_be16s(x)
+#define be32_to_cpus(x) cpu_to_be32s(x)
 
+#endif /* __KERNEL__ */
+#endif /* !(_PPC_BYTEORDER_H) */
diff -u --recursive --new-file v2.1.42/linux/include/asm-ppc/keyboard.h linux/include/asm-ppc/keyboard.h
--- v2.1.42/linux/include/asm-ppc/keyboard.h	Sat May 24 09:10:25 1997
+++ linux/include/asm-ppc/keyboard.h	Thu Jun 12 16:22:10 1997
@@ -16,10 +16,6 @@
 #define KEYBOARD_IRQ			1
 #define DISABLE_KBD_DURING_INTERRUPTS	0
 
-#define KBD_REPORT_ERR
-#define KBD_REPORT_UNKN
-/* #define KBD_IS_FOCUS_9000 */
-
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
 extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc/byteorder.h linux/include/asm-sparc/byteorder.h
--- v2.1.42/linux/include/asm-sparc/byteorder.h	Thu May 29 21:53:09 1997
+++ linux/include/asm-sparc/byteorder.h	Thu Jun 12 16:22:10 1997
@@ -1,4 +1,4 @@
-/* $Id: byteorder.h,v 1.13 1997/05/26 23:37:46 davem Exp $ */
+/* $Id: byteorder.h,v 1.14 1997/05/28 11:35:38 jj Exp $ */
 #ifndef _SPARC_BYTEORDER_H
 #define _SPARC_BYTEORDER_H
 
@@ -37,19 +37,56 @@
 #define cpu_to_be16(x)  (x)
 #define cpu_to_be32(x)  (x)
 
-/* Convert from specified byte order, to CPU byte order. */
-extern __inline__ __u16 le16_to_cpu(__u16 value)
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
 {
-	return (value >> 8) | (value << 8);
+	return cpu_to_le16(*addr);
 }
 
-extern __inline__ __u32 le32_to_cpu(__u32 value)
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
 {
-	return((value>>24) | ((value>>8)&0xff00) |
-	       ((value<<8)&0xff0000) | (value<<24));
+	return cpu_to_le32(*addr);
+}
+
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr)
+{
+	return cpu_to_be16(*addr);
+}
+
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr)
+{
+	return cpu_to_be32(*addr);
 }
-#define be16_to_cpu(x)  (x)
-#define be32_to_cpu(x)  (x)
+
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+extern __inline__ void cpu_to_le16s(__u16 *addr)
+{
+	*addr = cpu_to_le16(*addr);
+}
+
+extern __inline__ void cpu_to_le32s(__u32 *addr)
+{
+	*addr = cpu_to_le32(*addr);
+}
+
+#define cpu_to_be16s(x) do { } while (0)
+#define cpu_to_be32s(x) do { } while (0)
+
+/* Convert from specified byte order, to CPU byte order. */
+#define le16_to_cpu(x)  cpu_to_le16(x)
+#define le32_to_cpu(x)  cpu_to_le32(x)
+#define be16_to_cpu(x)  cpu_to_be16(x)
+#define be32_to_cpu(x)  cpu_to_be32(x)
+
+#define le16_to_cpup(x) cpu_to_le16p(x)
+#define le32_to_cpup(x) cpu_to_le32p(x)
+#define be16_to_cpup(x) cpu_to_be16p(x)
+#define be32_to_cpup(x) cpu_to_be32p(x)
+
+#define le16_to_cpus(x) cpu_to_le16s(x)
+#define le32_to_cpus(x) cpu_to_le32s(x)
+#define be16_to_cpus(x) cpu_to_be16s(x)
+#define be32_to_cpus(x) cpu_to_be32s(x)
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc/namei.h linux/include/asm-sparc/namei.h
--- v2.1.42/linux/include/asm-sparc/namei.h	Mon Jan 27 00:42:54 1997
+++ linux/include/asm-sparc/namei.h	Thu Jun 12 16:22:10 1997
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.3 1997/01/26 23:36:36 davem Exp $
+/* $Id: namei.h,v 1.5 1997/06/07 08:32:54 ecd Exp $
  * linux/include/asm-sparc/namei.h
  *
  * Routines to handle famous /usr/gnemul/s*.
@@ -11,44 +11,37 @@
 #define SPARC_BSD_EMUL "usr/gnemul/sunos/"
 #define SPARC_SOL_EMUL "usr/gnemul/solaris/"
 
-#define translate_namei(pathname, base, follow_links, res_inode) ({					\
-	if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') {			\
-		struct inode *emul_ino;									\
-		int namelen;										\
-		const char *name;									\
-													\
-		while (*pathname == '/')								\
-			pathname++;									\
-		current->fs->root->i_count++;								\
-		if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, 	\
-				&namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) {	\
-			*res_inode = NULL;								\
-			if (_namei (pathname, emul_ino, follow_links, res_inode) >= 0 && *res_inode) 	\
-				return 0;								\
-		}											\
-		base = current->fs->root;								\
-		base->i_count++;									\
-	}												\
-})
-
-#define translate_open_namei(pathname, flag, mode, res_inode, base) ({					\
-	if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') {			\
-		struct inode *emul_ino;									\
-		int namelen;										\
-		const char *name;									\
-													\
-		while (*pathname == '/')								\
-			pathname++;									\
-		current->fs->root->i_count++;								\
-		if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, 	\
-				&namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) {	\
-			*res_inode = NULL;								\
-			if (open_namei (pathname, flag, mode, res_inode, emul_ino) >= 0 && *res_inode)	\
-				return 0;								\
-		}											\
-		base = current->fs->root;								\
-		base->i_count++;									\
-	}												\
-})
+extern int __namei(int, const char *, struct inode *, char *, struct inode **,
+		   struct inode **, struct qstr *, struct dentry **, int *);
+
+static __inline__ int
+__prefix_namei(int retrieve_mode, const char * name, struct inode * base,
+	       char * buf, struct inode ** res_dir, struct inode ** res_inode,
+	       struct qstr * last_name, struct dentry ** last_entry,
+	       int * last_error)
+{
+	int error;
+
+	if (!(current->personality & (PER_BSD|PER_SVR4)))
+		return -ENOENT;
+
+	while (*name == '/')
+		name++;
+
+	atomic_inc(&current->fs->root->i_count);
+	error = __namei(NAM_FOLLOW_LINK,
+		        current->personality & PER_BSD ?
+		        SPARC_BSD_EMUL : SPARC_SOL_EMUL, current->fs->root,
+		        buf, NULL, &base, NULL, NULL, NULL);
+	if (error)
+		return error;
+
+	error = __namei(retrieve_mode, name, base, buf, res_dir, res_inode,
+			last_name, last_entry, last_error);
+	if (error)
+		return error;
+
+	return 0;
+}
 
 #endif /* __SPARC_NAMEI_H */
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc/spinlock.h linux/include/asm-sparc/spinlock.h
--- v2.1.42/linux/include/asm-sparc/spinlock.h	Thu May 15 16:48:04 1997
+++ linux/include/asm-sparc/spinlock.h	Thu Jun 12 16:22:10 1997
@@ -56,7 +56,7 @@
 #include <asm/psr.h>
 
 /* Define this to use the verbose/debugging versions in arch/sparc/lib/debuglocks.c */
-#define SPIN_LOCK_DEBUG
+/* #define SPIN_LOCK_DEBUG */
 
 #ifdef SPIN_LOCK_DEBUG
 struct _spinlock_debug {
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/bitops.h linux/include/asm-sparc64/bitops.h
--- v2.1.42/linux/include/asm-sparc64/bitops.h	Thu May 29 21:53:09 1997
+++ linux/include/asm-sparc64/bitops.h	Thu Jun 12 16:22:10 1997
@@ -1,4 +1,4 @@
-/* $Id: bitops.h,v 1.13 1997/05/27 06:47:16 davem Exp $
+/* $Id: bitops.h,v 1.16 1997/05/28 13:48:56 jj Exp $
  * bitops.h: Bit string operations on the V9.
  *
  * Copyright 1996 David S. Miller (davem@caip.rutgers.edu)
@@ -121,11 +121,33 @@
 	  : "0" (word)
 	  : "g1", "g2");
 #else
+#ifdef EASY_CHEESE_VERSION
 	result = 0;
 	while(word & 1) {
 		result++;
 		word >>= 1;
 	}
+#else
+	unsigned long tmp;
+
+	result = 0;	
+	tmp = ~word & -~word;
+	if (!(unsigned)tmp) {
+		tmp >>= 32;
+		result = 32;
+	}
+	if (!(unsigned short)tmp) {
+		tmp >>= 16;
+		result += 16;
+	}
+	if (!(unsigned char)tmp) {
+		tmp >>= 8;
+		result += 8;
+	}
+	if (tmp & 0xf0) result += 4;
+	if (tmp & 0xcc) result += 2;
+	if (tmp & 0xaa) result ++;
+#endif
 #endif
 	return result;
 }
@@ -137,29 +159,31 @@
 
 extern __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
 {
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
-	unsigned long result = offset & ~31UL;
+	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
+	unsigned long result = offset & ~63UL;
 	unsigned long tmp;
 
 	if (offset >= size)
 		return size;
 	size -= result;
-	offset &= 31UL;
+	offset &= 63UL;
 	if (offset) {
 		tmp = *(p++);
-		tmp |= ~0UL >> (32-offset);
-		if (size < 32)
+		tmp |= ~0UL >> (64-offset);
+		if (size < 64)
 			goto found_first;
 		if (~tmp)
 			goto found_middle;
-		size -= 32;
-		result += 32;
+		size -= 64;
+		result += 64;
 	}
-	while (size & ~31UL) {
+	offset = size >> 6;
+	size &= 63UL;
+	while (offset) {
 		if (~(tmp = *(p++)))
 			goto found_middle;
-		result += 32;
-		size -= 32;
+		result += 64;
+		offset--;
 	}
 	if (!size)
 		return result;
@@ -248,9 +272,16 @@
 		((value<<56) & 0xff00000000000000));
 }     
 
+extern __inline__ unsigned long __swab64p(unsigned long *addr)
+{
+	unsigned long ret;
+	__asm__ __volatile__ ("ldxa [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL));
+	return ret;
+}
+
 extern __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
 {
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
+	unsigned long *p = ((unsigned long *) addr) + (offset >> 6);
 	unsigned long result = offset & ~63UL;
 	unsigned long tmp;
 
@@ -259,8 +290,8 @@
 	size -= result;
 	offset &= 63UL;
 	if(offset) {
-		tmp = *(p++);
-		tmp |= __swab64((~0UL >> (64-offset)));
+		tmp = __swab64p(p++);
+		tmp |= (~0UL >> (64-offset));
 		if(size < 64)
 			goto found_first;
 		if(~tmp)
@@ -268,20 +299,21 @@
 		size -= 64;
 		result += 64;
 	}
-	while(size & ~63UL) {
-		if(~(tmp = *(p++)))
+	offset = size >> 6;
+	size &= 63UL;
+	while(offset) {
+		if(~(tmp = __swab64p(p++)))
 			goto found_middle;
 		result += 64;
-		size -= 64;
+		offset--;
 	}
 	if(!size)
 		return result;
-	tmp = *p;
-
+	tmp = __swab64p(p);
 found_first:
-	return result + ffz(__swab64(tmp) | (~0UL << size));
+	tmp |= (~0UL << size);
 found_middle:
-	return result + ffz(__swab64(tmp));
+	return result + ffz(tmp);
 }
 
 #ifdef __KERNEL__
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/byteorder.h linux/include/asm-sparc64/byteorder.h
--- v2.1.42/linux/include/asm-sparc64/byteorder.h	Thu May 29 21:53:09 1997
+++ linux/include/asm-sparc64/byteorder.h	Thu Jun 12 16:22:10 1997
@@ -1,7 +1,9 @@
-/* $Id: byteorder.h,v 1.4 1997/05/26 23:37:47 davem Exp $ */
+/* $Id: byteorder.h,v 1.5 1997/05/28 11:35:41 jj Exp $ */
 #ifndef _SPARC64_BYTEORDER_H
 #define _SPARC64_BYTEORDER_H
 
+#include <asm/asi.h>
+
 #define ntohl(x) ((unsigned long int)(x))
 #define ntohs(x) ((unsigned short int)(x))
 #define htonl(x) ((unsigned long int)(x))
@@ -34,22 +36,87 @@
 	return((value>>24) | ((value>>8)&0xff00) |
 	       ((value<<8)&0xff0000) | (value<<24));
 }
+
+extern __inline__ __u64 cpu_to_le64(__u64 value)
+{
+        return (((value>>56) & 0x00000000000000ffUL) |
+                ((value>>40) & 0x000000000000ff00UL) |
+                ((value>>24) & 0x0000000000ff0000UL) |
+                ((value>>8)  & 0x00000000ff000000UL) |
+                ((value<<8)  & 0x000000ff00000000UL) |
+                ((value<<24) & 0x0000ff0000000000UL) |
+                ((value<<40) & 0x00ff000000000000UL) |
+                ((value<<56) & 0xff00000000000000UL));
+}
 #define cpu_to_be16(x)  (x)
 #define cpu_to_be32(x)  (x)
+#define cpu_to_be64(x)	(x)
 
-/* Convert from specified byte order, to CPU byte order. */
-extern __inline__ __u16 le16_to_cpu(__u16 value)
+/* The same, but returns converted value from the location pointer by addr. */
+extern __inline__ __u16 cpu_to_le16p(__u16 *addr)
 {
-	return (value >> 8) | (value << 8);
+	__u16 ret;
+	__asm__ __volatile__ ("lduha [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL));
+	return ret;
 }
 
-extern __inline__ __u32 le32_to_cpu(__u32 value)
+extern __inline__ __u32 cpu_to_le32p(__u32 *addr)
 {
-	return((value>>24) | ((value>>8)&0xff00) |
-	       ((value<<8)&0xff0000) | (value<<24));
+	__u32 ret;
+	__asm__ __volatile__ ("lduwa [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL));
+	return ret;
+}
+
+extern __inline__ __u64 cpu_to_le64p(__u64 *addr)
+{
+	__u64 ret;
+	__asm__ __volatile__ ("ldxa [%1] %2, %0" : "=r" (ret) : "r" (addr), "i" (ASI_PL));
+	return ret;
 }
-#define be16_to_cpu(x)  (x)
-#define be32_to_cpu(x)  (x)
+extern __inline__ __u16 cpu_to_be16p(__u16 *addr) { return *addr; }
+extern __inline__ __u32 cpu_to_be32p(__u32 *addr) { return *addr; }
+extern __inline__ __u64 cpu_to_be64p(__u64 *addr) { return *addr; }
+
+/* The same, but do the conversion in situ, ie. put the value back to addr. */
+extern __inline__ void cpu_to_le16s(__u16 *addr)
+{
+	*addr = cpu_to_le16p(addr);
+}
+
+extern __inline__ void cpu_to_le32s(__u32 *addr)
+{
+	*addr = cpu_to_le32p(addr);
+}
+
+extern __inline__ void cpu_to_le64s(__u64 *addr)
+{
+	*addr = cpu_to_le64p(addr);
+}
+#define cpu_to_be16s(x) do { } while (0)
+#define cpu_to_be32s(x) do { } while (0)
+#define cpu_to_be64s(x) do { } while (0)
+
+/* Convert from specified byte order, to CPU byte order. */
+#define le16_to_cpu(x)	cpu_to_le16(x)
+#define le32_to_cpu(x)	cpu_to_le32(x)
+#define le64_to_cpu(x)	cpu_to_le64(x)
+#define be16_to_cpu(x)  cpu_to_be16(x)
+#define be32_to_cpu(x)  cpu_to_be32(x)
+#define be64_to_cpu(x)	cpu_to_be64(x)
+
+#define le16_to_cpup(x)	cpu_to_le16p(x)
+#define le32_to_cpup(x)	cpu_to_le32p(x)
+#define le64_to_cpup(x)	cpu_to_le64p(x)
+#define be16_to_cpup(x)	cpu_to_be16p(x)
+#define be32_to_cpup(x)	cpu_to_be32p(x)
+#define be64_to_cpup(x)	cpu_to_be64p(x)
+
+#define le16_to_cpus(x)	cpu_to_le16s(x)
+#define le32_to_cpus(x)	cpu_to_le32s(x)
+#define le64_to_cpus(x)	cpu_to_le64s(x)
+#define be16_to_cpus(x)	cpu_to_be16s(x)
+#define be32_to_cpus(x)	cpu_to_be32s(x)
+#define be64_to_cpus(x)	cpu_to_be64s(x)
 
 #endif /* __KERNEL__ */
 
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/checksum.h linux/include/asm-sparc64/checksum.h
--- v2.1.42/linux/include/asm-sparc64/checksum.h	Thu May 15 16:48:04 1997
+++ linux/include/asm-sparc64/checksum.h	Thu Jun 12 16:22:10 1997
@@ -1,4 +1,4 @@
-/* $Id: checksum.h,v 1.7 1997/05/14 07:02:44 davem Exp $ */
+/* $Id: checksum.h,v 1.8 1997/05/29 12:45:03 jj Exp $ */
 #ifndef __SPARC64_CHECKSUM_H
 #define __SPARC64_CHECKSUM_H
 
@@ -41,7 +41,7 @@
 #define csum_partial_copy(src, dst, len, sum) \
 			csum_partial_copy_nocheck(src,dst,len,sum)
 #define csum_partial_copy_fromuser(s, d, l, w)  \
-			csum_partial_copy((char *) (s), (d), (l), (w))
+			csum_partial_copy_from_user((char *) (s), (d), (l), (w), NULL)
 			
 extern __inline__ unsigned int 
 csum_partial_copy_nocheck (const char *src, char *dst, int len, 
@@ -50,12 +50,13 @@
 	register unsigned long ret asm("o0") = (unsigned long)src;
 	register char *d asm("o1") = dst;
 	register unsigned long l asm("g1") = len;
-	
+
 	__asm__ __volatile__ ("
+		wr	%%g0, %5, %%asi
 		call __csum_partial_copy_sparc_generic
 		 mov %4, %%g7
 		srl	%%o0, 0, %%o0
-	" : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum) :
+	" : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (sum), "i" (ASI_P) :
 	"o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
 	return (unsigned int)ret;
 }
@@ -64,58 +65,35 @@
 csum_partial_copy_from_user(const char *src, char *dst, int len, 
 			    unsigned int sum, int *err)
 {
-	if (!access_ok (VERIFY_READ, src, len)) {
-		*err = -EFAULT;
-		memset (dst, 0, len);
-		return sum;
-	} else {
-		register unsigned long ret asm("o0") = (unsigned long)src;
-		register char *d asm("o1") = dst;
-		register unsigned long l asm("g1") = len;
-		register unsigned long s asm("g7") = sum;
-
-		__asm__ __volatile__ ("
-		.section __ex_table,#alloc
-		.align 4
-		.word 1f,2
-		.previous
+	register unsigned long ret asm("o0") = (unsigned long)src;
+	register char *d asm("o1") = dst;
+	register unsigned long l asm("g1") = len;
+	register unsigned long s asm("g7") = sum;
+
+	__asm__ __volatile__ ("
+	.section __ex_table,#alloc
+	.align 8
+	.xword 1f,2
+	.previous
+	wr	%%g0, %6, %%asi
 1:
-		call __csum_partial_copy_sparc_generic
-		 stx %5, [%%sp + 0x7ff + 128]
-		srl	%%o0, 0, %%o0
-		" : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) :
-		"o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
-		return (unsigned int)ret;
-	}
+	call __csum_partial_copy_sparc_generic
+	 stx %5, [%%sp + 0x7ff + 128]
+	srl	%%o0, 0, %%o0
+	" : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err), "i" (ASI_S) :
+	"o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
+	return (unsigned int)ret;
 }
-  
+
+#if 0
+/* Not implemented, but nobody uses it yet... */
 extern __inline__ unsigned int 
 csum_partial_copy_to_user(const char *src, char *dst, int len, 
 			  unsigned int sum, int *err)
 {
-	if (!access_ok (VERIFY_WRITE, dst, len)) {
-		*err = -EFAULT;
-		return sum;
-	} else {
-		register unsigned long ret asm("o0") = (unsigned long)src;
-		register char *d asm("o1") = dst;
-		register unsigned long l asm("g1") = len;
-		register unsigned long s asm("g7") = sum;
-
-		__asm__ __volatile__ ("
-		.section __ex_table,#alloc
-		.align 4
-		.word 1f,1
-		.previous
-1:
-		call __csum_partial_copy_sparc_generic
-		 stx %5, [%%sp + 0x7ff + 128]
-		srl	%%o0, 0, %%o0
-		" : "=r" (ret) : "0" (ret), "r" (d), "r" (l), "r" (s), "r" (err) :
-		"o1", "o2", "o3", "o4", "o5", "o7", "g1", "g2", "g3", "g5", "g7");
-		return (unsigned int)ret;
-	}
+	return 0;
 }
+#endif
   
 /* ihl is always 5 or greater, almost always is 5, and iph is word aligned
  * the majority of the time.
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/fpumacro.h linux/include/asm-sparc64/fpumacro.h
--- v2.1.42/linux/include/asm-sparc64/fpumacro.h	Mon Apr 14 16:28:22 1997
+++ linux/include/asm-sparc64/fpumacro.h	Thu Jun 12 16:22:10 1997
@@ -1,12 +1,27 @@
 /* fpumacro.h: FPU related macros.
  *
  * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
 #ifndef _SPARC64_FPUMACRO_H
 #define _SPARC64_FPUMACRO_H
 
-extern __inline__ void fpsave32(unsigned long *fpregs, unsigned long *fsr)
+extern __inline__ unsigned long fprs_read(void)
+{
+	unsigned long retval;
+
+	__asm__ __volatile__("rd %%fprs, %0" : "=r" (retval));
+
+	return retval;
+}
+
+extern __inline__ void fprs_write(unsigned long val)
+{
+	__asm__ __volatile__("wr %0, 0x0, %%fprs" : : "r" (val));
+}
+
+extern __inline__ void fpsave32(unsigned int *fpregs, unsigned long *fsr)
 {
 	__asm__ __volatile__ ("
 	wr	%%g0, %2, %%asi
@@ -16,7 +31,7 @@
 	" : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
 }
 
-extern __inline__ void fpload32(unsigned long *fpregs, unsigned long *fsr)
+extern __inline__ void fpload32(unsigned int *fpregs, unsigned long *fsr)
 {
 	__asm__ __volatile__ ("
 	wr	%%g0, %2, %%asi
@@ -26,7 +41,27 @@
 	" : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
 }
 
-extern __inline__ void fpsave(unsigned long *fpregs, unsigned long *fsr)
+extern __inline__ void fpsave64hi(unsigned int *fpregs, unsigned long *fsr)
+{
+	__asm__ __volatile__ ("
+	wr	%%g0, %2, %%asi
+	stx	%%fsr, [%1]
+	stda	%%f32, [%0 + 128] %%asi
+	stda	%%f48, [%0 + 192] %%asi
+	" : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
+}
+
+extern __inline__ void fpload64hi(unsigned int *fpregs, unsigned long *fsr)
+{
+	__asm__ __volatile__ ("
+	wr	%%g0, %2, %%asi
+	ldda	[%0 + 128] %%asi, %%f32
+	ldda	[%0 + 192] %%asi, %%f48
+	ldx	[%1], %%fsr
+	" : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
+}
+
+extern __inline__ void fpsave(unsigned int *fpregs, unsigned long *fsr)
 {
 	__asm__ __volatile__ ("
 	wr	%%g0, %2, %%asi
@@ -38,7 +73,7 @@
 	" : : "r" (fpregs), "r" (fsr), "i" (ASI_BLK_P));
 }
 
-extern __inline__ void fpload(unsigned long *fpregs, unsigned long *fsr)
+extern __inline__ void fpload(unsigned int *fpregs, unsigned long *fsr)
 {
 	__asm__ __volatile__ ("
 	wr	%%g0, %2, %%asi
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/head.h linux/include/asm-sparc64/head.h
--- v2.1.42/linux/include/asm-sparc64/head.h	Thu May 29 21:53:09 1997
+++ linux/include/asm-sparc64/head.h	Thu Jun 12 16:22:10 1997
@@ -1,4 +1,4 @@
-/* $Id: head.h,v 1.21 1997/05/27 06:28:17 davem Exp $ */
+/* $Id: head.h,v 1.22 1997/06/02 06:33:40 davem Exp $ */
 #ifndef _SPARC64_HEAD_H
 #define _SPARC64_HEAD_H
 
@@ -9,12 +9,13 @@
 
 /* We need a "cleaned" instruction... */
 #define CLEAN_WINDOW							\
+	rdpr	%cleanwin, %l0;		add	%l0, 1, %l0;		\
+	wrpr	%l0, 0x0, %cleanwin;					\
 	clr	%o0;	clr	%o1;	clr	%o2;	clr	%o3;	\
 	clr	%o4;	clr	%o5;	clr	%o6;	clr	%o7;	\
 	clr	%l0;	clr	%l1;	clr	%l2;	clr	%l3;	\
 	clr	%l4;	clr	%l5;	clr	%l6;	clr	%l7;	\
-	rdpr %cleanwin, %g1; 		add %g1, 1, %g1;		\
-	wrpr %g1, 0x0, %cleanwin;	retry;				\
+	retry;								\
 	nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;nop;
 
 #define TRAP(routine)					\
@@ -23,7 +24,7 @@
 	call	routine;				\
 	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
 	ba,pt	%xcc, rtrap;				\
-	 nop;						\
+	 clr	%l6;					\
 	nop;						\
 	nop;
 
@@ -38,7 +39,7 @@
 	call	routine;				\
 	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
 	ba,pt	%xcc, rtrap;				\
-	 nop;						\
+	 clr	%l6;					\
 	nop;						\
 	nop;
 	
@@ -60,7 +61,7 @@
 	call	routine;				\
 	 mov	arg, %o1;				\
 	ba,pt	%xcc, rtrap;				\
-	 nop;						\
+	 clr	%l6;					\
 	nop;
 	
 #define TRAPTL1_ARG(routine, arg)			\
@@ -70,7 +71,7 @@
 	call	routine;				\
 	 mov	arg, %o1;				\
 	ba,pt	%xcc, rtrap;				\
-	 nop;						\
+	 clr	%l6;					\
 	nop;
 	
 #define SYSCALL_TRAP(routine, systbl)			\
@@ -89,7 +90,7 @@
 	call	routine;				\
 	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
 	ba,pt	%xcc, rtrap;				\
-	 nop;
+	 clr	%l6;
 
 #define ACCESS_EXCEPTION_TRAPTL1(routine)		\
 	rdpr	%pstate, %g1;				\
@@ -99,7 +100,7 @@
 	call	routine;				\
 	 add	%sp, STACK_BIAS + REGWIN_SZ, %o0;	\
 	ba,pt	%xcc, rtrap;				\
-	 nop;
+	 clr	%l6;
 
 #define SUNOS_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sunos_sys_table)
 #define	LINUX_32BIT_SYSCALL_TRAP SYSCALL_TRAP(linux_sparc_syscall, sys_call_table32)
@@ -120,7 +121,7 @@
 	mov	level, %o0;				\
 	call	routine;				\
 	 add	%sp, STACK_BIAS + REGWIN_SZ, %o1;	\
-	ba,a,pt	%xcc, rtrap;
+	ba,a,pt	%xcc, rtrap_clr_l6;
 
 /* On UP this is ok, and worth the effort, for SMP we need
  * a different mechanism and thus cannot do it all in trap table. -DaveM
@@ -150,7 +151,7 @@
 	ldx	[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC], %l1;	\
 	add	%l1, 4, %l2;						\
 	stx	%l1, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TPC];	\
-	ba,pt	%xcc, rtrap;						\
+	ba,pt	%xcc, rtrap_clr_l6;					\
 	 stx	%l2, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_TNPC];
 	        
 /* Before touching these macros, you owe it to yourself to go and
@@ -198,7 +199,8 @@
 	stxa	%i6, [%sp + STACK_BIAS + 0x70] %asi;	\
 	stxa	%i7, [%sp + STACK_BIAS + 0x78] %asi;	\
 	saved; retry; nop; nop; nop; nop; nop; nop;	\
-	nop; nop; nop; nop; nop; nop;			\
+	nop; nop; nop; nop; nop;			\
+	b,a,pt	%xcc, spill_fixup_mna;			\
 	b,a,pt	%xcc, spill_fixup;
 
 /* Normal 32bit spill */
@@ -215,7 +217,8 @@
 	stda	%i6, [%sp + 0x38] %asi;			\
 	saved; retry; nop; nop; nop; nop;		\
 	nop; nop; nop; nop; nop; nop; nop; nop;		\
-	nop; nop; nop; nop; nop; nop; nop;		\
+	nop; nop; nop; nop; nop; nop;			\
+	b,a,pt	%xcc, spill_fixup_mna;			\
 	b,a,pt	%xcc, spill_fixup;
 
 #define SPILL_1_NORMAL SPILL_1_GENERIC(ASI_AIUP)
@@ -276,7 +279,8 @@
 	ldxa	[%sp + STACK_BIAS + 0x70] %asi, %i6;	\
 	ldxa	[%sp + STACK_BIAS + 0x78] %asi, %i7;	\
 	restored; retry; nop; nop; nop; nop; nop; nop;	\
-	nop; nop; nop; nop; nop; nop;			\
+	nop; nop; nop; nop; nop;			\
+	b,a,pt	%xcc, fill_fixup_mna;			\
 	b,a,pt	%xcc, fill_fixup;
 
 /* Normal 32bit fill */
@@ -293,7 +297,8 @@
 	ldda	[%sp + 0x38] %asi, %i6;			\
 	restored; retry; nop; nop; nop; nop;		\
 	nop; nop; nop; nop; nop; nop; nop; nop;		\
-	nop; nop; nop; nop; nop; nop; nop;		\
+	nop; nop; nop; nop; nop; nop;			\
+	b,a,pt	%xcc, fill_fixup_mna;			\
 	b,a,pt	%xcc, fill_fixup;
 
 #define FILL_1_NORMAL FILL_1_GENERIC(ASI_AIUP)
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/namei.h linux/include/asm-sparc64/namei.h
--- v2.1.42/linux/include/asm-sparc64/namei.h	Mon Apr 14 16:28:23 1997
+++ linux/include/asm-sparc64/namei.h	Thu Jun 12 16:22:10 1997
@@ -1,4 +1,4 @@
-/* $Id: namei.h,v 1.2 1997/03/19 17:28:27 jj Exp $
+/* $Id: namei.h,v 1.4 1997/06/07 08:32:56 ecd Exp $
  * linux/include/asm-sparc64/namei.h
  *
  * Routines to handle famous /usr/gnemul/s*.
@@ -11,44 +11,37 @@
 #define SPARC_BSD_EMUL "usr/gnemul/sunos/"
 #define SPARC_SOL_EMUL "usr/gnemul/solaris/"
 
-#define translate_namei(pathname, base, follow_links, res_inode) ({					\
-	if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') {			\
-		struct inode *emul_ino;									\
-		int namelen;										\
-		const char *name;									\
-													\
-		while (*pathname == '/')								\
-			pathname++;									\
-		current->fs->root->i_count++;								\
-		if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, 	\
-				&namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) {	\
-			*res_inode = NULL;								\
-			if (_namei (pathname, emul_ino, follow_links, res_inode) >= 0 && *res_inode) 	\
-				return 0;								\
-		}											\
-		base = current->fs->root;								\
-		base->i_count++;									\
-	}												\
-})
-
-#define translate_open_namei(pathname, flag, mode, res_inode, base) ({					\
-	if ((current->personality & (PER_BSD|PER_SVR4)) && !base && *pathname == '/') {			\
-		struct inode *emul_ino;									\
-		int namelen;										\
-		const char *name;									\
-													\
-		while (*pathname == '/')								\
-			pathname++;									\
-		current->fs->root->i_count++;								\
-		if (dir_namei (current->personality & PER_BSD ? SPARC_BSD_EMUL : SPARC_SOL_EMUL, 	\
-				&namelen, &name, current->fs->root, &emul_ino) >= 0 && emul_ino) {	\
-			*res_inode = NULL;								\
-			if (open_namei (pathname, flag, mode, res_inode, emul_ino) >= 0 && *res_inode)	\
-				return 0;								\
-		}											\
-		base = current->fs->root;								\
-		base->i_count++;									\
-	}												\
-})
+extern int __namei(int, const char *, struct inode *, char *, struct inode **,
+		   struct inode **, struct qstr *, struct dentry **, int *);
+
+static inline int
+__prefix_namei(int retrieve_mode, const char * name, struct inode * base,
+	       char * buf, struct inode ** res_dir, struct inode ** res_inode,
+	       struct qstr * last_name, struct dentry ** last_entry,
+	       int * last_error)
+{
+	int error;
+
+	if (!(current->personality & (PER_BSD|PER_SVR4)))
+		return -ENOENT;
+
+	while (*name == '/')
+		name++;
+
+	atomic_inc(&current->fs->root->i_count);
+	error = __namei(NAM_FOLLOW_LINK,
+		        current->personality & PER_BSD ?
+		        SPARC_BSD_EMUL : SPARC_SOL_EMUL, current->fs->root,
+		        buf, NULL, &base, NULL, NULL, NULL);
+	if (error)
+		return error;
+
+	error = __namei(retrieve_mode, name, base, buf, res_dir, res_inode,
+			last_name, last_entry, last_error);
+	if (error)
+		return error;
+
+	return 0;
+}
 
 #endif /* __SPARC64_NAMEI_H */
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/pgtable.h linux/include/asm-sparc64/pgtable.h
--- v2.1.42/linux/include/asm-sparc64/pgtable.h	Thu May 29 21:53:09 1997
+++ linux/include/asm-sparc64/pgtable.h	Thu Jun 12 16:22:10 1997
@@ -1,4 +1,4 @@
-/* $Id: pgtable.h,v 1.32 1997/05/26 23:39:20 davem Exp $
+/* $Id: pgtable.h,v 1.34 1997/06/02 06:33:41 davem Exp $
  * pgtable.h: SpitFire page table operations.
  *
  * Copyright 1996,1997 David S. Miller (davem@caip.rutgers.edu)
@@ -160,45 +160,6 @@
 
 /* Cache and TLB flush operations. */
 
-/* This is a bit tricky to do most efficiently.  The I-CACHE on the
- * SpitFire will snoop stores from _other_ processors and changes done
- * by DMA, but it does _not_ snoop stores on the local processor.
- * Also, even if the I-CACHE snoops the store from someone else correctly,
- * you can still lose if the instructions are in the pipeline already.
- * A big issue is that this cache is only 16K in size, using a pseudo
- * 2-set associative scheme.  A full flush of the cache is far too much
- * for me to accept, especially since most of the time when we get to
- * running this code the icache data we want to flush is not even in
- * the cache.  Thus the following seems to be the best method.
- */
-extern __inline__ void spitfire_flush_icache_page(unsigned long page)
-{
-	unsigned long temp;
-
-	/* Commit all potential local stores to the instruction space
-	 * on this processor before the flush.
-	 */
-	membar("#StoreStore");
-
-	/* Actually perform the flush. */
-	__asm__ __volatile__("
-1:
-	flush		%0 + 0x00
-	flush		%0 + 0x08
-	flush		%0 + 0x10
-	flush		%0 + 0x18
-	flush		%0 + 0x20
-	flush		%0 + 0x28
-	flush		%0 + 0x30
-	flush		%0 + 0x38
-	subcc		%1, 0x40, %1
-	bge,pt		%%icc, 1b
-	 add		%2, %1, %0
-"	: "=&r" (page), "=&r" (temp)
-	: "r" (page), "0" (page + PAGE_SIZE - 0x40), "1" (PAGE_SIZE - 0x40)
-	: "cc");
-}
-
 extern __inline__ void flush_cache_all(void)
 {
 	unsigned long addr;
@@ -283,13 +244,14 @@
 1:
 	stxa		%%g0, [%%g3] %3
 	stxa		%%g0, [%%g3] %4
-	bne,a,pn	%%icc, 1f
-	 stxa		%%g2, [%%g7] %2
+	be,a,pt		%%icc, 1f
+	 nop
+	stxa		%%g2, [%%g7] %2
 1:
 	flush		%%g4
 	wrpr		%%g1, 0x0, %%pil
 "	: /* no outputs */
-	: "r" (mm->context), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
+	: "r" (mm->context & 0x1fff), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
 	  "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP)
 	: "g1", "g2", "g3", "g7", "cc");
 	}
@@ -300,7 +262,7 @@
 {
 	if(mm->context != NO_CONTEXT) {
 		unsigned long old_ctx = spitfire_get_secondary_context();
-		unsigned long new_ctx = mm->context;
+		unsigned long new_ctx = (mm->context & 0x1fff);
 		unsigned long flags;
 
 		start &= PAGE_MASK;
@@ -332,22 +294,20 @@
 	ldxa		[%%g7] %2, %%g2
 	cmp		%%g2, %0
 	be,pt		%%icc, 1f
-	 or		%5, 0x10, %5
+	 or		%5, 0x10, %%g3
 	stxa		%0, [%%g7] %2
 1:
-	stxa		%%g0, [%5] %3
-	brnz,a		%6, 1f
-	 stxa		%%g0, [%5] %4
-1:
-	bne,a,pn	%%icc, 1f
-	 stxa		%%g2, [%%g7] %2
+	stxa		%%g0, [%%g3] %3
+	stxa		%%g0, [%%g3] %4
+	be,a,pt		%%icc, 1f
+	 nop
+	stxa		%%g2, [%%g7] %2
 1:
 	flush		%%g4
 	wrpr		%%g1, 0x0, %%pil
 "	: /* no outputs */
-	: "r" (mm->context), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
-	  "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP), "r" (page & PAGE_MASK),
-	  "r" (vma->vm_flags & VM_EXEC)
+	: "r" (mm->context & 0x1fff), "i" (SECONDARY_CONTEXT), "i" (ASI_DMMU),
+	  "i" (ASI_DMMU_DEMAP), "i" (ASI_IMMU_DEMAP), "r" (page & PAGE_MASK)
 	: "g1", "g2", "g3", "g7", "cc");
 	}
 }
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/psrcompat.h linux/include/asm-sparc64/psrcompat.h
--- v2.1.42/linux/include/asm-sparc64/psrcompat.h	Mon Apr 14 16:28:23 1997
+++ linux/include/asm-sparc64/psrcompat.h	Thu Jun 12 16:22:10 1997
@@ -1,4 +1,4 @@
-/* $Id: psrcompat.h,v 1.2 1997/04/07 18:57:17 jj Exp $ */
+/* $Id: psrcompat.h,v 1.3 1997/06/05 06:22:54 davem Exp $ */
 #ifndef _SPARC64_PSRCOMPAT_H
 #define _SPARC64_PSRCOMPAT_H
 
@@ -47,7 +47,7 @@
 {
 	unsigned long tstate;
 
-	tstate = (psr & PSR_ICC) << 12;
+	tstate = ((unsigned long)(psr & PSR_ICC)) << 12;
 
 	return tstate;
 }
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/pstate.h linux/include/asm-sparc64/pstate.h
--- v2.1.42/linux/include/asm-sparc64/pstate.h	Mon Apr 14 16:28:23 1997
+++ linux/include/asm-sparc64/pstate.h	Thu Jun 12 16:22:10 1997
@@ -1,4 +1,4 @@
-/* $Id: pstate.h,v 1.3 1997/03/25 03:58:31 davem Exp $ */
+/* $Id: pstate.h,v 1.4 1997/05/29 12:45:02 jj Exp $ */
 #ifndef _SPARC64_PSTATE_H
 #define _SPARC64_PSTATE_H
 
@@ -78,5 +78,33 @@
 #define VERS_MASK	0x00000000ff000000	/* Mask Set Revision.		*/
 #define VERS_MAXTL	0x000000000000ff00	/* Maximum Trap Level.		*/
 #define VERS_MAXWIN	0x000000000000001f	/* Maximum Reg Window Index.	*/
+
+#if defined(__KERNEL__) && !defined(__ASSEMBLY__)
+#define set_pstate(bits)					\
+	__asm__ __volatile__(					\
+		"rdpr      %%pstate, %%g1\n\t"			\
+		"or        %%g1, %0, %%g1\n\t"			\
+		"wrpr      %%g1, 0x0, %%pstate\n\t"		\
+		: /* no outputs */				\
+		: "i" (bits)					\
+		: "g1")
+
+#define clear_pstate(bits)					\
+	__asm__ __volatile__(					\
+		"rdpr      %%pstate, %%g1\n\t"			\
+		"andn        %%g1, %0, %%g1\n\t"		\
+		"wrpr      %%g1, 0x0, %%pstate\n\t"		\
+		: /* no outputs */				\
+		: "i" (bits)					\
+		: "g1")
+
+#define change_pstate(bits)					\
+	__asm__ __volatile__(					\
+		"rdpr      %%pstate, %%g1\n\t"			\
+		"wrpr      %%g1, %0, %%pstate\n\t"		\
+		: /* no outputs */				\
+		: "i" (bits)					\
+		: "g1")
+#endif
 
 #endif /* !(_SPARC64_PSTATE_H) */
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/system.h linux/include/asm-sparc64/system.h
--- v2.1.42/linux/include/asm-sparc64/system.h	Sat May 24 09:10:25 1997
+++ linux/include/asm-sparc64/system.h	Thu Jun 12 16:22:10 1997
@@ -1,4 +1,4 @@
-/* $Id: system.h,v 1.19 1997/05/18 22:52:32 davem Exp $ */
+/* $Id: system.h,v 1.22 1997/06/01 10:27:28 davem Exp $ */
 #ifndef __SPARC64_SYSTEM_H
 #define __SPARC64_SYSTEM_H
 
@@ -114,16 +114,24 @@
 #define flush_user_windows flushw_user
 
 #ifdef __SMP__
-#error SMP not supported on sparc64
+
+#include <asm/fpumacro.h>
+
+#define SWITCH_ENTER(prev)						\
+	if((prev)->flags & PF_USEDFPU) { 				\
+		fprs_write(FPRS_FEF);					\
+		fpsave((unsigned long *) &(prev)->tss.float_regs[0],	\
+		       &(prev)->tss.fsr);				\
+		(prev)->flags &= ~PF_USEDFPU;				\
+		(prev)->tss.kregs->tstate &= ~TSTATE_PEF;		\
+	}
+
+#define SWITCH_DO_LAZY_FPU(next)
 #else
-#if 0
+#define SWITCH_ENTER(prev)
 #define SWITCH_DO_LAZY_FPU(next)			\
 	if(last_task_used_math != (next))		\
-		(next)->tss.kregs->tstate&=~TSTATE_PEF
-#else
-/* XXX FIX ME BIG TIME XXX -DaveM */
-#define SWITCH_DO_LAZY_FPU(next)	do { } while(0)
-#endif
+		(next)->tss.kregs->tstate &= ~TSTATE_PEF
 #endif
 
 	/* See what happens when you design the chip correctly?
@@ -138,29 +146,33 @@
 do {											\
 	__label__ switch_continue;							\
 	register unsigned long task_pc asm("o7");					\
+	SWITCH_ENTER(prev)								\
 	SWITCH_DO_LAZY_FPU(next);							\
 	task_pc = ((unsigned long) &&switch_continue) - 0x8;				\
 	__asm__ __volatile__(								\
+	"rdpr	%%pstate, %%g2\n\t"							\
+	"wrpr	%%g2, 0x2, %%pstate\n\t"						\
 	"flushw\n\t"									\
 	"stx	%%i6, [%%sp + 2047 + 0x70]\n\t"						\
 	"stx	%%i7, [%%sp + 2047 + 0x78]\n\t"						\
-	"stx	%%o6, [%%g6 + %3]\n\t"							\
 	"rdpr	%%wstate, %%o5\n\t"							\
-	"stx	%%o7, [%%g6 + %4]\n\t"							\
+	"stx	%%o6, [%%g6 + %3]\n\t"							\
 	"stx	%%o5, [%%g6 + %2]\n\t"							\
 	"rdpr	%%cwp, %%o5\n\t"							\
+	"stx	%%o7, [%%g6 + %4]\n\t"							\
 	"stx	%%o5, [%%g6 + %5]\n\t"							\
 	"mov	%0, %%g6\n\t"								\
+	"ldx	[%0 + %5], %%g1\n\t"							\
 	"wr	%0, 0x0, %%pic\n\t"							\
-	"ldx	[%%g6 + %5], %%g1\n\t"							\
 	"wrpr	%%g1, %%cwp\n\t"							\
 	"ldx	[%%g6 + %2], %%o5\n\t"							\
 	"ldx	[%%g6 + %3], %%o6\n\t"							\
 	"ldx	[%%g6 + %4], %%o7\n\t"							\
 	"wrpr	%%o5, 0x0, %%wstate\n\t"						\
 	"ldx	[%%sp + 2047 + 0x70], %%i6\n\t"						\
+	"ldx	[%%sp + 2047 + 0x78], %%i7\n\t"						\
 	"jmpl	%%o7 + 0x8, %%g0\n\t"							\
-	" ldx	[%%sp + 2047 + 0x78], %%i7\n\t"						\
+	" wrpr	%%g2, 0x0, %%pstate\n\t"						\
 	: /* No outputs */								\
 	: "r" (next), "r" (task_pc),							\
 	  "i" ((const unsigned long)(&((struct task_struct *)0)->tss.wstate)),		\
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/uaccess.h linux/include/asm-sparc64/uaccess.h
--- v2.1.42/linux/include/asm-sparc64/uaccess.h	Mon Apr 14 16:28:24 1997
+++ linux/include/asm-sparc64/uaccess.h	Thu Jun 12 16:22:10 1997
@@ -1,4 +1,4 @@
-/* $Id: uaccess.h,v 1.12 1997/04/10 23:32:50 davem Exp $ */
+/* $Id: uaccess.h,v 1.13 1997/05/29 12:45:04 jj Exp $ */
 #ifndef _ASM_UACCESS_H
 #define _ASM_UACCESS_H
 
@@ -151,8 +151,8 @@
 	" mov	%3, %0\n\n\t"						\
 	".previous\n\t"							\
 	".section __ex_table,#alloc\n\t"				\
-	".align	4\n\t"							\
-	".word	1b, 3b\n\t"						\
+	".align	8\n\t"							\
+	".xword	1b, 3b\n\t"						\
 	".previous\n\n\t"						\
        : "=r" (ret) : "r" (x), "r" (__m(addr)),				\
 	 "i" (-EFAULT), "i" (ASI_S))
@@ -163,8 +163,8 @@
 	"/* Put user asm ret, inline. */\n"				\
 "1:\t"	"st"#size "a %1, [%2] %3\n\n\t"					\
 	".section __ex_table,#alloc\n\t"				\
-	".align	4\n\t"							\
-	".word	1b, __ret_efault\n\n\t"					\
+	".align	8\n\t"							\
+	".xword	1b, __ret_efault\n\n\t"					\
 	".previous\n\n\t"						\
        : "=r" (foo) : "r" (x), "r" (__m(addr)), "i" (ASI_S));		\
 else									\
@@ -178,8 +178,8 @@
 	" restore %%g0, %3, %%o0\n\n\t"					\
 	".previous\n\t"							\
 	".section __ex_table,#alloc\n\t"				\
-	".align	4\n\t"							\
-	".word	1b, 3b\n\n\t"						\
+	".align	8\n\t"							\
+	".xword	1b, 3b\n\n\t"						\
 	".previous\n\n\t"						\
        : "=r" (foo) : "r" (x), "r" (__m(addr)),				\
          "i" (ret), "i" (ASI_S))
@@ -221,8 +221,8 @@
 	" mov	%3, %0\n\n\t"						\
 	".previous\n\t"							\
 	".section __ex_table,#alloc\n\t"				\
-	".align	4\n\t"							\
-	".word	1b, 3b\n\n\t"						\
+	".align	8\n\t"							\
+	".xword	1b, 3b\n\n\t"						\
 	".previous\n\t"							\
        : "=r" (ret), "=r" (x) : "r" (__m(addr)),			\
 	 "i" (-EFAULT), "i" (ASI_S))
@@ -233,8 +233,8 @@
 	"/* Get user asm ret, inline. */\n"				\
 "1:\t"	"ld"#size "a [%1] %2, %0\n\n\t"					\
 	".section __ex_table,#alloc\n\t"				\
-	".align	4\n\t"							\
-	".word	1b,__ret_efault\n\n\t"					\
+	".align	8\n\t"							\
+	".xword	1b,__ret_efault\n\n\t"					\
 	".previous\n\t"							\
        : "=r" (x) : "r" (__m(addr)), "i" (ASI_S));			\
 else									\
@@ -248,8 +248,8 @@
 	" restore %%g0, %3, %%o0\n\n\t"					\
 	".previous\n\t"							\
 	".section __ex_table,#alloc\n\t"				\
-	".align	4\n\t"							\
-	".word	1b, 3b\n\n\t"						\
+	".align	8\n\t"							\
+	".xword	1b, 3b\n\n\t"						\
 	".previous\n\t"							\
        : "=r" (x) : "r" (__m(addr)), "i" (retval), "i" (ASI_S))
 
@@ -291,8 +291,8 @@
   __kernel_size_t ret;
   __asm__ __volatile__ ("
 	.section __ex_table,#alloc
-	.align 4
-	.word 1f,3
+	.align 8
+	.xword 1f,3
 	.previous
 1:
 	wr %%g0, %3, %%asi
diff -u --recursive --new-file v2.1.42/linux/include/asm-sparc64/vuid_event.h linux/include/asm-sparc64/vuid_event.h
--- v2.1.42/linux/include/asm-sparc64/vuid_event.h	Mon Dec 30 02:00:03 1996
+++ linux/include/asm-sparc64/vuid_event.h	Thu Jun 12 16:22:10 1997
@@ -5,8 +5,6 @@
 	unsigned char  pair_type; /* unused by X11 */
         unsigned char  pair;	  /* unused by X11 */
         int            value;	  /* VKEY_UP, VKEY_DOWN or delta */
-
-	/* XXX Timeval could hose old 32-bit programs, investigate and fixme XXX */
         struct timeval time;
 } Firm_event;
 
diff -u --recursive --new-file v2.1.42/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h
--- v2.1.42/linux/include/linux/affs_fs.h	Tue May 13 22:41:18 1997
+++ linux/include/linux/affs_fs.h	Thu Jun 12 16:22:10 1997
@@ -69,8 +69,7 @@
 extern int	affs_symlink(struct inode *dir, const char *name, int len,
 		             const char *symname);
 extern int	affs_rename(struct inode *old_dir, const char *old_name, int old_len,
-			    struct inode *new_dir, const char *new_name, int new_len,
-			    int must_be_dir);
+			    struct inode *new_dir, const char *new_name, int new_len);
 
 /* inode.c */
 
diff -u --recursive --new-file v2.1.42/linux/include/linux/atalk.h linux/include/linux/atalk.h
--- v2.1.42/linux/include/linux/atalk.h	Thu Jun 12 15:29:21 1997
+++ linux/include/linux/atalk.h	Sun Jun 15 15:13:16 1997
@@ -17,6 +17,8 @@
 #define ATADDR_BCAST	(__u8)255
 #define DDP_MAXSZ	587
 
+#define SIOCATALKDIFADDR       (SIOCPROTOPRIVATE + 0)
+
 struct at_addr 
 {
 	__u16	s_net;
diff -u --recursive --new-file v2.1.42/linux/include/linux/binfmts.h linux/include/linux/binfmts.h
--- v2.1.42/linux/include/linux/binfmts.h	Mon Apr 14 16:28:25 1997
+++ linux/include/linux/binfmts.h	Thu Jun 12 16:22:10 1997
@@ -53,6 +53,7 @@
 extern int init_script_binfmt(void);
 extern int init_java_binfmt(void);
 extern int init_em86_binfmt(void);
+extern int init_misc_binfmt(void);
 
 extern int prepare_binprm(struct linux_binprm *);
 extern void remove_arg_zero(struct linux_binprm *);
diff -u --recursive --new-file v2.1.42/linux/include/linux/console_struct.h linux/include/linux/console_struct.h
--- v2.1.42/linux/include/linux/console_struct.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/console_struct.h	Thu Jun 12 16:22:10 1997
@@ -0,0 +1,142 @@
+/*
+ * console_struct.h
+ *
+ * Data structure and defines shared between console.c, vga.c and tga.c
+ */
+
+#define NPAR 16
+
+struct vc_data {
+	unsigned long	vc_screenbuf_size;
+	unsigned short	vc_video_erase_char;	/* Background erase character */
+	unsigned char	vc_attr;		/* Current attributes */
+	unsigned char	vc_def_color;		/* Default colors */
+	unsigned char	vc_color;		/* Foreground & background */
+	unsigned char	vc_s_color;		/* Saved foreground & background */
+	unsigned char	vc_ulcolor;		/* Colour for underline mode */
+	unsigned char	vc_halfcolor;		/* Colour for half intensity mode */
+	unsigned long	vc_origin;		/* Used for EGA/VGA fast scroll	*/
+	unsigned long	vc_scr_end;		/* Used for EGA/VGA fast scroll	*/
+	unsigned long	vc_pos;
+	unsigned long	vc_x,vc_y;
+	unsigned long	vc_top,vc_bottom;
+	unsigned long	vc_state;
+	unsigned long	vc_npar,vc_par[NPAR];
+	unsigned long	vc_video_mem_start;	/* Start of video RAM		*/
+	unsigned long	vc_video_mem_end;	/* End of video RAM (sort of)	*/
+	unsigned long	vc_saved_x;
+	unsigned long	vc_saved_y;
+	/* mode flags */
+	unsigned long	vc_charset	: 1;	/* Character set G0 / G1 */
+	unsigned long	vc_s_charset	: 1;	/* Saved character set */
+	unsigned long	vc_disp_ctrl	: 1;	/* Display chars < 32? */
+	unsigned long	vc_toggle_meta	: 1;	/* Toggle high bit? */
+	unsigned long	vc_decscnm	: 1;	/* Screen Mode */
+	unsigned long	vc_decom	: 1;	/* Origin Mode */
+	unsigned long	vc_decawm	: 1;	/* Autowrap Mode */
+	unsigned long	vc_deccm	: 1;	/* Cursor Visible */
+	unsigned long	vc_decim	: 1;	/* Insert Mode */
+	unsigned long	vc_deccolm	: 1;	/* 80/132 Column Mode */
+	/* attribute flags */
+	unsigned long	vc_intensity	: 2;	/* 0=half-bright, 1=normal, 2=bold */
+	unsigned long	vc_underline	: 1;
+	unsigned long	vc_blink	: 1;
+	unsigned long	vc_reverse	: 1;
+	unsigned long	vc_s_intensity	: 2;	/* saved rendition */
+	unsigned long	vc_s_underline	: 1;
+	unsigned long	vc_s_blink	: 1;
+	unsigned long	vc_s_reverse	: 1;
+	/* misc */
+	unsigned long	vc_ques		: 1;
+	unsigned long	vc_need_wrap	: 1;
+	unsigned long	vc_can_do_color	: 1;
+	unsigned long	vc_has_scrolled : 1;	/* Info for unblank_screen */
+	unsigned long	vc_kmalloced	: 1;	/* kfree_s() needed */
+	unsigned long	vc_report_mouse : 2;
+	unsigned char	vc_utf		: 1;	/* Unicode UTF-8 encoding */
+	unsigned char	vc_utf_count;
+		 long	vc_utf_char;
+	unsigned long	vc_tab_stop[5];		/* Tab stops. 160 columns. */
+	unsigned char   vc_palette[16*3];       /* Colour palette for VGA+ */
+	unsigned short * vc_translate;
+	unsigned char 	vc_G0_charset;
+	unsigned char 	vc_G1_charset;
+	unsigned char 	vc_saved_G0;
+	unsigned char 	vc_saved_G1;
+	unsigned int	vc_bell_pitch;		/* Console bell pitch */
+	unsigned int	vc_bell_duration;	/* Console bell duration */
+	/* additional information is in vt_kern.h */
+};
+
+struct vc {
+	struct vc_data *d;
+
+	/* might add  scrmem, vt_struct, kbd  at some time,
+	   to have everything in one place - the disadvantage
+	   would be that vc_cons etc can no longer be static */
+};
+
+extern struct vc vc_cons [MAX_NR_CONSOLES];
+
+#define screenbuf_size	(vc_cons[currcons].d->vc_screenbuf_size)
+#define origin		(vc_cons[currcons].d->vc_origin)
+#define scr_end	(vc_cons[currcons].d->vc_scr_end)
+#define pos		(vc_cons[currcons].d->vc_pos)
+#define top		(vc_cons[currcons].d->vc_top)
+#define bottom		(vc_cons[currcons].d->vc_bottom)
+#define x		(vc_cons[currcons].d->vc_x)
+#define y		(vc_cons[currcons].d->vc_y)
+#define vc_state	(vc_cons[currcons].d->vc_state)
+#define npar		(vc_cons[currcons].d->vc_npar)
+#define par		(vc_cons[currcons].d->vc_par)
+#define ques		(vc_cons[currcons].d->vc_ques)
+#define attr		(vc_cons[currcons].d->vc_attr)
+#define saved_x	(vc_cons[currcons].d->vc_saved_x)
+#define saved_y	(vc_cons[currcons].d->vc_saved_y)
+#define translate	(vc_cons[currcons].d->vc_translate)
+#define G0_charset	(vc_cons[currcons].d->vc_G0_charset)
+#define G1_charset	(vc_cons[currcons].d->vc_G1_charset)
+#define saved_G0	(vc_cons[currcons].d->vc_saved_G0)
+#define saved_G1	(vc_cons[currcons].d->vc_saved_G1)
+#define utf		(vc_cons[currcons].d->vc_utf)
+#define utf_count	(vc_cons[currcons].d->vc_utf_count)
+#define utf_char	(vc_cons[currcons].d->vc_utf_char)
+#define video_mem_start (vc_cons[currcons].d->vc_video_mem_start)
+#define video_mem_end	(vc_cons[currcons].d->vc_video_mem_end)
+#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)
+#define disp_ctrl	(vc_cons[currcons].d->vc_disp_ctrl)
+#define toggle_meta	(vc_cons[currcons].d->vc_toggle_meta)
+#define decscnm	(vc_cons[currcons].d->vc_decscnm)
+#define decom		(vc_cons[currcons].d->vc_decom)
+#define decawm		(vc_cons[currcons].d->vc_decawm)
+#define deccm		(vc_cons[currcons].d->vc_deccm)
+#define decim		(vc_cons[currcons].d->vc_decim)
+#define deccolm	(vc_cons[currcons].d->vc_deccolm)
+#define need_wrap	(vc_cons[currcons].d->vc_need_wrap)
+#define has_scrolled	(vc_cons[currcons].d->vc_has_scrolled)
+#define kmalloced	(vc_cons[currcons].d->vc_kmalloced)
+#define report_mouse	(vc_cons[currcons].d->vc_report_mouse)
+#define color		(vc_cons[currcons].d->vc_color)
+#define s_color	(vc_cons[currcons].d->vc_s_color)
+#define def_color	(vc_cons[currcons].d->vc_def_color)
+#define 	foreground	(color & 0x0f)
+#define 	background	(color & 0xf0)
+#define charset	(vc_cons[currcons].d->vc_charset)
+#define s_charset	(vc_cons[currcons].d->vc_s_charset)
+#define	intensity	(vc_cons[currcons].d->vc_intensity)
+#define	underline	(vc_cons[currcons].d->vc_underline)
+#define	blink		(vc_cons[currcons].d->vc_blink)
+#define	reverse		(vc_cons[currcons].d->vc_reverse)
+#define	s_intensity	(vc_cons[currcons].d->vc_s_intensity)
+#define	s_underline	(vc_cons[currcons].d->vc_s_underline)
+#define	s_blink		(vc_cons[currcons].d->vc_s_blink)
+#define	s_reverse	(vc_cons[currcons].d->vc_s_reverse)
+#define	ulcolor		(vc_cons[currcons].d->vc_ulcolor)
+#define	halfcolor	(vc_cons[currcons].d->vc_halfcolor)
+#define tab_stop	(vc_cons[currcons].d->vc_tab_stop)
+#define palette		(vc_cons[currcons].d->vc_palette)
+#define bell_pitch	(vc_cons[currcons].d->vc_bell_pitch)
+#define bell_duration	(vc_cons[currcons].d->vc_bell_duration)
+
+#define vcmode		(vt_cons[currcons]->vc_mode)
+#define structsize	(sizeof(struct vc_data) + sizeof(struct vt_struct))
diff -u --recursive --new-file v2.1.42/linux/include/linux/consolemap.h linux/include/linux/consolemap.h
--- v2.1.42/linux/include/linux/consolemap.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/consolemap.h	Thu Jun 12 16:22:10 1997
@@ -0,0 +1,14 @@
+/*
+ * consolemap.h
+ *
+ * Interface between console.c, selection.c  and consolemap.c
+ */
+#define LAT1_MAP 0
+#define GRAF_MAP 1
+#define IBMPC_MAP 2
+#define USER_MAP 3
+
+extern int hashtable_contents_valid;
+extern unsigned char inverse_translate(int glyph);
+extern unsigned short *set_translate(int m);
+extern int conv_uni_to_pc(long ucs);
diff -u --recursive --new-file v2.1.42/linux/include/linux/dalloc.h linux/include/linux/dalloc.h
--- v2.1.42/linux/include/linux/dalloc.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/dalloc.h	Thu Jun 12 21:53:45 1997
@@ -0,0 +1,102 @@
+#ifndef DALLOC_H
+#define DALLOC_H
+/*
+ * $Id: dalloc.h,v 1.3 1997/06/13 04:39:34 davem Exp $
+ *
+ * include/linux/dalloc.h - alloc routines for dcache
+ * alloc / free space for pathname strings
+ * Copyright (C) 1997, Thomas Schoebel-Theuer,
+ * <schoebel@informatik.uni-stuttgart.de>.
+ */
+
+#define D_MAXLEN   1024
+
+/* public flags for d_add() */
+#define D_NORMAL     0
+#define D_BASKET     1 /* put into basket (deleted/unref'd files) */
+#define D_DUPLICATE  2 /* allow duplicate entries */
+#define D_NOCHECKDUP 4 /* no not check for duplicates */
+
+/* public flags for d_flag */
+#define D_PRELOADED 8
+
+/* public flags for d_del() */
+#define D_REMOVE         0
+#define D_NO_CLEAR_INODE 1
+
+#define IS_ROOT(x) ((x) == (x)->d_parent)
+
+struct dentry {
+	union {
+		struct inode  * d_inode;  /* Where the name belongs to */
+		unsigned long d_ino;      /* for preliminary entries */
+	} u;
+	struct dentry * d_parent; /* parent directory */
+	struct dentry * d_next;   /* hardlink aliasname / empty list */
+	struct dentry * d_prev;   /* hardlink aliasname */
+	struct dentry * d_hash_next;
+	struct dentry * d_hash_prev;
+	struct dentry * d_basket_next;
+	struct dentry * d_basket_prev;
+	short d_len;              /* set by dalloc() */
+	short d_flag;
+	char d_name[D_MAXLEN];
+};
+
+/* "quick string" -- I introduced this to shorten the parameter list
+ * of many routines. Think of it as a (str,stlen) pair.
+ * Storing the len instead of doing strlen() very often is performance
+ * critical.
+ */
+struct qstr {
+	const char * name;
+	int len;
+};
+
+extern struct dentry * the_root;
+
+/* Note that all these routines must be called with vfs_lock() held */
+
+/* get inode, if necessary retrieve it with iget() */
+extern blocking struct inode * d_inode(struct dentry ** changing_entry);
+
+/* allocate proper space for the len */
+extern struct dentry * d_alloc(struct dentry * parent, int len, int isdir);
+
+/* only used once at mount_root() */
+extern blocking
+struct dentry * d_alloc_root(struct inode * root_inode);
+
+/* d_inode is connected with inode, and d_name is copied from ininame.
+ * either of them may be NULL, but when ininame is NULL, dname must be
+ * set by the caller prior to calling this. */
+extern blocking
+void d_add(struct dentry * entry, struct inode * inode,
+	   struct qstr * ininame, int flags);
+
+/* combination of d_alloc() and d_add(), less lookup overhead */
+extern blocking 
+struct dentry * d_entry(struct dentry * parent, struct qstr * name, struct inode * inode);
+extern blocking
+void d_entry_preliminary(struct dentry * parent, struct qstr * name, unsigned long ino);
+
+/* recursive d_del() all successors */
+extern blocking
+void d_del(struct dentry * entry, int flags);
+
+/* used for rename() and baskets */
+extern blocking 
+void d_move(struct dentry * entry, struct inode * newdir,
+	    struct qstr * newname, struct qstr * newapp);
+
+/* appendix may either be NULL or be used for transname suffixes */
+extern struct dentry * d_lookup(struct inode * dir, struct qstr * name,
+				struct qstr * appendix);
+
+/* write full pathname into buffer and return length */
+extern int d_path(struct dentry * entry, struct inode * chroot, char * buf);
+
+extern struct dentry * d_basket(struct dentry * dir_entry);
+
+extern int d_isbasket(struct dentry * entry);
+#endif
diff -u --recursive --new-file v2.1.42/linux/include/linux/dlists.h linux/include/linux/dlists.h
--- v2.1.42/linux/include/linux/dlists.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/dlists.h	Thu Jun 12 16:22:10 1997
@@ -0,0 +1,108 @@
+#ifndef DLISTS_H
+#define DLISTS_H
+/*
+ * include/linux/dlists.h - macros for double linked lists
+ *
+ * Copyright (C) 1997, Thomas Schoebel-Theuer,
+ * <schoebel@informatik.uni-stuttgart.de>.
+ */
+
+/* dlists are cyclic ringlists, so the last element cannot be tested
+ * for NULL. Use the following construct for traversing cyclic lists:
+ * ptr = anchor;
+ * if(ptr) do {
+ *      ...
+ *      ptr = ptr->{something}_{next,prev};
+ * } while(ptr != anchor);
+ * The effort here is paid off with much simpler inserts/removes.
+ * Examples for usage of these macros can be found in fs/ninode.c.
+ * To access the last element in constant time, simply use
+ * anchor->{something}_prev.
+ */
+
+#define DEF_GENERIC_INSERT(CHANGE,PREFIX,NAME,TYPE,NEXT,PREV) \
+static inline void PREFIX##NAME(TYPE ** anchor, TYPE * elem)\
+{\
+	TYPE * oldfirst = *anchor;\
+	if(!oldfirst) {\
+		elem->NEXT = elem->PREV = *anchor = elem;\
+	} else {\
+		elem->PREV = oldfirst->PREV;\
+		elem->NEXT = oldfirst;\
+		oldfirst->PREV->NEXT = elem;\
+		oldfirst->PREV = elem;\
+		if(CHANGE)\
+			*anchor = elem;\
+	}\
+}
+
+/* insert_* is always at the first position */
+#define DEF_INSERT(NAME,TYPE,NEXT,PREV) \
+                   DEF_GENERIC_INSERT(1,insert_,NAME,TYPE,NEXT,PREV)
+
+/* append_* is always at the tail  */
+#define DEF_APPEND(NAME,TYPE,NEXT,PREV) \
+                   DEF_GENERIC_INSERT(0,append_,NAME,TYPE,NEXT,PREV)
+
+/* use this to insert _before_ oldelem somewhere in the middle of the list.
+ * the list must not be empty, and oldelem must be already a member.*/
+#define DEF_INSERT_MIDDLE(NAME,TYPE) \
+static inline void insert_middle_##NAME(TYPE ** anchor, TYPE * oldelem, TYPE * elem)\
+{\
+	int status = (oldelem == *anchor);\
+	insert_##NAME(&oldelem, elem);\
+	if(status)\
+		*anchor = oldelem;\
+}
+
+/* remove can be done with any element in the list */
+#define DEF_REMOVE(NAME,TYPE,NEXT,PREV) \
+static inline void remove_##NAME(TYPE ** anchor, TYPE * elem)\
+{\
+	TYPE * next = elem->NEXT;\
+	if(next == elem) {\
+		*anchor = NULL;\
+	} else {\
+		TYPE * prev = elem->PREV;\
+		prev->NEXT = next;\
+		next->PREV = prev;\
+		elem->NEXT = elem->PREV = NULL;/*leave this during debugging*/\
+		if(*anchor == elem)\
+			*anchor = next;\
+	}\
+}
+
+
+/* According to ideas from David S. Miller, here is a slightly
+ * more efficient plug-in compatible version using non-cyclic lists,
+ * but allowing neither backward traversals nor constant time access
+ * to the last element.
+ * Note that although the interface is the same, the PPREV pointer must be
+ * declared doubly indirect and the test for end-of-list is different. */
+
+/* as above, this inserts always at the head */
+#define DEF_LIN_INSERT(NAME,TYPE,NEXT,PPREV) \
+static inline void insert_##NAME(TYPE ** anchor, TYPE * elem)\
+{\
+	TYPE * first;\
+	if((elem->NEXT = first = *anchor))\
+		first->PPREV = &elem->NEXT;\
+	*anchor = elem;\
+	elem->PPREV = anchor;\
+}
+
+/* as above, this works with any list element */
+#define DEF_LIN_REMOVE(NAME,TYPE,NEXT,PPREV) \
+static inline void remove_##NAME(TYPE ** anchor, TYPE * elem)\
+{\
+	TYPE * pprev;\
+	if((pprev = elem->PPREV)) {\
+		TYPE * next;\
+		if((next = elem->NEXT))\
+			next->PPREV = pprev;\
+		*pprev = next;\
+		elem->PPREV = elem->NEXT = NULL; /*leave this for debugging*/\
+	}\
+}
+
+#endif
diff -u --recursive --new-file v2.1.42/linux/include/linux/ext2_fs.h linux/include/linux/ext2_fs.h
--- v2.1.42/linux/include/linux/ext2_fs.h	Tue May 13 22:41:18 1997
+++ linux/include/linux/ext2_fs.h	Thu Jun 12 16:22:10 1997
@@ -502,7 +502,7 @@
 extern int ext2_link (struct inode *, struct inode *, const char *, int);
 extern int ext2_mknod (struct inode *, const char *, int, int, int);
 extern int ext2_rename (struct inode *, const char *, int,
-			struct inode *, const char *, int, int);
+			struct inode *, const char *, int);
 
 /* super.c */
 extern void ext2_error (struct super_block *, const char *, const char *, ...)
diff -u --recursive --new-file v2.1.42/linux/include/linux/fs.h linux/include/linux/fs.h
--- v2.1.42/linux/include/linux/fs.h	Thu Jun 12 15:28:33 1997
+++ linux/include/linux/fs.h	Sun Jun 15 15:12:29 1997
@@ -15,6 +15,12 @@
 #include <linux/net.h>
 #include <linux/kdev_t.h>
 #include <linux/ioctl.h>
+#include <asm/atomic.h>
+
+/* Prefixes for routines (having no effect), but indicate what
+ * the routine may do. This can greatly ease reasoning about routines...
+ */
+#define blocking /*routine may schedule()*/
 
 /*
  * It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix
@@ -34,7 +40,7 @@
 #define BLOCK_SIZE_BITS 10
 
 /* And dynamically-tunable limits and defaults: */
-extern int max_inodes, nr_inodes;
+extern int max_inodes;
 extern int max_files, nr_files;
 #define NR_INODE 4096	/* this should be bigger than NR_FILE */
 #define NR_FILE 1024	/* this can well be larger on a larger system */
@@ -60,6 +66,17 @@
 #define SEL_OUT		2
 #define SEL_EX		4
 
+/* public flags for file_system_type */
+#define FS_REQUIRES_DEV 1 
+#define FS_NO_DCACHE    2 /* Only dcache the necessary things. */
+#define FS_NO_PRELIM    4 /* prevent preloading of dentries, even if
+			   * FS_NO_DCACHE is not set.
+			   */
+#define FS_IBASKET      8 /* FS does callback to free_ibasket() if space gets low. */
+
+/* public flags for i_status */
+#define ST_MODIFIED 1024
+
 /*
  * These are the fs-independent mount-flags: up to 16 flags are supported
  */
@@ -87,6 +104,13 @@
 #define MS_MGC_MSK 0xffff0000	/* magic flag number mask */
 
 /*
+ * Public flags for namei()
+ */
+#define NAM_PLAIN		0 /* Retrieve last component of pathname as is. */
+#define NAM_FOLLOW_LINK		2 /* If last component of path is a symlink, follow it */
+#define NAM_FOLLOW_TRAILSLASH	4 /* Follow last symlink only if trailed by slash. */
+
+/*
  * Note that read-only etc flags are inode-specific: setting some file-system
  * flags just means all the inodes inherit those flags by default. It might be
  * possible to override it selectively if you really wanted to with some
@@ -281,58 +305,75 @@
 #include <linux/quota.h>
 
 struct inode {
-	struct inode 	*i_hash_next;
-	struct inode	**i_hash_pprev;
-	struct inode	*i_next;
-	struct inode	**i_pprev;
-	unsigned long	i_ino;
-	kdev_t		i_dev;
-	unsigned short	i_count;
-	umode_t		i_mode;
-	nlink_t		i_nlink;
-	uid_t		i_uid;
-	gid_t		i_gid;
-	kdev_t		i_rdev;
-	off_t		i_size;
-	time_t		i_atime;
-	time_t		i_mtime;
-	time_t		i_ctime;
-	unsigned long	i_blksize;
-	unsigned long	i_blocks;
-	unsigned long	i_version;
-	unsigned long	i_nrpages;
-	struct semaphore i_sem;
-	struct inode_operations *i_op;
-	struct super_block *i_sb;
-	struct wait_queue *i_wait;
-	struct file_lock *i_flock;
-	struct vm_area_struct *i_mmap;
-	struct page *i_pages;
-	struct dquot *i_dquot[MAXQUOTAS];
-	struct inode *i_bound_to, *i_bound_by;
-	struct inode *i_mount;
-	unsigned short i_flags;
-	unsigned char i_lock;
-	unsigned char i_dirt;
-	unsigned char i_pipe;
-	unsigned char i_sock;
-	int i_writecount;
-	unsigned int i_attr_flags;
+	struct inode 		*i_hash_next;
+	struct inode		*i_hash_prev;
+	struct inode		*i_next;
+	struct inode		*i_prev;
+
+	unsigned long		i_ino;
+	kdev_t			i_dev;
+	atomic_t		i_count;
+	umode_t			i_mode;
+	nlink_t			i_nlink;
+	uid_t			i_uid;
+	gid_t			i_gid;
+	kdev_t			i_rdev;
+	off_t			i_size;
+	time_t			i_atime;
+	time_t			i_mtime;
+	time_t			i_ctime;
+	unsigned long		i_blksize;
+	unsigned long		i_blocks;
+	unsigned long		i_version;
+	unsigned long		i_nrpages;
+	struct semaphore	i_sem;
+	struct inode_operations	*i_op;
+	struct super_block	*i_sb;
+	struct wait_queue	*i_wait;
+	struct file_lock	*i_flock;
+	struct vm_area_struct	*i_mmap;
+	struct page		*i_pages;
+	struct dquot		*i_dquot[MAXQUOTAS];
+
+	struct inode		*i_lru_next;
+	struct inode		*i_lru_prev;
+
+	struct inode		*i_basket_next;
+	struct inode		*i_basket_prev;
+	struct dentry		*i_dentry;
+
+	short			i_ddir_count;
+	short			i_dent_count;
+	unsigned short		i_status;
+	unsigned short		i_reuse_count;
+
+	struct inode		*i_mount;
+	unsigned int		i_flags;
+	unsigned char		i_lock;
+	unsigned char		i_dirt;
+	unsigned char		i_pipe;
+	unsigned char		i_sock;
+
+	unsigned char		i_level;
+	unsigned short		i_fill;
+
+	int			i_writecount;
+	unsigned int		i_attr_flags;
 	union {
-		struct pipe_inode_info pipe_i;
-		struct minix_inode_info minix_i;
-		struct ext2_inode_info ext2_i;
-		struct hpfs_inode_info hpfs_i;
-		struct msdos_inode_info msdos_i;
-		struct umsdos_inode_info umsdos_i;
-		struct iso_inode_info isofs_i;
-		struct nfs_inode_info nfs_i;
-		struct sysv_inode_info sysv_i;
-		struct affs_inode_info affs_i;
-		struct ufs_inode_info ufs_i;
-		struct romfs_inode_info romfs_i;
-		struct socket socket_i;
-		void * generic_ip;
+		struct pipe_inode_info		pipe_i;
+		struct minix_inode_info		minix_i;
+		struct ext2_inode_info		ext2_i;
+		struct hpfs_inode_info		hpfs_i;
+		struct msdos_inode_info		msdos_i;
+		struct umsdos_inode_info	umsdos_i;
+		struct iso_inode_info		isofs_i;
+		struct nfs_inode_info		nfs_i;
+		struct sysv_inode_info		sysv_i;
+		struct affs_inode_info		affs_i;
+		struct ufs_inode_info		ufs_i;
+		struct romfs_inode_info		romfs_i;
+		struct socket			socket_i;
+		void				*generic_ip;
 	} u;
 };
 
@@ -450,33 +491,38 @@
 #include <linux/romfs_fs_sb.h>
 
 struct super_block {
-	kdev_t s_dev;
-	unsigned long s_blocksize;
-	unsigned char s_blocksize_bits;
-	unsigned char s_lock;
-	unsigned char s_rd_only;
-	unsigned char s_dirt;
-	struct file_system_type *s_type;
-	struct super_operations *s_op;
-	struct dquot_operations *dq_op;
-	unsigned long s_flags;
-	unsigned long s_magic;
-	unsigned long s_time;
-	struct inode * s_covered;
-	struct inode * s_mounted;
-	struct wait_queue * s_wait;
+	kdev_t			s_dev;
+	unsigned long		s_blocksize;
+	unsigned char		s_blocksize_bits;
+	unsigned char		s_lock;
+	unsigned char		s_rd_only;
+	unsigned char		s_dirt;
+	struct file_system_type	*s_type;
+	struct super_operations	*s_op;
+	struct dquot_operations	*dq_op;
+	unsigned long		s_flags;
+	unsigned long		s_magic;
+	unsigned long		s_time;
+	struct inode		*s_covered;
+	struct inode		*s_mounted;
+	struct wait_queue	*s_wait;
+
+	struct inode		*s_ibasket;
+	short int		s_ibasket_count;
+	short int		s_ibasket_max;
+
 	union {
-		struct minix_sb_info minix_sb;
-		struct ext2_sb_info ext2_sb;
-		struct hpfs_sb_info hpfs_sb;
-		struct msdos_sb_info msdos_sb;
-		struct isofs_sb_info isofs_sb;
-		struct nfs_sb_info nfs_sb;
-		struct sysv_sb_info sysv_sb;
-		struct affs_sb_info affs_sb;
-		struct ufs_sb_info ufs_sb;
-		struct romfs_sb_info romfs_sb;
-		void *generic_sbp;
+		struct minix_sb_info	minix_sb;
+		struct ext2_sb_info	ext2_sb;
+		struct hpfs_sb_info	hpfs_sb;
+		struct msdos_sb_info	msdos_sb;
+		struct isofs_sb_info	isofs_sb;
+		struct nfs_sb_info	nfs_sb;
+		struct sysv_sb_info	sysv_sb;
+		struct affs_sb_info	affs_sb;
+		struct ufs_sb_info	ufs_sb;
+		struct romfs_sb_info	romfs_sb;
+		void			*generic_sbp;
 	} u;
 };
 
@@ -515,9 +561,8 @@
 	int (*mkdir) (struct inode *,const char *,int,int);
 	int (*rmdir) (struct inode *,const char *,int);
 	int (*mknod) (struct inode *,const char *,int,int,int);
-	int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int, int);
+	int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int);
 	int (*readlink) (struct inode *,char *,int);
-	int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **);
 	int (*readpage) (struct inode *, struct page *);
 	int (*writepage) (struct inode *, struct page *);
 	int (*bmap) (struct inode *,int);
@@ -551,9 +596,9 @@
 };
 
 struct file_system_type {
-	struct super_block *(*read_super) (struct super_block *, void *, int);
 	const char *name;
-	int requires_dev;
+	int fs_flags;
+	struct super_block *(*read_super) (struct super_block *, void *, int);
 	struct file_system_type * next;
 };
 
@@ -644,8 +689,7 @@
 extern void sync_supers(kdev_t dev);
 extern int bmap(struct inode * inode,int block);
 extern int notify_change(struct inode *, struct iattr *);
-extern int namei(const char * pathname, struct inode ** res_inode);
-extern int lnamei(const char * pathname, struct inode ** res_inode);
+extern int namei(int retr_mode, const char *pathname, struct inode **res_inode);
 extern int permission(struct inode * inode,int mask);
 extern int get_write_access(struct inode *inode);
 extern void put_write_access(struct inode *inode);
@@ -653,12 +697,116 @@
 	struct inode ** res_inode, struct inode * base);
 extern int do_mknod(const char * filename, int mode, dev_t dev);
 extern int do_pipe(int *);
-extern void iput(struct inode * inode);
-extern struct inode * __iget(struct super_block * sb,int nr,int crsmnt);
-extern struct inode * get_empty_inode(void);
+
+#include <asm/semaphore.h>
+
+/* Intended for short locks of the global data structures in inode.c.
+ * Could be replaced with spinlocks completely, since there is
+ * no blocking during manipulation of the static data; however the
+ * lock in invalidate_inodes() may last relatively long.
+ */
+extern struct semaphore vfs_sem;
+extern inline void vfs_lock(void)
+{
+#if 0
+#ifdef __SMP__
+	down(&vfs_sem);
+#endif
+#endif
+}
+
+extern inline void vfs_unlock(void)
+{
+#if 0
+#ifdef __SMP__
+	up(&vfs_sem);
+#endif
+#endif
+}
+
+/* Not to be used by ordinary vfs users */
+extern void _get_inode(struct inode * inode);
+extern blocking void __iput(struct inode * inode);
+
+/* This must not be called if the inode is not in use (i.e. given
+ * back with iput(). The atomic inc assumes that the inode is
+ * already in use, and just has to be incremented higher. 
+ * Please do not directly manipulate i_count any more.
+ * Use iget, iinc and iput.
+ * You may test i_count for zero if you are aware that it
+ * might change under you.
+ */
+extern inline void iinc(struct inode * inode)
+{
+	atomic_inc(&inode->i_count);
+}
+
+/* The same, but the inode may not be in use. This must be called
+ * with vfslock() held, and be asure that the inode argument is
+ * valid (i.e. not out of cache). So the vfs_lock() must span the
+ * retrieval method of the inode.
+ */
+extern inline void iinc_zero(struct inode * inode)
+{
+	if(!atomic_read(&inode->i_count)) {
+		atomic_inc(&inode->i_count);
+		_get_inode(inode);
+	} else
+		atomic_inc(&inode->i_count);
+}
+
+extern blocking void _iput(struct inode * inode);
+extern inline blocking void iput(struct inode * inode)
+{
+	if(inode) {
+		extern void wake_up_interruptible(struct wait_queue **q);
+
+		if(inode->i_pipe)
+			wake_up_interruptible(&inode->u.pipe_i.wait);
+
+		/* It does not matter if somebody re-increments it in between,
+		 * only the _last_ user needs to call _iput().
+		 */
+		if(atomic_dec_and_test(&inode->i_count) && inode->i_ddir_count <= 0)
+			_iput(inode);
+	}
+}
+
+extern blocking struct inode * __iget(struct super_block * sb, unsigned long nr, int crsmnt);
+extern blocking void _clear_inode(struct inode * inode, int external, int verbose);
+extern blocking inline void clear_inode(struct inode * inode)
+{
+	vfs_lock();
+	_clear_inode(inode, 1, 1);
+	vfs_unlock();
+}
+extern blocking struct inode * _get_empty_inode(void);
+extern inline blocking struct inode * get_empty_inode(void)
+{
+	struct inode * inode;
+	vfs_lock();
+	inode = _get_empty_inode();
+	vfs_unlock();
+	return inode;
+}
+/* Please prefer to use this function in future, instead of using
+ * a get_empty_inode()/insert_inode_hash() combination.
+ * It allows for better checking and less race conditions.
+ */
+blocking struct inode * get_empty_inode_hashed(dev_t i_dev, unsigned long i_ino);
+
+extern inline blocking int free_ibasket(struct super_block * sb)
+{
+	extern blocking int _free_ibasket(struct super_block * sb);
+	int res;
+	vfs_lock();
+	res = _free_ibasket(sb);
+	vfs_unlock();
+	return res;
+}
+
 extern void insert_inode_hash(struct inode *);
-extern void clear_inode(struct inode *);
-extern struct inode * get_pipe_inode(void);
+extern blocking struct inode * get_pipe_inode(void);
 extern int get_unused_fd(void);
 extern void put_unused_fd(int);
 extern struct file * get_empty_filp(void);
@@ -694,6 +842,7 @@
 extern long generic_file_read(struct inode *, struct file *, char *, unsigned long);
 extern long generic_file_write(struct inode *, struct file *, const char *, unsigned long);
 
+extern struct super_block *get_super(kdev_t dev);
 extern void put_super(kdev_t dev);
 unsigned long generate_cluster(kdev_t dev, int b[], int size);
 unsigned long generate_cluster_swab32(kdev_t dev, int b[], int size);
@@ -723,7 +872,8 @@
 extern int inode_change_ok(struct inode *, struct iattr *);
 extern void inode_setattr(struct inode *, struct iattr *);
 
-extern inline struct inode * iget(struct super_block * sb,int nr)
+extern inline blocking 
+struct inode * iget(struct super_block * sb, unsigned long nr)
 {
 	return __iget(sb, nr, 1);
 }
diff -u --recursive --new-file v2.1.42/linux/include/linux/kbd_diacr.h linux/include/linux/kbd_diacr.h
--- v2.1.42/linux/include/linux/kbd_diacr.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/kbd_diacr.h	Thu Jun 12 16:22:10 1997
@@ -0,0 +1,8 @@
+#ifndef _DIACR_H
+#define _DIACR_H
+#include <linux/kd.h>
+
+extern struct kbdiacr accent_table[];
+extern unsigned int accent_table_size;
+
+#endif /* _DIACR_H */
diff -u --recursive --new-file v2.1.42/linux/include/linux/kbd_kern.h linux/include/linux/kbd_kern.h
--- v2.1.42/linux/include/linux/kbd_kern.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/kbd_kern.h	Fri Jun 13 13:46:44 1997
@@ -0,0 +1,141 @@
+#ifndef _KBD_KERN_H
+#define _KBD_KERN_H
+
+#include <linux/interrupt.h>
+#include <linux/keyboard.h>
+
+extern int shift_state;
+
+extern char *func_table[MAX_NR_FUNC];
+extern char func_buf[];
+extern char *funcbufptr;
+extern int funcbufsize, funcbufleft;
+
+/*
+ * kbd->xxx contains the VC-local things (flag settings etc..)
+ *
+ * Note: externally visible are LED_SCR, LED_NUM, LED_CAP defined in kd.h
+ *       The code in KDGETLED / KDSETLED depends on the internal and
+ *       external order being the same.
+ *
+ * Note: lockstate is used as index in the array key_map.
+ */
+struct kbd_struct {
+
+	unsigned char lockstate;
+/* 8 modifiers - the names do not have any meaning at all;
+   they can be associated to arbitrarily chosen keys */
+#define VC_SHIFTLOCK	KG_SHIFT	/* shift lock mode */
+#define VC_ALTGRLOCK	KG_ALTGR	/* altgr lock mode */
+#define VC_CTRLLOCK	KG_CTRL 	/* control lock mode */
+#define VC_ALTLOCK	KG_ALT  	/* alt lock mode */
+#define VC_SHIFTLLOCK	KG_SHIFTL	/* shiftl lock mode */
+#define VC_SHIFTRLOCK	KG_SHIFTR	/* shiftr lock mode */
+#define VC_CTRLLLOCK	KG_CTRLL 	/* ctrll lock mode */
+#define VC_CTRLRLOCK	KG_CTRLR 	/* ctrlr lock mode */
+	unsigned char slockstate; 	/* for `sticky' Shift, Ctrl, etc. */
+
+	unsigned char ledmode:2; 	/* one 2-bit value */
+#define LED_SHOW_FLAGS 0        /* traditional state */
+#define LED_SHOW_IOCTL 1        /* only change leds upon ioctl */
+#define LED_SHOW_MEM 2          /* `heartbeat': peek into memory */
+
+	unsigned char ledflagstate:3;	/* flags, not lights */
+	unsigned char default_ledflagstate:3;
+#define VC_SCROLLOCK	0	/* scroll-lock mode */
+#define VC_NUMLOCK	1	/* numeric lock mode */
+#define VC_CAPSLOCK	2	/* capslock mode */
+
+	unsigned char kbdmode:2;	/* one 2-bit value */
+#define VC_XLATE	0	/* translate keycodes using keymap */
+#define VC_MEDIUMRAW	1	/* medium raw (keycode) mode */
+#define VC_RAW		2	/* raw (scancode) mode */
+#define VC_UNICODE	3	/* Unicode mode */
+
+	unsigned char modeflags:5;
+#define VC_APPLIC	0	/* application key mode */
+#define VC_CKMODE	1	/* cursor key mode */
+#define VC_REPEAT	2	/* keyboard repeat */
+#define VC_CRLF		3	/* 0 - enter sends CR, 1 - enter sends CRLF */
+#define VC_META		4	/* 0 - meta, 1 - meta=prefix with ESC */
+};
+
+extern struct kbd_struct kbd_table[];
+
+extern int kbd_init(void);
+
+extern unsigned char getledstate(void);
+extern void setledstate(struct kbd_struct *kbd, unsigned int led);
+
+extern int do_poke_blanked_console;
+
+extern inline void show_console(void)
+{
+	do_poke_blanked_console = 1;
+	mark_bh(CONSOLE_BH);
+}
+
+extern inline void set_console(int nr)
+{
+	want_console = nr;
+	mark_bh(CONSOLE_BH);
+}
+
+extern inline void set_leds(void)
+{
+	mark_bh(KEYBOARD_BH);
+}
+
+extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
+{
+	return ((kbd->modeflags >> flag) & 1);
+}
+
+extern inline int vc_kbd_led(struct kbd_struct * kbd, int flag)
+{
+	return ((kbd->ledflagstate >> flag) & 1);
+}
+
+extern inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+{
+	kbd->modeflags |= 1 << flag;
+}
+
+extern inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag)
+{
+	kbd->ledflagstate |= 1 << flag;
+}
+
+extern inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+{
+	kbd->modeflags &= ~(1 << flag);
+}
+
+extern inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag)
+{
+	kbd->ledflagstate &= ~(1 << flag);
+}
+
+extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
+{
+	kbd->lockstate ^= 1 << flag;
+}
+
+extern inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag)
+{
+	kbd->slockstate ^= 1 << flag;
+}
+
+extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+{
+	kbd->modeflags ^= 1 << flag;
+}
+
+extern inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
+{
+	kbd->ledflagstate ^= 1 << flag;
+}
+
+#define U(x) ((x) ^ 0xf000)
+
+#endif
diff -u --recursive --new-file v2.1.42/linux/include/linux/kbd_ll.h linux/include/linux/kbd_ll.h
--- v2.1.42/linux/include/linux/kbd_ll.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/kbd_ll.h	Thu Jun 12 16:22:10 1997
@@ -0,0 +1,12 @@
+/*
+ *	Interface between the low-level keyboard driver and the keymapper
+ */
+
+#ifndef _KBD_LL_H
+#define _KBD_LL_H
+
+extern struct pt_regs *kbd_pt_regs;
+
+void handle_scancode(unsigned char scancode);
+
+#endif	/* _KBD_LL_H */
diff -u --recursive --new-file v2.1.42/linux/include/linux/linkage.h linux/include/linux/linkage.h
--- v2.1.42/linux/include/linux/linkage.h	Wed Apr 16 14:15:00 1997
+++ linux/include/linux/linkage.h	Thu Jun 12 16:22:10 1997
@@ -15,6 +15,10 @@
 #define SYMBOL_NAME_LABEL(X) X/**/:
 #endif
 
+#ifdef __mc68000__
+#define __ALIGN .align 4
+#define __ALIGN_STR ".align 4"
+#else
 #if !defined(__i486__) && !defined(__i586__)
 #define __ALIGN .align 4,0x90
 #define __ALIGN_STR ".align 4,0x90"
@@ -22,6 +26,7 @@
 #define __ALIGN .align 16,0x90
 #define __ALIGN_STR ".align 16,0x90"
 #endif /* __i486__/__i586__ */
+#endif /* __mc68000__ */
 
 #ifdef __ASSEMBLY__
 
diff -u --recursive --new-file v2.1.42/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h
--- v2.1.42/linux/include/linux/minix_fs.h	Sat Nov 30 02:24:02 1996
+++ linux/include/linux/minix_fs.h	Thu Jun 12 16:22:10 1997
@@ -100,7 +100,7 @@
 extern int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len);
 extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
 extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len, int must_be_dir);
+			struct inode * new_dir, const char * new_name, int new_len);
 extern struct inode * minix_new_inode(const struct inode * dir);
 extern void minix_free_inode(struct inode * inode);
 extern unsigned long minix_count_free_inodes(struct super_block *sb);
diff -u --recursive --new-file v2.1.42/linux/include/linux/mm.h linux/include/linux/mm.h
--- v2.1.42/linux/include/linux/mm.h	Thu Jun 12 15:28:33 1997
+++ linux/include/linux/mm.h	Mon Jun 16 08:46:24 1997
@@ -124,7 +124,7 @@
 	struct wait_queue *wait;
 	struct page **pprev_hash;
 	struct buffer_head * buffers;
-	unsigned long swap_unlock_entry;
+	unsigned long pg_swap_entry;
 	unsigned long map_nr;	/* page->map_nr == page - mem_map */
 } mem_map_t;
 
@@ -138,6 +138,7 @@
 #define PG_swap_unlock_after	 6
 #define PG_DMA			 7
 #define PG_Slab			 8
+#define PG_swap_cache		 9
 #define PG_reserved		31
 
 /* Make it prettier to test the above... */
@@ -151,10 +152,19 @@
 #define PageSwapUnlockAfter(page) (test_bit(PG_swap_unlock_after, &(page)->flags))
 #define PageDMA(page)		(test_bit(PG_DMA, &(page)->flags))
 #define PageSlab(page)		(test_bit(PG_Slab, &(page)->flags))
+#define PageSwapCache(page)	(test_bit(PG_swap_cache, &(page)->flags))
 #define PageReserved(page)	(test_bit(PG_reserved, &(page)->flags))
 
 #define PageSetSlab(page)	(set_bit(PG_Slab, &(page)->flags))
+#define PageSetSwapCache(page)	(set_bit(PG_swap_cache, &(page)->flags))
+#define PageTestandSetSwapCache(page)	\
+			(test_and_set_bit(PG_swap_cache, &(page)->flags))
+
 #define PageClearSlab(page)	(clear_bit(PG_Slab, &(page)->flags))
+#define PageClearSwapCache(page)(clear_bit(PG_swap_cache, &(page)->flags))
+
+#define PageTestandClearSwapCache(page)	\
+			(test_and_clear_bit(PG_swap_cache, &(page)->flags))
 
 /*
  * page->reserved denotes a page which must never be accessed (which
diff -u --recursive --new-file v2.1.42/linux/include/linux/msdos_fs.h linux/include/linux/msdos_fs.h
--- v2.1.42/linux/include/linux/msdos_fs.h	Thu Jun 12 15:30:06 1997
+++ linux/include/linux/msdos_fs.h	Sun Jun 15 15:14:00 1997
@@ -261,8 +261,7 @@
 extern int msdos_unlink(struct inode *dir,const char *name,int len);
 extern int msdos_unlink_umsdos(struct inode *dir,const char *name,int len);
 extern int msdos_rename(struct inode *old_dir,const char *old_name,int old_len,
-			struct inode *new_dir,const char *new_name,int new_len,
-			int must_be_dir);
+			struct inode *new_dir,const char *new_name,int new_len);
 
 /* fatfs_syms.c */
 extern int init_fat_fs(void);
@@ -274,8 +273,7 @@
 extern int vfat_mkdir(struct inode *dir,const char *name,int len,int mode);
 extern int vfat_rmdir(struct inode *dir,const char *name,int len);
 extern int vfat_rename(struct inode *old_dir,const char *old_name,int old_len,
-		       struct inode *new_dir,const char *new_name,int new_len,
-		       int must_be_dir);
+		       struct inode *new_dir,const char *new_name,int new_len);
 extern void vfat_put_super(struct super_block *sb);
 extern struct super_block *vfat_read_super(struct super_block *sb,void *data,
 					   int silent);
diff -u --recursive --new-file v2.1.42/linux/include/linux/nametrans.h linux/include/linux/nametrans.h
--- v2.1.42/linux/include/linux/nametrans.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/nametrans.h	Fri Jun 13 13:46:16 1997
@@ -0,0 +1,69 @@
+#ifndef NAMETRANS_H
+#define NAMETRANS_H
+/*
+ * $Id: nametrans.h,v 1.1 1997/06/04 08:26:57 davem Exp $
+ *
+ * include/linux/nametrans.h - context-dependend filename suffixes.
+ * Copyright (C) 1997, Thomas Schoebel-Theuer,
+ * <schoebel@informatik.uni-stuttgart.de>.
+ */
+
+#include <linux/dalloc.h>
+#include <linux/sysctl.h>
+
+#define MAX_DEFAULT_TRANSLEN 128
+
+/* only filenames matching the following length restrictions can be
+ * translated. I introduced these restrictions because they *greatly*
+ * simplify buffer management (no need to allocate kernel pages and free them).
+ * The maximal total length of a context-dependend filename is the
+ * sum of both constants. */
+#define MAX_TRANS_FILELEN 128 /* max len of a name that could be translated */
+#define MAX_TRANS_SUFFIX   64 /* max len of a #keyword=value# suffix */
+
+/* max number of translations */
+#define MAX_TRANSLATIONS 16
+
+struct translations {
+	int count;
+	struct qstr name[MAX_TRANSLATIONS];
+	struct qstr c_name[MAX_TRANSLATIONS];
+};
+
+/* global/default translations */
+extern char nametrans_txt[MAX_DEFAULT_TRANSLEN];
+
+/* Any changer of a built-in translation must set this flag */
+extern int translations_dirty;
+
+
+/* called once at boot time */
+extern void init_nametrans(void);
+
+/* set global translations */
+extern void nametrans_setup(char * line);
+
+/* return reusable global buffer. needed by VFS. */
+struct translations * get_translations(char * env);
+
+/* if the _first_ environment variable is "NAMETRANS", return
+ * a pointer to the list of appendices.
+ * You can set the first environment variable using
+ * 'env - NAMETRANS=... "`env`" command ...'
+ */
+extern char * env_transl(void);
+
+/* if name has the correct suffix "#keyword=correct_context#",
+ * return position of the suffix, else 0.
+ */
+extern char* testname(int restricted, char* name);
+
+/* for use in kernel/sysctrl.h */
+extern int nametrans_dostring(ctl_table * table, int write, struct file * filp,
+			      void * buffer, size_t * lenp);
+extern int nametrans_string(ctl_table * table, int * name, int nlen,
+			    void * oldval, size_t * oldlenp,
+			    void * newval, size_t newlen, void ** context);
+
+
+#endif
diff -u --recursive --new-file v2.1.42/linux/include/linux/nfsd/nfsfh.h linux/include/linux/nfsd/nfsfh.h
--- v2.1.42/linux/include/linux/nfsd/nfsfh.h	Thu Jun 12 15:30:33 1997
+++ linux/include/linux/nfsd/nfsfh.h	Sun Jun 15 15:14:28 1997
@@ -151,7 +151,7 @@
 	if (!(inode = fhp->fh_inode))
 		return;
 
-	if (!inode->i_count) {
+	if (!atomic_read(&inode->i_count)) {
 		printk("nfsd: trying to free free inode in %s:%d\n"
 		       "      dev %04x ino %ld, mode %07o\n",
 		       file, line, inode->i_dev,
diff -u --recursive --new-file v2.1.42/linux/include/linux/omirr.h linux/include/linux/omirr.h
--- v2.1.42/linux/include/linux/omirr.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/omirr.h	Sun Jun 15 15:14:39 1997
@@ -0,0 +1,17 @@
+/*
+ * fs/proc/omirr.c  -  online mirror support
+ *
+ * (C) 1997 Thomas Schoebel-Theuer
+ */
+
+#ifndef OMIRR_H
+#define OMIRR_H
+#include <linux/fs.h>
+#include <linux/dalloc.h>
+
+extern int omirr_print(struct dentry * ent1, struct dentry * ent2, 
+		       struct qstr * suffix, const char * fmt, ...);
+
+extern int omirr_printall(struct inode * inode, const char * fmt, ...);
+
+#endif
diff -u --recursive --new-file v2.1.42/linux/include/linux/pci.h linux/include/linux/pci.h
--- v2.1.42/linux/include/linux/pci.h	Sat May 24 09:10:25 1997
+++ linux/include/linux/pci.h	Thu Jun 12 16:22:10 1997
@@ -238,7 +238,9 @@
 #define PCI_DEVICE_ID_ATI_68800		0x4158
 #define PCI_DEVICE_ID_ATI_215CT222	0x4354
 #define PCI_DEVICE_ID_ATI_210888CX	0x4358
+#define PCI_DEVICE_ID_ATI_215GT		0x4754
 #define PCI_DEVICE_ID_ATI_210888GX	0x4758
+#define PCI_DEVICE_ID_ATI_264VT		0x5654
 
 #define PCI_VENDOR_ID_VLSI		0x1004
 #define PCI_DEVICE_ID_VLSI_82C592	0x0005
@@ -270,6 +272,7 @@
 #define PCI_DEVICE_ID_DEC_TULIP_FAST	0x0009
 #define PCI_DEVICE_ID_DEC_FDDI		0x000F
 #define PCI_DEVICE_ID_DEC_TULIP_PLUS	0x0014
+#define PCI_DEVICE_ID_DEC_21142		0x0019
 #define PCI_DEVICE_ID_DEC_21052		0x0021
 #define PCI_DEVICE_ID_DEC_21152		0x0024
 
@@ -279,12 +282,16 @@
 #define PCI_DEVICE_ID_CIRRUS_5434_4	0x00a4
 #define PCI_DEVICE_ID_CIRRUS_5434_8	0x00a8
 #define PCI_DEVICE_ID_CIRRUS_5436	0x00ac
+#define PCI_DEVICE_ID_CIRRUS_5446	0x00b8
+#define PCI_DEVICE_ID_CIRRUS_5464	0x00d4
 #define PCI_DEVICE_ID_CIRRUS_6729	0x1100
 #define PCI_DEVICE_ID_CIRRUS_7542	0x1200
 #define PCI_DEVICE_ID_CIRRUS_7543	0x1202
+#define PCI_DEVICE_ID_CIRRUS_7541	0x1204
 
 #define PCI_VENDOR_ID_IBM		0x1014
 #define PCI_DEVICE_ID_IBM_82G2675	0x001d
+#define PCI_DEVICE_ID_IBM_82351		0x0022
 
 #define PCI_VENDOR_ID_WD		0x101c
 #define PCI_DEVICE_ID_WD_7197		0x3296
@@ -311,6 +318,7 @@
 #define PCI_DEVICE_ID_CT_65545		0x00d8
 #define PCI_DEVICE_ID_CT_65548		0x00dc
 #define PCI_DEVICE_ID_CT_65550		0x00e0
+#define PCI_DEVICE_ID_CT_65554		0x00e4
 
 #define PCI_VENDOR_ID_MIRO		0x1031
 #define PCI_DEVICE_ID_MIRO_36050	0x5601
@@ -328,6 +336,8 @@
 #define PCI_DEVICE_ID_SI_601		0x0601
 #define PCI_DEVICE_ID_SI_5511		0x5511
 #define PCI_DEVICE_ID_SI_5513		0x5513
+#define PCI_DEVICE_ID_SI_5571		0x5571
+#define PCI_DEVICE_ID_SI_7001		0x7001
 
 #define PCI_VENDOR_ID_HP		0x103c
 #define PCI_DEVICE_ID_HP_J2585A		0x1030
@@ -363,6 +373,11 @@
 #define PCI_VENDOR_ID_WINBOND2		0x1050
 #define PCI_DEVICE_ID_WINBOND2_89C940	0x0940
 
+#define PCI_VENDOR_ID_MOTOROLA		0x1057
+#define PCI_DEVICE_ID_MOTOROLA_MPC105	0x0001
+#define PCI_DEVICE_ID_MOTOROLA_MPC106	0x0002
+#define PCI_DEVICE_ID_MOTOROLA_RAVEN	0x4801
+
 #define PCI_VENDOR_ID_PROMISE		0x105a
 #define PCI_DEVICE_ID_PROMISE_5300	0x5300
 
@@ -421,6 +436,7 @@
 #define PCI_VENDOR_ID_WINBOND		0x10ad
 #define PCI_DEVICE_ID_WINBOND_83769	0x0001
 #define PCI_DEVICE_ID_WINBOND_82C105	0x0105
+#define PCI_DEVICE_ID_WINBOND_83C553	0x0565
 
 #define PCI_VENDOR_ID_3COM		0x10b7
 #define PCI_DEVICE_ID_3COM_3C590	0x5900
@@ -428,6 +444,7 @@
 #define PCI_DEVICE_ID_3COM_3C595T4	0x5951
 #define PCI_DEVICE_ID_3COM_3C595MII	0x5952
 #define PCI_DEVICE_ID_3COM_3C900TPO	0x9000
+#define PCI_DEVICE_ID_3COM_3C900COMBO	0x9001
 #define PCI_DEVICE_ID_3COM_3C905TX	0x9050
 
 #define PCI_VENDOR_ID_AL		0x10b9
@@ -445,6 +462,7 @@
 
 #define PCI_VENDOR_ID_ASP		0x10cd
 #define PCI_DEVICE_ID_ASP_ABP940	0x1200
+#define PCI_DEVICE_ID_ASP_ABP940U	0x1300
 
 #define PCI_VENDOR_ID_CERN		0x10dc
 #define PCI_DEVICE_ID_CERN_SPSB_PMC	0x0001
@@ -456,8 +474,12 @@
 #define PCI_VENDOR_ID_TEKRAM2		0x10e1
 #define PCI_DEVICE_ID_TEKRAM2_690c	0x690c
 
+#define PCI_VENDOR_ID_TUNDRA		0x10e3
+#define PCI_DEVICE_ID_TUNDRA_CA91C042	0x0000
+
 #define PCI_VENDOR_ID_AMCC		0x10e8
 #define PCI_DEVICE_ID_AMCC_MYRINET	0x8043
+#define PCI_DEVICE_ID_AMCC_S5933	0x807d
 
 #define PCI_VENDOR_ID_INTERG		0x10ea
 #define PCI_DEVICE_ID_INTERG_1680	0x1680
@@ -472,7 +494,10 @@
 #define PCI_VENDOR_ID_VIA		0x1106
 #define PCI_DEVICE_ID_VIA_82C505	0x0505
 #define PCI_DEVICE_ID_VIA_82C561	0x0561
+#define PCI_DEVICE_ID_VIA_82C586_1	0x0571
 #define PCI_DEVICE_ID_VIA_82C576	0x0576
+#define PCI_DEVICE_ID_VIA_82C585	0x0585
+#define PCI_DEVICE_ID_VIA_82C586_0	0x0586
 #define PCI_DEVICE_ID_VIA_82C416	0x1571
 
 #define PCI_VENDOR_ID_VORTEX		0x1119
@@ -519,15 +544,22 @@
 #define PCI_DEVICE_ID_MUTECH_MV1000	0x0001
 
 #define PCI_VENDOR_ID_TOSHIBA		0x1179
+#define PCI_DEVICE_ID_TOSHIBA_601	0x0601
 
 #define PCI_VENDOR_ID_ZEITNET		0x1193
 #define PCI_DEVICE_ID_ZEITNET_1221	0x0001
 #define PCI_DEVICE_ID_ZEITNET_1225	0x0002
 
+#define PCI_VENDOR_ID_OMEGA		0x119b
+#define PCI_DEVICE_ID_OMEGA_PCMCIA     	0x1221
+
 #define PCI_VENDOR_ID_SPECIALIX		0x11cb
 #define PCI_DEVICE_ID_SPECIALIX_XIO	0x4000
 #define PCI_DEVICE_ID_SPECIALIX_RIO	0x8000
 
+#define PCI_VENDOR_ID_ZORAN		0x11de
+#define PCI_DEVICE_ID_ZORAN_36120	0x6120
+
 #define PCI_VENDOR_ID_COMPEX		0x11f6
 #define PCI_DEVICE_ID_COMPEX_RL2000	0x1401
 
@@ -543,6 +575,12 @@
 #define PCI_DEVICE_ID_CYCLOM_Z_Lo	0x0200
 #define PCI_DEVICE_ID_CYCLOM_Z_Hi	0x0201
 
+#define PCI_VENDOR_ID_3DFX		0x121a
+#define PCI_DEVICE_ID_3DFX_VOODOO	0x0001
+
+#define PCI_VENDOR_ID_SIGMADES		0x1236
+#define PCI_DEVICE_ID_SIGMADES_6425	0x6401
+
 #define PCI_VENDOR_ID_OPTIBASE		0x1255
 #define PCI_DEVICE_ID_OPTIBASE_FORGE	0x1110
 #define PCI_DEVICE_ID_OPTIBASE_FUSION	0x1210
@@ -556,10 +594,13 @@
 #define PCI_VENDOR_ID_TEKRAM		0x1de1
 #define PCI_DEVICE_ID_TEKRAM_DC290	0xdc29
 
-#define PCI_VENDOR_ID_3DLABS		0x3D3D
+#define PCI_VENDOR_ID_3DLABS		0x3d3d
 #define PCI_DEVICE_ID_3DLABS_300SX	0x0001
+#define PCI_DEVICE_ID_3DLABS_DELTA	0x0003
+#define PCI_DEVICE_ID_3DLABS_PERMEDIA	0x0004
 
 #define PCI_VENDOR_ID_AVANCE		0x4005
+#define PCI_DEVICE_ID_AVANCE_ALG2064	0x2064
 #define PCI_DEVICE_ID_AVANCE_2302	0x2302
 
 #define PCI_VENDOR_ID_S3		0x5333
@@ -582,6 +623,8 @@
 #define PCI_DEVICE_ID_INTEL_82378	0x0484
 #define PCI_DEVICE_ID_INTEL_82430	0x0486
 #define PCI_DEVICE_ID_INTEL_82434	0x04a3
+#define PCI_DEVICE_ID_INTEL_82092AA_0	0x1221
+#define PCI_DEVICE_ID_INTEL_82092AA_1	0x1222
 #define PCI_DEVICE_ID_INTEL_7116	0x1223
 #define PCI_DEVICE_ID_INTEL_82596	0x1226
 #define PCI_DEVICE_ID_INTEL_82865	0x1227
@@ -589,15 +632,19 @@
 #define PCI_DEVICE_ID_INTEL_82437	0x122d
 #define PCI_DEVICE_ID_INTEL_82371_0	0x122e
 #define PCI_DEVICE_ID_INTEL_82371_1	0x1230
-#define PCI_DEVICE_ID_INTEL_430MX_0	0x1234
-#define PCI_DEVICE_ID_INTEL_430MX_1	0x1235
+#define PCI_DEVICE_ID_INTEL_82371MX	0x1234
+#define PCI_DEVICE_ID_INTEL_82437MX	0x1235
 #define PCI_DEVICE_ID_INTEL_82441	0x1237
 #define PCI_DEVICE_ID_INTEL_82439	0x1250
 #define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
 #define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
 #define PCI_DEVICE_ID_INTEL_82371SB_2	0x7020
 #define PCI_DEVICE_ID_INTEL_82437VX	0x7030
+#define PCI_DEVICE_ID_INTEL_82439TX	0x7100
+#define PCI_DEVICE_ID_INTEL_82371AB_0	0x7110
 #define PCI_DEVICE_ID_INTEL_82371AB	0x7111
+#define PCI_DEVICE_ID_INTEL_82371AB_2	0x7112
+#define PCI_DEVICE_ID_INTEL_82371AB_3	0x7113
 #define PCI_DEVICE_ID_INTEL_P6		0x84c4
 #define PCI_DEVICE_ID_INTEL_P6_2	0x84c5
 
diff -u --recursive --new-file v2.1.42/linux/include/linux/proc_fs.h linux/include/linux/proc_fs.h
--- v2.1.42/linux/include/linux/proc_fs.h	Thu Jun 12 15:28:33 1997
+++ linux/include/linux/proc_fs.h	Sun Jun 15 15:12:30 1997
@@ -48,8 +48,10 @@
 	PROC_RTC,
 	PROC_LOCKS,
 	PROC_ZORRO,
+	PROC_HARDWARE,
 	PROC_SLABINFO,
-	PROC_PARPORT
+	PROC_PARPORT,
+	PROC_OMIRR /* whether enabled or not */
 };
 
 enum pid_directory_inos {
@@ -133,6 +135,11 @@
 	PROC_NET_X25_ROUTES,
 	PROC_NET_X25,
 	PROC_NET_TR_RIF,
+	PROC_NET_DN_DEV,
+	PROC_NET_DN_ADJ,
+	PROC_NET_DN_L1,
+	PROC_NET_DN_L2,
+	PROC_NET_DN_SKT,
 	PROC_NET_LAST
 };
 
@@ -353,6 +360,11 @@
 #if CONFIG_AP1000
 extern struct inode_operations proc_ringbuf_inode_operations;
 #endif
+extern struct inode_operations proc_omirr_inode_operations;
+
+/* Not sure whether this belongs here */
+int proc_arbitrary_lookup(struct inode * dir, const char * name,
+			  int len, struct inode ** result);
 #endif
 
 /*
diff -u --recursive --new-file v2.1.42/linux/include/linux/sched.h linux/include/linux/sched.h
--- v2.1.42/linux/include/linux/sched.h	Thu Jun 12 15:28:33 1997
+++ linux/include/linux/sched.h	Sun Jun 15 15:12:29 1997
@@ -500,13 +500,8 @@
  */
 extern inline void __add_wait_queue(struct wait_queue ** p, struct wait_queue * wait)
 {
-	struct wait_queue *head = *p;
-	struct wait_queue *next = WAIT_QUEUE_HEAD(p);
-
-	if (head)
-		next = head;
+	wait->next = *p ? : WAIT_QUEUE_HEAD(p);
 	*p = wait;
-	wait->next = next;
 }
 
 extern rwlock_t waitqueue_lock;
diff -u --recursive --new-file v2.1.42/linux/include/linux/selection.h linux/include/linux/selection.h
--- v2.1.42/linux/include/linux/selection.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/selection.h	Sun Jun 15 15:12:58 1997
@@ -0,0 +1,208 @@
+/*
+ * selection.h
+ *
+ * Interface between console.c, tty_io.c, vt.c, vc_screen.c and selection.c
+ */
+
+#include <linux/config.h>
+
+extern int sel_cons;
+
+extern void clear_selection(void);
+extern int set_selection(const unsigned long arg, struct tty_struct *tty, int user);
+extern int paste_selection(struct tty_struct *tty);
+extern int sel_loadlut(const unsigned long arg);
+extern int mouse_reporting(void);
+extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry);
+
+#ifdef CONFIG_FB_CONSOLE
+extern unsigned long get_video_num_columns(unsigned int console);
+extern unsigned long get_video_num_lines(unsigned int console);
+extern unsigned long get_video_size_row(unsigned int console);
+#else
+#define get_video_num_columns(dummy) video_num_columns
+#define get_video_num_lines(dummy) video_num_lines
+#define get_video_size_row(dummy) video_size_row
+#endif
+
+extern unsigned long video_num_columns;
+extern unsigned long video_num_lines;
+extern unsigned long video_size_row;
+extern unsigned char video_type;
+extern unsigned long video_mem_base;
+extern unsigned long video_mem_term;
+extern unsigned long video_screen_size;
+extern unsigned short video_port_reg;
+extern unsigned short video_port_val;
+
+extern int console_blanked;
+extern int can_do_color;
+
+extern unsigned long video_font_height;
+extern unsigned long video_scan_lines;
+extern unsigned long default_font_height;
+extern int video_font_is_default;
+
+extern unsigned char color_table[];
+extern int default_red[];
+extern int default_grn[];
+extern int default_blu[];
+
+extern unsigned short __real_origin;
+extern unsigned short __origin;
+extern unsigned char has_wrapped;
+
+extern unsigned short *vc_scrbuf[MAX_NR_CONSOLES];
+
+extern void do_unblank_screen(void);
+extern unsigned short *screen_pos(int currcons, int w_offset, int viewed);
+extern unsigned short screen_word(int currcons, int offset, int viewed);
+extern int scrw2glyph(unsigned short scr_word);
+extern void complement_pos(int currcons, int offset);
+extern void invert_screen(int currcons, int offset, int count, int shift);
+
+#define reverse_video_char(a)	(((a) & 0x88) | ((((a) >> 4) | ((a) << 4)) & 0x77))
+#define reverse_video_short(a)	(((a) & 0x88ff) | \
+	(((a) & 0x7000) >> 4) | (((a) & 0x0700) << 4))
+/* this latter line used to have masks 0xf000 and 0x0f00, but selection
+   requires a self-inverse operation; moreover, the old version looks wrong */
+
+extern void getconsxy(int currcons, char *p);
+extern void putconsxy(int currcons, char *p);
+
+
+/* how to access screen memory */
+
+#if defined(CONFIG_TGA_CONSOLE)
+
+extern int tga_blitc(unsigned int, unsigned long);
+extern unsigned long video_mem_term;
+
+/*
+ * TGA console screen memory access
+ * 
+ * TGA is *not* a character/attribute cell device; font bitmaps must be rendered
+ * to the screen pixels.
+ *
+ * We must test for an Alpha kernel virtual address that falls within
+ *  the "shadow screen" memory. This condition indicates we really want 
+ *  to write to the screen, so, we do... :-)
+ *
+ * NOTE also: there's only *TWO* operations: to put/get a character/attribute.
+ *  All the others needed by VGA support go away, as Not Applicable for TGA.
+ */
+static inline void scr_writew(unsigned short val, unsigned short * addr)
+{
+        /*
+         * always deposit the char/attr, then see if it was to "screen" mem.
+	 * if so, then render the char/attr onto the real screen.
+         */
+        *addr = val;
+        if ((unsigned long)addr < video_mem_term &&
+	    (unsigned long)addr >= video_mem_base) {
+                tga_blitc(val, (unsigned long) addr);
+        }
+}
+
+static inline unsigned short scr_readw(unsigned short * addr)
+{
+	return *addr;
+}
+
+#elif defined(CONFIG_SUN_CONSOLE)
+#include <linux/vt_kern.h>
+#include <linux/kd.h>
+extern int sun_blitc(unsigned int, unsigned long);
+extern void memsetw(void * s, unsigned short c, unsigned int count);
+extern void memcpyw(unsigned short *to, unsigned short *from, unsigned int count);
+extern unsigned long video_mem_term;
+
+/* Basically the same as the TGA stuff. */
+static inline void scr_writew(unsigned short val, unsigned short * addr)
+{
+        /*
+         * always deposit the char/attr, then see if it was to "screen" mem.
+	 * if so, then render the char/attr onto the real screen.
+         */
+	if (*addr != val) {
+        	*addr = val;
+		if ((unsigned long)addr < video_mem_term &&
+		    (unsigned long)addr >= video_mem_base &&
+		    vt_cons [fg_console]->vc_mode == KD_TEXT)
+			sun_blitc(val, (unsigned long) addr);
+	}
+}
+
+static inline unsigned short scr_readw(unsigned short * addr)
+{
+	return *addr;
+}
+
+#else /* CONFIG_TGA_CONSOLE  || CONFIG_SUN_CONSOLE */
+
+/*
+ * normal VGA console access
+ *
+ */ 
+
+#include <asm/io.h> 
+
+/*
+ * NOTE: "(long) addr < 0" tests for an Alpha kernel virtual address; this
+ *  indicates a VC's backing store; otherwise, it's a bus memory address, for
+ *  the VGA's screen memory, so we do the Alpha "swizzle"... :-)
+ */
+static inline void scr_writeb(unsigned char val, unsigned char * addr)
+{
+	if ((long) addr < 0)
+		*addr = val;
+	else
+		writeb(val, (unsigned long) addr);
+}
+
+static inline unsigned char scr_readb(unsigned char * addr)
+{
+	if ((long) addr < 0)
+		return *addr;
+	return readb((unsigned long) addr);
+}
+
+static inline void scr_writew(unsigned short val, unsigned short * addr)
+{
+	if ((long) addr < 0)
+		*addr = val;
+	else
+		writew(val, (unsigned long) addr);
+}
+
+static inline unsigned short scr_readw(unsigned short * addr)
+{
+	if ((long) addr < 0)
+		return *addr;
+	return readw((unsigned long) addr);
+}
+
+#endif /* CONFIG_TGA_CONSOLE */
+
+#ifndef CONFIG_SUN_CONSOLE
+static inline void memsetw(void * s, unsigned short c, unsigned int count)
+{
+	unsigned short * addr = (unsigned short *) s;
+
+	count /= 2;
+	while (count) {
+		count--;
+		scr_writew(c, addr++);
+	}
+}
+
+static inline void memcpyw(unsigned short *to, unsigned short *from,
+			   unsigned int count)
+{
+	count /= 2;
+	while (count) {
+		count--;
+		scr_writew(scr_readw(from++), to++);
+	}
+}
+#endif /* CONFIG_SUN_CONSOLE */
diff -u --recursive --new-file v2.1.42/linux/include/linux/socket.h linux/include/linux/socket.h
--- v2.1.42/linux/include/linux/socket.h	Thu May 15 16:48:05 1997
+++ linux/include/linux/socket.h	Thu Jun 12 16:22:10 1997
@@ -140,7 +140,7 @@
 #define AF_X25		9	/* Reserved for X.25 project 	*/
 #define AF_INET6	10	/* IP version 6			*/
 #define AF_ROSE		11	/* Amateur Radio X.25 PLP	*/
-#define AF_DECNET	12	/* Reserved for DECnet project	*/
+#define AF_DECnet	12	/* Reserved for DECnet project	*/
 #define AF_NETBEUI	13	/* Reserved for 802.2LLC project*/
 #define AF_SECURITY	14	/* Security callback pseudo AF */
 #define pseudo_AF_KEY   15      /* PF_KEY key management API */
@@ -160,7 +160,7 @@
 #define PF_X25		AF_X25
 #define PF_INET6	AF_INET6
 #define PF_ROSE		AF_ROSE
-#define PF_DECNET	AF_DECNET
+#define PF_DECnet	AF_DECnet
 #define PF_NETBEUI	AF_NETBEUI
 #define PF_SECURITY	AF_SECURITY
 #define PF_KEY          pseudo_AF_KEY
diff -u --recursive --new-file v2.1.42/linux/include/linux/swap.h linux/include/linux/swap.h
--- v2.1.42/linux/include/linux/swap.h	Thu Jun 12 15:28:33 1997
+++ linux/include/linux/swap.h	Mon Jun 16 08:46:24 1997
@@ -66,8 +66,7 @@
 
 /* linux/mm/swap_state.c */
 extern void show_swap_cache_info(void);
-extern int add_to_swap_cache(unsigned long, unsigned long);
-extern unsigned long init_swap_cache(unsigned long, unsigned long);
+extern int add_to_swap_cache(struct page *, unsigned long);
 extern void swap_duplicate(unsigned long);
 
 /* linux/mm/swapfile.c */
@@ -90,8 +89,6 @@
 
 #define SWAP_CACHE_INFO
 
-extern unsigned long * swap_cache;
-
 #ifdef SWAP_CACHE_INFO
 extern unsigned long swap_cache_add_total;
 extern unsigned long swap_cache_add_success;
@@ -101,39 +98,37 @@
 extern unsigned long swap_cache_find_success;
 #endif
 
-extern inline unsigned long in_swap_cache(unsigned long index)
+extern inline unsigned long in_swap_cache(struct page *page)
 {
-	return swap_cache[index]; 
+	if (PageSwapCache(page))
+		return page->pg_swap_entry;
+	return 0;
 }
 
-extern inline long find_in_swap_cache(unsigned long index)
+extern inline long find_in_swap_cache(struct page *page)
 {
-	unsigned long entry;
-
 #ifdef SWAP_CACHE_INFO
 	swap_cache_find_total++;
 #endif
-	entry = xchg(swap_cache + index, 0);
+	if (PageTestandClearSwapCache(page))  {
 #ifdef SWAP_CACHE_INFO
-	if (entry)
 		swap_cache_find_success++;
 #endif	
-	return entry;
+		return page->pg_swap_entry;
+	}
+	return 0;
 }
 
-extern inline int delete_from_swap_cache(unsigned long index)
+extern inline int delete_from_swap_cache(struct page *page)
 {
-	unsigned long entry;
-	
 #ifdef SWAP_CACHE_INFO
 	swap_cache_del_total++;
 #endif	
-	entry = xchg(swap_cache + index, 0);
-	if (entry)  {
+	if (PageTestandClearSwapCache(page))  {
 #ifdef SWAP_CACHE_INFO
 		swap_cache_del_success++;
 #endif
-		swap_free(entry);
+		swap_free(page->pg_swap_entry);
 		return 1;
 	}
 	return 0;
diff -u --recursive --new-file v2.1.42/linux/include/linux/sysctl.h linux/include/linux/sysctl.h
--- v2.1.42/linux/include/linux/sysctl.h	Thu May 29 21:53:11 1997
+++ linux/include/linux/sysctl.h	Thu Jun 12 16:22:10 1997
@@ -68,6 +68,8 @@
 	KERN_SPARC_REBOOT,	/* reboot command on Sparc */
 	KERN_CTLALTDEL,		/* int: allow ctl-alt-del to reboot */
 	KERN_PRINTK,            /* sturct: control printk logging parameters */
+	KERN_NAMETRANS,		/* Name translation */
+	KERN_STATINODE
 };
 
 
@@ -75,7 +77,6 @@
 enum
 {
 	VM_SWAPCTL=1,		/* struct: Set vm swapping control */
-	VM_KSWAPD,		/* struct: control background pageout */
 	VM_SWAPOUT,		/* int: Background pageout interval */
 	VM_FREEPG,		/* struct: Set free page thresholds */
 	VM_BDFLUSH,		/* struct: Control buffer cache flushing */
@@ -100,6 +101,7 @@
 	NET_ROSE,
 	NET_X25,
 	NET_TR,
+	NET_DECNET
 };
 
 
@@ -110,6 +112,7 @@
 	NET_CORE_RMEM_MAX,
 	NET_CORE_WMEM_DEFAULT,
 	NET_CORE_RMEM_DEFAULT,
+	NET_CORE_DESTROY_DELAY,
 };
 
 /* /proc/sys/net/ethernet */
@@ -118,12 +121,19 @@
 
 /* /proc/sys/net/unix */
 
+enum
+{
+	NET_UNIX_DESTROY_DELAY=1,
+	NET_UNIX_DELETE_DELAY,
+};
+
 /* /proc/sys/net/ipv4 */
 enum
 {
 	NET_IPV4_ARP_RES_TIME=1,
 	NET_IPV4_ARP_DEAD_RES_TIME,
 	NET_IPV4_ARP_MAX_TRIES,
+	NET_IPV4_ARP_MAX_PINGS,
 	NET_IPV4_ARP_TIMEOUT,
 	NET_IPV4_ARP_CHECK_INTERVAL,
 	NET_IPV4_ARP_CONFIRM_INTERVAL,
@@ -147,9 +157,22 @@
 	NET_IPV4_ACCEPT_REDIRECTS,
 	NET_IPV4_SECURE_REDIRECTS,
 	NET_IPV4_RFC1620_REDIRECTS,
-	NET_TCP_SYN_RETRIES,
-	NET_IPFRAG_HIGH_THRESH,
-	NET_IPFRAG_LOW_THRESH,
+	NET_IPV4_TCP_SYN_RETRIES,
+	NET_IPV4_IPFRAG_HIGH_THRESH,
+	NET_IPV4_IPFRAG_LOW_THRESH,
+	NET_IPV4_IPFRAG_TIME,
+	NET_IPV4_TCP_MAX_KA_PROBES,
+	NET_IPV4_TCP_KEEPALIVE_TIME,
+	NET_IPV4_TCP_KEEPALIVE_PROBES,
+	NET_IPV4_TCP_RETRIES1,
+	NET_IPV4_TCP_RETRIES2,
+	NET_IPV4_TCP_MAX_DELAY_ACKS,
+	NET_IPV4_TCP_FIN_TIMEOUT,
+	NET_IPV4_IGMP_MAX_HOST_REPORT_DELAY,
+	NET_IPV4_IGMP_TIMER_SCALE,
+	NET_IPV4_IGMP_AGE_THRESHOLD,
+	NET_TCP_SYNCOOKIES,
+	NET_TCP_ALWAYS_SYNCOOKIE,
 };
 
 
@@ -176,7 +199,15 @@
 
 /* /proc/sys/net/ipx */
 
+
 /* /proc/sys/net/appletalk */
+enum {
+	NET_ATALK_AARP_EXPIRY_TIME = 1,
+	NET_ATALK_AARP_TICK_TIME,
+	NET_ATALK_AARP_RETRANSMIT_LIMIT,
+	NET_ATALK_AARP_RESOLVE_TIME,
+};
+
 
 /* /proc/sys/net/netrom */
 enum {
@@ -240,6 +271,16 @@
 	NET_TR_RIF_TIMEOUT=1
 };
 
+/* /proc/sys/net/decnet */
+enum {
+	NET_DECNET_DEF_T3_BROADCAST = 1,
+	NET_DECNET_DEF_T3_POINTTOPOINT,
+	NET_DECNET_DEF_T1,
+	NET_DECNET_DEF_BCT1,
+	NET_DECNET_CACHETIMEOUT,
+	NET_DECNET_DEBUG_LEVEL
+};
+
 /* CTL_PROC names: */
 
 /* CTL_FS names: */
@@ -269,6 +310,8 @@
 			 void *, size_t *);
 extern int proc_dointvec_minmax(ctl_table *, int, struct file *,
 				void *, size_t *);
+extern int proc_dointvec_jiffies(ctl_table *, int, struct file *,
+				 void *, size_t *);
 
 extern int do_sysctl (int *name, int nlen,
 		      void *oldval, size_t *oldlenp,
diff -u --recursive --new-file v2.1.42/linux/include/linux/sysrq.h linux/include/linux/sysrq.h
--- v2.1.42/linux/include/linux/sysrq.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/sysrq.h	Sun Jun 15 15:12:30 1997
@@ -0,0 +1,25 @@
+/* -*- linux-c -*-
+ *
+ *	$Id: sysrq.h,v 1.2 1997/05/31 18:33:41 mj Exp $
+ *
+ *	Linux Magic System Request Key Hacks
+ *
+ *	(c) 1997 Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+ */
+
+#include <linux/config.h>
+
+extern int emergency_sync_scheduled;
+
+#define EMERG_SYNC 1
+#define EMERG_REMOUNT 2
+
+extern void do_emergency_sync(void);
+
+#ifdef CONFIG_MAGIC_SYSRQ
+#define CHECK_EMERGENCY_SYNC			\
+	if (emergency_sync_scheduled)		\
+		do_emergency_sync();
+#else
+#define CHECK_EMERGENCY_SYNC
+#endif
diff -u --recursive --new-file v2.1.42/linux/include/linux/sysv_fs.h linux/include/linux/sysv_fs.h
--- v2.1.42/linux/include/linux/sysv_fs.h	Thu Jun 12 15:30:55 1997
+++ linux/include/linux/sysv_fs.h	Sun Jun 15 15:14:49 1997
@@ -373,7 +373,7 @@
 extern int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len);
 extern int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev);
 extern int sysv_rename(struct inode * old_dir, const char * old_name, int old_len,
-	struct inode * new_dir, const char * new_name, int new_len, int must_be_dir);
+		       struct inode * new_dir, const char * new_name, int new_len);
 extern struct inode * sysv_new_inode(const struct inode * dir);
 extern void sysv_free_inode(struct inode * inode);
 extern unsigned long sysv_count_free_inodes(struct super_block *sb);
diff -u --recursive --new-file v2.1.42/linux/include/linux/umsdos_fs.p linux/include/linux/umsdos_fs.p
--- v2.1.42/linux/include/linux/umsdos_fs.p	Sat Nov 30 02:24:02 1996
+++ linux/include/linux/umsdos_fs.p	Thu Jun 12 16:22:10 1997
@@ -122,8 +122,7 @@
 	 int old_len,
 	 struct inode *new_dir,
 	 const char *new_name,
-	 int new_len,
-	 int must_be_dir);
+	 int new_len);
 /* rdir.c 22/03/95 03.31.42 */
 int umsdos_rlookup_x (struct inode *dir,
 	 const char *name,
diff -u --recursive --new-file v2.1.42/linux/include/linux/vt_kern.h linux/include/linux/vt_kern.h
--- v2.1.42/linux/include/linux/vt_kern.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/vt_kern.h	Thu Jun 12 16:22:10 1997
@@ -0,0 +1,39 @@
+#ifndef _VT_KERN_H
+#define _VT_KERN_H
+
+/*
+ * this really is an extension of the vc_cons structure in console.c, but
+ * with information needed by the vt package
+ */
+
+#include <linux/vt.h>
+
+/*
+ * Presently, a lot of graphics programs do not restore the contents of
+ * the higher font pages.  Defining this flag will avoid use of them, but
+ * will lose support for PIO_FONTRESET.  Note that many font operations are
+ * not likely to work with these programs anyway; they need to be
+ * fixed.  The linux/Documentation directory includes a code snippet
+ * to save and restore the text font.
+ */
+#define BROKEN_GRAPHICS_PROGRAMS 1
+
+extern struct vt_struct {
+	int vc_num;				/* The console number */
+	unsigned char	vc_mode;		/* KD_TEXT, ... */
+	unsigned char	vc_kbdraw;
+	unsigned char	vc_kbde0;
+	unsigned char   vc_kbdleds;
+	struct vt_mode	vt_mode;
+	int		vt_pid;
+	int		vt_newvt;
+	struct wait_queue *paste_wait;
+} *vt_cons[MAX_NR_CONSOLES];
+
+void (*kd_mksound)(unsigned int hz, unsigned int ticks);
+int vc_allocate(unsigned int console);
+int vc_cons_allocated(unsigned int console);
+int vc_resize(unsigned long lines, unsigned long cols);
+void vc_disallocate(unsigned int console);
+
+#endif /* _VT_KERN_H */
diff -u --recursive --new-file v2.1.42/linux/include/linux/wrapper.h linux/include/linux/wrapper.h
--- v2.1.42/linux/include/linux/wrapper.h	Fri Apr 12 00:33:25 1996
+++ linux/include/linux/wrapper.h	Thu Jun 12 16:22:10 1997
@@ -20,9 +20,9 @@
 #define module_unregister_blkdev unregister_blkdev
 
 #define inode_get_rdev(i) i->i_rdev
-#define inode_get_count(i) i->i_count
-#define inode_inc_count(i) i->i_count++
-#define inode_dec_count(i) i->i_count--
+#define inode_get_count(i) atomic_read(&((i)->i_count))
+#define inode_inc_count(i) atomic_inc(&((i)->i_count))
+#define inode_dec_count(i) atomic_dec(&((i)->i_count))
 
 #define file_get_flags(f) f->f_flags
 
@@ -35,6 +35,6 @@
 
 #define mem_map_reserve(p) set_bit(PG_reserved, &mem_map[p].flags)
 #define mem_map_unreserve(p) clear_bit(PG_reserved, &mem_map[p].flags)
-#define mem_map_inc_count(p) mem_map[p].count++
-#define mem_map_dec_count(p) mem_map[p].count--
+#define mem_map_inc_count(p) atomic_inc(&(mem_map[p].count))
+#define mem_map_dec_count(p) atomic_dec(&(mem_map[p].count))
 #endif
diff -u --recursive --new-file v2.1.42/linux/include/net/checksum.h linux/include/net/checksum.h
--- v2.1.42/linux/include/net/checksum.h	Thu Jun 12 15:31:03 1997
+++ linux/include/net/checksum.h	Sun Jun 15 15:14:59 1997
@@ -26,6 +26,7 @@
 #ifndef _CHECKSUM_H
 #define _CHECKSUM_H
 
+#include <asm/types.h>
 #include <asm/byteorder.h>
 #include <net/ip.h>
 #include <asm/checksum.h>
diff -u --recursive --new-file v2.1.42/linux/include/net/sock.h linux/include/net/sock.h
--- v2.1.42/linux/include/net/sock.h	Thu Jun 12 15:29:23 1997
+++ linux/include/net/sock.h	Sun Jun 15 15:13:17 1997
@@ -70,6 +70,10 @@
 #include <linux/atalk.h>
 #endif
 
+#if defined(CONFIG_DECNET) || defined(CONFIG_DECNET_MODULE)
+#include <net/dn.h>
+#endif
+
 #include <linux/igmp.h>
 
 #include <asm/atomic.h>
@@ -447,6 +451,7 @@
 
 	union
 	{
+		void *destruct_hook;
 	  	struct unix_opt	af_unix;
 #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
 		struct atalk_sock	af_at;
@@ -472,6 +477,9 @@
 		rose_cb			*rose;
 #endif
 #endif
+#if defined(CONFIG_DECNET) || defined(CONFIG_DECNET_MODULE)
+	        dn_cb                    *dn;
+#endif
 	} protinfo;  		
 
 /* 
@@ -523,6 +531,7 @@
 
   	int			(*backlog_rcv) (struct sock *sk,
 						struct sk_buff *skb);  
+	void                    (*destruct)(struct sock *sk);
 };
 
 /*
diff -u --recursive --new-file v2.1.42/linux/init/main.c linux/init/main.c
--- v2.1.42/linux/init/main.c	Thu May 29 21:53:11 1997
+++ linux/init/main.c	Thu Jun 12 16:22:10 1997
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/major.h>
 #include <linux/blk.h>
+#include <linux/nametrans.h>
 #include <linux/init.h>
 #ifdef CONFIG_ROOT_NFS
 #include <linux/nfs_fs.h>
@@ -72,6 +73,7 @@
 extern long mca_init(long, long);
 extern long sbus_init(long, long);
 extern void sysctl_init(void);
+extern void filescache_init(void);
 
 extern void smp_setup(char *str, int *ints);
 extern void no_scroll(char *str, int *ints);
@@ -84,6 +86,9 @@
 extern void lp_setup(char *str, int *ints);
 #endif
 extern void eth_setup(char *str, int *ints);
+#ifdef CONFIG_DECNET
+extern void decnet_setup(char *str, int *ints);
+#endif
 extern void xd_setup(char *str, int *ints);
 #ifdef CONFIG_BLK_DEV_EZ
 extern void ez_setup(char *str, int *ints);
@@ -324,6 +329,9 @@
 #ifdef CONFIG_INET
 	{ "ether=", eth_setup },
 #endif
+#ifdef CONFIG_DECNET
+	{ "decnet=", decnet_setup },
+#endif
 #ifdef CONFIG_PRINTER
         { "lp=", lp_setup },
 #endif
@@ -551,6 +559,12 @@
 		return 1;
 	}
 #endif
+#ifdef CONFIG_TRANS_NAMES
+	if(!strncmp(line,"nametrans=",10)) {
+		nametrans_setup(line+10);
+		return 1;
+	}
+#endif
 	while (bootsetups[i].str) {
 		int n = strlen(bootsetups[i].str);
 		if (!strncmp(line,bootsetups[i].str,n)) {
@@ -886,6 +900,7 @@
 	proc_root_init();
 #endif
 	uidcache_init();
+	filescache_init();
 	vma_init();
 	buffer_init();
 	inode_init();
diff -u --recursive --new-file v2.1.42/linux/kernel/exit.c linux/kernel/exit.c
--- v2.1.42/linux/kernel/exit.c	Wed May 28 10:51:33 1997
+++ linux/kernel/exit.c	Thu Jun 12 16:22:10 1997
@@ -19,6 +19,7 @@
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/module.h>
+#include <linux/slab.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -366,14 +367,18 @@
 		if (i >= NR_OPEN)
 			break;
 		while (set) {
-			if (set & 1)
+			if (set & 1) {
 				close_fp(files->fd[i]);
+				files->fd[i] = NULL;
+			}
 			i++;
 			set >>= 1;
 		}
 	}
 }
 
+extern kmem_cache_t *files_cachep;  
+
 static inline void __exit_files(struct task_struct *tsk)
 {
 	struct files_struct * files = tsk->files;
@@ -382,7 +387,7 @@
 		tsk->files = NULL;
 		if (!--files->count) {
 			close_files(files);
-			kfree(files);
+			kmem_cache_free(files_cachep, files);
 		}
 	}
 }
diff -u --recursive --new-file v2.1.42/linux/kernel/fork.c linux/kernel/fork.c
--- v2.1.42/linux/kernel/fork.c	Sat May 24 09:10:25 1997
+++ linux/kernel/fork.c	Thu Jun 12 16:22:10 1997
@@ -11,6 +11,7 @@
  * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()'
  */
 
+#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -36,6 +37,9 @@
 /* SLAB cache for mm_struct's. */
 kmem_cache_t *mm_cachep;
 
+/* SLAB cache for files structs */
+kmem_cache_t *files_cachep; 
+
 struct task_struct *pidhash[PIDHASH_SZ];
 spinlock_t pidhash_lock = SPIN_LOCK_UNLOCKED;
 
@@ -52,7 +56,10 @@
 	unsigned short uid;
 	int task_count;
 } *uidhash[UIDHASH_SZ];
+
+#ifdef __SMP__
 static spinlock_t uidhash_lock = SPIN_LOCK_UNLOCKED;
+#endif
 
 kmem_cache_t *uid_cachep;
 
@@ -116,7 +123,7 @@
 	return 0;
 }
 
-void uidcache_init(void)
+__initfunc(void uidcache_init(void))
 {
 	int i;
 
@@ -148,8 +155,10 @@
 	return -EAGAIN;
 }
 
+#ifdef __SMP__
 /* Protects next_safe and last_pid. */
 static spinlock_t lastpid_lock = SPIN_LOCK_UNLOCKED;
+#endif
 
 static int get_pid(unsigned long flags)
 {
@@ -216,7 +225,7 @@
 		tmp->vm_next = NULL;
 		inode = tmp->vm_inode;
 		if (inode) {
-			inode->i_count++;
+			atomic_inc(&inode->i_count);
 			if (tmp->vm_flags & VM_DENYWRITE)
 				inode->i_writecount--;
       
@@ -294,15 +303,35 @@
 	tsk->fs->count = 1;
 	tsk->fs->umask = current->fs->umask;
 	if ((tsk->fs->root = current->fs->root))
-		tsk->fs->root->i_count++;
+		atomic_inc(&tsk->fs->root->i_count);
 	if ((tsk->fs->pwd = current->fs->pwd))
-		tsk->fs->pwd->i_count++;
+		atomic_inc(&tsk->fs->pwd->i_count);
 	return 0;
 }
 
+/* return value is only accurate by +-sizeof(long)*8 fds */ 
+/* XXX make this architecture specific */
+static inline int __copy_fdset(unsigned long *d, unsigned long *src)
+{
+	int i; 
+	unsigned long *p = src; 
+	unsigned long *max = src; 
+
+	for (i = __FDSET_LONGS; i; --i) {
+		if ((*d++ = *p++) != 0) 
+			max = p; 
+	}
+	return (max - src)*sizeof(long)*8; 
+}
+
+static inline int copy_fdset(fd_set *dst, fd_set *src)
+{
+	return __copy_fdset(dst->fds_bits, src->fds_bits);  
+}
+
 static inline int copy_files(unsigned long clone_flags, struct task_struct * tsk)
 {
-	int i;
+	int i;  
 	struct files_struct *oldf, *newf;
 	struct file **old_fds, **new_fds;
 
@@ -312,18 +341,18 @@
 		return 0;
 	}
 
-	newf = kmalloc(sizeof(*newf), GFP_KERNEL);
+	newf = kmem_cache_alloc(files_cachep, SLAB_KERNEL);
 	tsk->files = newf;
-	if (!newf)
+	if (!newf) 
 		return -1;
 
 	newf->count = 1;
 	newf->close_on_exec = oldf->close_on_exec;
-	newf->open_fds = oldf->open_fds;
+	i = copy_fdset(&newf->open_fds,&oldf->open_fds);
 
 	old_fds = oldf->fd;
 	new_fds = newf->fd;
-	for (i = NR_OPEN; i != 0; i--) {
+	for (; i != 0; i--) {
 		struct file * f = *old_fds;
 		old_fds++;
 		*new_fds = f;
@@ -469,4 +498,22 @@
 fork_out:
 	unlock_kernel();
 	return error;
+}
+
+static void files_ctor(void *fp, kmem_cache_t *cachep, unsigned long flags)
+{
+	struct files_struct *f = fp;
+
+	memset(f, 0, sizeof(*f));
+}
+
+__initfunc(void filescache_init(void))
+{
+	files_cachep = kmem_cache_create("files_cache", 
+					 sizeof(struct files_struct),
+					 0, 
+					 SLAB_HWCACHE_ALIGN,
+					 files_ctor, NULL);
+	if (!files_cachep) 
+		panic("Cannot create files cache"); 
 }
diff -u --recursive --new-file v2.1.42/linux/kernel/ksyms.c linux/kernel/ksyms.c
--- v2.1.42/linux/kernel/ksyms.c	Sat May 24 09:10:25 1997
+++ linux/kernel/ksyms.c	Thu Jun 12 16:22:10 1997
@@ -142,9 +142,8 @@
 EXPORT_SYMBOL(putname);
 EXPORT_SYMBOL(__fput);
 EXPORT_SYMBOL(__iget);
-EXPORT_SYMBOL(iput);
+EXPORT_SYMBOL(_iput);
 EXPORT_SYMBOL(namei);
-EXPORT_SYMBOL(lnamei);
 EXPORT_SYMBOL(open_namei);
 EXPORT_SYMBOL(sys_close);
 EXPORT_SYMBOL(close_fp);
@@ -168,8 +167,6 @@
 EXPORT_SYMBOL(__wait_on_buffer);
 EXPORT_SYMBOL(mark_buffer_uptodate);
 EXPORT_SYMBOL(unlock_buffer);
-EXPORT_SYMBOL(dcache_lookup);
-EXPORT_SYMBOL(dcache_add);
 EXPORT_SYMBOL(add_blkdev_randomness);
 EXPORT_SYMBOL(generic_file_read);
 EXPORT_SYMBOL(generic_file_write);
@@ -245,6 +242,7 @@
 EXPORT_SYMBOL(sysctl_intvec);
 EXPORT_SYMBOL(proc_dostring);
 EXPORT_SYMBOL(proc_dointvec);
+EXPORT_SYMBOL(proc_dointvec_jiffies);
 EXPORT_SYMBOL(proc_dointvec_minmax);
 
 /* interrupt handling */
@@ -338,11 +336,12 @@
 EXPORT_SYMBOL(si_meminfo);
 
 /* Added to make file system as module */
+EXPORT_SYMBOL(get_super);
 EXPORT_SYMBOL(set_writetime);
 EXPORT_SYMBOL(sys_tz);
 EXPORT_SYMBOL(__wait_on_super);
 EXPORT_SYMBOL(file_fsync);
-EXPORT_SYMBOL(clear_inode);
+EXPORT_SYMBOL(_clear_inode);
 EXPORT_SYMBOL(refile_buffer);
 EXPORT_SYMBOL(nr_async_pages);
 EXPORT_SYMBOL(___strtok);
@@ -353,7 +352,7 @@
 EXPORT_SYMBOL(blkdev_inode_operations);
 EXPORT_SYMBOL(read_ahead);
 EXPORT_SYMBOL(get_hash_table);
-EXPORT_SYMBOL(get_empty_inode);
+EXPORT_SYMBOL(_get_empty_inode);
 EXPORT_SYMBOL(insert_inode_hash);
 EXPORT_SYMBOL(event);
 EXPORT_SYMBOL(__down);
diff -u --recursive --new-file v2.1.42/linux/kernel/panic.c linux/kernel/panic.c
--- v2.1.42/linux/kernel/panic.c	Tue May 13 22:41:20 1997
+++ linux/kernel/panic.c	Thu Jun 12 16:22:10 1997
@@ -16,6 +16,7 @@
 #include <linux/smp.h>
 #include <linux/reboot.h>
 #include <linux/init.h>
+#include <linux/sysrq.h>
 
 asmlinkage void sys_sync(void);	/* it's really int */
 extern void unblank_console(void);
@@ -69,6 +70,8 @@
 	printk("Press L1-A to return to the boot prom\n");
 #endif
 	sti();
-	for(;;);
+	for(;;) {
+		CHECK_EMERGENCY_SYNC
+	}
 }
 
diff -u --recursive --new-file v2.1.42/linux/kernel/sched.c linux/kernel/sched.c
--- v2.1.42/linux/kernel/sched.c	Sat May 24 09:10:25 1997
+++ linux/kernel/sched.c	Thu Jun 12 16:22:10 1997
@@ -140,6 +140,7 @@
 	prev->next_run = p;
 }
 
+#ifdef __SMP__
 /*
  * The tasklist_lock protects the linked list of processes.
  *
@@ -154,6 +155,7 @@
 rwlock_t tasklist_lock = RW_LOCK_UNLOCKED;
 spinlock_t scheduler_lock = SPIN_LOCK_UNLOCKED;
 static spinlock_t runqueue_lock = SPIN_LOCK_UNLOCKED;
+#endif
 
 /*
  * Wake up a process. Put it on the run-queue if it's not
diff -u --recursive --new-file v2.1.42/linux/kernel/sys.c linux/kernel/sys.c
--- v2.1.42/linux/kernel/sys.c	Sat May 24 09:10:25 1997
+++ linux/kernel/sys.c	Thu Jun 12 16:22:10 1997
@@ -4,6 +4,7 @@
  *  Copyright (C) 1991, 1992  Linus Torvalds
  */
 
+#include <linux/config.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -20,6 +21,7 @@
 #include <linux/fcntl.h>
 #include <linux/acct.h>
 #include <linux/tty.h>
+#include <linux/nametrans.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
 #include <linux/notifier.h>
@@ -397,6 +399,7 @@
 
       acct_file.f_op->write(acct_file.f_inode, &acct_file,
                              (char *)&ac, sizeof(struct acct));
+      /* inode->i_status |= ST_MODIFIED is willingly *not* done here */
 
       set_fs(fs);
    }
@@ -940,6 +943,9 @@
 	if(copy_from_user(system_utsname.nodename, name, len))
 		return -EFAULT;
 	system_utsname.nodename[len] = 0;
+#ifdef CONFIG_TRANS_NAMES
+	translations_dirty = 1;
+#endif
 	return 0;
 }
 
@@ -968,6 +974,9 @@
 	if(copy_from_user(system_utsname.domainname, name, len))
 		return -EFAULT;
 	system_utsname.domainname[len] = 0;
+#ifdef CONFIG_TRANS_NAMES
+	translations_dirty = 1;
+#endif
 	return 0;
 }
 
diff -u --recursive --new-file v2.1.42/linux/kernel/sysctl.c linux/kernel/sysctl.c
--- v2.1.42/linux/kernel/sysctl.c	Tue May 13 22:41:20 1997
+++ linux/kernel/sysctl.c	Thu Jun 12 16:22:10 1997
@@ -16,6 +16,7 @@
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 #include <linux/swapctl.h>
+#include <linux/nametrans.h>
 #include <linux/proc_fs.h>
 #include <linux/malloc.h>
 #include <linux/stat.h>
@@ -37,9 +38,7 @@
 
 /* External variables not in a header file. */
 extern int panic_timeout;
-extern int console_loglevel, default_message_loglevel;
-extern int minimum_console_loglevel, default_console_loglevel;
-extern int C_A_D, swapout_interval;
+extern int console_loglevel, C_A_D, swapout_interval;
 extern int bdf_prm[], bdflush_min[], bdflush_max[];
 extern char binfmt_java_interpreter[], binfmt_java_appletviewer[];
 extern int sysctl_overcommit_memory;
@@ -104,7 +103,6 @@
 	NULL,		/* mknod */
 	NULL,		/* rename */
 	NULL,		/* readlink */
-	NULL,		/* follow_link */
 	NULL,		/* readpage */
 	NULL,		/* writepage */
 	NULL,		/* bmap */
@@ -114,6 +112,7 @@
 
 extern struct proc_dir_entry proc_sys_root;
 
+extern int inodes_stat[];
 static void register_proc_table(ctl_table *, struct proc_dir_entry *);
 static void unregister_proc_table(ctl_table *, struct proc_dir_entry *);
 #endif
@@ -142,7 +141,9 @@
 	 0644, NULL, &proc_dostring, &sysctl_string},
 	{KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
 	 0644, NULL, &proc_dostring, &sysctl_string},
-	{KERN_NRINODE, "inode-nr", &nr_inodes, 2*sizeof(int),
+	{KERN_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int),
+	 0444, NULL, &proc_dointvec},
+	{KERN_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int),
 	 0444, NULL, &proc_dointvec},
 	{KERN_MAXINODE, "inode-max", &max_inodes, sizeof(int),
 	 0644, NULL, &proc_dointvec},
@@ -170,6 +171,10 @@
 	{KERN_JAVA_APPLETVIEWER, "java-appletviewer", binfmt_java_appletviewer,
 	 64, 0644, NULL, &proc_dostring, &sysctl_string },
 #endif
+#ifdef CONFIG_TRANS_NAMES
+	{KERN_NAMETRANS, "nametrans", nametrans_txt, MAX_DEFAULT_TRANSLEN,
+	 0644, NULL, &nametrans_dostring, &nametrans_string},
+#endif
 #ifdef __sparc__
 	{KERN_SPARC_REBOOT, "reboot-cmd", reboot_command,
 	 256, 0644, NULL, &proc_dostring, &sysctl_string },
@@ -184,6 +189,8 @@
 static ctl_table vm_table[] = {
 	{VM_SWAPCTL, "swapctl", 
 	 &swap_control, sizeof(swap_control_t), 0600, NULL, &proc_dointvec},
+	{VM_SWAPOUT, "swapout_interval",
+	 &swapout_interval, sizeof(int), 0600, NULL, &proc_dointvec_jiffies},
 	{VM_FREEPG, "freepages", 
 	 &min_free_pages, 3*sizeof(int), 0600, NULL, &proc_dointvec},
 	{VM_BDFLUSH, "bdflush", &bdf_prm, 9*sizeof(int), 0600, NULL,
@@ -611,8 +618,8 @@
 	return 0;
 }
 
-int proc_dointvec(ctl_table *table, int write, struct file *filp,
-		  void *buffer, size_t *lenp)
+static int do_proc_dointvec(ctl_table *table, int write, struct file *filp,
+		  void *buffer, size_t *lenp, int conv)
 {
 	int *i, vleft, first=1, len, left, neg, val;
 	#define TMPBUFLEN 20
@@ -655,7 +662,7 @@
 			}
 			if (*p < '0' || *p > '9')
 				break;
-			val = simple_strtoul(p, &p, 0);
+			val = simple_strtoul(p, &p, 0) * conv;
 			len = p-buf;
 			if ((len < left) && *p && !isspace(*p))
 				break;
@@ -668,7 +675,7 @@
 			p = buf;
 			if (!first)
 				*p++ = '\t';
-			sprintf(p, "%d", *i);
+			sprintf(p, "%d", (*i) / conv);
 			len = strlen(buf);
 			if (len > left)
 				len = left;
@@ -702,6 +709,12 @@
 	return 0;
 }
 
+int proc_dointvec(ctl_table *table, int write, struct file *filp,
+		     void *buffer, size_t *lenp)
+{
+    return do_proc_dointvec(table,write,filp,buffer,lenp,1);
+}
+
 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
 		  void *buffer, size_t *lenp)
 {
@@ -800,6 +813,13 @@
 	return 0;
 }
 
+/* Like proc_dointvec, but converts seconds to jiffies */
+int proc_dointvec_jiffies(ctl_table *table, int write, struct file *filp,
+			  void *buffer, size_t *lenp)
+{
+    return do_proc_dointvec(table,write,filp,buffer,lenp,HZ);
+}
+
 #else /* CONFIG_PROC_FS */
 
 int proc_dostring(ctl_table *table, int write, struct file *filp,
@@ -862,6 +882,9 @@
 		if (len == table->maxlen)
 			len--;
 		((char *) table->data)[len] = 0;
+#ifdef CONFIG_TRANS_NAMES
+		translations_dirty = 1;
+#endif
 	}
 	return 0;
 }
diff -u --recursive --new-file v2.1.42/linux/mm/filemap.c linux/mm/filemap.c
--- v2.1.42/linux/mm/filemap.c	Tue May 13 22:41:20 1997
+++ linux/mm/filemap.c	Thu Jun 12 16:22:10 1997
@@ -919,6 +919,7 @@
 	retval = -EIO;
 	if (size == file->f_op->write(inode, file, (const char *) page, size))
 		retval = 0;
+	/* inode->i_status |= ST_MODIFIED is willingly *not* done here */
 	set_fs(old_fs);
 	return retval;
 }
@@ -1193,7 +1194,7 @@
 		inode->i_dirt = 1;
 	}
 	vma->vm_inode = inode;
-	inode->i_count++;
+	atomic_inc(&inode->i_count);
 	vma->vm_ops = ops;
 	return 0;
 }
diff -u --recursive --new-file v2.1.42/linux/mm/memory.c linux/mm/memory.c
--- v2.1.42/linux/mm/memory.c	Sat May 24 09:10:25 1997
+++ linux/mm/memory.c	Mon Jun 16 08:46:24 1997
@@ -195,7 +195,7 @@
 	}
 	if (cow)
 		pte = pte_wrprotect(pte);
-	if (delete_from_swap_cache(page_nr))
+	if (delete_from_swap_cache(&mem_map[page_nr]))
 		pte = pte_mkdirty(pte);
 	set_pte(new_pte, pte_mkold(pte));
 	set_pte(old_pte, pte);
diff -u --recursive --new-file v2.1.42/linux/mm/mlock.c linux/mm/mlock.c
--- v2.1.42/linux/mm/mlock.c	Sun Jan 26 02:07:49 1997
+++ linux/mm/mlock.c	Thu Jun 12 16:22:11 1997
@@ -39,7 +39,7 @@
 	vma->vm_offset += vma->vm_start - n->vm_start;
 	n->vm_flags = newflags;
 	if (n->vm_inode)
-		n->vm_inode->i_count++;
+		atomic_inc(&n->vm_inode->i_count);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -60,7 +60,7 @@
 	n->vm_offset += n->vm_start - vma->vm_start;
 	n->vm_flags = newflags;
 	if (n->vm_inode)
-		n->vm_inode->i_count++;
+		atomic_inc(&n->vm_inode->i_count);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -90,7 +90,7 @@
 	right->vm_offset += right->vm_start - left->vm_start;
 	vma->vm_flags = newflags;
 	if (vma->vm_inode)
-		vma->vm_inode->i_count += 2;
+		atomic_add(2, &vma->vm_inode->i_count);
 	if (vma->vm_ops && vma->vm_ops->open) {
 		vma->vm_ops->open(left);
 		vma->vm_ops->open(right);
diff -u --recursive --new-file v2.1.42/linux/mm/mmap.c linux/mm/mmap.c
--- v2.1.42/linux/mm/mmap.c	Thu May 15 16:48:05 1997
+++ linux/mm/mmap.c	Thu Jun 12 16:22:11 1997
@@ -409,7 +409,7 @@
 		mpnt->vm_offset += (end - area->vm_start);
 		mpnt->vm_start = end;
 		if (mpnt->vm_inode)
-			mpnt->vm_inode->i_count++;
+			atomic_inc(&mpnt->vm_inode->i_count);
 		if (mpnt->vm_ops && mpnt->vm_ops->open)
 			mpnt->vm_ops->open(mpnt);
 		area->vm_end = addr;	/* Truncate area */
@@ -646,7 +646,7 @@
 		}
 		remove_shared_vm_struct(mpnt);
 		if (mpnt->vm_inode)
-			mpnt->vm_inode->i_count--;
+			atomic_dec(&mpnt->vm_inode->i_count);
 		kmem_cache_free(vm_area_cachep, mpnt);
 		mpnt = prev;
 	}
diff -u --recursive --new-file v2.1.42/linux/mm/mprotect.c linux/mm/mprotect.c
--- v2.1.42/linux/mm/mprotect.c	Sun Jan 26 02:07:49 1997
+++ linux/mm/mprotect.c	Thu Jun 12 16:22:11 1997
@@ -111,7 +111,7 @@
 	n->vm_flags = newflags;
 	n->vm_page_prot = prot;
 	if (n->vm_inode)
-		n->vm_inode->i_count++;
+		atomic_inc(&n->vm_inode->i_count);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -134,7 +134,7 @@
 	n->vm_flags = newflags;
 	n->vm_page_prot = prot;
 	if (n->vm_inode)
-		n->vm_inode->i_count++;
+		atomic_inc(&n->vm_inode->i_count);
 	if (n->vm_ops && n->vm_ops->open)
 		n->vm_ops->open(n);
 	insert_vm_struct(current->mm, n);
@@ -166,7 +166,7 @@
 	vma->vm_flags = newflags;
 	vma->vm_page_prot = prot;
 	if (vma->vm_inode)
-		vma->vm_inode->i_count += 2;
+		atomic_add(2, &vma->vm_inode->i_count);
 	if (vma->vm_ops && vma->vm_ops->open) {
 		vma->vm_ops->open(left);
 		vma->vm_ops->open(right);
diff -u --recursive --new-file v2.1.42/linux/mm/mremap.c linux/mm/mremap.c
--- v2.1.42/linux/mm/mremap.c	Sun Jan 26 02:07:49 1997
+++ linux/mm/mremap.c	Thu Jun 12 16:22:11 1997
@@ -141,7 +141,7 @@
 			new_vma->vm_end = new_addr+new_len;
 			new_vma->vm_offset = vma->vm_offset + (addr - vma->vm_start);
 			if (new_vma->vm_inode)
-				new_vma->vm_inode->i_count++;
+				atomic_inc(&new_vma->vm_inode->i_count);
 			if (new_vma->vm_ops && new_vma->vm_ops->open)
 				new_vma->vm_ops->open(new_vma);
 			insert_vm_struct(current->mm, new_vma);
diff -u --recursive --new-file v2.1.42/linux/mm/page_alloc.c linux/mm/page_alloc.c
--- v2.1.42/linux/mm/page_alloc.c	Wed May 28 10:51:33 1997
+++ linux/mm/page_alloc.c	Mon Jun 16 08:46:24 1997
@@ -97,7 +97,9 @@
  *
  * Hint: -mask = 1+~mask
  */
+#ifdef __SMP__
 static spinlock_t page_alloc_lock;
+#endif
 
 static inline void free_pages_ok(unsigned long map_nr, unsigned long order)
 {
@@ -131,9 +133,8 @@
 void __free_page(struct page *page)
 {
 	if (!PageReserved(page) && atomic_dec_and_test(&page->count)) {
-		unsigned long map_nr = page->map_nr;
-		delete_from_swap_cache(map_nr);
-		free_pages_ok(map_nr, 0);
+		delete_from_swap_cache(page);
+		free_pages_ok(page->map_nr, 0);
 	}
 }
 
@@ -146,7 +147,7 @@
 		if (PageReserved(map))
 			return;
 		if (atomic_dec_and_test(&map->count)) {
-			delete_from_swap_cache(map_nr);
+			delete_from_swap_cache(map);
 			free_pages_ok(map_nr, order);
 			return;
 		}
@@ -278,8 +279,7 @@
 	min_free_pages = i;
 	free_pages_low = i + (i>>1);
 	free_pages_high = i + i;
-	start_mem = init_swap_cache(start_mem, end_mem);
-	mem_map = (mem_map_t *) start_mem;
+	mem_map = (mem_map_t *) LONG_ALIGN(start_mem);
 	p = mem_map + MAP_NR(end_mem);
 	start_mem = LONG_ALIGN((unsigned long) p);
 	memset(mem_map, 0, start_mem - (unsigned long) mem_map);
@@ -334,7 +334,7 @@
 	}
 	vma->vm_mm->rss++;
 	tsk->maj_flt++;
-	if (!write_access && add_to_swap_cache(MAP_NR(page), entry)) {
+	if (!write_access && add_to_swap_cache(&mem_map[MAP_NR(page)], entry)) {
 		/* keep swap page allocated for the moment (swap cache) */
 		set_pte(page_table, mk_pte(page, vma->vm_page_prot));
 		return;
diff -u --recursive --new-file v2.1.42/linux/mm/page_io.c linux/mm/page_io.c
--- v2.1.42/linux/mm/page_io.c	Tue May 13 22:41:20 1997
+++ linux/mm/page_io.c	Mon Jun 16 08:46:24 1997
@@ -83,7 +83,9 @@
 			set_bit(PG_free_after, &page->flags);
 			set_bit(PG_decr_after, &page->flags);
 			set_bit(PG_swap_unlock_after, &page->flags);
-			page->swap_unlock_entry = entry;
+			/* swap-cache  shouldn't be set, but play safe */
+			PageClearSwapCache(page);
+			page->pg_swap_entry = entry;
 			atomic_inc(&nr_async_pages);
 		}
 		ll_rw_page(rw,p->swap_device,offset,buf);
diff -u --recursive --new-file v2.1.42/linux/mm/slab.c linux/mm/slab.c
--- v2.1.42/linux/mm/slab.c	Wed May 28 10:51:33 1997
+++ linux/mm/slab.c	Thu Jun 12 16:22:11 1997
@@ -769,6 +769,7 @@
 		printk("%sForcing size word alignment - %s\n", func_nm, name);
 	}
 
+	cachep->c_org_size = size;
 #if	SLAB_DEBUG_SUPPORT
 	if (flags & SLAB_RED_ZONE) {
 		/* There is no point trying to honour cache alignment when redzoning. */
@@ -776,7 +777,6 @@
 		size += 2*BYTES_PER_WORD;		/* words for redzone */
 	}
 #endif	/* SLAB_DEBUG_SUPPORT */
-	cachep->c_org_size = size;
 
 	align = BYTES_PER_WORD;
 	if (flags & SLAB_HWCACHE_ALIGN)
@@ -1250,18 +1250,18 @@
 opps1:
 	kmem_freepages(cachep, objp); 
 failed:
+	spin_lock_irq(&cachep->c_spinlock);
 	if (local_flags != SLAB_ATOMIC && cachep->c_gfporder) {
 		/* For large order (>0) slabs, we try again.
 		 * Needed because the gfp() functions are not good at giving
 		 * out contigious pages unless pushed (but do not push too hard).
 		 */
-		spin_lock_irq(&cachep->c_spinlock);
 		if (cachep->c_failures++ < 4 && cachep->c_freep == kmem_slab_end(cachep))
 			goto re_try;
 		cachep->c_failures = 1;	/* Memory is low, don't try as hard next time. */
-		cachep->c_growing--;
-		spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
 	}
+	cachep->c_growing--;
+	spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
 	return 0;
 }
 
@@ -1467,16 +1467,14 @@
 		goto null_addr;
 
 #if	SLAB_DEBUG_SUPPORT
-	if (cachep->c_flags & SLAB_RED_ZONE)
-		objp -= BYTES_PER_WORD;
-#endif	/* SLAB_DEBUG_SUPPORT */
-
-
-#if	SLAB_DEBUG_SUPPORT
 	/* A verify func is called without the cache-lock held. */
 	if (cachep->c_flags & SLAB_DEBUG_INITIAL)
 		goto init_state_check;
 finished_initial:
+
+	if (cachep->c_flags & SLAB_RED_ZONE)
+		goto red_zone;
+return_red:
 #endif	/* SLAB_DEBUG_SUPPORT */
 
 	spin_lock_irqsave(&cachep->c_spinlock, save_flags);
@@ -1511,25 +1509,24 @@
 		slabp->s_inuse--;
 		bufp->buf_nextp = slabp->s_freep;
 		slabp->s_freep = bufp;
-		if (slabp->s_inuse) {
-			if (bufp->buf_nextp) {
+		if (bufp->buf_nextp) {
+			if (slabp->s_inuse) {
 				/* (hopefully) The most common case. */
 finished:
 #if	SLAB_DEBUG_SUPPORT
-				/* Need to poision the obj while holding the lock. */
-				if (cachep->c_flags & SLAB_POISION)
+				if (cachep->c_flags & SLAB_POISION) {
+					if (cachep->c_flags & SLAB_RED_ZONE)
+						objp += BYTES_PER_WORD;
 					kmem_poision_obj(cachep, objp);
-				if (cachep->c_flags & SLAB_RED_ZONE)
-					goto red_zone;
-return_red:
+				}
 #endif	/* SLAB_DEBUG_SUPPORT */
 				spin_unlock_irqrestore(&cachep->c_spinlock, save_flags);
 				return;
 			}
-			kmem_cache_one_free(cachep, slabp);
+			kmem_cache_full_free(cachep, slabp);
 			goto finished;
 		}
-		kmem_cache_full_free(cachep, slabp);
+		kmem_cache_one_free(cachep, slabp);
 		goto finished;
 	}
 
@@ -1563,20 +1560,20 @@
 	}
 	goto passed_extra;
 red_zone:
-	/* We hold the cache-lock while checking the red-zone, just incase
-	 * some tries to take this obj from us...
+	/* We do not hold the cache-lock while checking the red-zone.
 	 */
+	objp -= BYTES_PER_WORD;
 	if (xchg((unsigned long *)objp, SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) {
 		/* Either write before start of obj, or a double free. */
 		kmem_report_free_err("Bad front redzone", objp, cachep);
 	}
-	objp += BYTES_PER_WORD;
-	if (xchg((unsigned long *)(objp+cachep->c_org_size), SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) {
+	if (xchg((unsigned long *)(objp+cachep->c_org_size+BYTES_PER_WORD), SLAB_RED_MAGIC1) != SLAB_RED_MAGIC2) {
 		/* Either write past end of obj, or a double free. */
 		kmem_report_free_err("Bad rear redzone", objp, cachep);
 	}
 	goto return_red;
 #endif	/* SLAB_DEBUG_SUPPORT */
+
 bad_slab:
 	/* Slab doesn't contain the correct magic num. */
 	if (slabp->s_magic == SLAB_MAGIC_DESTROYED) {
@@ -1712,24 +1709,49 @@
 	kmem_slab_t	*slabp;
 	kmem_cache_t	*searchp;
 	kmem_cache_t	*best_cachep;
-	unsigned long	 scan;
-	unsigned long	 reap_level;
+	unsigned int	 scan;
+	unsigned int	 reap_level;
+	static unsigned long	call_count = 0;
 
 	if (in_interrupt()) {
 		printk("kmem_cache_reap() called within int!\n");
 		return 0;
 	}
-	scan = 9-pri;
-	reap_level = pri >> 1;
 
 	/* We really need a test semphore op so we can avoid sleeping when
 	 * !wait is true.
 	 */
 	down(&cache_chain_sem);
+
+	scan = 10-pri;
+	if (pri == 6 && !dma) {
+		if (++call_count == 199) {
+			/* Hack Alert!
+			 * Occassionally we try hard to reap a slab.
+			 */
+			call_count = 0UL;
+			reap_level = 0;
+			scan += 2;
+		} else
+			reap_level = 3;
+	} else {
+		if (pri >= 5) {
+			/* We also come here for dma==1 at pri==6, just
+			 * to try that bit harder (assumes that there are
+			 * less DMAable pages in a system - not always true,
+			 * but this doesn't hurt).
+			 */
+			reap_level = 2;
+		} else
+			reap_level = 0;
+	}
+
 	best_cachep = NULL;
 	searchp = clock_searchp;
 	do {
-		unsigned long	full_free;
+		unsigned int	full_free;
+		unsigned int	dma_flag;
+
 		/* It's safe to test this without holding the cache-lock. */
 		if (searchp->c_flags & SLAB_NO_REAP)
 			goto next;
@@ -1746,6 +1768,7 @@
 			printk(KERN_ERR "kmem_reap: Corrupted cache struct for %s\n", searchp->c_name);
 			goto next;
 		}
+		dma_flag = 0;
 		full_free = 0;
 
 		/* Count num of fully free slabs.  Hopefully there are not many,
@@ -1755,9 +1778,14 @@
 		while (!slabp->s_inuse && slabp != kmem_slab_end(searchp)) {
 			slabp = slabp->s_prevp;
 			full_free++;
+			if (slabp->s_dma)
+				dma_flag++;
 		}
 		spin_unlock_irq(&searchp->c_spinlock);
 
+		if (dma && !dma_flag)
+			goto next;
+
 		if (full_free) {
 			if (full_free >= 10) {
 				best_cachep = searchp;
@@ -1768,10 +1796,8 @@
 			 * more than one page per slab (as it can be difficult
 			 * to get high orders from gfp()).
 			 */
-			if (pri == 6) {		/* magic '6' from try_to_free_page() */
-				if (searchp->c_ctor)
-					full_free--;
-				if (full_free && searchp->c_gfporder)
+			if (pri == 6) {	/* magic '6' from try_to_free_page() */
+				if (searchp->c_gfporder || searchp->c_ctor)
 					full_free--;
 			}
 			if (full_free >= reap_level) {
@@ -1796,8 +1822,21 @@
 
 	spin_lock_irq(&best_cachep->c_spinlock);
 	if (!best_cachep->c_growing && !(slabp = best_cachep->c_lastp)->s_inuse && slabp != kmem_slab_end(best_cachep)) {
+		if (dma) {
+			do {
+				if (slabp->s_dma)
+					goto good_dma;
+				slabp = slabp->s_prevp;
+			} while (!slabp->s_inuse && slabp != kmem_slab_end(best_cachep));
+
+			/* Didn't found a DMA slab (there was a free one -
+			 * must have been become active).
+			 */
+			goto dma_fail;
+good_dma:
+		}
 		if (slabp == best_cachep->c_freep)
-			best_cachep->c_freep = kmem_slab_end(best_cachep);
+			best_cachep->c_freep = slabp->s_nextp;
 		kmem_slab_unlink(slabp);
 		SLAB_STATS_INC_REAPED(best_cachep);
 
@@ -1808,6 +1847,7 @@
 		kmem_slab_destroy(best_cachep, slabp);
 		return 1;
 	}
+dma_fail:
 	spin_unlock_irq(&best_cachep->c_spinlock);
 	return 0;
 }
diff -u --recursive --new-file v2.1.42/linux/mm/swap_state.c linux/mm/swap_state.c
--- v2.1.42/linux/mm/swap_state.c	Tue May 13 22:41:20 1997
+++ linux/mm/swap_state.c	Mon Jun 16 08:46:24 1997
@@ -24,15 +24,6 @@
 #include <asm/bitops.h>
 #include <asm/pgtable.h>
 
-/*
- * To save us from swapping out pages which have just been swapped in and
- * have not been modified since then, we keep in swap_cache[page>>PAGE_SHIFT]
- * the swap entry which was last used to fill the page, or zero if the
- * page does not currently correspond to a page in swap. PAGE_DIRTY makes
- * this info useless.
- */
-unsigned long *swap_cache;
-
 #ifdef SWAP_CACHE_INFO
 unsigned long swap_cache_add_total = 0;
 unsigned long swap_cache_add_success = 0;
@@ -50,7 +41,7 @@
 }
 #endif
 
-int add_to_swap_cache(unsigned long index, unsigned long entry)
+int add_to_swap_cache(struct page *page, unsigned long entry)
 {
 	struct swap_info_struct * p = &swap_info[SWP_TYPE(entry)];
 
@@ -58,28 +49,15 @@
 	swap_cache_add_total++;
 #endif
 	if ((p->flags & SWP_WRITEOK) == SWP_WRITEOK) {
-		entry = xchg(swap_cache + index, entry);
-		if (entry)  {
-			printk("swap_cache: replacing non-NULL entry\n");
-		}
+		page->pg_swap_entry = entry;
+		if (PageTestandSetSwapCache(page))
+			printk("swap_cache: replacing non-empty entry\n");
 #ifdef SWAP_CACHE_INFO
 		swap_cache_add_success++;
 #endif
 		return 1;
 	}
 	return 0;
-}
-
-__initfunc(unsigned long init_swap_cache(unsigned long mem_start,
-					 unsigned long mem_end))
-{
-	unsigned long swap_cache_size;
-
-	mem_start = (mem_start + 15) & ~15;
-	swap_cache = (unsigned long *) mem_start;
-	swap_cache_size = MAP_NR(mem_end);
-	memset(swap_cache, 0, swap_cache_size * sizeof (unsigned long));
-	return (unsigned long) (swap_cache + swap_cache_size);
 }
 
 void swap_duplicate(unsigned long entry)
diff -u --recursive --new-file v2.1.42/linux/mm/swapfile.c linux/mm/swapfile.c
--- v2.1.42/linux/mm/swapfile.c	Tue May 13 22:41:20 1997
+++ linux/mm/swapfile.c	Mon Jun 16 08:46:24 1997
@@ -176,14 +176,16 @@
 	if (pte_none(pte))
 		return 0;
 	if (pte_present(pte)) {
+		struct page *pg;
 		unsigned long page_nr = MAP_NR(pte_page(pte));
 		if (page_nr >= max_mapnr)
 			return 0;
-		if (!in_swap_cache(page_nr))
+		pg = mem_map + page_nr;
+		if (!in_swap_cache(pg))
 			return 0;
-		if (SWP_TYPE(in_swap_cache(page_nr)) != type)
+		if (SWP_TYPE(in_swap_cache(pg)) != type)
 			return 0;
-		delete_from_swap_cache(page_nr);
+		delete_from_swap_cache(pg);
 		set_pte(dir, pte_mkdirty(pte));
 		return 0;
 	}
@@ -332,7 +334,7 @@
 	lock_kernel();
 	if (!suser())
 		goto out;
-	err = namei(specialfile,&inode);
+	err = namei(NAM_FOLLOW_LINK, specialfile, &inode);
 	if (err)
 		goto out;
 	prev = -1;
@@ -486,12 +488,12 @@
 	} else {
 		p->prio = --least_priority;
 	}
-	error = namei(specialfile,&swap_inode);
+	error = namei(NAM_FOLLOW_LINK, specialfile, &swap_inode);
 	if (error)
 		goto bad_swap_2;
 	p->swap_file = swap_inode;
 	error = -EBUSY;
-	if (swap_inode->i_count != 1)
+	if (atomic_read(&swap_inode->i_count) != 1)
 		goto bad_swap_2;
 	error = -EINVAL;
 
diff -u --recursive --new-file v2.1.42/linux/mm/vmscan.c linux/mm/vmscan.c
--- v2.1.42/linux/mm/vmscan.c	Wed May 28 10:51:33 1997
+++ linux/mm/vmscan.c	Mon Jun 16 08:46:24 1997
@@ -87,7 +87,7 @@
 	/* Deal with page aging.  Pages age from being unused; they
 	 * rejuvenate on being accessed.  Only swap old pages (age==0
 	 * is oldest). */
-	if ((pte_dirty(pte) && delete_from_swap_cache(MAP_NR(page))) 
+	if ((pte_dirty(pte) && delete_from_swap_cache(page_map)) 
 	    || pte_young(pte))  {
 		set_pte(page_table, pte_mkold(pte));
 		touch_page(page_map);
@@ -117,7 +117,7 @@
 		free_page(page);
 		return 1;	/* we slept: the process may not exist any more */
 	}
-        if ((entry = find_in_swap_cache(MAP_NR(page))))  {
+        if ((entry = find_in_swap_cache(page_map)))  {
 		if (atomic_read(&page_map->count) != 1) {
 			set_pte(page_table, pte_mkdirty(pte));
 			printk("Aiee.. duplicated cached swap-cache entry\n");
diff -u --recursive --new-file v2.1.42/linux/net/Config.in linux/net/Config.in
--- v2.1.42/linux/net/Config.in	Thu Mar 27 14:40:12 1997
+++ linux/net/Config.in	Thu Jun 12 16:22:11 1997
@@ -42,6 +42,10 @@
   dep_tristate 'Amateur Radio X.25 PLP (Rose)' CONFIG_ROSE $CONFIG_AX25
 fi
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+#  tristate 'DECnet Support (NOT YET FUNCTIONAL)' CONFIG_DECNET
+#  if [ "$CONFIG_DECNET" != "n" ]; then
+#    source net/decnet/Config.in
+#  fi
   tristate 'CCITT X.25 Packet Layer (EXPERIMENTAL)' CONFIG_X25
   tristate 'LAPB Data Link Driver (EXPERIMENTAL)' CONFIG_LAPB
   bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE
diff -u --recursive --new-file v2.1.42/linux/net/Makefile linux/net/Makefile
--- v2.1.42/linux/net/Makefile	Mon Apr  7 11:35:32 1997
+++ linux/net/Makefile	Thu Jun 12 16:22:11 1997
@@ -105,6 +105,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_DECNET),y)
+SUB_DIRS += decnet
+else
+  ifeq ($(CONFIG_DECNET),m)
+  MOD_SUB_DIRS += decnet
+  endif
+endif
+
 # We must attach netsyms.o to socket.o, as otherwise there is nothing
 # to pull the object file from the archive.
 
diff -u --recursive --new-file v2.1.42/linux/net/README linux/net/README
--- v2.1.42/linux/net/README	Thu Mar 27 14:40:13 1997
+++ linux/net/README	Thu Jun 12 16:22:11 1997
@@ -8,6 +8,7 @@
 appletalk		alan@lxorguk.ukuu.org.uk and netatalk@umich.edu
 ax25			jsn@cs.nott.ac.uk
 core			alan@lxorguk.ukuu.org.uk
+decnet			SteveW@ACM.org
 ethernet		alan@lxorguk.ukuu.org.uk
 ipv4			davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se
 ipv6			davem@caip.rutgers.edu,Eric.Schenk@dna.lth.se
diff -u --recursive --new-file v2.1.42/linux/net/appletalk/aarp.c linux/net/appletalk/aarp.c
--- v2.1.42/linux/net/appletalk/aarp.c	Tue May 13 22:41:20 1997
+++ linux/net/appletalk/aarp.c	Thu Jun 12 16:22:11 1997
@@ -49,6 +49,12 @@
 #include <linux/atalk.h>
 #include <linux/init.h>
 
+ 
+int sysctl_aarp_expiry_time = AARP_EXPIRY_TIME;
+int sysctl_aarp_tick_time = AARP_TICK_TIME;
+int sysctl_aarp_retransmit_limit = AARP_RETRANSMIT_LIMIT;
+int sysctl_aarp_resolve_time = AARP_RESOLVE_TIME;
+
 /*
  *	Lists of aarp entries
  */
@@ -309,7 +315,7 @@
 	{
 		/* Expired - if this will be the 11th transmit, we delete
 		   instead */
-		if((*n)->xmit_count>=AARP_RETRANSMIT_LIMIT)
+		if((*n)->xmit_count>=sysctl_aarp_retransmit_limit)
 		{
 			t= *n;
 			*n=(*n)->next;
@@ -359,9 +365,9 @@
 	}
 	del_timer(&aarp_timer);
 	if(unresolved_count==0)
-		aarp_timer.expires=jiffies+AARP_EXPIRY_TIME;
+		aarp_timer.expires=jiffies+sysctl_aarp_expiry_time;
 	else
-		aarp_timer.expires=jiffies+AARP_TICK_TIME;
+		aarp_timer.expires=jiffies+sysctl_aarp_tick_time;
 	add_timer(&aarp_timer);
 }
 
@@ -475,6 +481,21 @@
 		dev_queue_xmit(skb);
 		return 1;
 	}	
+
+	/*
+	 *	On a PPP link we neither compress nor aarp.
+	 */
+	if(dev->type==ARPHRD_PPP)
+	{
+		skb->protocol = htons(ETH_P_PPPTALK);
+		if(skb->sk==NULL)
+			skb->priority = SOPRI_NORMAL;
+		else
+			skb->priority = skb->sk->priority;
+		skb->dev = dev;
+		dev_queue_xmit(skb);
+		return 1;
+	}
 	 
 	/*
 	 *	Non ELAP we cannot do.
@@ -514,7 +535,7 @@
 		 *	Return 1 and fill in the address
 		 */
 
-		a->expires_at=jiffies+AARP_EXPIRY_TIME*10;
+		a->expires_at=jiffies+sysctl_aarp_expiry_time*10;
 		ddp_dl->datalink_header(ddp_dl, skb, a->hwaddr);
 		if(skb->sk==NULL)
 			skb->priority = SOPRI_NORMAL;
@@ -561,7 +582,7 @@
 	 */
 
 	skb_queue_tail(&a->packet_queue, skb);
-	a->expires_at=jiffies+AARP_RESOLVE_TIME;
+	a->expires_at=jiffies+sysctl_aarp_resolve_time;
 	a->dev=dev;
 	a->next=unresolved[hash];
 	a->target_addr= *sa;
@@ -584,7 +605,7 @@
 	if(unresolved_count==1)
 	{
 		del_timer(&aarp_timer);
-		aarp_timer.expires=jiffies+AARP_TICK_TIME;
+		aarp_timer.expires=jiffies+sysctl_aarp_tick_time;
 		add_timer(&aarp_timer);
 	}
 
@@ -623,7 +644,7 @@
 			 
 			while((skb=skb_dequeue(&a->packet_queue))!=NULL)
 			{
-				a->expires_at=jiffies+AARP_EXPIRY_TIME*10;
+				a->expires_at=jiffies+sysctl_aarp_expiry_time*10;
 				ddp_dl->datalink_header(ddp_dl,skb,a->hwaddr);
 				if(skb->sk==NULL)
 					skb->priority = SOPRI_NORMAL;
@@ -751,7 +772,7 @@
 			if(unresolved_count==0)
 			{
 				del_timer(&aarp_timer);
-				aarp_timer.expires=jiffies+AARP_EXPIRY_TIME;
+				aarp_timer.expires=jiffies+sysctl_aarp_expiry_time;
 				add_timer(&aarp_timer);
 			}
 			break;
@@ -804,7 +825,7 @@
 	init_timer(&aarp_timer);
 	aarp_timer.function=aarp_expire_timeout;
 	aarp_timer.data=0;
-	aarp_timer.expires=jiffies+AARP_EXPIRY_TIME;
+	aarp_timer.expires=jiffies+sysctl_aarp_expiry_time;
 	add_timer(&aarp_timer);
 	register_netdevice_notifier(&aarp_notifier);
 }
diff -u --recursive --new-file v2.1.42/linux/net/appletalk/ddp.c linux/net/appletalk/ddp.c
--- v2.1.42/linux/net/appletalk/ddp.c	Tue May 13 22:41:20 1997
+++ linux/net/appletalk/ddp.c	Thu Jun 12 16:22:11 1997
@@ -79,6 +79,11 @@
 #define DPRINT(x)
 #endif
 
+#ifdef CONFIG_SYSCTL
+extern inline void atalk_register_sysctl(void);
+extern inline void atalk_unregister_sysctl(void);
+#endif
+
 struct datalink_proto *ddp_dl, *aarp_dl;
 static struct proto_ops atalk_dgram_ops;
 
@@ -262,7 +267,6 @@
 		else
 			iface = &tmp->next;
 	}
-	MOD_DEC_USE_COUNT;
 }
 
 static struct atalk_iface *atif_add_device(struct device *dev, struct at_addr *sa)
@@ -281,7 +285,6 @@
 	iface->next=atalk_iface_list;
 	atalk_iface_list=iface;
 	restore_flags(flags);
-	MOD_INC_USE_COUNT;
 	return iface;
 }
 
@@ -399,9 +402,21 @@
 static struct at_addr *atalk_find_primary(void)
 {
 	struct atalk_iface *iface;
+	struct atalk_iface *fiface;
+	/*
+	 *	Return a point-to-point interface only if
+	 *	there is no non-ptp interface available.
+	 */
+	fiface=NULL;
 	for(iface=atalk_iface_list;iface!=NULL;iface=iface->next)
-		if(!(iface->dev->flags&IFF_LOOPBACK))
+	{
+		if(!fiface && !(iface->dev->flags&IFF_LOOPBACK))
+			fiface=iface;
+		if(!(iface->dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT)))
 			return &iface->address;
+	}
+	if (fiface)
+		return &fiface->address;
 	if ( atalk_iface_list != NULL )
 		return &atalk_iface_list->address;
 	else
@@ -779,6 +794,16 @@
 			((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_net=atif->address.s_net;
 			((struct sockaddr_at *)(&atreq.ifr_addr))->sat_addr.s_node=ATADDR_BCAST;
 			break;
+	        case SIOCATALKDIFADDR:
+			if(!suser())
+				return -EPERM;
+			if(sa->sat_family!=AF_APPLETALK)
+				return -EINVAL;
+			if(atif==NULL)
+				return -EADDRNOTAVAIL;
+			atrtr_device_down(atif->dev);
+			atif_drop_device(atif->dev);
+			break;			
 	}
 	err = copy_to_user(arg,&atreq,sizeof(atreq));
 
@@ -951,7 +976,8 @@
 	MOD_INC_USE_COUNT;
 
 	sock_init_data(sock,sk);
-	
+
+	sk->destruct=NULL;
 	/* Checksums on by default */
 	sk->mtu=DDP_MAXSZ;
 	sk->zapped=1;
@@ -1928,6 +1954,7 @@
 		case SIOCGIFADDR:
 		case SIOCSIFADDR:
 		case SIOCGIFBRDADDR:
+		case SIOCATALKDIFADDR:
 			return atif_ioctl(cmd,(void *)arg);
 		/*
 		 *	Physical layer ioctl calls
@@ -2056,6 +2083,10 @@
 	proc_net_register(&proc_atalk_iface);
 #endif	
 
+#ifdef CONFIG_SYSCTL
+	atalk_register_sysctl();
+#endif
+
 #ifdef CONFIG_IPDDP
 	register_netdev(&dev_ipddp);
 #endif /* CONFIG_IPDDP */
@@ -2098,6 +2129,7 @@
 	while (list != NULL)
 	{
 		tmp = list->next;
+		list->dev->atalk_ptr = NULL;
 		kfree_s(list, sizeof(struct atalk_iface));
 		list = tmp;
 	}
@@ -2111,6 +2143,10 @@
 	cli();
 
 	aarp_cleanup_module();
+
+#ifdef CONFIG_SYSCTL
+	atalk_unregister_sysctl();
+#endif
 
 #ifdef CONFIG_PROC_FS
 	proc_net_unregister(PROC_NET_ATALK);
diff -u --recursive --new-file v2.1.42/linux/net/appletalk/sysctl_net_atalk.c linux/net/appletalk/sysctl_net_atalk.c
--- v2.1.42/linux/net/appletalk/sysctl_net_atalk.c	Mon Apr  1 22:03:35 1996
+++ linux/net/appletalk/sysctl_net_atalk.c	Thu Jun 12 16:22:11 1997
@@ -3,11 +3,55 @@
  *
  * Begun April 1, 1996, Mike Shaver.
  * Added /proc/sys/net/atalk directory entry (empty =) ). [MS]
+ * Dynamic registration, added aarp entries. (5/30/97 Chris Horn)
  */
 
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 
-ctl_table atalk_table[] = {
+extern int sysctl_aarp_expiry_time;
+extern int sysctl_aarp_tick_time;
+extern int sysctl_aarp_retransmit_limit;
+extern int sysctl_aarp_resolve_time;
+
+
+static ctl_table atalk_table[] = {
+	{NET_ATALK_AARP_EXPIRY_TIME, "aarp-expiry-time",
+	 &sysctl_aarp_expiry_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	{NET_ATALK_AARP_TICK_TIME, "aarp-tick-time",
+	 &sysctl_aarp_tick_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	{NET_ATALK_AARP_RETRANSMIT_LIMIT, "aarp-retransmit-limit",
+	 &sysctl_aarp_retransmit_limit, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_ATALK_AARP_RESOLVE_TIME, "aarp-resolve-time",
+	 &sysctl_aarp_resolve_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	{0}
+};
+
+static ctl_table atalk_dir_table[] = {
+	{NET_ATALK, "appletalk", NULL, 0, 0555, atalk_table},
 	{0}
 };
+
+static ctl_table atalk_root_table[] = {
+	{CTL_NET, "net", NULL, 0, 0555, atalk_dir_table},
+	{0}
+};
+
+static struct ctl_table_header *atalk_table_header;
+
+inline void atalk_register_sysctl(void)
+{
+	atalk_table_header = register_sysctl_table(atalk_root_table, 1);
+}
+
+inline void atalk_unregister_sysctl(void)
+{
+	unregister_sysctl_table(atalk_table_header);
+}
+
+
+
+
+
+
+
diff -u --recursive --new-file v2.1.42/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- v2.1.42/linux/net/ax25/af_ax25.c	Thu May 29 21:53:11 1997
+++ linux/net/ax25/af_ax25.c	Thu Jun 12 16:22:11 1997
@@ -148,6 +148,11 @@
 	MOD_DEC_USE_COUNT;
 }
 
+static void ax25_free_sock(struct sock *sk)
+{
+	ax25_free_cb(sk->protinfo.ax25);
+}
+
 /*
  *	Socket removal during an interrupt is now safe.
  */
@@ -428,7 +433,6 @@
 			add_timer(&ax25->timer);
 		} else {
 			sk_free(ax25->sk);
-			ax25_free_cb(ax25);
 		}
 	} else {
 		ax25_free_cb(ax25);
@@ -858,7 +862,8 @@
 	}
 
 	sock_init_data(sock, sk);
-	
+
+	sk->destruct = ax25_free_sock;
 	sock->ops    = &ax25_proto_ops;
 	sk->protocol = protocol;
 	sk->mtu      = AX25_MTU;	/* 256 */
@@ -894,7 +899,8 @@
 	}
 
 	sock_init_data(NULL, sk);
-	
+
+	sk->destruct = ax25_free_sock;
 	sk->type     = osk->type;
 	sk->socket   = osk->socket;
 	sk->priority = osk->priority;
@@ -926,7 +932,6 @@
 	if (osk->protinfo.ax25->digipeat != NULL) {
 		if ((ax25->digipeat = kmalloc(sizeof(ax25_digi), GFP_ATOMIC)) == NULL) {
 			sk_free(sk);
-			ax25_free_cb(ax25);
 			return NULL;
 		}
 
@@ -1182,8 +1187,8 @@
 
 #ifdef CONFIG_AX25_DAMA_SLAVE
 		case AX25_PROTO_DAMA_SLAVE:
-			ax25->modulus = AX25_MODULUS;
-			ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];
+			sk->protinfo.ax25->modulus = AX25_MODULUS;
+			sk->protinfo.ax25->window  = sk->protinfo.ax25->ax25_dev->values[AX25_VALUES_WINDOW];
 			if (sk->protinfo.ax25->ax25_dev->dama.slave)
 				ax25_ds_establish_data_link(sk->protinfo.ax25);
 			else
diff -u --recursive --new-file v2.1.42/linux/net/core/dev.c linux/net/core/dev.c
--- v2.1.42/linux/net/core/dev.c	Sat May 24 09:10:25 1997
+++ linux/net/core/dev.c	Thu Jun 12 16:22:11 1997
@@ -1485,7 +1485,6 @@
 		case SIOCGIFMTU:
 		case SIOCGIFMEM:
 		case SIOCGIFHWADDR:
-		case SIOCSIFHWADDR:
 		case SIOCGIFSLAVE:
 		case SIOCGIFMAP:
 		case SIOGIFINDEX:
@@ -1499,6 +1498,7 @@
 		case SIOCSIFMETRIC:
 		case SIOCSIFMTU:
 		case SIOCSIFMEM:
+		case SIOCSIFHWADDR:
 		case SIOCSIFMAP:
 		case SIOCSIFSLAVE:
 		case SIOCADDMULTI:
diff -u --recursive --new-file v2.1.42/linux/net/core/sock.c linux/net/core/sock.c
--- v2.1.42/linux/net/core/sock.c	Tue May 13 22:41:21 1997
+++ linux/net/core/sock.c	Thu Jun 12 16:22:11 1997
@@ -71,6 +71,8 @@
  *		Alan Cox	: 	Generic socket allocation to make hooks
  *					easier (suggested by Craig Metz).
  *		Michael Pall	:	SO_ERROR returns positive errno again
+ *             Steve Whitehouse:       Added default destructor to free
+ *                                     protocol private data.
  *
  * To Fix:
  *
@@ -124,6 +126,8 @@
 __u32 sysctl_wmem_default = SK_WMEM_MAX;
 __u32 sysctl_rmem_default = SK_RMEM_MAX;
 
+int sysctl_core_destroy_delay = SOCK_DESTROY_TIME;
+
 /*
  *	This is meant for all protocols to use and covers goings on
  *	at the socket level. Everything here is generic.
@@ -465,6 +469,9 @@
 
 void sk_free(struct sock *sk)
 {
+	if (sk->destruct)
+		sk->destruct(sk);
+
 	kmem_cache_free(sk_cachep, sk);
 }
 
@@ -787,7 +794,7 @@
 		 *	Someone is using our buffers still.. defer
 		 */
 		init_timer(&sk->timer);
-		sk->timer.expires=jiffies+10*HZ;
+		sk->timer.expires=jiffies+sysctl_core_destroy_delay;
 		sk->timer.function=sklist_destroy_timer;
 		sk->timer.data = (unsigned long)sk;
 		add_timer(&sk->timer);
@@ -874,6 +881,12 @@
 	}
 }
 
+void sock_def_destruct(struct sock *sk)
+{
+	if (sk->protinfo.destruct_hook)
+		kfree(sk->protinfo.destruct_hook);
+}
+
 void sock_init_data(struct socket *sock, struct sock *sk)
 {
 	skb_queue_head_init(&sk->receive_queue);
@@ -901,6 +914,7 @@
 	sk->data_ready		=	sock_def_callback2;
 	sk->write_space		=	sock_def_callback3;
 	sk->error_report	=	sock_def_callback1;
+	sk->destruct            =       sock_def_destruct;
 
 	sk->peercred.pid 	=	0;
 	sk->peercred.uid	=	-1;
diff -u --recursive --new-file v2.1.42/linux/net/core/sysctl_net_core.c linux/net/core/sysctl_net_core.c
--- v2.1.42/linux/net/core/sysctl_net_core.c	Tue May 13 22:41:21 1997
+++ linux/net/core/sysctl_net_core.c	Thu Jun 12 16:22:11 1997
@@ -13,6 +13,8 @@
 extern __u32 sysctl_wmem_default;
 extern __u32 sysctl_rmem_default;
 
+extern int sysctl_core_destroy_delay;
+
 ctl_table core_table[] = {
 	{NET_CORE_WMEM_MAX, "wmem_max",
 	 &sysctl_wmem_max, sizeof(int), 0644, NULL,
@@ -26,5 +28,8 @@
 	{NET_CORE_RMEM_DEFAULT, "rmem_default",
 	 &sysctl_rmem_default, sizeof(int), 0644, NULL,
 	 &proc_dointvec},
+	{NET_CORE_DESTROY_DELAY, "destroy_delay",
+	 &sysctl_core_destroy_delay, sizeof(int), 0644, NULL,
+	 &proc_dointvec_jiffies},
 	{ 0 }
 };
diff -u --recursive --new-file v2.1.42/linux/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- v2.1.42/linux/net/ipv4/af_inet.c	Tue May 13 22:41:23 1997
+++ linux/net/ipv4/af_inet.c	Thu Jun 12 16:22:11 1997
@@ -114,6 +114,7 @@
 
 #define min(a,b)	((a)<(b)?(a):(b))
 
+extern int sysctl_core_destroy_delay;
 extern struct proto packet_prot;
 extern int raw_get_info(char *, char **, off_t, int, int);
 extern int snmp_get_info(char *, char **, off_t, int, int);
@@ -190,7 +191,7 @@
 	sk->destroy = 1;
 	sk->ack_backlog = 0;
 	release_sock(sk);
-	net_reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
+	net_reset_timer(sk, TIME_DESTROY, sysctl_core_destroy_delay);
 }
 
 void destroy_sock(struct sock *sk)
@@ -366,7 +367,8 @@
 	}
 
 	sock_init_data(sock,sk);
-	
+	sk->destruct = NULL;
+
 	sk->zapped=0;
 #ifdef CONFIG_TCP_NAGLE_OFF
 	sk->nonagle = 1;
diff -u --recursive --new-file v2.1.42/linux/net/ipv4/devinet.c linux/net/ipv4/devinet.c
--- v2.1.42/linux/net/ipv4/devinet.c	Sun Jan 19 05:47:28 1997
+++ linux/net/ipv4/devinet.c	Thu Jun 12 16:22:11 1997
@@ -81,7 +81,7 @@
  *	This checks bitmasks for the ioctl calls for devices.
  */
  
-static inline int bad_mask(unsigned long mask, unsigned long addr)
+static inline int bad_mask(__u32 mask, __u32 addr)
 {
 	if (addr & (mask = ~mask))
 		return 1;
diff -u --recursive --new-file v2.1.42/linux/net/ipv4/fib.c linux/net/ipv4/fib.c
--- v2.1.42/linux/net/ipv4/fib.c	Tue May 13 22:41:23 1997
+++ linux/net/ipv4/fib.c	Thu Jun 12 16:22:11 1997
@@ -1896,8 +1896,8 @@
 void ip_rt_change_broadcast(struct device *dev, u32 new_brd)
 {
 	fib_lock();
-	printk(KERN_DEBUG "%s changes brd %08lX -> %08X\n",
-	       dev->name, dev->pa_brdaddr, new_brd);
+	printk(KERN_DEBUG "%s changes brd %08X -> %08X\n",
+	       dev->name, (u32)dev->pa_brdaddr, new_brd);
 	if (!ZERONET(dev->pa_addr) && dev->flags&IFF_BROADCAST) {
 		fib_magic(RTMSG_DELROUTE, RTF_IFBRD, dev->pa_brdaddr, ~0, dev);
 		rtmsg_dev(RTMSG_DELDEVICE, dev, NULL);
@@ -1911,8 +1911,8 @@
 {
 	fib_lock();
 	if (!ZERONET(dev->pa_addr) && (dev->flags&IFF_POINTOPOINT) && dev->type != ARPHRD_TUNNEL) {
-		printk(KERN_DEBUG "%s changes dst %08lX -> %08X\n",
-		       dev->name, dev->pa_dstaddr, dstaddr);
+		printk(KERN_DEBUG "%s changes dst %08X -> %08X\n",
+		       dev->name, (u32)dev->pa_dstaddr, dstaddr);
 		fib_magic(RTMSG_DELROUTE, RTF_IFPREFIX, dev->pa_dstaddr, ~0, dev);
 		rtmsg_dev(RTMSG_DELDEVICE, dev, NULL);
 		rtmsg_dev(RTMSG_NEWDEVICE, dev, NULL);
@@ -1927,8 +1927,8 @@
 	u32 net;
 
 	fib_lock();
-	printk(KERN_DEBUG "%s changes netmask %08lX -> %08X\n",
-	       dev->name, dev->pa_mask, mask);
+	printk(KERN_DEBUG "%s changes netmask %08X -> %08X\n",
+	       dev->name, (u32)dev->pa_mask, mask);
 	if (ZERONET(dev->pa_addr)) {
 		fib_unlock();
 		return;
@@ -1961,9 +1961,9 @@
 		return NOTIFY_DONE;
 	}
 	if (event == NETDEV_CHANGE) {
-		printk(KERN_DEBUG "%s(%s) changes state fl=%08x pa=%08lX/%08lX brd=%08lX dst=%08lX\n",
-		       dev->name, current->comm, dev->flags, dev->pa_addr, dev->pa_mask,
-		       dev->pa_brdaddr, dev->pa_dstaddr);
+		printk(KERN_DEBUG "%s(%s) changes state fl=%08x pa=%08X/%08X brd=%08X dst=%08X\n",
+		       dev->name, current->comm, dev->flags, (u32)dev->pa_addr, (u32)dev->pa_mask,
+		       (u32)dev->pa_brdaddr, (u32)dev->pa_dstaddr);
 		if (!(dev->flags&IFF_BROADCAST))
 			fib_magic(RTMSG_DELROUTE, RTF_IFBRD, dev->pa_brdaddr, ~0, dev);
 		if (!(dev->flags&IFF_POINTOPOINT))
@@ -1985,9 +1985,9 @@
 		}
 
 		if (event == NETDEV_UP)
-			printk(KERN_DEBUG "%s UP fl=%08x pa=%08lX/%08lX brd=%08lX dst=%08lX\n",
-			       dev->name, dev->flags, dev->pa_addr,
-			       dev->pa_mask, dev->pa_brdaddr, dev->pa_dstaddr);
+			printk(KERN_DEBUG "%s UP fl=%08x pa=%08X/%08X brd=%08X dst=%08X\n",
+			       dev->name, dev->flags, (u32)dev->pa_addr,
+			       (u32)dev->pa_mask, (u32)dev->pa_brdaddr, (u32)dev->pa_dstaddr);
 
 		rtmsg_dev(RTMSG_NEWDEVICE, dev, NULL);
 
diff -u --recursive --new-file v2.1.42/linux/net/ipv4/igmp.c linux/net/ipv4/igmp.c
--- v2.1.42/linux/net/ipv4/igmp.c	Fri Apr  4 08:52:28 1997
+++ linux/net/ipv4/igmp.c	Thu Jun 12 16:22:11 1997
@@ -88,6 +88,9 @@
 #include <linux/igmp.h>
 #include <net/checksum.h>
 
+int sysctl_igmp_max_host_report_delay = IGMP_MAX_HOST_REPORT_DELAY;
+int sysctl_igmp_timer_scale = IGMP_TIMER_SCALE;
+int sysctl_igmp_age_threshold = IGMP_AGE_THRESHOLD;
 
 /*
  *	If time expired, change the router type to IGMP_NEW_ROUTER.
@@ -133,7 +136,7 @@
 		return NULL;
 	i->dev = dev;
 	i->type = IGMP_NEW_ROUTER;
-	i->time = IGMP_AGE_THRESHOLD;
+	i->time = sysctl_igmp_age_threshold;
 	i->next = ip_router_info_head;
 	ip_router_info_head = i;
 
@@ -229,7 +232,7 @@
 	int tv;
 	if(im->tm_running)
 		return;
-	tv=random()%(max_resp_time*HZ/IGMP_TIMER_SCALE); /* Pick a number any number 8) */
+	tv=random()%(max_resp_time*HZ/sysctl_igmp_timer_scale); /* Pick a number any number 8) */
 	im->timer.expires=jiffies+tv;
 	im->tm_running=1;
 	add_timer(&im->timer);
@@ -363,7 +366,7 @@
 			if (group && group != im->multiaddr)
 				continue;
 			if(im->tm_running) {
-				if(im->timer.expires>jiffies+max_resp_time*HZ/IGMP_TIMER_SCALE) {
+				if(im->timer.expires>jiffies+max_resp_time*HZ/sysctl_igmp_timer_scale) {
 					igmp_stop_timer(im);
 					igmp_start_timer(im,max_resp_time);
 				}
@@ -372,9 +375,9 @@
 		}
 	} else {
 		mrouter_type=IGMP_OLD_ROUTER;
-		max_resp_time=IGMP_MAX_HOST_REPORT_DELAY*IGMP_TIMER_SCALE;
+		max_resp_time=sysctl_igmp_max_host_report_delay*sysctl_igmp_timer_scale;
 
-		if(igmp_set_mrouter_info(dev,mrouter_type,IGMP_AGE_THRESHOLD)==NULL)
+		if(igmp_set_mrouter_info(dev,mrouter_type,sysctl_igmp_age_threshold)==NULL)
 			return;
 
 		/*
diff -u --recursive --new-file v2.1.42/linux/net/ipv4/ip_fragment.c linux/net/ipv4/ip_fragment.c
--- v2.1.42/linux/net/ipv4/ip_fragment.c	Sat May 24 09:10:25 1997
+++ linux/net/ipv4/ip_fragment.c	Thu Jun 12 16:22:11 1997
@@ -5,7 +5,7 @@
  *
  *		The IP fragmentation functionality.
  *		
- * Version:	$Id: ip_fragment.c,v 1.22 1997/05/17 05:21:56 freitag Exp $
+ * Version:	$Id: ip_fragment.c,v 1.23 1997/05/31 12:36:35 freitag Exp $
  *
  * Authors:	Fred N. van Kempen <waltje@uWalt.NL.Mugnet.ORG>
  *		Alan Cox <Alan.Cox@linux.org>
@@ -41,6 +41,8 @@
 int sysctl_ipfrag_high_thresh = 256*1024;
 int sysctl_ipfrag_low_thresh = 192*1024;
 
+int sysctl_ipfrag_time = IP_FRAG_TIME;
+
 /* Describe an IP fragment. */
 struct ipfrag {
 	int		offset;		/* offset of fragment in IP datagram	*/
@@ -251,7 +253,7 @@
 	qp->dev = skb->dev;
 
 	/* Start a timer for this entry. */
-	qp->timer.expires = jiffies + IP_FRAG_TIME;	/* about 30 seconds	*/
+	qp->timer.expires = jiffies + sysctl_ipfrag_time;	/* about 30 seconds	*/
 	qp->timer.data = (unsigned long) qp;		/* pointer to queue	*/
 	qp->timer.function = ip_expire;			/* expire function	*/
 	add_timer(&qp->timer);
@@ -417,7 +419,7 @@
 			memcpy(qp->iph, iph, ihl+8);
 		}
 		del_timer(&qp->timer);
-		qp->timer.expires = jiffies + IP_FRAG_TIME;	/* about 30 seconds */
+		qp->timer.expires = jiffies + sysctl_ipfrag_time;	/* about 30 seconds */
 		qp->timer.data = (unsigned long) qp;	/* pointer to queue */
 		qp->timer.function = ip_expire;		/* expire function */
 		add_timer(&qp->timer);
diff -u --recursive --new-file v2.1.42/linux/net/ipv4/ipmr.c linux/net/ipv4/ipmr.c
--- v2.1.42/linux/net/ipv4/ipmr.c	Tue May 13 22:41:23 1997
+++ linux/net/ipv4/ipmr.c	Thu Jun 12 16:22:11 1997
@@ -1031,7 +1031,7 @@
 			}
 			if(pos>offset+length)
 			{
-				sti();
+				end_bh_atomic();
 				goto done;
 			}
 			mfc=mfc->next;
diff -u --recursive --new-file v2.1.42/linux/net/ipv4/packet.c linux/net/ipv4/packet.c
--- v2.1.42/linux/net/ipv4/packet.c	Tue Mar  4 10:25:27 1997
+++ linux/net/ipv4/packet.c	Thu Jun 12 16:22:11 1997
@@ -160,7 +160,7 @@
 	if(len>dev->mtu+dev->hard_header_len)
   		return -EMSGSIZE;
 
-	skb = sock_wmalloc(sk, len, 0, GFP_KERNEL);
+	skb = sock_wmalloc(sk, len+dev->hard_header_len, 0, GFP_KERNEL);
 
 	/*
 	 *	If the write buffer is full, then tough. At this level the user gets to
@@ -177,6 +177,11 @@
 	 *	Fill it in 
 	 */
 	 
+	/* FIXME: Save some space for broken drivers that write a
+	 * hard header at transmission time by themselves. PPP is the
+	 * notable one here. This should really be fixed at the driver level.
+	 */
+	skb_reserve(skb,dev->hard_header_len);
 	err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len);
 	skb->arp = 1;	/* No ARP needs doing on this (complete) frame */
 	skb->protocol = proto;
diff -u --recursive --new-file v2.1.42/linux/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c
--- v2.1.42/linux/net/ipv4/sysctl_net_ipv4.c	Sat May 24 09:10:25 1997
+++ linux/net/ipv4/sysctl_net_ipv4.c	Thu Jun 12 16:22:11 1997
@@ -34,10 +34,17 @@
 extern int sysctl_arp_check_interval;
 extern int sysctl_arp_confirm_interval;
 extern int sysctl_arp_confirm_timeout;
+extern int sysctl_arp_max_pings;
 
 /* From ip_fragment.c */
 extern int sysctl_ipfrag_low_thresh;
 extern int sysctl_ipfrag_high_thresh; 
+extern int sysctl_ipfrag_time;
+
+/* From igmp.c */
+extern int sysctl_igmp_max_host_report_delay;
+extern int sysctl_igmp_timer_scale;
+extern int sysctl_igmp_age_threshold;
 
 extern int sysctl_tcp_cong_avoidance;
 extern int sysctl_tcp_hoe_retransmits;
@@ -45,7 +52,16 @@
 extern int sysctl_tcp_tsack;
 extern int sysctl_tcp_timestamps;
 extern int sysctl_tcp_window_scaling;
-extern int sysctl_syn_retries;
+extern int sysctl_tcp_keepalive_time;
+extern int sysctl_tcp_keepalive_probes;
+extern int sysctl_tcp_max_ka_probes;
+extern int sysctl_tcp_retries1;
+extern int sysctl_tcp_retries2;
+extern int sysctl_tcp_max_delay_acks;
+extern int sysctl_tcp_fin_timeout;
+extern int sysctl_tcp_syncookies;
+extern int sysctl_tcp_always_syncookie;
+extern int sysctl_tcp_syn_retries;
 
 extern int tcp_sysctl_congavoid(ctl_table *ctl, int write, struct file * filp,
 				void *buffer, size_t *lenp);
@@ -82,6 +98,8 @@
          &sysctl_arp_dead_res_time, sizeof(int), 0644, NULL, &proc_dointvec},
         {NET_IPV4_ARP_MAX_TRIES, "arp_max_tries",
          &sysctl_arp_max_tries, sizeof(int), 0644, NULL, &proc_dointvec},
+        {NET_IPV4_ARP_MAX_PINGS, "arp_max_pings",
+         &sysctl_arp_max_pings, sizeof(int), 0644, NULL, &proc_dointvec},
         {NET_IPV4_ARP_TIMEOUT, "arp_timeout",
          &sysctl_arp_timeout, sizeof(int), 0644, NULL, &proc_dointvec},
         {NET_IPV4_ARP_CHECK_INTERVAL, "arp_check_interval",
@@ -149,12 +167,46 @@
         {NET_IPV4_RFC1620_REDIRECTS, "ip_rfc1620_redirects",
          &ipv4_config.rfc1620_redirects, sizeof(int), 0644, NULL,
          &proc_dointvec},
-	{NET_TCP_SYN_RETRIES, "tcp_syn_retries",
-	&sysctl_syn_retries, sizeof(int), 0644, NULL, &proc_dointvec},
-	{NET_IPFRAG_HIGH_THRESH, "ipfrag_high_thresh",
-	&sysctl_ipfrag_high_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
-	{NET_IPFRAG_LOW_THRESH, "ipfrag_low_thresh",
-	&sysctl_ipfrag_low_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPV4_TCP_SYN_RETRIES, "tcp_syn_retries",
+	 &sysctl_tcp_syn_retries, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPV4_IPFRAG_HIGH_THRESH, "ipfrag_high_thresh",
+	 &sysctl_ipfrag_high_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPV4_IPFRAG_LOW_THRESH, "ipfrag_low_thresh",
+	 &sysctl_ipfrag_low_thresh, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPV4_IPFRAG_TIME, "ipfrag_time",
+	 &sysctl_ipfrag_time, sizeof(int), 0644, NULL, &proc_dointvec_jiffies},
+	{NET_IPV4_TCP_MAX_KA_PROBES, "tcp_max_ka_probes",
+	 &sysctl_tcp_max_ka_probes, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPV4_TCP_KEEPALIVE_TIME, "tcp_keepalive_time",
+	 &sysctl_tcp_keepalive_time, sizeof(int), 0644, NULL, 
+	 &proc_dointvec_jiffies},
+	{NET_IPV4_TCP_KEEPALIVE_PROBES, "tcp_keepalive_probes",
+	 &sysctl_tcp_keepalive_probes, sizeof(int), 0644, NULL, 
+	 &proc_dointvec},
+	{NET_IPV4_TCP_RETRIES1, "tcp_retries1",
+	 &sysctl_tcp_retries1, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPV4_TCP_RETRIES2, "tcp_retries2",
+	 &sysctl_tcp_retries2, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPV4_TCP_MAX_DELAY_ACKS, "tcp_max_delay_acks",
+	 &sysctl_tcp_max_delay_acks, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_IPV4_TCP_FIN_TIMEOUT, "tcp_fin_timeout",
+	 &sysctl_tcp_fin_timeout, sizeof(int), 0644, NULL, 
+	 &proc_dointvec_jiffies},
+	{NET_IPV4_IGMP_MAX_HOST_REPORT_DELAY, "igmp_max_host_report_delay",
+	 &sysctl_igmp_max_host_report_delay, sizeof(int), 0644, NULL, 
+	 &proc_dointvec},
+	{NET_IPV4_IGMP_TIMER_SCALE, "igmp_timer_scale",
+	 &sysctl_igmp_timer_scale, sizeof(int), 0644, NULL, &proc_dointvec},
+#if 0
+	/* This one shouldn't be exposed to the user (too implementation
+	   specific): */
+	{NET_IPV4_IGMP_AGE_THRESHOLD, "igmp_age_threshold",
+	 &sysctl_igmp_age_threshold, sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
+	{NET_TCP_SYNCOOKIES, "tcp_syncookies",
+	 &sysctl_tcp_syncookies, sizeof(int), 0644, NULL, &proc_dointvec},
+	{NET_TCP_ALWAYS_SYNCOOKIE, "tcp_always_syncookie",
+	 &sysctl_tcp_always_syncookie, sizeof(int), 0644, NULL, &proc_dointvec},
 	{0}
 };
 
diff -u --recursive --new-file v2.1.42/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- v2.1.42/linux/net/ipv4/tcp.c	Thu May 15 16:48:06 1997
+++ linux/net/ipv4/tcp.c	Thu Jun 12 16:22:11 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp.c,v 1.65 1997/05/06 09:31:43 davem Exp $
+ * Version:	$Id: tcp.c,v 1.66 1997/05/31 12:36:39 freitag Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -431,6 +431,8 @@
 
 #include <asm/uaccess.h>
 
+int sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT;
+
 unsigned long seq_offset;
 struct tcp_mib	tcp_statistics;
 
@@ -1385,7 +1387,7 @@
 		if(timer_active)
 			add_timer(&sk->timer);
 		else
-			tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT);
+			tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
 	}
 
 	return send_fin;
@@ -1499,7 +1501,7 @@
 		if(timer_active)
 			add_timer(&sk->timer);
 		else
-			tcp_reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT);
+			tcp_reset_msl_timer(sk, TIME_CLOSE, sysctl_tcp_fin_timeout);
 	}
 
 	sk->dead = 1;
diff -u --recursive --new-file v2.1.42/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- v2.1.42/linux/net/ipv4/tcp_input.c	Tue May 13 22:41:23 1997
+++ linux/net/ipv4/tcp_input.c	Thu Jun 12 16:22:11 1997
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.51 1997/04/27 19:24:40 schenk Exp $
+ * Version:	$Id: tcp_input.c,v 1.52 1997/05/31 12:36:42 freitag Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -56,13 +56,15 @@
 static void tcp_cong_avoid_vegas(struct sock *sk, u32 seq, u32 ack,
 				 u32 seq_rtt);
 
-int sysctl_tcp_cong_avoidance = 0;
-int sysctl_tcp_hoe_retransmits = 0;
-int sysctl_tcp_sack = 0;
-int sysctl_tcp_tsack = 0;
-int sysctl_tcp_timestamps = 0;
-int sysctl_tcp_window_scaling = 0;
- 
+int sysctl_tcp_cong_avoidance;
+int sysctl_tcp_hoe_retransmits;
+int sysctl_tcp_sack;
+int sysctl_tcp_tsack;
+int sysctl_tcp_timestamps;
+int sysctl_tcp_window_scaling;
+int sysctl_tcp_syncookies; 
+int sysctl_tcp_always_syncookie;
+int sysctl_tcp_max_delay_acks = MAX_DELAY_ACK;
 
 static tcp_sys_cong_ctl_t tcp_sys_cong_ctl_f = &tcp_cong_avoid_vanj;
 
@@ -1080,7 +1082,7 @@
 		/* A retransmit, 2nd most common case.  Force an imediate ack. */
 		SOCK_DEBUG(sk, "retransmit received: seq %X\n", skb->seq);
 
-		tp->delayed_acks = MAX_DELAY_ACK;
+		tp->delayed_acks = sysctl_tcp_max_delay_acks;
 		kfree_skb(skb, FREE_READ);
 		return;
 	}
@@ -1094,7 +1096,7 @@
 	}
 
 	/* Ok. This is an out_of_order segment, force an ack. */
-	tp->delayed_acks = MAX_DELAY_ACK;
+	tp->delayed_acks = sysctl_tcp_max_delay_acks;
 
 	/* Disable header predition. */
 	tp->pred_flags = 0;
@@ -1218,7 +1220,7 @@
 		return;
 	}
 
-	if (tp->delayed_acks >= MAX_DELAY_ACK || tcp_raise_window(sk))
+	if (tp->delayed_acks >= sysctl_tcp_max_delay_acks || tcp_raise_window(sk))
 		tcp_send_ack(sk);
 	else
 		tcp_send_delayed_ack(sk, HZ/2);
diff -u --recursive --new-file v2.1.42/linux/net/ipv4/tcp_timer.c linux/net/ipv4/tcp_timer.c
--- v2.1.42/linux/net/ipv4/tcp_timer.c	Thu May 15 16:48:06 1997
+++ linux/net/ipv4/tcp_timer.c	Thu Jun 12 16:22:11 1997
@@ -22,7 +22,11 @@
 
 #include <net/tcp.h>
 
-int sysctl_syn_retries = TCP_SYN_RETRIES; 
+int sysctl_tcp_syn_retries = TCP_SYN_RETRIES; 
+int sysctl_tcp_keepalive_time = TCP_KEEPALIVE_TIME;
+int sysctl_tcp_keepalive_probes = TCP_KEEPALIVE_PROBES;
+int sysctl_tcp_retries1 = TCP_RETR1;
+int sysctl_tcp_retries2 = TCP_RETR2;
 
 static void tcp_sltimer_handler(unsigned long);
 static void tcp_syn_recv_timer(unsigned long);
@@ -172,7 +176,7 @@
 	     /* Eric, what the heck is this doing?!?! */
 	     tp->retransmits && !(tp->retransmits & 7)) ||
 
-	    (sk->state != TCP_ESTABLISHED && tp->retransmits > TCP_RETR1)) {
+	    (sk->state != TCP_ESTABLISHED && tp->retransmits > sysctl_tcp_retries1)) {
 		/*	Attempt to recover if arp has changed (unlikely!) or
 		 *	a route has shifted (not supported prior to 1.3).
 		 */
@@ -180,7 +184,7 @@
 	}
 	
 	/* Have we tried to SYN too many times (repent repent 8)) */
-	if(tp->retransmits > sysctl_syn_retries && sk->state==TCP_SYN_SENT) {
+	if(tp->retransmits > sysctl_tcp_syn_retries && sk->state==TCP_SYN_SENT) {
 		if(sk->err_soft)
 			sk->err=sk->err_soft;
 		else
@@ -198,7 +202,7 @@
 	}
 
 	/* Has it gone just too far? */
-	if (tp->retransmits > TCP_RETR2) {
+	if (tp->retransmits > sysctl_tcp_retries2) {
 		if(sk->err_soft)
 			sk->err = sk->err_soft;
 		else
@@ -251,7 +255,7 @@
 	 *	FIXME: We ought not to do it, Solaris 2.5 actually has fixing
 	 *	this behaviour in Solaris down as a bug fix. [AC]
 	 */
-	if (tp->probes_out > TCP_RETR2) {
+	if (tp->probes_out > sysctl_tcp_retries2) {
 		if(sk->err_soft)
 			sk->err = sk->err_soft;
 		else
@@ -281,8 +285,8 @@
 		struct tcp_opt *tp = &sk->tp_pinfo.af_tcp;
 		__u32 elapsed = jiffies - tp->rcv_tstamp;
 
-		if (elapsed >= TCP_KEEPALIVE_TIME) {
-			if (tp->probes_out > TCP_KEEPALIVE_PROBES) {
+		if (elapsed >= sysctl_tcp_keepalive_time) {
+			if (tp->probes_out > sysctl_tcp_keepalive_probes) {
 				if(sk->err_soft)
 					sk->err = sk->err_soft;
 				else
@@ -316,6 +320,8 @@
  */
 #define MAX_KA_PROBES	5
 
+int sysctl_tcp_max_ka_probes = MAX_KA_PROBES;
+
 /* Keepopen's are only valid for "established" TCP's, nicely our listener
  * hash gets rid of most of the useless testing, so we run through a couple
  * of the established hash chains each clock tick.  -DaveM
@@ -341,7 +347,7 @@
 		while(sk) {
 			if(sk->keepopen) {
 				count += tcp_keepopen_proc(sk);
-				if(count == MAX_KA_PROBES)
+				if(count == sysctl_tcp_max_ka_probes)
 					goto out;
 			}
 			sk = sk->next;
@@ -455,7 +461,7 @@
 						break;
 
 					tcp_synq_unlink(tp, conn);
-					if (conn->retrans >= TCP_RETR1) {
+					if (conn->retrans >= sysctl_tcp_retries1) {
 #ifdef TCP_DEBUG
 						printk(KERN_DEBUG "syn_recv: "
 						       "too many retransmits\n");
diff -u --recursive --new-file v2.1.42/linux/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- v2.1.42/linux/net/ipv6/af_inet6.c	Thu May 15 16:48:06 1997
+++ linux/net/ipv6/af_inet6.c	Thu Jun 12 16:22:11 1997
@@ -7,7 +7,7 @@
  *
  *	Adapted from linux/net/ipv4/af_inet.c
  *
- *	$Id: af_inet6.c,v 1.18 1997/05/07 09:40:12 davem Exp $
+ *	$Id: af_inet6.c,v 1.19 1997/06/02 14:40:40 alan Exp $
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -105,6 +105,7 @@
 	
 	sock_init_data(sock, sk);
 
+	sk->destruct            = NULL;
 	sk->zapped		= 0;
 	sk->family		= AF_INET6;
 	sk->protocol		= protocol;
diff -u --recursive --new-file v2.1.42/linux/net/ipv6/tcp_ipv6.c linux/net/ipv6/tcp_ipv6.c
--- v2.1.42/linux/net/ipv6/tcp_ipv6.c	Tue May 13 22:41:24 1997
+++ linux/net/ipv6/tcp_ipv6.c	Thu Jun 12 16:22:11 1997
@@ -5,7 +5,7 @@
  *	Authors:
  *	Pedro Roque		<roque@di.fc.ul.pt>	
  *
- *	$Id: tcp_ipv6.c,v 1.31 1997/04/29 21:51:23 davem Exp $
+ *	$Id: tcp_ipv6.c,v 1.32 1997/06/04 08:28:58 davem Exp $
  *
  *	Based on: 
  *	linux/net/ipv4/tcp.c
@@ -643,7 +643,6 @@
 	skb->end_seq = skb->seq + 1;
 	th->seq = ntohl(skb->seq);
 	th->ack_seq = htonl(req->rcv_isn + 1);
-	th->doff = sizeof(*th)/4 + 1;
 
 	/* Don't offer more than they did.
 	 * This way we don't have to memorize who said what.
@@ -669,8 +668,9 @@
 	th->window = htons(req->rcv_wnd);
 
 	tmp = tcp_syn_build_options(skb, req->mss, req->sack_ok, req->tstamp_ok,
-		req->snd_wscale,req->rcv_wscale);
-	th->doff = sizeof(*th)/4 + (tmp>>2);
+		req->wscale_ok,req->rcv_wscale);
+	skb->csum = 0;
+	th->doff = (sizeof(*th) + tmp)>>2;
 	th->check = tcp_v6_check(th, sizeof(*th) + tmp,
 				 &req->af.v6_req.loc_addr, &req->af.v6_req.rmt_addr,
 				 csum_partial((char *)th, sizeof(*th)+tmp, skb->csum));
diff -u --recursive --new-file v2.1.42/linux/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- v2.1.42/linux/net/ipx/af_ipx.c	Tue May 13 22:41:24 1997
+++ linux/net/ipx/af_ipx.c	Thu Jun 12 16:22:11 1997
@@ -751,7 +751,7 @@
 	}
 
 #ifdef CONFIG_IPX_PPROP_ROUTING
-	if( ipx->ipx_type == IPX_TYPE_PPROP && ipx->ipx_tctrl < 8 ) 
+	if( ipx->ipx_type == IPX_TYPE_PPROP && ipx->ipx_tctrl < 8 && skb->pkt_type == PACKET_HOST ) 
 	{
 		int i;
         	ipx_interface *ifcs;
@@ -759,35 +759,10 @@
   		long *l;
 		char *c;
 		
-		if(skb->pkt_type!=PACKET_HOST)
-		{
-			kfree_skb(skb, FREE_READ);
-			return 0;
-		}
-
-#ifdef DEBUG_IPX_PPROP_ROUTING
-		printk(KERN_INFO "IPX: PPROP packet received\n"
-			" Src: %8x:%02x:%02x:%02x:%02x:%02x:%02x:%d/%d\n",
-			htonl(ipx->ipx_source.net),
-			ipx->ipx_source.node[0], ipx->ipx_source.node[1],
-			ipx->ipx_source.node[2], ipx->ipx_source.node[3],
-			ipx->ipx_source.node[4], ipx->ipx_source.node[5],
-			htons(ipx->ipx_source.sock),
-			htons(ipx->ipx_dest.sock)
-			);
-#endif
-
 		c = (char *) skb->data;
 		c += sizeof( struct ipxhdr );
-
 		l = (long *) c;
 
-#ifdef DEBUG_IPX_PPROP_ROUTING
-		printk( "IPX: Routing PPROP from net num %08x\n", (unsigned int) htonl(intrfc->if_netnum) );
-		for( i = 0 ; i < ipx->ipx_tctrl ; i++ )
-			printk( "IPX: Routing PPROP seen net num %08x\n", (unsigned int) htonl(*l++) );
-		l = (long *) c;
-#endif
 		i = 0;
 		/* 
 		 *	Dump packet if too many hops or already seen this net 
@@ -812,25 +787,13 @@
 				if( i - 1 == ipx->ipx_tctrl ) 
 				{
 					ipx->ipx_dest.net = ifcs->if_netnum;
-#ifdef DEBUG_IPX_PPROP_ROUTING
-					printk( "IPX: Forward PPROP onto net num %08x\n", (unsigned int) htonl(ifcs->if_netnum) );
-#endif
-					skb2 = skb_clone(skb, GFP_ATOMIC);
-
-					/*
-					 *	See if we are allowed to firewall forward
-					 */
-					if (call_fw_firewall(PF_IPX, skb2->dev, ipx, NULL, &skb)!=FW_ACCEPT)
+					/* See if we are allowed to firewall forward */
+					if (call_fw_firewall(PF_IPX, skb->dev, ipx, NULL, &skb)==FW_ACCEPT)
 					{
-						kfree_skb(skb, FREE_READ);
-						return 0;
-					}
+					        skb2 = skb_clone(skb, GFP_ATOMIC);
 					ipxrtr_route_skb(skb2);
 				}
-#ifdef DEBUG_IPX_PPROP_ROUTING
-				else
-					printk( "IPX: Ignoring PPROP for net num %08x\n", (unsigned int) htonl(ifcs->if_netnum) );
-#endif
+				}
 			}
 			/*
 			 *	Reset network number in packet 
@@ -1793,6 +1756,7 @@
 			return(-ESOCKTNOSUPPORT);
 	}
 	sock_init_data(sock,sk);
+	sk->destruct=NULL;
 	sk->mtu=IPX_MTU;
 	sk->no_check = 1;		/* Checksum off by default */
 	MOD_INC_USE_COUNT;
diff -u --recursive --new-file v2.1.42/linux/net/netrom/af_netrom.c linux/net/netrom/af_netrom.c
--- v2.1.42/linux/net/netrom/af_netrom.c	Thu May 29 21:53:11 1997
+++ linux/net/netrom/af_netrom.c	Thu Jun 12 16:22:11 1997
@@ -86,8 +86,6 @@
 
 static void nr_free_sock(struct sock *sk)
 {
-	kfree(sk->protinfo.nr);
-
 	sk_free(sk);
 
 	MOD_DEC_USE_COUNT;
diff -u --recursive --new-file v2.1.42/linux/net/netsyms.c linux/net/netsyms.c
--- v2.1.42/linux/net/netsyms.c	Thu May 29 21:53:11 1997
+++ linux/net/netsyms.c	Thu Jun 12 16:22:11 1997
@@ -326,6 +326,17 @@
 EXPORT_SYMBOL(kill_fasync);
 EXPORT_SYMBOL(ip_rcv);
 EXPORT_SYMBOL(arp_rcv);
+
+#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) 
+#include<linux/if_ltalk.h>
+EXPORT_SYMBOL(ltalk_setup);
+#endif
+
+#ifdef CONFIG_DLCI_MODULE
+extern int (*dlci_ioctl_hook)(unsigned int, void *);
+EXPORT_SYMBOL(dlci_ioctl_hook);
+#endif
+
 #endif  /* CONFIG_NET */
 
 #ifdef CONFIG_NETLINK
diff -u --recursive --new-file v2.1.42/linux/net/protocols.c linux/net/protocols.c
--- v2.1.42/linux/net/protocols.c	Thu Jan  2 05:13:29 1997
+++ linux/net/protocols.c	Thu Jun 12 16:22:11 1997
@@ -47,6 +47,10 @@
 #endif
 #endif
 
+#if defined(CONFIG_DECNET)
+#include <net/decnet_call.h>
+#endif
+
 #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
 #define NEED_802
 #include <net/atalkcall.h>
@@ -107,9 +111,11 @@
   { "Rose",	rose_proto_init },			/* Amateur Radio X.25 PLP */
 #endif
 #endif  
-
+#ifdef CONFIG_DECNET
+  { "DECnet",   decnet_proto_init },                    /* DECnet */
+#endif
 #ifdef	CONFIG_INET
-  { "INET",	inet_proto_init	},			/* TCP/IP			*/
+  { "INET",	inet_proto_init	},			/* TCP/IP */
 #ifdef	CONFIG_IPV6
   { "INET6",	inet6_proto_init},			/* IPv6	*/
 #endif
diff -u --recursive --new-file v2.1.42/linux/net/rose/af_rose.c linux/net/rose/af_rose.c
--- v2.1.42/linux/net/rose/af_rose.c	Thu May 29 21:53:12 1997
+++ linux/net/rose/af_rose.c	Thu Jun 12 16:22:11 1997
@@ -136,8 +136,6 @@
 
 static void rose_free_sock(struct sock *sk)
 {
-	kfree(sk->protinfo.rose);
-
 	sk_free(sk);
 
 	MOD_DEC_USE_COUNT;
diff -u --recursive --new-file v2.1.42/linux/net/socket.c linux/net/socket.c
--- v2.1.42/linux/net/socket.c	Thu May 15 16:48:07 1997
+++ linux/net/socket.c	Thu Jun 12 16:22:11 1997
@@ -212,7 +212,7 @@
 		file->f_flags = O_RDWR;
 		file->f_inode = inode;
 		if (inode) 
-			inode->i_count++;
+			atomic_inc(&inode->i_count);
 		file->f_pos = 0;
 	}
 	return fd;
@@ -797,6 +797,7 @@
 	int len;
 
 	lock_kernel();
+restart:
   	if ((sock = sockfd_lookup(fd, &err))!=NULL)
   	{
 		if (!(newsock = sock_alloc())) 
@@ -834,7 +835,13 @@
 	
 		if (upeer_sockaddr)
 		{
-			newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1);
+			/* Handle the race where the accept works and we
+			   then getname after it has closed again */
+			if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 1)<0)
+			{
+				sys_close(err);
+				goto restart;
+			}
 			move_addr_to_user(address,len, upeer_sockaddr, upeer_addrlen);
 		}
 out:
diff -u --recursive --new-file v2.1.42/linux/net/sysctl_net.c linux/net/sysctl_net.c
--- v2.1.42/linux/net/sysctl_net.c	Fri Feb  7 05:54:55 1997
+++ linux/net/sysctl_net.c	Thu Jun 12 16:22:11 1997
@@ -24,10 +24,6 @@
 extern ctl_table ipx_table[];
 #endif
 
-#ifdef CONFIG_ATALK
-extern ctl_table atalk_table[];
-#endif
-
 extern ctl_table core_table[], unix_table[];
 
 #ifdef CONFIG_NET
@@ -58,9 +54,6 @@
 #endif
 #ifdef CONFIG_IPX
         {NET_IPX,    "ipx",       NULL, 0, 0555, ipx_table},
-#endif
-#ifdef CONFIG_ATALK
-        {NET_ATALK,  "appletalk", NULL, 0, 0555, atalk_table},
 #endif
 #ifdef CONFIG_BRIDGE
         {NET_BRIDGE, "bridge",    NULL, 0, 0555, bridge_table},
diff -u --recursive --new-file v2.1.42/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- v2.1.42/linux/net/unix/af_unix.c	Tue May 13 22:41:25 1997
+++ linux/net/unix/af_unix.c	Thu Jun 12 16:22:11 1997
@@ -87,6 +87,8 @@
 
 #define min(a,b)	(((a)<(b))?(a):(b))
 
+int sysctl_unix_delete_delay = HZ;
+int sysctl_unix_destroy_delay = 10*HZ;
 
 unix_socket *unix_socket_table[UNIX_HASH_SIZE+1];
 
@@ -138,6 +140,12 @@
 	}
 }
 
+static void unix_destruct_addr(struct sock *sk)
+{
+	struct unix_address *addr = sk->protinfo.af_unix.addr;
+
+	unix_release_addr(addr);
+}
 
 /*
  *	Check unix socket name:
@@ -231,7 +239,6 @@
 	unix_socket *sk=(unix_socket *)data;
 	if(!unix_locked(sk) && atomic_read(&sk->wmem_alloc) == 0)
 	{
-		unix_release_addr(sk->protinfo.af_unix.addr);
 		sk_free(sk);
 		return;
 	}
@@ -240,7 +247,7 @@
 	 *	Retry;
 	 */
 	 
-	sk->timer.expires=jiffies+10*HZ;	/* No real hurry try it every 10 seconds or so */
+	sk->timer.expires=jiffies+sysctl_unix_destroy_delay;	/* No real hurry try it every 10 seconds or so */
 	add_timer(&sk->timer);
 }
 	 
@@ -248,7 +255,7 @@
 static void unix_delayed_delete(unix_socket *sk)
 {
 	sk->timer.data=(unsigned long)sk;
-	sk->timer.expires=jiffies+HZ;		/* Normally 1 second after will clean up. After that we try every 10 */
+	sk->timer.expires=jiffies+sysctl_unix_delete_delay;		/* Normally 1 second after will clean up. After that we try every 10 */
 	sk->timer.function=unix_destroy_timer;
 	add_timer(&sk->timer);
 }
@@ -284,7 +291,6 @@
 	
 	if(!unix_unlock(sk) && atomic_read(&sk->wmem_alloc) == 0)
 	{
-		unix_release_addr(sk->protinfo.af_unix.addr);
 		sk_free(sk);
 	}
 	else
@@ -346,7 +352,8 @@
 		return -ENOMEM;
 
 	sock_init_data(sock,sk);
-	
+
+	sk->destruct = unix_destruct_addr;
 	sk->protinfo.af_unix.family=AF_UNIX;
 	sk->protinfo.af_unix.inode=NULL;
 	sk->sock_readers=1;			/* Us */
@@ -792,7 +799,7 @@
 	}
 	if (sk->protinfo.af_unix.inode)
 	{
-		sk->protinfo.af_unix.inode->i_count++;
+		atomic_inc(&sk->protinfo.af_unix.inode->i_count);
 		newsk->protinfo.af_unix.inode=sk->protinfo.af_unix.inode;
 	}
 		
diff -u --recursive --new-file v2.1.42/linux/net/unix/sysctl_net_unix.c linux/net/unix/sysctl_net_unix.c
--- v2.1.42/linux/net/unix/sysctl_net_unix.c	Thu Jan  2 05:13:35 1997
+++ linux/net/unix/sysctl_net_unix.c	Thu Jun 12 16:22:11 1997
@@ -14,6 +14,15 @@
 #include <linux/mm.h>
 #include <linux/sysctl.h>
 
+extern int sysctl_unix_destroy_delay;
+extern int sysctl_unix_delete_delay;
+
 ctl_table unix_table[] = {
+	{NET_UNIX_DESTROY_DELAY, "destroy_delay",
+	&sysctl_unix_destroy_delay, sizeof(int), 0644, NULL, 
+	 &proc_dointvec_jiffies},
+	{NET_UNIX_DELETE_DELAY, "delete_delay",
+	&sysctl_unix_delete_delay, sizeof(int), 0644, NULL, 
+	 &proc_dointvec_jiffies},
 	{0}
 };
diff -u --recursive --new-file v2.1.42/linux/net/wanrouter/wanproc.c linux/net/wanrouter/wanproc.c
--- v2.1.42/linux/net/wanrouter/wanproc.c	Tue May 13 22:41:25 1997
+++ linux/net/wanrouter/wanproc.c	Thu Jun 12 16:22:11 1997
@@ -121,7 +121,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
@@ -160,7 +159,6 @@
 	NULL,			/* mknod */
 	NULL,			/* rename */
 	NULL,			/* readlink */
-	NULL,			/* follow_link */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
diff -u --recursive --new-file v2.1.42/linux/net/x25/af_x25.c linux/net/x25/af_x25.c
--- v2.1.42/linux/net/x25/af_x25.c	Thu May 29 21:53:12 1997
+++ linux/net/x25/af_x25.c	Thu Jun 12 16:22:11 1997
@@ -341,7 +341,6 @@
 		sk->timer.data     = (unsigned long)sk;
 		add_timer(&sk->timer);
 	} else {
-		kfree(sk->protinfo.x25);
 		sk_free(sk);
 		MOD_DEC_USE_COUNT;
 	}
diff -u --recursive --new-file v2.1.42/linux/scripts/Configure linux/scripts/Configure
--- v2.1.42/linux/scripts/Configure	Mon Apr 14 16:28:29 1997
+++ linux/scripts/Configure	Thu Jun 12 16:22:11 1997
@@ -363,6 +363,28 @@
 }
 
 #
+# define_string sets the value of a string argument
+#
+#	define_string define value
+#
+function define_string () {
+	echo "$1="'"'$2'"' >>$CONFIG
+	echo "#define $1 "'"'$2'"' >>$CONFIG_H
+	eval "$1=$2"
+}
+
+#
+# string processes a string argument
+#
+#	string question define default
+#
+function string () {
+	old=$(eval echo "\${$2}")
+	def=${old:-$3}
+	readln "$1 ($2) [$def] " "$def" "$old"
+	define_string "$2" "$ans"
+}
+#
 # choice processes a choice list (1-out-of-n)
 #
 #	choice question choice-list default
diff -u --recursive --new-file v2.1.42/linux/scripts/header.tk linux/scripts/header.tk
--- v2.1.42/linux/scripts/header.tk	Sat Apr 13 04:20:03 1996
+++ linux/scripts/header.tk	Thu Jun 12 16:22:11 1997
@@ -209,6 +209,10 @@
 			set cmd "global $var; set $var $value"
 			eval $cmd
 		}
+		if [regexp {([0-9A-Za-z_]+)="([0-9A-Za-z]+)"} $line foo var value] {
+			set cmd "global $var; set $var $value"
+			eval $cmd
+		}
 	}
 	close $file1
 	update_choices
@@ -260,6 +264,16 @@
 	}
 }
 
+proc write_string { file1 file2 varname variable dep } {
+	if { $dep == 0 } \
+		then { puts $file1 "# $varname is not set"; \
+		       puts $file2 "#undef $varname"} \
+	else {
+		puts $file1 "$varname=\"$variable\""; \
+		puts $file2 "#define $varname \"$variable\""; \
+	}
+}
+
 proc option_name {w mnum line text helpidx} {
 	button $w.x$line.l -text "$text" -relief groove -anchor w
 	$w.x$line.l configure -activefore [cget $w.x$line.l -fg] \
@@ -310,6 +324,15 @@
 
 proc hex { w mnum line text variable } {
 	int $w $mnum $line $text $variable
+}
+
+proc istring { w mnum line text variable } {
+	frame $w.x$line
+	entry $w.x$line.x -width 18 -relief sunken -borderwidth 2 \
+		-textvariable $variable
+	option_name $w $mnum $line $text $variable
+	pack $w.x$line.x -anchor w -side right -fill y
+	pack $w.x$line -anchor w -fill both -expand on
 }
 
 proc minimenu { w mnum line text variable helpidx } {
diff -u --recursive --new-file v2.1.42/linux/scripts/mkdep.c linux/scripts/mkdep.c
--- v2.1.42/linux/scripts/mkdep.c	Tue May 13 22:41:25 1997
+++ linux/scripts/mkdep.c	Thu Jun 12 16:22:12 1997
@@ -6,7 +6,6 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
-#include <errno.h>
 #include <sys/fcntl.h>
 #include <sys/mman.h>
 
diff -u --recursive --new-file v2.1.42/linux/scripts/tkcond.c linux/scripts/tkcond.c
--- v2.1.42/linux/scripts/tkcond.c	Mon May  6 02:26:18 1996
+++ linux/scripts/tkcond.c	Thu Jun 12 16:22:12 1997
@@ -195,6 +195,7 @@
 		      if( cfg->tok != tok_bool
 		         && cfg->tok != tok_int
 		         && cfg->tok != tok_hex
+		         && cfg->tok != tok_string
 			 && cfg->tok != tok_tristate 
 			 && cfg->tok != tok_choice
 			 && cfg->tok != tok_dep_tristate)
@@ -358,6 +359,7 @@
 	case tok_tristate:
 	case tok_int:
 	case tok_hex:
+	case tok_string:
 	case tok_choice:
 	case tok_make:
 	  /*
@@ -402,6 +404,7 @@
 	case tok_dep_tristate:
 	case tok_int:
 	case tok_hex:
+	case tok_string:
 	  for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
 	    {
 	      switch(cfg1->tok)
@@ -412,6 +415,7 @@
 		case tok_dep_tristate:
 		case tok_int:
 		case tok_hex:
+		case tok_string:
 		  if( strcmp(cfg->optionname, cfg1->optionname) == 0)
 		    {
 		      cfg->flags |= CFG_DUP;
diff -u --recursive --new-file v2.1.42/linux/scripts/tkgen.c linux/scripts/tkgen.c
--- v2.1.42/linux/scripts/tkgen.c	Fri Jan  3 01:33:27 1997
+++ linux/scripts/tkgen.c	Thu Jun 12 16:22:12 1997
@@ -289,6 +289,7 @@
       break;
     case tok_int:
     case tok_hex:
+    case tok_string:
       printf("} then { ");
       printf(".menu%d.config.f.x%d.x configure -state normal -fore [ cget .ref -foreground ]; ", menu_num, line_num);
       printf(".menu%d.config.f.x%d.l configure -state normal; ", menu_num, line_num);
@@ -487,6 +488,10 @@
       printf("} then { write_hex $cfg $autocfg %s $%s $notmod }\n",
              item->optionname, item->optionname);
       break;
+    case tok_string:
+      printf("} then { write_string $cfg $autocfg %s $%s $notmod }\n",
+             item->optionname, item->optionname);
+      break;
     case tok_make:
       printf("} then { do_make {%s} }\n",item->value);
       break;
@@ -646,6 +651,7 @@
       case tok_dep_tristate:
       case tok_int:
       case tok_hex:
+      case tok_string:
       case tok_choose:
 	tot++;
 	break;
@@ -702,6 +708,7 @@
 	case tok_dep_tristate:
 	case tok_int:
 	case tok_hex:
+	case tok_string:
 	case tok_choose:
 	  /*
 	   * If we have overfilled the menu, then go to the next one.
@@ -862,6 +869,19 @@
 		 cfg->label,
 		 cfg->optionname);
 	  break;
+	case tok_string:
+	  if( cfg->menu_number != menu_num )
+	    {
+	      end_proc(menu_num);
+	      start_proc(menulabel, cfg->menu_number, FALSE);
+	      menu_num = cfg->menu_number;
+	    }
+	  printf("\tistring $w.config.f %d %d \"%s\" %s\n",
+		 cfg->menu_number,
+		 cfg->menu_line,
+		 cfg->label,
+		 cfg->optionname);
+	  break;
 	default:
 	  break;
 	}
@@ -951,6 +971,7 @@
 	  break;
 	case tok_int:
 	case tok_hex:
+	case tok_string:
 	  printf("set %s %s\n", cfg->optionname, cfg->value);
 	  break;
 	case tok_choose:
@@ -985,6 +1006,7 @@
 	{
 	case tok_int:
 	case tok_hex:
+	case tok_string:
 	case tok_bool:
 	case tok_tristate:
 	case tok_dep_tristate:
@@ -1047,6 +1069,12 @@
 	      else if (cfg->tok == tok_hex )
 	        {
 		  printf("\twrite_hex $cfg $autocfg %s $%s $notmod\n",
+			 cfg->optionname,
+			 cfg->optionname);
+	        }
+	      else if (cfg->tok == tok_string )
+	        {
+		  printf("\twrite_string $cfg $autocfg %s $%s $notmod\n",
 			 cfg->optionname,
 			 cfg->optionname);
 	        }
diff -u --recursive --new-file v2.1.42/linux/scripts/tkparse.c linux/scripts/tkparse.c
--- v2.1.42/linux/scripts/tkparse.c	Mon May  6 02:26:18 1996
+++ linux/scripts/tkparse.c	Thu Jun 12 16:22:12 1997
@@ -370,6 +370,11 @@
       tok = tok_hex;
       pnt += 3;
     }
+  else if (strncmp(pnt, "string", 6) == 0) 
+    {
+      tok = tok_string;
+      pnt += 6;
+    }
   else if (strncmp(pnt, "if", 2) == 0) 
     {
       tok = tok_if;
@@ -457,6 +462,7 @@
       break;
     case tok_int:
     case tok_hex:
+    case tok_string:
       pnt = get_qstring(pnt, &kcfg->label);
       pnt = get_string(pnt, &kcfg->optionname);
       pnt = get_string(pnt, &kcfg->value);
@@ -702,6 +708,9 @@
 	case tok_hex:
 	  printf("hex ");
 	  break;
+	case tok_string:
+	  printf("istring ");
+	  break;
 	case tok_comment:
 	  printf("comment ");
 	  break;
@@ -732,6 +741,7 @@
 	case tok_dep_tristate:
 	case tok_int:
 	case tok_hex:
+	case tok_string:
 	  printf("%s %s\n", cfg->label, cfg->optionname);
 	  break;
 	case tok_if:
diff -u --recursive --new-file v2.1.42/linux/scripts/tkparse.h linux/scripts/tkparse.h
--- v2.1.42/linux/scripts/tkparse.h	Sat Mar 16 23:58:21 1996
+++ linux/scripts/tkparse.h	Thu Jun 12 16:22:12 1997
@@ -12,6 +12,7 @@
   tok_fi, 
   tok_int,
   tok_hex,
+  tok_string,
   tok_make,
   tok_define,
   tok_choose,
