diff -u --recursive --new-file pre2.0.4/linux/CREDITS linux/CREDITS
--- pre2.0.4/linux/CREDITS	Mon May 13 23:02:46 1996
+++ linux/CREDITS	Thu May 16 17:16:52 1996
@@ -221,7 +221,12 @@
 
 N: Juan Jose Ciarlante
 E: jjciarla@raiz.uncu.edu.ar
+E: juanjo@irriga.uncu.edu.ar
 D: Network driver alias support
+D: IP masq hashing and app modules
+S: Las Cuevas 2385 - Bo Guemes
+S: Las Heras, Mendoza CP 5539
+S: Argentina
 
 N: Hamish Coleman
 E: hamish@zot.apana.org.au
@@ -436,6 +441,16 @@
 S: Poltava 314023
 S: Ukraine
 
+N: Paul Gortmaker
+E: gpg109@rsphy1.anu.edu.au
+W: http://rsphy1.anu.edu.au/~gpg109
+D: Real Time Clock driver author.
+D: 8390 net driver hacker (ne2000, wd8013, smc-ultra, 3c503, etc.) 
+D: Ethernet-HowTo and BootPrompt-HowTo author.
+D: Added many new CONFIG options (modules, ramdisk, generic-serial, etc.)
+D: Implemented 1st "official" kernel thread (moved user bdflush to kflushd)
+D: Various other random hacks, patches and utilities.
+
 N: John E. Gotts
 E: jgotts@engin.umich.edu
 D: kernel hacker
@@ -472,6 +487,14 @@
 S: Atlanta, Georgia 30332
 S: USA
 
+N: Angelo Haritsis
+E: ah@doc.ic.ac.uk
+D: kernel patches (serial, watchdog)
+D: xringd, vuzkern, greekXfonts
+S: 58 Henfield Close
+S: London N19 3UL
+S: United Kingdom
+
 N: Kai Harrekilde-Petersen
 E: khp@dolphinics.no
 W: http://www.pip.dknet.dk/~pip93
@@ -1048,6 +1071,13 @@
 E: rubini@ipvvis.unipv.it
 D: the gpm mouse server and kernel support for it
 
+N: Thomas Sailer
+E: sailer@ife.ee.ethz.ch
+D: Baycom radio modem driver
+S: Weinbergstrasse 76
+S: 8408 Winterthur
+S: Switzerland
+
 N: Robert Sanders
 E: gt8134b@prism.gatech.edu
 D: Dosemu
@@ -1156,13 +1186,14 @@
 S: Canada M2N 2Z1
 
 N: Tommy Thorn
-E: Tommy.Thorn@daimi.aau.dk
+E: Tommy.Thorn@irisa.fr
+W: http://www.irisa.fr/prive/thorn/index.html
+P: 512/B4AFC909 BC BF 6D B1 52 26 1E D6  E3 2F A3 24 2A 84 FE 21
 D: Device driver hacker (aha1542 & plip)
-S: Aarhus University
-S: Computer Science Department
-S: Ny Munkegade 116
-S: DK-8000 Aarhus C
-S: Denmark
+S: IRISA
+S: Universit=E9 de Rennes I
+S: F-35042 Rennes Cedex
+S: FRANCE
 
 N: Jon Tombs
 E: jon@gtex02.us.es
diff -u --recursive --new-file pre2.0.4/linux/Documentation/Changes linux/Documentation/Changes
--- pre2.0.4/linux/Documentation/Changes	Wed May 15 11:01:14 1996
+++ linux/Documentation/Changes	Wed May 15 09:09:00 1996
@@ -26,6 +26,7 @@
 - Linux C++ Library	 2.7.1.4
 - Termcap		 2.0.8
 - Procps		 0.99a
+- Kbd			 0.91
 - Gpm			 1.06
 - SysVinit		 2.60
 - Util-linux		 2.5
@@ -188,6 +189,14 @@
 
    Better yet, just get the latest official Linux termcap from
 ftp://sunsite.unc.edu/pub/Linux/GCC/termcap-2.0.8.tar.gz
+
+   The console driver keeps track of the correspondence between character
+codes and glyph bitmaps loaded into the character ROM of your video card.
+Say
+
+   loadunimap def
+
+to get back to the default correspondence.
 
 Hdparm
 ======
diff -u --recursive --new-file pre2.0.4/linux/Documentation/Configure.help linux/Documentation/Configure.help
--- pre2.0.4/linux/Documentation/Configure.help	Mon May 13 23:02:46 1996
+++ linux/Documentation/Configure.help	Thu May 16 16:35:39 1996
@@ -1666,6 +1666,18 @@
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt.
 
+BAYCOM ser12 and par96 kiss emulation driver for AX.25
+CONFIG_BAYCOM
+  This is an experimental driver for Baycom style simple amateur radio
+  modems that connect to either a serial interface or a parallel 
+  interface. The driver supports the ser12 and par96 designs. To configure
+  the driver, use the setbaycom utility available from
+  http://www.ife.ee.ethz.ch/~sailer/ham/ham.html#lnxbay. For informations
+  on the modems, see http://www.baycom.de.
+  If you want to compile this as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. This is recommended.
+
 PLIP (parallel port) support
 CONFIG_PLIP
   PLIP (Parallel Line Internet Protocol) is used to create a mini
@@ -2060,18 +2072,20 @@
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
-FMV-181/182 support
+FMV-181/182/183/184 support
 CONFIG_FMV18X
-  If you have a Fujitsu FMV-181/182 network (ethernet) card, say Y and
-  read the Ethernet-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. This driver is also available
-  as a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want). If you want to compile it as a
-  module, say M here and read Documentation/modules.txt as well as
+  If you have a Fujitsu FMV-181/182/183/184 network (ethernet) card,
+  say Y and read the Ethernet-HOWTO, available via ftp (user: anonymous)
+  in sunsite.unc.edu:/pub/Linux/docs/HOWTO. This driver is also
+  available as a module ( = code which can be inserted in and removed
+  from the running kernel whenever you want). If you want to compile it
+  as a module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt. If you plan to use more
   than one network card under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If you use FMV-183 or
+  FMV-184 and it is not working, you may need to disable Plug & Play
+  mode of the card.
 
 EtherExpressPro support
 CONFIG_EEXPRESS_PRO
diff -u --recursive --new-file pre2.0.4/linux/Documentation/cdrom/cdrom-standard.tex linux/Documentation/cdrom/cdrom-standard.tex
--- pre2.0.4/linux/Documentation/cdrom/cdrom-standard.tex	Mon May 13 23:02:46 1996
+++ linux/Documentation/cdrom/cdrom-standard.tex	Wed May 15 17:30:36 1996
@@ -1,5 +1,5 @@
 \documentclass{article}
-\def\version{$Id: cdrom-standard.tex,v 0.5 1996/05/12 22:00:00 emoenke Exp $}
+\def\version{$Id: cdrom-standard.tex,v 0.6 1996/05/14 15:42:39 david Exp david $}
 
 \evensidemargin=0pt
 \oddsidemargin=0pt
@@ -9,6 +9,7 @@
 \def\linux{{\sc Linux}}
 \def\cdrom{{\sc CDrom}}
 \def\cdromc{{\tt cdrom.c}}
+\def\cdromh{{\tt cdrom.h}}
 \def\ucdrom{{\tt ucdrom.h}}
 
 \everymath{\it} \everydisplay{\it}
@@ -35,7 +36,7 @@
 hardware devices, but also to a certain divergence in behavior. Especially
 for \cdrom\ devices, the way a particular drive reacts to a `standard'
 $ioctl()$ call varies a lot from one brand to another; until today, the
-\linux \cdrom\ driver writers kept away from wilderness by a good practice:
+\linux\ \cdrom\ driver writers kept away from wilderness by a good practice:
 to evolve a new driver by copying, understanding and changing an existing
 one.
 
@@ -57,37 +58,36 @@
 But history has delivered us \cdrom\ support for many different interfaces.
 
 Some of the \linux\ \cdrom\ driver writers look at the existing standard
-which is expressed through <linux/cdrom.h> as to a rather wild set of
+which is expressed through \cdromh\ as to a rather wild set of
 commands and data formats and feel that any structure is lost, and from
 this point of view, this documentation shall help to achieve a common
 programming interface.
  
-Others - mainly those who used the already existing drivers not only as
-a coding example, but also as a `user interface' reference during their
-own development - have taken care that <linux/cdrom.h> reflects a
-software interface to `user programs' which is unique between all drivers
-as much as possible; these driver writers will continue to refine the
-existing <linux/cdrom.h> where it seems necessary, and they tend to look
-if any newly requested functionality isn't already there before they are
-ready to define new structures. The sbpcd driver gives an example that
-it is possible to let a robot arm play juke box - either with audio or
-with data CDs -, and that it is possible to let the juke box work on
-even if a disk has fallen upon the floor and the drive door has closed 
-without having a disk inside; without any new software layer or any
-structures which are not already present in <linux/cdrom.h>.
-This `other' group of \linux\ \cdrom\ driver writers explicitely does
-NOT support the idea to define an additional software layer between driver
-and user program.
-
+Others---mainly those who used the already existing drivers not only
+as a coding example, but also as a `user interface' reference during
+their own development---have taken care that \cdromh\ reflects a
+software interface to `user programs' which is unique between all
+drivers as much as possible; these driver writers will continue to
+refine the existing \cdromh\ where it seems necessary, and they tend
+to look if any newly requested functionality isn't already there
+before they are ready to define new structures. The sbpcd driver gives
+an example that it is possible to let a robot arm play juke
+box---either with audio or with data CDs---and that it is possible to
+let the juke box work on even if a disk has fallen upon the floor and
+the drive door has closed without having a disk inside; without any
+new software layer or any structures which are not already present in
+\cdromh.  This `other' group of \linux\ \cdrom\ driver writers
+explicitely does {\em not\/} support the idea to define an additional
+software layer between driver and user program.
 
 The following text reflects the opinion of the first mentioned \linux\ 
 \cdrom\ driver writer group only; the other group (not only the `silent
 majority') sees this text as a good base for a future documentation of the
 existing common \linux\ \cdrom\ programming interface, as it is stated 
-within <linux/cdrom.h>. Where <linux/cdrom.h> needs some external 
-explanation, this text can give it if the reader is aware that - at least
-at the moment - this text claims to be the proposal of something else than
-<linux/cdrom.h>.
+within \cdromh. Where \cdromh\ needs some external 
+explanation, this text can give it if the reader is aware that---at least
+at the moment---this text claims to be the proposal of something else than
+\cdromh.
 
 
 Apart from the somewhat unstructured interfacing with software, the
@@ -139,8 +139,8 @@
 \halign{$#$\ \hfil&$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
 struct& file_operations\ cdrom_fops = \{\hidewidth\cr
         &NULL,                  & lseek \cr
-        &block_read,            & read - general\ block-dev\ read \cr
-        &block_write,           & write - general block-dev write \cr
+        &block_read,            & read---general\ block-dev\ read \cr
+        &block_write,           & write---general block-dev write \cr
         &NULL,                  & readdir \cr
         &NULL,                  & select \cr
         &cdrom_ioctl,           & ioctl \cr
diff -u --recursive --new-file pre2.0.4/linux/Documentation/ioctl-number.txt linux/Documentation/ioctl-number.txt
--- pre2.0.4/linux/Documentation/ioctl-number.txt	Sun May 12 10:16:05 1996
+++ linux/Documentation/ioctl-number.txt	Thu May 16 16:35:39 1996
@@ -63,9 +63,10 @@
 0x09	linux/md.h
 0x12	linux/fs.h
 0x20	linux/cm206.h
-0x22	linux/scc.h		conflict!
+0x22	linux/scc.h		conflict! (version 2.01 of z8530drv)
 0x22	scsi/sg.h		conflict!
 'A'	linux/apm_bios.h
+'B'	linux/baycom.h
 'C'	linux/soundcard.h
 'F'	linux/fb.h
 'I'	linux/isdn.h
@@ -82,6 +83,7 @@
 'T'	asm/ioctls.h		conflict!
 'V'	linux/vt.h
 'Y'	linux/cyclades.h	codes in 0x004359NN
+'Z'	linux/scc.h		version 2.2 of z8530drv
 'a'	various, see http://lrcwww.epfl.ch/linux-atm/magic.html
 'c'	linux/comstats.h
 'f'	linux/ext2_fs.h
diff -u --recursive --new-file pre2.0.4/linux/Documentation/locks.txt linux/Documentation/locks.txt
--- pre2.0.4/linux/Documentation/locks.txt	Sun May  5 08:51:57 1996
+++ linux/Documentation/locks.txt	Wed May 15 11:22:04 1996
@@ -2,7 +2,7 @@
 
 		Andy Walker <andy@lysaker.kvaerner.no>
 
-			   15 April 1996
+			    15 May 1996
 
 
 What's New?
@@ -42,15 +42,23 @@
 over time, or under a very heavy mail load, would eventually cause the kernel
 to lock solid with deadlocked processes.
 
-I have chosen the rather cruel solution of returning an error when such a
-deadlock would occur. I can't see any other way to handle this situation
-gracefully. The other options are to maintain two entirely separate lists
-for flock() and fcntl() locks, thus defeating any protection between the
-two, or to free locks placed by one method when the same process later
-tries to lock the same file by the other method. Neither option seems
-satisfactory.
+Disallow Mixed Locks
+--------------------
+I have chosen the rather cruel solution of disallowing mixed locking styles
+on a given file at a given time. Attempts to lock a file with flock() when
+fcntl() locks exist, or vice versa, return with an error status of EBUSY.
+This seemed to be the only way to avoid all possible deadlock conditions,
+as flock() locks do not strictly have one owner process and so can't be
+checked for deadlocking in the usual manner.
+
+The process that created a lock with flock() might have forked multiple
+children and exited. Previously the parent process would have been marked
+as the owner of the lock, but deadlocks could just have easily occurred in
+one or more of the children, which we would not have been able to identify
+and avoid.
 
 Some programs may break (again, groan). In particular the aforementioned
 sendmail may have problems running in 'newaliases' mode. It will no longer
 deadlock though. Recompile sendmail to use flock() and your troubles will
 be over.
+
diff -u --recursive --new-file pre2.0.4/linux/Documentation/magic-number.txt linux/Documentation/magic-number.txt
--- pre2.0.4/linux/Documentation/magic-number.txt	Sun May 12 10:16:06 1996
+++ linux/Documentation/magic-number.txt	Thu May 16 16:35:39 1996
@@ -59,3 +59,5 @@
 STL_BOARDMAGIC      0xa2267f52  stlbrd_t             include/linux/stallion.h
 STL_PORTMAGIC       0x5a7182c9  stlport_t            include/linux/stallion.h
 PCXX_MAGIC          0x5c6df104  struct channel       drivers/char/pcxx.h
+BAYCOM_MAGIC        0x3105bac0  struct baycom_state  drivers/char/baycom.c
+
diff -u --recursive --new-file pre2.0.4/linux/Documentation/smp.ez linux/Documentation/smp.ez
--- pre2.0.4/linux/Documentation/smp.ez	Fri Apr 12 15:51:45 1996
+++ linux/Documentation/smp.ez	Thu Jan  1 02:00:00 1970
@@ -1,413 +0,0 @@
-\begindata{text,748928}
-\textdsversion{12}
-\template{default}
-\center{\underline{\bigger{\bigger{\bigger{An Implementation Of 
-Multiprocessor Linux
-
-}}}}}
-\italic{
-}\indent{\indent{This document describes the implementation of a simple SMP 
-Linux kernel extension and how to use this to develop SMP Linux kernels for 
-architectures other than the Intel MP v1.1 architecture for Pentium and 486 
-processors.}\italic{
-
-}}\italic{
-
-
-Alan Cox, 1995
-
-
-The author wishes to thank Caldera Inc whose donation of an ASUS dual 
-pentium board made this project possible, and Thomas Radke, whose initial 
-work on multiprocessor Linux formed the backbone of this project.
-
-\begindata{bp,941568}
-\enddata{bp,941568}
-\view{bpv,941568,0,0,0}
-}
-\heading{Background: The Intel MP specification.
-
-}
-	Most IBM PC style multiprocessor motherboards combine Intel 486 or Pentium 
-processors and glue chipsets with a hardware/software specification. The 
-specification places much of the onus for hard work on the chipset and 
-hardware rather than the operating system.
-
-
-	The Intel pentium processors have a wide variety of inbuilt facilities for 
-supporting multiprocessing, including hardware cache coherency, built in 
-interprocessor interrupt handling and a set of atomic test and set, 
-exchange and similar operations. The cache coherency in particular makes the 
-operating systems job far easier.
-
-
-	The specification defines a detailed configuration structure in ROM that 
-the boot up processor can read to find the full configuration of the 
-processors and busses. It also defines a procedure for starting up the 
-other processors.
-
-
-\heading{Mutual Exclusion Within A Single Processor Linux Kernel
-
-}
-	For any kernel to function in a sane manner it has to provide internal 
-locking and protection of its own tables to prevent two processes updating 
-them at once and for example allocating the same memory block. There are 
-two strategies for this within current Unix and Unixlike kernels. 
-Traditional unix systems from the earliest of days use a scheme of 'Coarse 
-Grained Locking' where the entire kernel is protected as a small number of 
-locks only. Some modern systems use fine grained locking. Because fine 
-grained locking has more overhead it is normally used only on 
-multiprocessor kernels and real time kernels. In a real time kernel the 
-fine grained locking reduces the amount of time locks are held and reduces 
-the critical (to real time programming at least) latency times.
-
-
-	Within the Linux kernel certain guarantees are made. No process running in 
-kernel mode will be pre-empted by another kernel mode process unless it 
-voluntarily sleeps.  This ensures that blocks of kernel code are 
-effectively atomic with respect to other processes and greatly simplifies 
-many operation. Secondly interrupts may pre-empt a kernel running process, 
-but will always return to that process. A process in kernel mode may 
-disable interrupts on the processor and guarantee such an interruption will 
-not occur. The final guarantee is that an interrupt will not bne pre-empted 
-by a kernel task. That is interrupts will run to completion or be 
-pre-empted by other interrupts only.
-
-
-	The SMP kernel chooses to continue these basic guarantees in order to make 
-initial implementation and deployment easier.  A single lock is maintained 
-across all processors. This lock is required to access the kernel space. 
-Any processor may hold it and once it is held may also re-enter the kernel 
-for interrupts and other services whenever it likes until the lock is 
-relinquished. This lock ensures that a kernel mode process will not be 
-pre-empted and ensures that blocking interrupts in kernel mode behaves 
-correctly. This is guaranteed because only the processor holding the lock 
-can be in kernel mode, only kernel mode processes can disable interrupts 
-and only the processor holding the lock may handle an interrupt.
-
-
-	Such a choice is however poor for performance. In the longer term it is 
-necessary to move to finer grained parallelism in order to get the best 
-system performance. This can be done hierarchically by gradually refining 
-the locks to cover smaller areas. With the current kernel highly CPU bound 
-process sets perform well but I/O bound task sets can easily degenerate to 
-near single processor performance levels. This refinement will be needed to 
-get the best from Linux/SMP.
-
-
-\subheading{\heading{Changes To The Portable Kernel Components
-
-
-}}	The kernel changes are split into generic SMP support changes and 
-architecture specific changes necessary to accommodate each different 
-processor type Linux is ported to.
-
-
-\subsection{Initialisation}
-
-
-	The first problem with a multiprocessor kernel is starting the other 
-processors up. Linux/SMP defines that a single processor enters the normal 
-kernel entry point start_kernel(). Other processors are assumed not to be 
-started or to have been captured elsewhere. The first processor begins the 
-normal Linux initialisation sequences and sets up paging, interrupts and 
-trap handlers. After it has obtained the processor information about the 
-boot CPU, the architecture specific function \
-
-
-\description{
-\leftindent{\bold{void smp_store_cpu_info(int processor_id)
-
-}}}
-is called to store any information about the processor into a per processor 
-array. This includes things like the bogomips speed ratings.
-
-
-	Having completed the kernel initialisation the architecture specific 
-function
-
-
-\description{\leftindent{\bold{void smp_boot_cpus(void)
-
-}}}
-is called and is expected to start up each other processor and cause it to 
-enter start_kernel() with its paging registers and other control 
-information correctly loaded. Each other processor skips the setup except 
-for calling the trap and irq initialisation functions that are needed on 
-some processors to set each CPU up correctly.  These functions will 
-probably need to be modified in existing kernels to cope with this.
-
-
-	Each additional CPU the calls the architecture specific function
-
-
-\description{\leftindent{\bold{void smp_callin(void)
-
-
-}}}which does any final setup and then spins the processor while the boot 
-up processor forks off enough idle threads for each processor. This is 
-necessary because the scheduler assumes there is always something to run. 
- Having generated these threads and forked init the architecture specific \
-
-
-
-\bold{\description{\leftindent{void smp_commence(void)}}}
-
-
-function is invoked. This does any final setup and indicates to the system 
-that multiprocessor mode is now active. All the processors spinning in the 
-smp_callin() function are now released to run the idle processes, which 
-they will run when they have no real work to process.
-
-
-\subsection{Scheduling
-
-}
-	The kernel scheduler implements a simple but very and effective task 
-scheduler. The basic structure of this scheduler is unchanged in the 
-multiprocessor kernel. A processor field is added to each task, and this 
-maintains the number of the processor executing a given task, or a magic 
-constant (NO_PROC_ID)  indicating the job is not allocated to a processor. \
-
-
-	\
-
-
-	Each processor executes the scheduler itself and will select the next task 
-to run from all runnable processes not allocated to a different processor. 
-The algorithm used by the selection is otherwise unchanged. This is 
-actually inadequate for the final system because there are advantages to 
-keeping a process on the same CPU, especially on processor boards with per 
-processor second level caches.
-
-
-	Throughout the kernel the variable 'current' is used as a global for the 
-current process. In Linux/SMP this becomes a macro which expands to 
-current_set[smp_processor_id()]. This enables almost the entire kernel to 
-be unaware of the array of running processors, but still allows the SMP 
-aware kernel modules to see all of the running processes.
-
-
-	The fork system call is modified to generate multiple processes with a 
-process id of zero until the SMP kernel starts up properly. This is 
-necessary because process number 1 must be init, and it is desirable that 
-all the system threads are process 0. \
-
-
-
-	The final area within the scheduling of processes that does cause problems 
-is the fact the uniprocessor kernel hard codes tests for the idle threads 
-as task[0] and the init process as task[1]. Because there are multiple idle 
-threads it is necessary to replace these with tests that the process id is 
-0 and a search for process ID 1, respectively.
-
-\subheading{
-}\subsection{Memory Management}\heading{
-
-
-}	The memory management core of the existing Linux system functions 
-adequately within the multiprocessor framework providing the locking is 
-used. Certain processor specific areas do need changing, in particular 
-invalidate() must invalidate the TLB's of all processors before it returns.
-
-
-\subsection{Miscellaneous Functions}
-
-\heading{
-}	The portable SMP code rests on a small set of functions and variables 
-that are provided by the processor specification functionality. These are
-
-
-\display{\bold{int smp_processor_id(void)
-
-
-}}which returns the identity of the process the call is executed upon. This 
-call is assumed to be valid at all times. This may mean additional tests 
-are needed during initialisation.
-
-
-	\display{\bold{int smp_num_cpus;
-
-}}
-	This is the number of processors in the system. \
-
-
-
-	\bold{void smp_message_pass(int target, int msg, unsigned long data,
-
-		int wait)
-
-}
-	This function passes messages between processors. At the moment it is not 
-sufficiently defined to sensibly document and needs cleaning up and further 
-work. Refer to the processor specific code documentation for more details.
-
-
-\heading{Architecture Specific Code For the Intel MP Port
-
-}
-	The architecture specific code for the intel port splits fairly cleanly 
-into four sections. Firstly the initialisation code used to boot the 
-system, secondly the message handling and support code, thirdly the 
-interrupt and kernel syscall entry function handling and finally the 
-extensions to standard kernel facilities to cope with multiple processors.
-
-
-\subsection{Initialisation
-
-
-}	The intel MP architecture captures all the processors except for a single 
-processor known as the 'boot processor' in the BIOS at boot time. Thus a 
-single processor enters the kernel bootup code. The first processor 
-executes the bootstrap code, loads and uncompresses the kernel. Having 
-unpacked the kernel it sets up the paging and control registers then enters 
-the C kernel startup.
-
-
-	The assembler startup code for the kernel is modified so that it can be 
-used by the other processors to do the processor identification and various 
-other low level configurations but does not execute those parts of the 
-startup code that would damage the running system (such as clearing the BSS 
-segment). \
-
-
-
-	In the initialisation done by the first processor the arch/i386/mm/init 
-code is modified to scan the low page, top page and BIOS for intel MP 
-signature blocks. This is necessary because the MP signature blocks must 
-be read and processed before the kernel is allowed to allocate and destroy 
-the page at the top of low memory. Having established the number of 
-processors it reserves a set of pages to provide a stack come boot up area 
-for each processor in the system. These must be allocated at startup to 
-ensure they fall below the 1Mb boundary.
-
-
-	Further processors are started up in smp_boot_cpus() by programming the 
-APIC controller registers and sending an inter-processor interrupt (IPI) to 
-the processor. This message causes the target processor to begin executing 
-code at the start of any page of memory within the lowest 1Mb, in 16bit 
-real mode. The kernel uses the single page it allocated for each processor 
-to use as stack. Before booting a given CPU the relocatable code from 
-trampoline.S and trampoline32.S is copied to the bottom of its stack page 
-and used as the target for the startup. \
-
-
-
-	The trampoline code calculates the desired stack base from the code 
-segment (since the code segment on startup is the bottom of the stack), 
- enters 32bit mode and jumps to the kernel entry assembler. This as 
-described above is modified to only execute the parts necessary for each 
-processor, and then to enter start_kernel(). On entering the kernel the 
-processor initialises its trap and interrupt handlers before entering 
-smp_callin(), where it reports its status and sets a flag that causes the 
-boot processor to continue and look for further processors. The processor 
-then spins until smp_commence() is invoked.
-
-
-	Having started each processor up the smp_commence( ) function flips a 
-flag. Each processor spinning in smp_callin() then loads the task register 
-with the task state segment (TSS) of its idle thread as is needed for task 
-switching.
-
-
-\subsection{Message Handling and Support Code}
-
-
-	The architecture specific code implements the smp_processor_id() function 
-by querying the APIC logical identity register. Because the APIC isn't 
-mapped into the kernel address space at boot, the initial value returned is 
-rigged by setting the APIC base pointer to point at a suitable constant. 
-Once the system starts doing the SMP setup (in smp_boot_cpus()), the APIC 
-is mapped with a vremap() call and the apic pointer is adjusted 
-appropriately. From then on the real APIC logical identity register is 
-read.
-
-
-	Message passing is accomplished using a pair of IPI's on interrupt 13 
-(unused by the 80486 FPU's in SMP mode) and interrupt 16. Two are used in 
-order to separate messages that cannot be processed until the receiver 
-obtains the kernel spinlock from messages that can be processed 
-immediately. In effect IRQ 13 is a fast IRQ handler that does not obtain 
-the locks, and cannot cause a reschedule, while IRQ 16 is a slow IRQ that 
-must acquire the kernel spinlocks and can cause a reschedule. This 
-interrupt is used for passing on slave timer messages from the processor 
-that receives the timer interrupt to the rest of the processors, so that 
-they can reschedule running tasks.
-
-
-\subsection{Entry And Exit Code}
-
-
-	A single spinlock protects the entire kernel. The interrupt handlers, the 
-syscall entry code and the exception handlers all acquire the lock before 
-entering the kernel proper. When the processor is trying to acquire the 
-spinlock it spins continually on the lock with interrupts disabled. This 
-causes a specific deadlock problem. The lock owner may need to send an 
-invalidate request to the rest of the processors and wait for these to 
-complete before continuing. A processor spinning on the lock would not be 
-able to do thus. Thus the loop of the spinlock tests and handles invalidate 
-requests. If the invalidate bit for the spinning CPU is set the processor 
-invalidates its TLB and atomically clears the bit. When the spinlock is 
-obtained that processor will take an IPI and in the IPI test the bit and 
-skip the invalidate as the bit is clear.
-
-
-	One complexity of the spinlock is that a process running in kernel mode 
-can sleep voluntarily and be pre-empted. A switch from such a process to a 
-process executing in user space may reduce the lock count. To track this 
-the kernel uses a syscall_count and a per process lock_depth parameter to 
-track the kernel lock state. The switch_to() function is modified in SMP 
-mode to adjust the lock appropriately.
-
-
-	The final problem is the idle thread. In the single processor kernel the 
-idle thread executes 'hlt' instructions. This saves power and reduces the 
-running temperature of the processors when they are idle. However it means 
-the process spends all its time in kernel mode and would thus hold the 
-kernel spinlock. The SMP idle thread continually reschedules a new task and 
-returns to user mode. This is far from ideal and will be modified to use 
-'hlt' instructions and release the spinlock soon. Using 'hlt' is even more 
-beneficial on a multiprocessor system as it almost completely takes an idle 
-processor off the bus.
-
-
-	Interrupts are distributed by an i82489 APIC. This chip is set up to work 
-as an emulation of the traditional PC interrupt controllers when the 
-machine boots (so that an Intel MP machine boots one CPU and PC 
-compatible). The kernel has all the relevant locks but does not yet 
-reprogram the 82489 to deliver interrupts to arbitrary processors as it 
-should. This requires further modification of the standard Linux interrupt 
-handling code, and is particularly messy as the interrupt handler behaviour 
-has to change as soon as the 82489 is switched into SMP mode.
-
-
-\subsection{Extensions To Standard Facilities}
-
-
-	The kernel maintains a set of per processor control information such as 
-the speed of the processor for delay loops. These functions on the SMP 
-kernel look the values up in a per processor array that is set up from the 
-data generated at boot up by the smp_store_cpu_info() function. This 
-includes other facts such as whether there is an FPU on the processor. The 
-current kernel does not handle only some processors having floating point.
-
-
-	The highly useful atomic bit operations are prefixed with the 'lock' 
-prefix in the SMP kernel to maintain their atomic properties when used 
-outside of (and by) the spinlock and message code. Amongst other things 
-this is needed for the invalidate handler, as all  CPU's will invalidate at 
-the same time without any locks.
-
-
-	Interrupt 13 floating point error reporting is removed. This facility is 
-not usable on a multiprocessor board, nor relevant to the Intel MP 
-architecture which does not cover the 80386/80387 processor pair. \
-
-
-
-	The /proc filesystem support is changed so that the /proc/cpuinfo file 
-contains a column for each processor present. This information is extracted 
-from the data save by smp_store_cpu_info().
-
-\enddata{text,748928}
diff -u --recursive --new-file pre2.0.4/linux/Documentation/smp.tex linux/Documentation/smp.tex
--- pre2.0.4/linux/Documentation/smp.tex	Fri Apr 12 15:51:45 1996
+++ linux/Documentation/smp.tex	Thu May 16 16:35:39 1996
@@ -24,9 +24,10 @@
 \hfill Alan Cox, 1995
 
 
-The author wishes to thank Caldera Inc whose donation of an ASUS dual 
-pentium board made this project possible, and Thomas Radke, whose initial 
-work on multiprocessor Linux formed the backbone of this project.
+The author wishes to thank Caldera Inc ( http://www.caldera.com )
+whose donation of an ASUS dual pentium board made this project possible, 
+and Thomas Radke, whose initial work on multiprocessor Linux formed 
+the backbone of this project.
 
 \section{Background: The Intel MP specification.}
 Most IBM PC style multiprocessor motherboards combine Intel 486 or Pentium 
diff -u --recursive --new-file pre2.0.4/linux/Makefile linux/Makefile
--- pre2.0.4/linux/Makefile	Wed May 15 11:01:14 1996
+++ linux/Makefile	Tue May 14 14:38:38 1996
@@ -1,6 +1,6 @@
 VERSION = 1
 PATCHLEVEL = 99
-SUBLEVEL = 4
+SUBLEVEL = 5
 
 ARCH = i386
 
diff -u --recursive --new-file pre2.0.4/linux/arch/alpha/boot/main.c linux/arch/alpha/boot/main.c
--- pre2.0.4/linux/arch/alpha/boot/main.c	Wed Apr  3 16:06:55 1996
+++ linux/arch/alpha/boot/main.c	Wed May 15 10:49:36 1996
@@ -228,10 +228,11 @@
 
 	nbytes = dispatch(CCB_GET_ENV, ENV_BOOTED_OSFLAGS,
 			  envval, sizeof(envval));
-	if (nbytes > 0) {
-		envval[nbytes] = '\0';
-		strcpy((char*)ZERO_PAGE, envval);
+	if (nbytes < 0) {
+		nbytes = 0;
 	}
+	envval[nbytes] = '\0';
+	strcpy((char*)ZERO_PAGE, envval);
 
 	printk(" Ok\nNow booting the kernel\n");
 	runkernel();
diff -u --recursive --new-file pre2.0.4/linux/arch/alpha/boot/tools/build.c linux/arch/alpha/boot/tools/build.c
--- pre2.0.4/linux/arch/alpha/boot/tools/build.c	Mon Jan 16 07:17:34 1995
+++ linux/arch/alpha/boot/tools/build.c	Wed May 15 10:49:36 1996
@@ -8,7 +8,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 
-#include <a.out.h>
+#include <linux/a.out.h>
 
 #include <asm/system.h>
 
diff -u --recursive --new-file pre2.0.4/linux/arch/alpha/config.in linux/arch/alpha/config.in
--- pre2.0.4/linux/arch/alpha/config.in	Tue May  7 16:22:16 1996
+++ linux/arch/alpha/config.in	Wed May 15 10:49:37 1996
@@ -40,6 +40,7 @@
 	 EB66+		CONFIG_ALPHA_EB66P		\
 	 EB64+		CONFIG_ALPHA_EB64P		\
 	 EB164		CONFIG_ALPHA_EB164		\
+	 PC164		CONFIG_ALPHA_PC164		\
 	 Jensen		CONFIG_ALPHA_JENSEN		\
 	 Noname		CONFIG_ALPHA_NONAME		\
 	 Platform2000	CONFIG_ALPHA_P2K" Cabriolet
@@ -56,14 +57,10 @@
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
 	-o "$CONFIG_ALPHA_EB64P" = "y" ]
 then
-	if [ "$CONFIG_ALPHA_XL" = "n" ]
-	then
-		bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM
-	fi
 	define_bool CONFIG_PCI y
 	define_bool CONFIG_ALPHA_APECS y
 fi
-if [ "$CONFIG_ALPHA_EB164" = "y" ]
+if [ "$CONFIG_ALPHA_EB164" = "y" -o "$CONFIG_ALPHA_PC164" = "y" ]
 then
 	define_bool CONFIG_PCI y
 	define_bool CONFIG_ALPHA_EV5 y
@@ -76,7 +73,10 @@
 if [ "$CONFIG_ALPHA_CABRIOLET" = "y" -o "$CONFIG_ALPHA_AVANTI" = "y" \
 	-o "$CONFIG_ALPHA_EB64P" = "y" -o "$CONFIG_ALPHA_JENSEN" = "y" ]
 then
-	bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM
+	if [ "$CONFIG_ALPHA_XL" = "n" ]
+	then
+		bool 'Using SRM as bootloader' CONFIG_ALPHA_SRM
+	fi
 fi
 
 bool 'Echo console messages on /dev/ttyS1' CONFIG_SERIAL_ECHO
diff -u --recursive --new-file pre2.0.4/linux/arch/alpha/kernel/bios32.c linux/arch/alpha/kernel/bios32.c
--- pre2.0.4/linux/arch/alpha/kernel/bios32.c	Tue May  7 16:22:16 1996
+++ linux/arch/alpha/kernel/bios32.c	Tue May 14 14:38:08 1996
@@ -607,6 +607,67 @@
 
 
 /*
+ * The PC164 has 19 PCI interrupts, four from each of the four PCI
+ * slots, the SIO, PCI/IDE, and USB.
+ * 
+ * Each of the interrupts can be individually masked. This is
+ * accomplished by setting the appropriate bit in the mask register.
+ * A bit is set by writing a "1" to the desired position in the mask
+ * register and cleared by writing a "0". There are 3 mask registers
+ * located at ISA address 804h, 805h and 806h.
+ * 
+ * An I/O read at ISA address 804h, 805h, 806h will return the
+ * state of the 11 PCI interrupts and not the state of the MASKED
+ * interrupts.
+ * 
+ * Note: A write to I/O 804h, 805h, and 806h the mask register will be
+ * updated.
+ * 
+ * 
+ * 				ISA DATA<7:0>
+ * ISA     +--------------------------------------------------------------+
+ * ADDRESS |   7   |   6   |   5   |   4   |   3   |   2  |   1   |   0   |
+ *         +==============================================================+
+ * 0x804   | INTB0 |  USB  |  IDE  |  SIO  | INTA3 |INTA2 | INTA1 | INTA0 |
+ *         +--------------------------------------------------------------+
+ * 0x805   | INTD0 | INTC3 | INTC2 | INTC1 | INTC0 |INTB3 | INTB2 | INTB1 |
+ *         +--------------------------------------------------------------+
+ * 0x806   | Rsrv  | Rsrv  | Rsrv  | Rsrv  | Rsrv  |INTD3 | INTD2 | INTD1 |
+ *         +--------------------------------------------------------------+
+ *         * Rsrv = reserved bits
+ *         Note: The mask register is write-only.
+ * 
+ * IdSel	
+ *   5	 32 bit PCI option slot 2
+ *   6	 64 bit PCI option slot 0
+ *   7	 64 bit PCI option slot 1
+ *   8	 Saturn I/O
+ *   9	 32 bit PCI option slot 3
+ *  10	 USB
+ *  11	 IDE
+ * 
+ */
+
+static inline void alphapc164_fixup(void)
+{
+	char irq_tab[7][5] = {
+	  /*
+	   *      int   intA  intB   intC   intD
+	   *      ----  ----  ----   ----   ----
+	   */
+		{ 16+2, 16+2, 16+9,  16+13, 16+17},	/* IdSel  5,  slot 2, J20 */
+		{ 16+0, 16+0, 16+7,  16+11, 16+15},	/* IdSel  6,  slot 0, J29 */
+		{ 16+1, 16+1, 16+8,  16+12, 16+16},	/* IdSel  7,  slot 1, J26 */
+		{   -1,   -1,   -1,    -1,    -1},	/* IdSel  8,  SIO         */
+		{ 16+3, 16+3, 16+10, 16+14, 16+18},	/* IdSel  9,  slot 3, J19 */
+		{ 16+6, 16+6, 16+6,  16+6,  16+6},	/* IdSel 10,  USB */
+		{ 16+5, 16+5, 16+5,  16+5,  16+5}	/* IdSel 11,  IDE */
+	};
+
+	common_fixup(5, 11, 5, irq_tab, 0);
+}
+
+/*
  * The AlphaPC64 is very similar to the EB66+ except that its slots
  * are numbered differently.  In the code below, I have used slot
  * number to refer to the id select line and *not* the slot number
@@ -860,6 +921,8 @@
 	sio_fixup();
 #elif defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB164)
 	cabriolet_fixup();
+#elif defined(CONFIG_ALPHA_PC164)
+	alphapc164_fixup();
 #elif defined(CONFIG_ALPHA_EB66P)
 	eb66p_fixup();
 #elif defined(CONFIG_ALPHA_EB66)
diff -u --recursive --new-file pre2.0.4/linux/arch/i386/kernel/traps.c linux/arch/i386/kernel/traps.c
--- pre2.0.4/linux/arch/i386/kernel/traps.c	Tue May  7 16:22:17 1996
+++ linux/arch/i386/kernel/traps.c	Wed May 15 07:56:41 1996
@@ -221,16 +221,6 @@
 }
 
 /*
- * Allow the process which triggered the interrupt to recover the error
- * condition.
- *  - the status word is saved in the cs selector.
- *  - the tag word is saved in the operand selector.
- *  - the status word is then cleared and the tags all set to Empty.
- *
- * This will give sufficient information for complete recovery provided that
- * the affected process knows or can deduce the code and data segments
- * which were in force when the exception condition arose.
- *
  * Note that we play around with the 'TS' bit to hopefully get
  * the correct behaviour even in the presence of the asynchronous
  * IRQ13 behaviour
diff -u --recursive --new-file pre2.0.4/linux/arch/m68k/atari/atafb.c linux/arch/m68k/atari/atafb.c
--- pre2.0.4/linux/arch/m68k/atari/atafb.c	Tue May  7 16:22:18 1996
+++ linux/arch/m68k/atari/atafb.c	Thu May 16 09:05:09 1996
@@ -515,6 +515,7 @@
 	fix->xpanstep=0;
 	fix->ypanstep=1;
 	fix->ywrapstep=0;
+	fix->line_length = 0;
 	for (i=0; i<arraysize(fix->reserved); i++)
 		fix->reserved[i]=0;
 	return 0;
@@ -832,6 +833,7 @@
 		fix->xpanstep = 1;
 	fix->ypanstep = 1;
 	fix->ywrapstep = 0;
+	fix->line_length = 0;
 	for (i=0; i<arraysize(fix->reserved); i++)
 		fix->reserved[i]=0;
 	return 0;
@@ -1717,6 +1719,7 @@
 	else
 		fix->ypanstep = 0;
 	fix->ywrapstep = 0;
+	fix->line_length = 0;
 	for (i=0; i<arraysize(fix->reserved); i++)
 		fix->reserved[i]=0;
 	return 0;
@@ -2049,6 +2052,7 @@
 	fix->xpanstep = 0;
 	fix->ypanstep = 0;
 	fix->ywrapstep = 0;
+	fix->line_length = 0;
 	for (i=0; i<arraysize(fix->reserved); i++)
 		fix->reserved[i]=0;
 	return 0;
@@ -2592,6 +2596,7 @@
 	disp[con].type_aux = fix.type_aux;
 	disp[con].ypanstep = fix.ypanstep;
 	disp[con].ywrapstep = fix.ywrapstep;
+	disp[con].line_length = fix.line_length;
 	if (fix.visual != FB_VISUAL_PSEUDOCOLOR &&
 		fix.visual != FB_VISUAL_DIRECTCOLOR)
 		disp[con].can_soft_blank = 0;
diff -u --recursive --new-file pre2.0.4/linux/arch/m68k/atari/config.c linux/arch/m68k/atari/config.c
--- pre2.0.4/linux/arch/m68k/atari/config.c	Tue May  7 16:22:19 1996
+++ linux/arch/m68k/atari/config.c	Thu May 16 09:05:09 1996
@@ -1054,6 +1054,7 @@
       jmp_addr_label040:
         __asm__ __volatile__
           ("moveq #0,%/d0\n\t"
+	   "nop\n\t"
 	   ".word 0xf4d8\n\t"		/* cinva i/d */
 	   ".word 0xf518\n\t"		/* pflusha */
            ".long 0x4e7b0003\n\t"	/* movec d0,tc */
diff -u --recursive --new-file pre2.0.4/linux/arch/m68k/atari/ksyms.c linux/arch/m68k/atari/ksyms.c
--- pre2.0.4/linux/arch/m68k/atari/ksyms.c	Tue Apr 23 13:57:03 1996
+++ linux/arch/m68k/atari/ksyms.c	Thu May 16 09:05:10 1996
@@ -7,9 +7,6 @@
 #include <asm/atarikb.h>
 #include <asm/atari_joystick.h>
 #include <asm/atari_stdma.h>
-#if 0
-#include <asm/atari_acsi.h>
-#endif
 
 static struct symbol_table mach_atari_symbol_table = {
 #include <linux/symtab_begin.h>
@@ -29,20 +26,6 @@
 	X(ikbd_mouse_thresh),
 	X(ikbd_mouse_rel_pos),
 	X(ikbd_mouse_disable),
-
-#if 0
-#ifdef CONFIG_ATARI_ACSI
-	X(acsi_wait_for_IRQ),
-	X(acsi_wait_for_noIRQ),
-	X(acsicmd_nodma),
-	X(acsi_getstatus),
-#ifdef CONFIG_ATARI_SLM
-	X(acsi_extstatus),
-	X(acsi_end_extstatus),
-	X(acsi_extcmd),
-#endif
-#endif
-#endif /* 0 */
 
 #include <linux/symtab_end.h>
 };
diff -u --recursive --new-file pre2.0.4/linux/arch/m68k/kernel/entry.S linux/arch/m68k/kernel/entry.S
--- pre2.0.4/linux/arch/m68k/kernel/entry.S	Sat Apr 27 15:19:47 1996
+++ linux/arch/m68k/kernel/entry.S	Thu May 16 09:05:10 1996
@@ -593,7 +593,7 @@
 	.long SYMBOL_NAME(sys_clone)		/* 120 */
 	.long SYMBOL_NAME(sys_setdomainname)
 	.long SYMBOL_NAME(sys_newuname)
-	.long SYMBOL_NAME(sys_ni_syscall)	/* modify_ldt for i386 */
+	.long SYMBOL_NAME(sys_cacheflush)	/* modify_ldt for i386 */
 	.long SYMBOL_NAME(sys_adjtimex)
 	.long SYMBOL_NAME(sys_mprotect)		/* 125 */
 	.long SYMBOL_NAME(sys_sigprocmask)
diff -u --recursive --new-file pre2.0.4/linux/arch/m68k/kernel/head.S linux/arch/m68k/kernel/head.S
--- pre2.0.4/linux/arch/m68k/kernel/head.S	Tue May  7 16:22:19 1996
+++ linux/arch/m68k/kernel/head.S	Thu May 16 09:05:10 1996
@@ -1,6 +1,6 @@
 /* -*- mode: asm -*-
 **
-** head.S -- This file contains the initial boot code for the the
+** head.S -- This file contains the initial boot code for the
 **	     Linux/68k kernel.
 **
 ** Copyright 1993 by Hamish Macdonald
@@ -12,13 +12,13 @@
 ** and Bjoern Brauel
 **
 ** 94/11/14 Andreas Schwab: put kernel at PAGESIZE
-** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari 
+** 94/11/18 Andreas Schwab: remove identity mapping of STRAM for Atari
 ** ++ Bjoern & Roman: ATARI-68040 support for the Medusa
 ** 96/04/26 G|nther Kelleter: fixed identity mapping for Falcon with
-**                            Magnum- and FX-alternate ram
+** 			      Magnum- and FX-alternate ram
 **
 ** This file is subject to the terms and conditions of the GNU General Public
-** License.  See the file README.legal in the main directory of this archive
+** License. See the file README.legal in the main directory of this archive
 ** for more details.
 **
 */
@@ -49,34 +49,36 @@
  * that should be applied to pages containing descriptors. This mode is
  * non-cached/non-serialized for the '040 and cacheable/write-through for
  * the '060.
+ *
+ * General register usage:
+ *   a6 - start of unused memory
+ *	  new pages can be allocated from here
+ *   a5 - mmu root table
+ *   a4 - mmu pointer table
+ *   a3 - mmu page tables
+ *   a2 - points to the page table entry for a6
+ *	  cache status can be changed (used for '0[46]0)
+ *	  you must increase a2 if alloc a new page
+ *   d7 - used for debug output and some macros
+ *   d6 - cpu type and cache mode
+ *   d5 - physical start address of kernel
+ *   d4 - machine type
  */
 
+#include <linux/autoconf.h>
 #include <linux/linkage.h>
 #include <asm/bootinfo.h>
+#include <asm/pgtable.h>
 
-.text
 .globl SYMBOL_NAME(kernel_pg_dir), SYMBOL_NAME(kpt)
 .globl SYMBOL_NAME(availmem), SYMBOL_NAME(is_medusa)
 .globl SYMBOL_NAME(m68k_pgtable_cachemode)
 .globl SYMBOL_NAME(kernel_pmd_table), SYMBOL_NAME(swapper_pg_dir)
 
-PAGESIZE = 4096
-BI_CPU = 4
-BI_MACH = 0
-BI_AMIGA_ECLK = 1234
-LF   = 10
-CR   = 13
-BI_BIT040 = 2	/* CPU bits in bootinfo */
-BI_BIT060 = 3
-BIT0460   = 16	/* indicates '0[46]0 in d6 */
-BIT060    = 17	/* indicates '060 in d6 */
-D6VAL_040 = 0x00010000
-D6VAL_060 = 0x00030000
-/* BIT040 = 2 */
-
-     /* Some definitions for the special registers of the 68040.
-      * (MMU, caches)
-      */
+D6B_0460 = 16		/* indicates 680[46]0 in d6 */
+D6B_060  = 17		/* indicates 68060 in d6 */
+D6F_040  = 1<<D6B_0460
+D6F_060  = (1<<D6B_0460)+(1<<D6B_060)
 
 /* Translation control register */
 TC_ENABLE = 0x8000
@@ -84,78 +86,96 @@
 TC_PAGE4K = 0x0000
 
 /* Transparent translation registers */
-TTR_ENABLE = 0x8000
-
-/* Some bits used in the page and table descriptors as well as in the 
- * special registers.
- */
-
-CM_CACHE_WT     = 0x0000          /* cacheable, write-through */
-CM_CACHE_CB     = 0x0020          /* cacheable, copyback */
-CM_NONCACHE_SER = 0x0040          /* noncacheable, serialized */
-CM_NONCACHE     = 0x0060          /* noncacheable */
-CM_MASK         = 0xffffff9f      /* mask */
-
-MODIFIED        = 0x0010
-WRITE_PROT      = 0x0004
-USED            = 0x0008
-GLOBAL          = 0x0400
-SV_ONLY         = 0x0080
-PAGEDESC	= 0x0001
-TABLEDESC	= 0x0002
-INVALID         = 0x0000
-
-/* Cache enabling */
-I_HALF		= 0x00002000	/* half-cache mode for I-cache ('060) */
-I_FREEZE	= 0x00004000	/* freeze I-cache ('060) */
-I_ENABLE        = 0x00008000	/* enable I-cache */
-BC_CLRU		= 0x00200000	/* clear user entries in branch cache ('060) */
-BC_CLRA		= 0x00400000	/* clear all entries in branch cache ('060) */
-BC_ENABLE	= 0x00800000	/* enable branch cache ('060) */
-D_HALF		= 0x08000000	/* half-cache mode for D-cache ('060) */
-PUSH_DPI	= 0x10000000	/* disable CPUSH invalidation ('060) */
-SB_ENABLE	= 0x20000000	/* enable store buffer ('060) */
-D_FREEZE	= 0x40000000	/* freeze D-cache ('060) */
-D_ENABLE        = 0x80000000	/* enable D-cache */
+TTR_ENABLE	= 0x8000	/* enable transparent translation */
+TTR_ANYMODE	= 0x4000	/* user and kernel mode access */
+TTR_KERNELMODE	= 0x2000	/* only kernel mode access */
+TTR_USERMODE	= 0x0000	/* only user mode access */
+TTR_CI		= 0x0400	/* inhibit cache */
+TTR_RW		= 0x0200	/* read/write mode */
+TTR_RWM		= 0x0100	/* read/write mask */
+TTR_FCB2	= 0x0040	/* function code base bit 2 */
+TTR_FCB1	= 0x0020	/* function code base bit 1 */
+TTR_FCB0	= 0x0010	/* function code base bit 0 */
+TTR_FCM2	= 0x0004	/* function code mask bit 2 */
+TTR_FCM1	= 0x0002	/* function code mask bit 1 */
+TTR_FCM0	= 0x0001	/* function code mask bit 0 */
+
+/* Cache Control registers */
+CC6_ENABLE_D	= 0x80000000	/* enable data cache (680[46]0) */
+CC6_FREEZE_D	= 0x40000000	/* freeze data cache (68060) */
+CC6_ENABLE_SB	= 0x20000000	/* enable store buffer (68060) */
+CC6_PUSH_DPI	= 0x10000000	/* disable CPUSH invalidation (68060) */
+CC6_HALF_D	= 0x08000000	/* half-cache mode for data cache (68060) */
+CC6_ENABLE_B	= 0x00800000	/* enable branch cache (68060) */
+CC6_CLRA_B	= 0x00400000	/* clear all entries in branch cache (68060) */
+CC6_CLRU_B	= 0x00200000	/* clear user entries in branch cache (68060) */
+CC6_ENABLE_I	= 0x00008000	/* enable instruction cache (680[46]0) */
+CC6_FREEZE_I	= 0x00004000	/* freeze instruction cache (68060) */
+CC6_HALF_I	= 0x00002000	/* half-cache mode for instruction cache (68060) */
+CC3_ALLOC_WRITE	= 0x00002000	/* write allocate mode(68030) */
+CC3_ENABLE_DB	= 0x00001000	/* enable data burst (68030) */
+CC3_CLR_D	= 0x00000800	/* clear data cache (68030) */
+CC3_CLRE_D	= 0x00000400	/* clear entry in data cache (68030) */
+CC3_FREEZE_D	= 0x00000200	/* freeze data cache (68030) */
+CC3_ENABLE_D	= 0x00000100	/* enable data cache (68030) */
+CC3_ENABLE_IB	= 0x00000010	/* enable instruction burst (68030) */
+CC3_CLR_I	= 0x00000008	/* clear instruction cache (68030) */
+CC3_CLRE_I	= 0x00000004	/* clear entry in instruction cache (68030) */
+CC3_FREEZE_I	= 0x00000002	/* freeze instruction cache (68030) */
+CC3_ENABLE_I	= 0x00000001	/* enable instruction cache (68030) */
 
 /* Miscellaneous definitions */
-PAGE_MASK       = (~(PAGESIZE-1))
+PAGESIZE	= 4096
 
-ROOT_TABLE_SIZE = 128
-PTR_TABLE_SIZE  = 128
-PAGE_TABLE_SIZE = 64
+ROOT_TABLE_SIZE	= 128
+PTR_TABLE_SIZE	= 128
+PAGE_TABLE_SIZE	= 64
 ROOT_INDEX_SHIFT = 25
+PTR_INDEX_SHIFT  = 18
 PAGE_INDEX_SHIFT = 12
 
+TABLENR_4MB	= 16	/* # of page tables needed to page 4 MB */
+TABLENR_16MB	= 64	/* same for 16 MB */
+
+#define putc(ch) moveq &ch,%d7; jbsr Lserial_putc
+#define putr() putc(13); putc(10)
+#define putn(nr) movel nr,%d7; jbsr Lserial_putnum
+
+#define is_not_amiga(lab) moveq &MACH_AMIGA,%d7; cmpl %d4,%d7; jne lab
+#define is_not_atari(lab) moveq &MACH_ATARI,%d7; cmpl %d4,%d7; jne lab
+
+#define is_040_or_060(lab) btst &D6B_0460,%d6; jne lab
+#define is_not_040_or_060(lab) btst &D6B_0460,%d6; jeq lab
+#define is_060(lab) btst &D6B_060,%d6; jne lab
+#define is_not_060(lab) btst &D6B_060,%d6; jeq lab
+
+.text
 ENTRY(_stext)
-ENTRY(_start)
-	bras	1f /* Jump over bootinfo version numbers */
 /*
  * Version numbers of the bootinfo interface
+ * The area from _stext to _start will later be used as kernel pointer table
  */
+	bras	1f	/* Jump over bootinfo version numbers */
 
 	.long	BOOTINFOV_MAGIC
 	.long	MACH_AMIGA, AMIGA_BOOTI_VERSION
 	.long	MACH_ATARI, ATARI_BOOTI_VERSION
 	.long	0
+1:	jra	SYMBOL_NAME(_start)
 
-1:
+.equ	SYMBOL_NAME(kernel_pmd_table),SYMBOL_NAME(_stext)
+.equ	SYMBOL_NAME(kernel_pg_dir),SYMBOL_NAME(kernel_pmd_table)
+.equ	SYMBOL_NAME(swapper_pg_dir),SYMBOL_NAME(kernel_pg_dir)+(ROOT_TABLE_SIZE<<2)
+.equ	Lavail_pmd_table,SYMBOL_NAME(swapper_pg_dir)+(ROOT_TABLE_SIZE<<2)
 
-/*
- * raise interrupt level
- */
+.equ	.,SYMBOL_NAME(_stext)+PAGESIZE
 
-	movew	#0x2700,%sr
+ENTRY(_start)
 
 /*
  * Setup initial stack pointer
  */
-	lea	%pc@(SYMBOL_NAME(_start)),%sp
-
-/* clear the fpu */
-	lea	%pc@(mmu),%a0
-	clrl	%a0@
-	frestore %a0@
+	lea	%pc@(SYMBOL_NAME(_stext):w),%sp
 
 /*
  * Copy bootinfo from position after BSS to final resting place
@@ -171,75 +191,89 @@
  * Record the CPU and machine type.
  */
 	lea	%pc@(SYMBOL_NAME(boot_info)),%a0
-	movel	%a0@(BI_MACH),%d4
-	movel	%a0@(BI_CPU),%d0
-	movel	%a0@(BI_CPU),%d6      /* !!!!!!!!!!!!!!!! */
+	movel	%a0@(BI_machtype),%d4
+	movel	%a0@(BI_cputype),%d0
 
-	btst	#BI_BIT060,%d0
-	beq	1f
+	btst	#CPUB_68060,%d0
+	jeq	1f
 	/* '060: d6 := BIT0460|BIT060, cache mode 0x60 (no-cache/non-ser) */
-	movel	#(D6VAL_060+CM_NONCACHE),%d6
-	bra	2f
-1:	btst	#BI_BIT040,%d0
-	beq	1f
+	movel	#D6F_060+_PAGE_NOCACHE,%d6
+	jra	2f
+1:	btst	#CPUB_68040,%d0
+	jeq	1f
 	/* '040: d6 := BIT0460, cache mode 0x00 (write-through) */
-	movel	#(D6VAL_040+CM_CACHE_WT),%d6
-	bra	2f
+	movel	#D6F_040+_PAGE_CACHE040W,%d6
+	jra	2f
 1:	/* '020 or '030: d6 := no CPU bit, cache mode unused */
 	moveq	#0,%d6
 
 2:	lea	%pc@(SYMBOL_NAME(m68k_pgtable_cachemode)),%a0
-	movel	%d6,%a0@		/* save cache mode for page tables */
-	andl	#0x0000ffff,%a0@
+	moveq	#0,%d0
+	movew	%d6,%d0
+	movel	%d0,%a0@		/* save cache mode for page tables */
+
+/*
+ * raise interrupt level with MASTER bit set, copy isp to msp (if not 68060)
+ */
+#ifdef FROM_PL9
+	movew	#0x3700,%sr
+	is_060(1f)
+	movec	%isp,%d0
+	movel	%d0,%sp
+1:
+#else
+	movew	#0x2700,%sr
+#endif
 
 /*
  * Initialize serial port
  */
 	jbsr Lserial_init
 
-	moveq	#CR,%d7
-	jbsr	Lserial_putc
-	moveq	#LF,%d7
-	jbsr	Lserial_putc
-	moveq	#'A',%d7
-	jbsr	Lserial_putc
+	putr()
+	putc('A')
 
 /*
  * Get address at end of kernel code/data/bss and
  * mask off at a page boundary.
  */
 	lea	%pc@(SYMBOL_NAME(_end)),%a0
+	addw	#PAGESIZE-1,%a0
 	movel	%a0,%d0
-	addl	#(PAGESIZE-1),%d0
-	andl	#PAGE_MASK,%d0
+	andl	#-PAGESIZE,%d0
 	movel	%d0,%a6
 
-	moveq	#'B',%d7
-	jbsr	Lserial_putc
+	putc('B')
+
+/*
+ * Save physical start address of kernel
+ */
+	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0
+	movel	%a0,%d5
+#ifdef HACKER_KERNEL
+	lea	%pc@(Lkernel_start),%a0
+	movel	%d5,%a0@
+#endif
 
 /*
  * initialize the kernel root table.
  */
-	lea	%pc@(SYMBOL_NAME(kernel_pg_dir)),%a4
-	movel	%a4,%a0
-	moveq	#0,%d0
-	moveq	#(ROOT_TABLE_SIZE-1),%d1
-1:	movel	%d0,%a0@+
+	lea	%pc@(SYMBOL_NAME(kernel_pg_dir):w),%a5
+	movel	%a5,%a0
+	moveq	#ROOT_TABLE_SIZE-1,%d1
+1:	clrl	%a0@+
 	dbra	%d1,1b
 
 	/*
 	 * Initialize root table descriptor pointing to the kernel pointer
 	 * table.
 	 */
-	movel	%a6,%a5
-	addw	#PAGESIZE,%a6
+	lea	%pc@(Lavail_pmd_table:w),%a4
+	moveq	#_PAGE_TABLE,%d0
+	addl	%a4,%d0
+	movel	%d0,%a5@
 
-	movel	%a5,%a0
-	addql	#TABLEDESC,%a0
-	movel	%a0,%a4@
-
-	moveq	#'C',%d7
-	jbsr	Lserial_putc
+	putc('C')
 
 /*
  * Initialize the pointer tables referred to above.  They either point
@@ -258,13 +292,12 @@
  */
 
 	/* clear the kernel pointer table */
-	movel	%a5,%a0
-	moveq	#0,%d0
-	moveq	#(PTR_TABLE_SIZE-1),%d1
-1:	movel	%d0,%a0@+
+	movel	%a4,%a0
+	moveq	#PTR_TABLE_SIZE-1,%d1
+1:	clrl	%a0@+
 	dbra	%d1,1b
 
-	movel	%a5,%a0
+	movel	%a4,%a0
 	moveq	#15,%d1
 
 	/*
@@ -272,29 +305,28 @@
 	 * the address of the first page table (680[46]0)
 	 * or the base address of physical memory (68030).
 	 */
-	btst	#BIT0460,%d6
-	bne	1f
+	is_040_or_060(1f)
 
 	/* 680[23]0 */
-	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a1  /* base address */
-	addql	#PAGEDESC,%a1	/* descriptor type */
-	movel	#0x40000,%d2	/* increment */
-	bra	2f
+	movel	%d5,%a1				/* base address */
+	addql	#_PAGE_PRESENT,%a1		/* descriptor type */
+	movel	#PAGE_TABLE_SIZE*PAGESIZE,%d2	/* increment */
+	jra	2f
 
 1:	/* 680[46]0 */
-	movel	%a6,%a1		/* base address */
-	addw	#PAGESIZE,%a6	/* allocate the page table */
-	lea	%pc@(SYMBOL_NAME(kpt)),%a3
-	movel	%a1,%a3@		/* save address of page table */
-	addql	#TABLEDESC,%a1	/* descriptor type */
-	movel	#256,%d2 	/* increment */
+	movel	%a6,%a3			/* base address */
+	addw	#PAGESIZE,%a6		/* allocate page for 16 page tables */
+	lea	%pc@(SYMBOL_NAME(kpt)),%a1
+	movel	%a3,%a1@		/* save address of page table */
+	movel	%a3,%a1
+	addql	#_PAGE_TABLE,%a1	/* descriptor type */
+	movel	#PAGE_TABLE_SIZE<<2,%d2 /* increment */
 
 2:	movel	%a1,%a0@+
 	addl	%d2,%a1
 	dbra	%d1,2b
 
-	moveq	#'D',%d7
-	jbsr	Lserial_putc
+	putc('D')
 
 /*
  * If we are running on a 680[46]0, we have a kernel page table and
@@ -303,20 +335,15 @@
  * Set the cache mode bits to Cacheable, Copyback.  Set the Global bits
  * in the descriptors also.
  */
+	is_not_040_or_060(Lnot040)
 
-	btst	#BIT0460,%d6
-	jeq	Lnot040
-
-	moveq	#'F',%d7
-	jbsr	Lserial_putc
-
-	movel	%pc@(SYMBOL_NAME(kpt)),%a0
-	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a1
+	putc('F')
 
-	addw	#(GLOBAL+CM_CACHE_CB+PAGEDESC),%a1
-	movew	#((PAGESIZE/4)-1),%d1
+	movel	%a3,%a0
+	movel	%d5,%a1
+	addw	#_PAGE_GLOBAL040+_PAGE_CACHE040+_PAGE_PRESENT,%a1
+	movew	#(PAGE_TABLE_SIZE*TABLENR_4MB)-1,%d1
 	movel	#PAGESIZE,%d2
-
 1:	movel	%a1,%a0@+
 	addl	%d2,%a1
 	dbra	%d1,1b
@@ -328,52 +355,46 @@
 	 * all pointer tables utilized thus far) and the
 	 * kernel page table.
 	 */
-	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0
-	movel	%a4,%d0		/* address of root table */
-	subl	%a0,%d0		/* determine offset of root table page */
-	moveq	#PAGE_INDEX_SHIFT,%d1	/* determine offset into kernel page table */
-	lsrl	%d1,%d0		/* i.e. page number of the address offset */
-	movel	%pc@(SYMBOL_NAME(kpt)),%a0
-	lea	%a0@(%d0:l:4),%a0
-	movel	%a0@,%d1
-	andl	#CM_MASK,%d1
+	movel	%a5,%d0
+	subl	%d5,%d0
+	moveq	#PAGE_INDEX_SHIFT,%d2
+	lsrl	%d2,%d0
+	lea	%a3@(%d0:l:4),%a2
+	movel	%a2@,%d1
+	andw	#_CACHEMASK040,%d1
 	orw	%d6,%d1
-	movel	%d1,%a0@+
-
-	movel	%a0@,%d1	/* do the same for the kernel page table */
-	bclr	#5,%d1		/* the kernel page table resides in the  */
-	bset	#6,%d1		/* page after the page containing the	 */
-	movel	%d1,%a0@	/* root table				 */
+	movel	%d1,%a2@
 
+	movel	%a3,%d0
+	subl	%d5,%d0
+	lsrl	%d2,%d0
+	lea	%a3@(%d0:l:4),%a2
+	movel	%a2@,%d1
+	andw	#_CACHEMASK040,%d1
+	orw	%d6,%d1
+	movel	%d1,%a2@+
+	/*
+	 * %a2 points now to the page table entry for available pages at %a6,
+	 * hence caching modes for new pages can easiely set unless increasing
+	 * of %a2 are forgotten.
+	 */
 Lnot040:
 /*
  * Do any machine specific page table initializations.
  */
-	moveq	#MACH_AMIGA,%d0
-	cmpl	%d4,%d0
-	bne	Lnotami
+#ifdef CONFIG_AMIGA
+	is_not_amiga(Lnotami)
 
 /*
- * On the Amiga:
- * Our current stack (in CHIP ram) may become invalid after the remapping
- * of the kernel virtual address space, so set it to point to PAGE_SIZE.
- * This will be in CHIP ram until after the remapping, and in the unused
- * first page (temporarily) after that.
- *
  * Setup a mapping of the first 16M of physical address space at virtual
  * address 0x80000000, using early termination page descriptors for the
  * 68030, and proper page tables for the 680[46]0.  Set this area as
  * non-cacheable.
  */
 
-	moveq	#'H',%d7
-	jbsr	Lserial_putc
-
-	move.w	#PAGESIZE,%sp
-
-	btst	#BIT0460,%d6
-	bne	Lspami68040
+	putc('H')
 
+	is_040_or_060(Lspami68040)
 
 	/*
 	 * for the 68030, just setup a translation to map in the first
@@ -381,13 +402,12 @@
          * using an early termination page descriptor.
 	 */
 
-	moveq	#'I',%d7
-	jbsr	Lserial_putc
+	putc('I')
 
-	moveq	#0x41,%d0
-	movel	%d0,%a4@(64*4)
+	moveq	#_PAGE_NOCACHE030+_PAGE_PRESENT,%d0
+	movel	%d0,%a5@(0x40<<2)
 
-	bra	Lmapphys
+	jra	Lmapphys
 
 Lspami68040:
 
@@ -399,41 +419,39 @@
 	 */
 
 	/* clear the amiga pointer table */
-	lea	%a5@(512),%a0
-	moveq	#0,%d0
-	moveq	#(PTR_TABLE_SIZE-1),%d1
-1:	movel	%d0,%a0@+
+	lea	%a4@(PTR_TABLE_SIZE<<2),%a4
+	moveq	#PTR_TABLE_SIZE-1,%d1
+1:	clrl	%a0@+
 	dbra	%d1,1b
 
-	/* allocate 4 page tables */
+	/* allocate 4 pages for 64 page tables */
 	movel	%a6,%a3
-	addw	#(4*PAGESIZE),%a6
+	addw	#4*PAGESIZE,%a6
 
 	/* initialize the pointer table */
-	lea	%a5@(512),%a0
+	movel	%a4,%a0
 	movel	%a3,%a1
-	addql	#TABLEDESC,%a1	/* base descriptor */
-	movel	#256,%d2 	/* increment */
-	moveq	#(PAGE_TABLE_SIZE-1),%d1
+	addql	#_PAGE_TABLE,%a1	/* base descriptor */
+	movel	#PAGE_TABLE_SIZE<<2,%d2 /* increment */
+	moveq	#TABLENR_16MB-1,%d1
 
 1:	movel	%a1,%a0@+
 	addl	%d2,%a1
 	dbra	%d1,1b
 
 	/* ensure that the root table points to the pointer table */
-	lea	%a5@(512),%a0
-	addql	#TABLEDESC,%a0
-	movel	%a0,%a4@(256)	/* 0x80000000>>(ROOT_INDEX_SHIFT-2) doesn't
-				   work */
+	movel	%a4,%a0
+	addql	#_PAGE_TABLE,%a0
+	movel	%a0,%a5@(0x40<<2)
 
 	/*
 	 * initialize the page tables
 	 * descriptor bits include noncachable/serialized and global bits.
 	 */
 	movel	%a3,%a0
-	movew	#(GLOBAL+CM_NONCACHE_SER+PAGEDESC),%a1
+	movew	#_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_PRESENT,%a1
 	movel	#PAGESIZE,%d2
-	movew	#PAGESIZE-1,%d1
+	movew	#(PAGE_TABLE_SIZE*TABLENR_16MB)-1,%d1
 
 1:	movel	%a1,%a0@+
 	addl	%d2,%a1
@@ -444,29 +462,20 @@
 	 * the virtual mapping of the 4 page tables indicates
 	 * noncachable/serialized.
 	 */
-	movel	%a3,%d0		/* ami page table start address */
-	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0
-	subl	%a0,%d0		/* determine offset of root table page */
-	moveq	#PAGE_INDEX_SHIFT,%d1	/* determine offset into kernel page table */
-	lsrl	%d1,%d0
-	movel	%pc@(SYMBOL_NAME(kpt)),%a0
-	movel	#3,%d2
-1:	lea	%a0@(%d0:l:4),%a1
-	movel	%a1@,%d1
-	bclr	#5,%d1
-	bset	#6,%d1
-	movel	%d1,%a1@
-	addql	#1,%d0
-	dbra	%d2,1b
-
-	bra	Lmapphys
+	moveq	#3,%d0
+1:	movel	%a2@,%d1	/* a2 already points to root table offset */
+	andw	#_CACHEMASK040,%d1
+	orw	%d6,%d1
+	movel	%d1,%a2@+
+	dbra	%d0,1b
 
+	jra	Lmapphys
 
-Lnotami:	/* other machines specific mappings go here! */
+Lnotami:
+#endif
 
-	moveq	#MACH_ATARI,%d0
-	cmpl	%d4,%d0
-	bne	Lnotatari
+#ifdef CONFIG_ATARI
+	is_not_atari(Lnotatari)
 
 	move.w	#PAGESIZE,%sp
 
@@ -490,7 +499,7 @@
 
 	moveq	#0,%d3			/* base addr for others: 0x00000000 */
 	movec	%d3,%vbr
-	lea	    %pc@(Ltest_berr),%a0
+	lea	%pc@(Ltest_berr),%a0
 	movel	%a0,0x8
 	movel	%sp,%a0
 	moveb	0x0,%d1
@@ -507,46 +516,45 @@
 	movel	%d3,%a0@
 
 	/* Let the root table point to the new pointer table */
-	lea	%a5@(512),%a0
-	addl	#TABLEDESC,%a0
-	movel	%a0,%a4@(508)		/* 0xFE000000 - 0xFFFFFFFF */
+	lea	%a4@(PTR_TABLE_SIZE<<2),%a4
+	movel	%a4,%a0
+	addl	#_PAGE_TABLE,%a0
+	movel	%a0,%a5@(0x7f<<2)       /* 0xFE000000 - 0xFFFFFFFF */
 
 	/* clear lower half of the pointer table (0xfexxxxxx) */
-	lea 	%a5@(512),%a0
-	movel	#0,%d0
-	movel	#63,%d2
-1:	movel	%d0,%a0@+
+	movel	%a4,%a0
+	movel	#(PTR_TABLE_SIZE/2)-1,%d2
+1:	clrl	%a0@+
 	dbra	%d2,1b
 
-	btst	#BIT0460,%d6
-	bne	Lspata68040
+	is_040_or_060(Lspata68040)
 
 /* Mapping of the last 16M of virtual address space to the first 16M
    for efficient addressing of hardware registers */
-	movel	#0x40000,%d1
-	movel	#63,%d2
+	movel	#PAGE_TABLE_SIZE*PAGESIZE,%d1
+	movel	#(PTR_TABLE_SIZE/2)-1,%d2
 	movel	%d3,%d0
-	addl	#PAGEDESC,%d0
+	addl	#_PAGE_PRESENT,%d0
 1:	movel	%d0,%a0@+
 	addl	%d1,%d0
 	dbra	%d2,1b
-	moveq	#0x40,%d0	/* make non-cachable */
-	addl	%d0,%a5@(1020)	/* 0xFFFC0000-0xFFFFFFFF (I/O space) */
+	moveq	#_PAGE_NOCACHE030,%d0	/* make non-cachable */
+	addl	%d0,%a4@(0x7f<<2)	/* 0xFFFC0000-0xFFFFFFFF (I/O space) */
 /* GK: 0xFFF00000-0xFFF3FFFF (IDE-bus) has to be non-cachable too */
-	addl	%d0,%a5@(1008)
+	addl	%d0,%a4@(0x7c<<2)
 
-	bra	Lmapphys
+	jra	Lmapphys
 
 Lspata68040:
 	/* allocate 4 page tables */
 	movel	%a6,%a3
-	addw	#(4*PAGESIZE),%a6
+	addw	#4*PAGESIZE,%a6
 
-/* Initialize the upper half of the pointer table (a0 is still valid) */
+	/* Initialize the upper half of the pointer table (a0 is still valid) */
 	movel	%a3,%a1
-	addql	#TABLEDESC,%a1
-	movel	#256,%d2
-	moveq	#63,%d1
+	addql	#_PAGE_TABLE,%a1
+	movel	#PAGE_TABLE_SIZE<<2,%d2
+	moveq	#TABLENR_16MB-1,%d1
 1:	movel	%a1,%a0@+
 	addl	%d2,%a1
 	dbra 	%d1,1b
@@ -554,9 +562,9 @@
 	/* Initialize the page tables as noncacheable/serialized! */
 	movel	%a3,%a0
 	movel	%d3,%a1
-	addw	#(GLOBAL+CM_NONCACHE_SER+PAGEDESC),%a1
+	addw	#_PAGE_GLOBAL040+_PAGE_NOCACHE_S+_PAGE_PRESENT,%a1
 	movel	#PAGESIZE,%d2
-	movew	#(PAGESIZE-1),%d1
+	movew	#(PAGE_TABLE_SIZE*TABLENR_16MB)-1,%d1
 1:	movel	%a1,%a0@+
 	addl	%d2,%a1
 	dbra	%d1,1b
@@ -566,23 +574,15 @@
 	 * the virtual mapping of the 4 page tables indicates
 	 * noncachable or write-through.
 	 */
-	movel	%a3,%d0		/* page table start address */
-	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0
-	subl	%a0,%d0		/* determine offset of root table page */
-	moveq	#PAGE_INDEX_SHIFT,%d1 /* determine offset into 
-                                         kernel page table */
-	lsrl	%d1,%d0
-	movel	%pc@(SYMBOL_NAME(kpt)),%a0
-	moveq	#3,%d2
-1:	lea	%a0@(%d0:l:4),%a1
-	movel	%a1@,%d1
-	andl	#CM_MASK,%d1
+	moveq	#3,%d0
+1:	movel	%a2@,%d1	/* a2 already points to root table offset */
+	andw	#_CACHEMASK040,%d1
 	orw	%d6,%d1
-	movel	%d1,%a1@
-	addql	#1,%d0
-	dbra	%d2,1b
+	movel	%d1,%a2@+
+	dbra	%d0,1b
 
 Lnotatari:
+#endif
 
 /*
  * Setup a transparent mapping of the physical memory we are executing in.
@@ -591,225 +591,180 @@
  * an Amiga since the first 16M is already identity mapped on the Amiga.
  */
 Lmapphys:
-	moveq	#'J',%d7
-	jbsr	Lserial_putc
-
-	clrl	%d5		/* indicate that no cleanup is required */
+	putc('J')
 
-	cmpl	#MACH_AMIGA,%d4
-	bne	Lmapphysnotamiga	/* other machines will probably have
-					 * to put in code and jump to it here
-					 */
+#ifdef CONFIG_AMIGA
+	is_not_amiga(Lmapphysnotamiga)
 
 /*
- * The virtual address of the start of the kernel is 0x1000.  On ALL
- * Amigas, there is CHIP RAM in this area.  Hence we will copy the MMU
- * enabling code to CHIP RAM (to the same physical address as the kernel
- * virtual address) and jump to it.  When the MMU is enabled, we will be
- * running from the code in the kernel virtual space, rather than the
- * physical space.
+ * The virtual address of the start of the kernel is 0x1000. We transparently
+ * translate the memory where we running in and can enable then the MMU. Hence
+ * we have now two locations of the kernel in memory and can jump to the final
+ * place. Except if the physical location is in the first 16MB, translation
+ * will overlap later virtual location, but as we already mapped the first
+ * 16MB to 0x80000000, we can jump there after translation and MMU is enabled
+ * and then we can switch off translation and go to the final place.
+ * When MMU is enabled, stack pointer and Lcustom will become again valid and
+ * points to the unused first page.
  */
 
 /*
  * Setup Supervisor Root Pointer register to point to page directory,
  * setup translation register contents and enable translation.
  */
-	btst	#BIT0460,%d6
-	bne	Lamimmu68040
+	putc('K')
 
-	moveq	#'K',%d7
-	jbsr	Lserial_putc
+	movew	#PAGESIZE,%sp
+
+	/* fixup the Amiga custom register location before printing */
+	lea	%pc@(Lcustom),%a0
+	movel	#0x80000000,%a0@
 
-	lea	%pc@(mmu),%a0
-	movel	#0x80000002,%a0@   /* no limit, 4byte descriptors */
-	movel	%a4,%a0@(4)
-	pmove	%a0@,%srp
-	pmove	%a0@,%crp
+	is_040_or_060(Lamimmu68040)
+
+	lea	2f:w,%a0
+	movel	%d5,%d0
+	andl	#0xff000000,%d0
+	jne	1f
+	lea	%pc@(2f+0x80000000),%a0
+1:	orw	#TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0
+	lea	%pc@(Lmmu),%a3
+	movel	%d0,%a3@
+	.long	0xf0130800	/* pmove %a3@,%tt0 */
+	/* no limit, 4byte descriptors */
+	movel	#0x80000002,%a3@
+	movel	%a5,%a3@(4)
+	.long	0xf0134800	/* pmove %a3@,%srp */
+	.long	0xf0134c00	/* pmove %a3@,%crp */
+	.long	0xf0002400	/* pflusha */
 	/*
 	 * enable,super root enable,4096 byte pages,7 bit root index,
 	 * 7 bit pointer index, 6 bit page table index.
 	 */
-	movel	#0x82c07760,%a0@
-
-	/* setup registers for jumping MMU enabling code */
-	lea	%pc@(Ldoit030ami),%a2
-	lea	Ldoit030ami,%a1
-
-	moveq	#CR,%d7
-	jbsr	Lserial_putc
-	moveq	#LF,%d7
-	jbsr	Lserial_putc
-	movel	%a2,%d7
-	jbsr	Lserial_putnum
-	moveq	#' ',%d7
-	jbsr	Lserial_putc
-	movel	%a1,%d7
-	jbsr	Lserial_putnum
-
-	bra	LdoitAmiga
-
-#ifdef __ELF__
-	.align	16
-#else
-	.align	4
-#endif
-Ldoit030ami:
-	pmove	%a0@,%tc	/* enable the MMU */
-	jra	LdoneMMUenable	/* branch to continuation of startup */
+	movel	#0x82c07760,%a3@
+	.long	0xf0134000	/* pmove %a3@,%tc (enable the MMU) */
+	jmp	%a0@
+2:	clrl	%a3@
+	.long	0xf0130800	/* pmove %a3@,%tt0 */
+	jmp	LdoneMMUenable:w
 
 Lamimmu68040:
-	moveq	#'L',%d7
-	jbsr	Lserial_putc
-	
-	.word	0xf4d8		/* CINVA I/D */
-	.word	0xf518		/* pflusha	*/
-	.long	0x4e7bc807	/* movec a4,srp */
-	.long	0x4e7bc806	/* movec a4,urp */
-	movel	#(TC_ENABLE+TC_PAGE4K),%d0
-
-	/* setup registers for jumping MMU enabling code */
-	lea	Ldoit040ami,%a1
-	lea	%pc@(Ldoit040ami),%a2
-	bra	LdoitAmiga
-
-#ifdef __ELF__
-	.align	16
-#else
-	.align	4
-#endif
-Ldoit040ami:
-	.long	0x4e7b0003	/* movec d0,tc  (enable the MMU) */
-	jra	LdoneMMUenable	/* branch to continuation of startup */
-
-LdoitAmiga:
-	/* copy the appropriate code (two longwords) to chipmem */
-	movel	%a2@,%a1@
-	movel	%a2@(4),%a1@(4)
 
+	lea	2f:w,%a0
+	movel	%d5,%d0
+	andl	#0xff000000,%d0
+	jne	1f
+	lea	%pc@(2f+0x80000000),%a0
+1:	orw	#TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0
+	.long	0x4e7b0004	/* movec %d0,%itt0 */
+	.long	0x4e7bd806	/* movec %a5,%urp */
+	.long	0x4e7bd807	/* movec %a5,%srp */
+	.word	0xf518		/* pflusha */
+	movel	#TC_ENABLE+TC_PAGE4K,%d0
 	/*
- 	 * save physaddr of phys mem in register a3
+	 * this value is also ok for the 68060, we don`t use the cache
+	 * mode/protection defaults
 	 */
-	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a3
-
-	/* jump to the physical address in chipmem */
-	jmp	%a1@
+	.long	0x4e7b0003	/* movec %d0,%tc (enable the MMU) */
+	jmp	%a0@
+2:	moveq	#0,%d0
+	.long	0x4e7b0004	/* movec %d0,%itt0 */
+	jmp	LdoneMMUenable:w
 
 Lmapphysnotamiga:
+#endif
 
-	cmpl	#MACH_ATARI,%d4
-	bne	Lmapphysnotatari
+#ifdef CONFIG_ATARI
+	is_not_atari(Lmapphysnotatari)
 
-	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE),%a0
-	tstl	%a0
-	jeq	Lnophys2
-
-	/* The kernel physical address is different from its virtual
-	   address.  Temporarily set up an identity mapping of the
-	   16MB chunk where the kernel is executing. */
-  
-	/* 680[46]0? */
-	btst	#BIT0460,%d6
-	jeq	1f
-
-	/*
-	 * For the 68040, we will use the transparent translation
-	 * registers to identity map the 16M chunk that contains
-	 * the physical memory.
-	 */
-	movel	%a0,%d2
-	andl	#0xff000000,%d2		/* logical address base */
-	orw	#0xc040,%d2		/* add in magic bits */
-	.long	0x4e7b2004		/* movec d2,ittr0 */
-	.long	0x4e7b2006		/* movec d2,dttr0 */
-
-	/* d5 is kept 0 to do no cleanup. This didn't work in head.S, I don't
-	 * know why... The transparent translation is turned off in
-	 * atari/config.c instead.
-	 */
-	jra	Lnophys2
+/*
+ * If the kernel physical address is different from its virtual address, we
+ * will temporarily set up an identity mapping of the 16MB chunk with
+ * transparent translation where the kernel is executing.
+ */
+	putc('L')
 
-	/* Transparent translation for the 68030 via transparent translation
-	   register */
+	/* fixup the  Atari iobase register location before printing */
+	lea	%pc@(Liobase),%a0
+	movel	#0xff000000,%a0@
 
-1:
-	/* cleanup is needed; note it */
-	moveq	#1,%d5
+	is_040_or_060(Latarimmu68040)
 
+	lea	%pc@(Lmmu),%a3
+	movel	%d5,%d0
+	jne	1f
+	lea	LdoneMMUenable:w,%a0
+	jra	3f
+1:	lea	4f:w,%a0
+	andl	#0xff000000,%d0 /* logical address base */
+	jeq	2f
+	orw	#TTR_ENABLE+TTR_CI+TTR_RWM+TTR_FCB2+TTR_FCM1+TTR_FCM0,%d0
+	movel	%d0,%a3@
+	.long	0xf0130800	/* pmove %a3@,%tt0 */
+	jra	3f
 	/* tt0 doesn't work if physical and virtual address of kernel is in
 	 * the same 16M area (Falcon with Magnum/FX, kernel in alternate ram)
-	 */
-	movel	%a0,%d2
-	andl	#0xff000000,%d2		/* logical address base */
-	jeq	1f
-	orw	#0x8143,%d2		/* add in magic bits */
-	lea	%pc@(mmu),%a0
-	movel	%d2,%a0@
-	pmove	%a0@,%tt0
-	jra	Lnophys2
-1:
-	/* Transparent translation through kernel pointer table
+	 * Transparent translation through kernel pointer table
 	 * Requires that this code until after MMU enabling lies in
-	 * the 256K page around %a0
+	 * the 256K page around %d5
 	 */
-	movel	%a0,%d2
-	moveq	#ROOT_INDEX_SHIFT,%d1
-	lsrl	%d1,%d2
-	movel	%a4@(%d2:l:4),%d0
-	andw	#0xfff0,%d0
-	movel	%d0,%a1
-	movel	%a0,%d2
-	andl	#0x01ffffff,%d2
-	moveq	#(ROOT_INDEX_SHIFT-7),%d1
-	lsrl	%d1,%d2
-	movel	%a0,%d0
-	addql	#PAGEDESC,%d0
-	movel	%a1@(%d2:l:4),%a2	/* save old_entry */
-	movel	%d0,%a1@(%d2:l:4)
-
-Lnophys2:
-	/*
- 	 * save physaddr of phys mem in register a3
-	 */
-	lea	%pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a3
-
-	btst	#BIT0460,%d6
-	jne	Latarimmu68040
-
-	moveq	#'K',%d7
-	jbsr	Lserial_putc
-
-	lea	%pc@(mmu),%a0
-	movel	#0x80000002,%a0@   /* no limit, 4byte descriptors */
-	movel	%a4,%a0@(4)
-	pmove	%a0@,%srp
-	pmove	%a0@,%crp
+2:	movel	%a4@,%d1
+	andw	#0xfff0,%d1
+	movel	%d1,%a1
+	movel	%d5,%d1
+	moveq	#PTR_INDEX_SHIFT,%d0
+	lsrl	%d0,%d1
+	lea	%a1@(%d1:l:4),%a1
+	movel	%d5,%d1
+	addql	#_PAGE_PRESENT,%d1
+	movel	%a1@,%d2
+	movel	%d1,%a1@
+	lea	5f:w,%a0
+	/* no limit, 4byte descriptors */
+3:	movel	#0x80000002,%a3@
+	movel	%a5,%a3@(4)
+	.long	0xf0134800	/* pmove %a3@,%srp */
+	.long	0xf0134c00	/* pmove %a3@,%crp */
+	.long	0xf0002400	/* pflusha */
 	/*
 	 * enable,super root enable,4096 byte pages,7 bit root index,
 	 * 7 bit pointer index, 6 bit page table index.
 	 */
-	movel	#0x82c07760,%a0@
-	pmove	%a0@,%tc		/* enable the MMU */
-
-	/* Jump to the virtual address of continuation of startup. */
-	jmp	LdoneMMUenable
+	movel	#0x82c07760,%a3@
+	.long	0xf0134000	/* pmove %a3@,%tc (enable the MMU) */
+	jmp	%a0@
+4:	clrl	%a3@
+	.long	0xf0130800	/* pmove %a3@,%tt0 */
+	jra	LdoneMMUenable
+5:	movel	%d2,%a1@
+	jra	LdoneMMUenable
 
 Latarimmu68040:
-	moveq	#'L',%d7
-	jbsr	Lserial_putc
-
-	.word	0xf4d8		/* CINVA I/D */
-	.word	0xf518		/* pflusha	*/
-	.long	0x4e7bc807	/* movec a4,srp */
-	.long	0x4e7bc806	/* movec a4,urp */
-	movel	#(TC_ENABLE+TC_PAGE4K),%d0
-	/* this value is also ok for the '060, we don't use the cache
-	 * mode/protection defaults */
-	.long	0x4e7b0003	/* movec d0,tc  (enable the MMU) */
-	jmp	LdoneMMUenable	/* jump to virtual address of
-				   continuation of startup */
+	movel	%d5,%d0
+	jne	1f
+	lea	LdoneMMUenable:w,%a0
+	jra	2f
+1:	lea	3f:w,%a0
+	andl	#0xff000000,%d0 /* logical address base */
+	orw	#TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0
+	.long	0x4e7b0004	/* movec %d0,%itt0 */
+2:	.word	0xf518		/* pflusha */
+	.long	0x4e7bd807	/* movec %a5,%srp */
+	.long	0x4e7bd806	/* movec %a5,%urp */
+	movel	#TC_ENABLE+TC_PAGE4K,%d0
+	/*
+	 * this value is also ok for the 68060, we don`t use the cache
+	 * mode/protection defaults
+	 */
+	.long	0x4e7b0003	/* movec %d0,%tc (enable the MMU) */
+	jmp	%a0@
+3:	moveq	#0,%d0
+	.long	0x4e7b0004	/* movec %d0,%itt0 */
+	tstl	%a1
+	jra	LdoneMMUenable
 
 Lmapphysnotatari:
-
+#endif
 
 LdoneMMUenable:
 
@@ -818,128 +773,72 @@
  * Convert them from physical addresses to virtual addresses.
  */
 
-	/*
-	 * fixup the Amiga custom register location before printing
-	 */
-	addl	#0x80000000,Lcustom
-
-	/* The same for the Atari */
-	movel	#0xff000000,Liobase
-
-	moveq	#'M',%d7
-	jbsr	Lserial_putc
+	putc('M')
 
 	/*
-	 * a3 contains physaddr of kernel start
+	 * d5 contains physaddr of kernel start
 	 */
-	movel	SYMBOL_NAME(kpt),%d1
-	subl	%a3,%d1
-	movel	%d1,SYMBOL_NAME(kpt)
+	subl	%d5,SYMBOL_NAME(kpt)
 
 	/*
 	 * do the same conversion on the first available memory
 	 * address (in a6).
 	 */
-	subl	%a3,%a6
-
-	/* Allocate a page to be used by get_kpointer_table.  */
-	movel	%a6,SYMBOL_NAME(kernel_pmd_table)
-	addl	#PAGESIZE,%a6
+	subl	%d5,%a6
 	movel	%a6,SYMBOL_NAME(availmem) /* first available memory address */
 
-	moveq	#'N',%d7
-	jbsr	Lserial_putc
-
-	/*
-	 * Clean up the temporary physical mapping (if necessary)
-	 */
-
-	tstl	%d5
-	jeq	Lnoclean
-
-	btst	#BIT0460,%d6
-	jne	Loff040
-
-	/* clean up physical identity mapping for 68020/68030 */
-	/* Is this needed for the Amiga anymore? */
-	/* it's not in 1.2.13pl6 - Jes */
-	cmpl	#MACH_AMIGA,%d4
-	jeq	Lclean030
-	cmpl	#MACH_ATARI,%d4
-	jne	Lnoclean
-
-	movel	%a3,%d2
-	andl	#0xff000000,%d2
-	jeq	1f
-	/* clear transparent translation register */
-	lea	%pc@(mmu),%a0
-	clrl	%a0@
-	pmove	%a0@,%tt0
-	jra	Lnoclean
-1:
-	movel	%a3,%d2
-	moveq	#ROOT_INDEX_SHIFT,%d1
-	lsrl	%d1,%d2
-	movel	%a4@(%d2:l:4),%d0
-	andw	#0xfff0,%d0
-	subl	%a3,%d0		/* to virtual address */
-	movel	%d0,%a0
-	movel	%a3,%d2
-	andl	#0x01ffffff,%d2
-	moveq	#(ROOT_INDEX_SHIFT-7),%d1
-	lsrl	%d1,%d2
-	movel	%a2,%a0@(%d2:l:4)	/* restore old entry */
-	jra	Lnoclean
-
-Lclean030:
-	movel	%a0,%d2		/* a0 contains physical start address */
-	moveq	#25,%d3		/* find appropriate index in root table */
-	lsrl	%d3,%d2
-	moveq	#0,%d0
-	movel	%d0,%a4@(%d2:l:4)  /* clear descriptor */
-
-	jra	Lnoclean
-
-Loff040:
-	/* turn off transparent translation registers for '0[46]0 */
-	moveq	#0,%d0
-	.long	0x4e7b0004	/* movec d0,ittr0 */
-	.long	0x4e7b0006	/* movec d0,dttr0 */
-
-Lnoclean:
-	moveq	#'O',%d7
-	jbsr	Lserial_putc
-
+	putc('N')
 
+#if 0
+	putr()
+	lea	SYMBOL_NAME(kernel_pmd_table),%a0
+	moveq	#63,%d0
+1:	moveq	#7,%d1
+	putn(%a0)
+	putc(':')
+	putc(' ')
+2:	putn(%a0@+)
+	dbra	%d1,2b
+	putr()
+	dbra	%d0,1b
+	putr()
+	movel	SYMBOL_NAME(kpt),%a0
+	moveq	#639,%d0
+1:	moveq	#7,%d1
+	putn(%a0)
+	putc(':')
+	putc(' ')
+2:	putn(%a0@+)
+	dbra	%d1,2b
+	putr()
+	dbra	%d0,1b
+#endif
 /*
  * Enable caches
  */
-	btst	#BIT0460,%d6
-	jne	Lcache680460
+	is_040_or_060(Lcache680460)
 
-	movel	#0x00001919,%d0
-	movec   %d0,%cacr
+	movel	#CC3_ENABLE_DB+CC3_CLR_D+CC3_ENABLE_D+CC3_ENABLE_IB+CC3_CLR_I+CC3_ENABLE_I,%d0
+	movec	%d0,%cacr
 	jra	1f
 
 Lcache680460:
-	btst	#BIT060,%d6
-	jne	Lcache68060
+	.word	0xf4f8		/* cpusha %bc */
 
-	.word	0xf4d8	     /* CINVA I/D */
-	movel	#I_ENABLE+D_ENABLE,%d0
+	is_060(Lcache68060)
+
+	movel	#CC6_ENABLE_D+CC6_ENABLE_I,%d0
 	/* MMU stuff works in copyback mode now, so enable the cache */
 	movec	%d0,%cacr
 	jra	1f
 
 Lcache68060:
-	.word	0xf4d8	     /* CINVA I/D */
-	movel	#I_ENABLE+D_ENABLE+SB_ENABLE+PUSH_DPI+BC_ENABLE+BC_CLRA,%d0
+	movel	#CC6_ENABLE_D+CC6_ENABLE_I+CC6_ENABLE_SB+CC6_PUSH_DPI+CC6_ENABLE_B+CC6_CLRA_B,%d0
 	/* MMU stuff works in copyback mode now, so enable the cache */
 	movec	%d0,%cacr
 	/* enable superscalar dispatch in PCR */
 	moveq	#1,%d0
 	.long	0x4e7b0808	/* movec d0,pcr */
-
 1:
 
 /*
@@ -948,40 +847,35 @@
 	lea	SYMBOL_NAME(init_user_stack)+PAGESIZE,%sp
 
 /* jump to the kernel start */
+	putr()
 
 	jbsr	SYMBOL_NAME(start_kernel)
 
-#if 0
-tmp_fault_handler:
-     lea       %pc@(tfh_1st_str),%a0
-     jbsr       Lserial_puts
-     move.l    %sp@(2),%d7                     /* PC */
-     jbsr       Lserial_putnum
-     move.w    %sp@(0xa),%d7
-     swap      %d7
-     move.w    %sp@(0x6),%d7
-     jbsr       Lserial_putnum
-     lea       %pc@(tfh_2nd_str),%a0
-     jbsr       Lserial_puts
-     move.l    %sp@(0x10),%d7                  /* Fault address */
-     jbsr       Lserial_putnum
-     moveq     #CR,%d7
-     jbsr       Lserial_putc
-     moveq     #LF,%d7
-     jbsr       Lserial_putc
-1:   jra       1b
-
-tfh_1st_str:
-     .byte     CR
-     .byte     LF
-     .ascii    "Access fault occurred. PC = "
-     .byte     0
-
-tfh_2nd_str:
-     .byte     CR
-     .byte     LF
-     .ascii    "FaultAddress = "
-     .byte     0
+/*
+ * switch off mmu and exit
+ */
+
+#ifdef HACKER_KERNEL
+ENTRY(kernel_exit)
+	lea	2f:w,%a0
+	movel	%pc@(Lkernel_start),%a0
+	lea	%a0@(2f:w),%a1
+	movel	%a1,%d0
+	andl	#0xff000000,%d0
+	jne	1f
+	jmp	%a0@(1f+0x80000000)
+1:	orw	#TTR_ENABLE+TTR_KERNELMODE+_PAGE_NOCACHE_S,%d0
+	.long	0x4e7b0004	/* movec %d0,%itt0 */
+	jmp	%a1@
+2:	moveq	#0,%d0
+	.long	0x4e7b0003	/* movec %d0,%tc (disable the MMU) */
+	.word	0xf518		/* pflusha */
+	.long	0x4e7b0004	/* movec %d0,%itt0 */
+	movec	%d0,%cacr
+	.word	0xf4f8		/* cpusha %bc */
+
+	lea	%pc@(SYMBOL_NAME(boot_info)),%a0
+	jmp	%a0@(BI_amiga_exit_func:w)@(0:w)
 #endif
 
 /*
@@ -991,7 +885,7 @@
 LSERDAT      = 0xdff030
 LSERDATR     = 0xdff018
 LNTSC_PERIOD = 371
-LPAL_PERIOD  = 368/2        /* /2 for 19200 baud */
+LPAL_PERIOD  = 368
 LNTSC_ECLOCK = 7159090
 LSERIAL_CNTRL = 0xbfd000
 LSERIAL_DTR   = 7
@@ -1002,6 +896,7 @@
  * from the MFP or a serial port of the SCC
  */
 
+#ifdef CONFIG_ATARI
 /* #define USE_PRINTER */
 /* #define USE_SCC */
 #define USE_MFP
@@ -1048,6 +943,7 @@
 LMFP_UDR     = 0xfffa2f
 
 #endif
+#endif
 
 /*
  * Initialize serial port hardware for 9600/8/1
@@ -1056,16 +952,21 @@
  */
 	.even
 Lserial_init:
+#ifdef CONFIG_AMIGA
 	cmpil	#MACH_AMIGA,%d4
 	jne	1f
+	lea	%pc@(SYMBOL_NAME(boot_info)),%a0
 	bclr	#LSERIAL_DTR,LSERIAL_CNTRL
 	movew	#LNTSC_PERIOD,LSERPER
-	cmpl	#LNTSC_ECLOCK,%a0@(BI_AMIGA_ECLK)
+	cmpl	#LNTSC_ECLOCK,%a0@(BI_amiga_eclock)
 	jeq	9f
 	movew	#LPAL_PERIOD,LSERPER
 	jra	9f
-1:	cmpil   #MACH_ATARI,%d4
-	jne	9f
+1:
+#endif
+#ifdef CONFIG_ATARI
+	cmpil   #MACH_ATARI,%d4
+	jne	4f
 #ifdef USE_PRINTER
 	bclr	#0,LSTMFP_IERB
 	bclr	#0,LSTMFP_DDR
@@ -1094,6 +995,8 @@
 	orb	#1,LMFP_TDCDR
 	bset	#1,LMFP_TSR
 #endif
+4:
+#endif
 9:
 	rts
 
@@ -1103,6 +1006,7 @@
  */
 Lserial_putc:
 	moveml	%a0/%a1,%sp@-
+#ifdef CONFIG_AMIGA
 	cmpil	#MACH_AMIGA,%d4
 	jne	2f
 	andw	#0x00ff,%d7
@@ -1113,8 +1017,11 @@
 	andw	#0x2000,%d7
 	jeq	1b
 	jra	9f
-2:	cmpil   #MACH_ATARI,%d4
-	jne	9f
+2:
+#endif
+#ifdef CONFIG_ATARI
+	cmpil   #MACH_ATARI,%d4
+	jne	4f
 	movel	%pc@(Liobase),%a1
 #ifdef USE_PRINTER
 3:	btst	#0,%a1@(LSTMFP_GPIP)
@@ -1138,6 +1045,8 @@
 	jeq	3b
 	moveb	%d7,%a1@(LMFP_UDR)
 #endif
+4:
+#endif
 9:
 	moveml	%sp@+,%a0/%a1
 	rts
@@ -1170,7 +1079,7 @@
 	moveb	%d1,%d7
 	andb	#0x0f,%d7
 	cmpb	#0x0a,%d7
-	bccs	1f
+	jcc	1f
 	addb	#'0',%d7
 	jra	2f
 1:	addb	#'A'-10,%d7
@@ -1180,79 +1089,46 @@
 	jbsr	Lserial_putc
 	moveml	%sp@+,%d0-%d2/%d7
 	rts
-#if 0
-.globl showtest
-showtest:
-	moveml	%a1/%d7,%sp@-
-	moveq	#'A',%d7
-	jbsr	Lserial_putc
-	moveq	#'=',%d7
-	jbsr	Lserial_putc
-	movel	%a0,%d7
-	jbsr	Lserial_putnum
-
-	ptestr	#5,%a0@,#7,%a1
-
-	moveq	#'D',%d7
-	jbsr	Lserial_putc
-	moveq	#'A',%d7
-	jbsr	Lserial_putc
-	moveq	#'=',%d7
-	jbsr	Lserial_putc
-
-	movel	%a1,%d7
-	jbsr	Lserial_putnum
-
-	moveq	#'D',%d7
-	jbsr	Lserial_putc
-	moveq	#'=',%d7
-	jbsr	Lserial_putc
-	movel	%a1@,%d7
-	jbsr	Lserial_putnum
 
-	moveq	#'S',%d7
-	jbsr	Lserial_putc
-	moveq	#'=',%d7
-	jbsr	Lserial_putc
-
-	lea	%pc@(mmu),%a1
-	pmove	%psr,%a1@
+Lshowtest:
+	moveml	%a0/%d7,%sp@-
+	putc('A')
+	putc('=')
+	putn(%a1)
+
+	ptestr	#5,%a1@,#7,%a0
+
+	putc('D')
+	putc('A')
+	putc('=')
+	putn(%a0)
+
+	putc('D')
+	putc('=')
+	putn(%a0@)
+
+	putc('S')
+	putc('=')
+	lea	%pc@(Lmmu),%a0
+	pmove	%psr,%a0@
 	clrl	%d7
-	movew	%a1@,%d7
+	movew	%a0@,%d7
 	jbsr	Lserial_putnum
 
-	moveq	#CR,%d7
-	jbsr	Lserial_putc
-	moveq	#LF,%d7
-	jbsr	Lserial_putc
-
-	moveml	%sp@+,%a1/%d7
+	putr()
+	moveml	%sp@+,%a0/%d7
 	rts
-#endif
-
-#ifdef __ELF__
-	.align 512
-#else
-	.align 9
-#endif			/*
-			 * MMU root-pointers need to be 512-byte
-			 * aligned on the 680[46]0 - Jes
-			 */
-
-SYMBOL_NAME_LABEL(swapper_pg_dir)
-	.skip ROOT_TABLE_SIZE * 4
-SYMBOL_NAME_LABEL(kernel_pg_dir)
-	.skip ROOT_TABLE_SIZE * 4
 
 	.data
 	.even
-Lcustom:
+#ifdef HACKER_KERNEL
+Lkernel_start:
 	.long 0
+#endif
+Lcustom:
 Liobase:
 	.long 0
-mmu:	.quad 0
-SYMBOL_NAME_LABEL(kernel_pmd_table)
-	.long 0
+Lmmu:	.quad 0
 SYMBOL_NAME_LABEL(kpt)
 	.long 0
 SYMBOL_NAME_LABEL(availmem)
diff -u --recursive --new-file pre2.0.4/linux/arch/m68k/kernel/ksyms.c linux/arch/m68k/kernel/ksyms.c
--- pre2.0.4/linux/arch/m68k/kernel/ksyms.c	Tue Apr 23 13:57:07 1996
+++ linux/arch/m68k/kernel/ksyms.c	Thu May 16 09:05:10 1996
@@ -3,9 +3,12 @@
 #include <linux/linkage.h>
 #include <linux/string.h>
 #include <linux/mm.h>
+#include <linux/user.h>
+#include <linux/elfcore.h>
 
 #include <asm/bootinfo.h>
 #include <asm/pgtable.h>
+#include <asm/irq.h>
 
 asmlinkage long long __ashrdi3 (long long, int);
 extern char m68k_debug_device[];
@@ -20,6 +23,9 @@
 extern void mach_mac_syms_export (void);
 #endif
 
+extern void dump_thread(struct pt_regs *, struct user *);
+extern int dump_fpu(elf_fpregset_t *);
+
 static struct symbol_table arch_symbol_table = {
 #include <linux/symtab_begin.h>
 	/* platform dependent support */
@@ -32,6 +38,10 @@
 	X(mm_vtop),
 	X(mm_ptov),
 	X(m68k_debug_device),
+	X(add_isr),
+	X(remove_isr),
+	X(dump_fpu),
+	X(dump_thread),
 
 	/* The following are special because they're not called
 	   explicitly (the C compiler generates them).  Fortunately,
diff -u --recursive --new-file pre2.0.4/linux/arch/m68k/kernel/ptrace.c linux/arch/m68k/kernel/ptrace.c
--- pre2.0.4/linux/arch/m68k/kernel/ptrace.c	Tue Apr 23 13:57:08 1996
+++ linux/arch/m68k/kernel/ptrace.c	Thu May 16 09:05:10 1996
@@ -342,8 +342,10 @@
 			return -EPERM;
 		if ((!child->dumpable ||
 		    (current->uid != child->euid) ||
+		    (current->uid != child->suid) ||
 		    (current->uid != child->uid) ||
 	 	    (current->gid != child->egid) ||
+		    (current->gid != child->sgid) ||
 	 	    (current->gid != child->gid)) && !suser())
 			return -EPERM;
 		/* the same process cannot be attached many times */
diff -u --recursive --new-file pre2.0.4/linux/arch/m68k/kernel/setup.c linux/arch/m68k/kernel/setup.c
--- pre2.0.4/linux/arch/m68k/kernel/setup.c	Tue May  7 16:22:19 1996
+++ linux/arch/m68k/kernel/setup.c	Thu May 16 09:05:10 1996
@@ -72,6 +72,7 @@
 #ifdef CONFIG_BLK_DEV_FD
 int (*mach_floppy_init) (void) = NULL;
 void (*mach_floppy_setup) (char *, int *) = NULL;
+void (*mach_floppy_eject) (void) = NULL;
 #endif
 
 extern void config_amiga(void);
@@ -115,6 +116,12 @@
 	else if (boot_info.cputype & CPU_68060)
 		m68k_is040or060 = 6;
 
+	/* clear the fpu if we have one */
+	if (boot_info.cputype & (FPU_68881|FPU_68882|FPU_68040|FPU_68060)) {
+		volatile int zero = 0;
+		asm __volatile__ ("frestore %0" : : "m" (zero));
+	}
+
 	memory_start = availmem;
 	memory_end = 0;
 
@@ -240,7 +247,7 @@
 		   "FPU:\t\t%s\n"
 		   "Clockspeed:\t%lu.%1luMHz\n"
 		   "BogoMips:\t%lu.%02lu\n",
-		   cpu, mmu, fpu, clockfreq/1000000,
+		   cpu, mmu, fpu, (clockfreq+50000)/1000000,
 		   ((clockfreq+50000)/100000)%10, loops_per_sec/500000,
 		   (loops_per_sec/5000)%100));
 }
@@ -311,6 +318,12 @@
 {
 	if (mach_floppy_setup)
 		mach_floppy_setup (str, ints);
+}
+
+void floppy_eject(void)
+{
+	if (mach_floppy_eject)
+		mach_floppy_eject();
 }
 #endif
 
diff -u --recursive --new-file pre2.0.4/linux/arch/m68k/kernel/sys_m68k.c linux/arch/m68k/kernel/sys_m68k.c
--- pre2.0.4/linux/arch/m68k/kernel/sys_m68k.c	Sat Apr 27 15:19:47 1996
+++ linux/arch/m68k/kernel/sys_m68k.c	Thu May 16 09:05:10 1996
@@ -17,6 +17,7 @@
 #include <linux/mman.h>
 
 #include <asm/segment.h>
+#include <asm/cachectl.h>
 
 /*
  * sys_pipe() is the normal C calling standard for creating
@@ -182,4 +183,324 @@
 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on)
 {
   return -ENOSYS;
+}
+
+/* Convert virtual address VADDR to physical address PADDR, recording
+   in VALID whether the virtual address is actually mapped.  */
+#define virt_to_phys_040(vaddr, paddr, valid)				\
+{									\
+  register unsigned long _tmp1 __asm__ ("a0") = (vaddr);		\
+  register unsigned long _tmp2 __asm__ ("d0");				\
+  unsigned long _mmusr;							\
+									\
+  __asm__ __volatile__ (".word 0xf568 /* ptestr (%1) */\n\t"		\
+			".long 0x4e7a0805 /* movec %%mmusr,%0 */"	\
+			: "=d" (_tmp2)					\
+			: "a" (_tmp1));					\
+  _mmusr = _tmp2;							\
+  if (0 /* XXX _mmusr & MMU_?_040 */)					\
+    (valid) = 0;							\
+  else									\
+    {									\
+      (valid) = 1;							\
+      (paddr) = _mmusr & ~0xfff;					\
+    }									\
+}
+
+static inline int
+cache_flush_040 (unsigned long addr, int scope, int cache, unsigned long len)
+{
+  unsigned long paddr;
+  int valid;
+
+  switch (scope)
+    {
+    case FLUSH_SCOPE_ALL:
+      switch (cache)
+	{
+	case FLUSH_CACHE_DATA:
+	  /* This nop is needed for some broken versions of the 68040.  */
+	  __asm__ __volatile__ ("nop\n\t"
+				".word 0xf478 /* cpusha %%dc */");
+	  break;
+	case FLUSH_CACHE_INSN:
+	  __asm__ __volatile__ ("nop\n\t"
+				".word 0xf4b8 /* cpusha %%ic */");
+	  break;
+	default:
+	case FLUSH_CACHE_BOTH:
+	  __asm__ __volatile__ ("nop\n\t"
+				".word 0xf4f8 /* cpusha %%bc */");
+	  break;
+	}
+      break;
+
+    case FLUSH_SCOPE_LINE:
+      len >>= 4;
+      for (;;)
+	{
+	  virt_to_phys_040 (addr, paddr, valid);
+	  if (valid)
+	    break;
+	  if (len <= PAGE_SIZE / 16)
+	    return 0;
+	  len -= PAGE_SIZE / 16;
+	  addr += PAGE_SIZE;
+	}
+      while (len--)
+	{
+	  register unsigned long tmp __asm__ ("a0") = paddr;
+	  switch (cache)
+	    {
+	    case FLUSH_CACHE_DATA:
+	      __asm__ __volatile__ ("nop\n\t"
+				    ".word 0xf468 /* cpushl %%dc,(%0) */"
+				    : : "a" (tmp));
+	      break;
+	    case FLUSH_CACHE_INSN:
+	      __asm__ __volatile__ ("nop\n\t"
+				    ".word 0xf4a8 /* cpushl %%ic,(%0) */"
+				    : : "a" (tmp));
+	      break;
+	    default:
+	    case FLUSH_CACHE_BOTH:
+	      __asm__ __volatile__ ("nop\n\t"
+				    ".word 0xf4e8 /* cpushl %%bc,(%0) */"
+				    : : "a" (paddr));
+	      break;
+	    }
+	  addr += 16;
+	  if (len)
+	    {
+	      if ((addr & (PAGE_SIZE-1)) < 16)
+		{
+		  /* Recompute physical address when crossing a page
+		     boundary. */
+		  for (;;)
+		    {
+		      virt_to_phys_040 (addr, paddr, valid);
+		      if (valid)
+			break;
+		      if (len <= PAGE_SIZE / 16)
+			return 0;
+		      len -= PAGE_SIZE / 16;
+		      addr += PAGE_SIZE;
+		    }
+		}
+	      else
+		paddr += 16;
+	    }
+	}
+      break;
+
+    default:
+    case FLUSH_SCOPE_PAGE:
+      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
+	{
+	  register unsigned long tmp __asm__ ("a0");
+	  virt_to_phys_040 (addr, paddr, valid);
+	  if (!valid)
+	    continue;
+	  tmp = paddr;
+	  switch (cache)
+	    {
+	    case FLUSH_CACHE_DATA:
+	      __asm__ __volatile__ ("nop\n\t"
+				    ".word 0xf470 /* cpushp %%dc,(%0) */"
+				    : : "a" (tmp));
+	      break;
+	    case FLUSH_CACHE_INSN:
+	      __asm__ __volatile__ ("nop\n\t"
+				    ".word 0xf4b0 /* cpushp %%ic,(%0) */"
+				    : : "a" (tmp));
+	      break;
+	    default:
+	    case FLUSH_CACHE_BOTH:
+	      __asm__ __volatile__ ("nop\n\t"
+				    ".word 0xf4f0 /* cpushp %%bc,(%0) */"
+				    : : "a" (tmp));
+	      break;
+	    }
+	}
+      break;
+    }
+  return 0;
+}
+
+#define virt_to_phys_060(vaddr, paddr, valid)		\
+{							\
+  register unsigned long _tmp __asm__ ("a0") = (vaddr);	\
+							\
+  __asm__ __volatile__ (".word 0xf5c8 /* plpar (%1) */"	\
+			: "=a" (_tmp)			\
+			: "0" (_tmp));			\
+  (valid) = 1; /* XXX */				\
+  (paddr) = _tmp;					\
+}
+
+static inline int
+cache_flush_060 (unsigned long addr, int scope, int cache, unsigned long len)
+{
+  unsigned long paddr;
+  int valid;
+
+  switch (scope)
+    {
+    case FLUSH_SCOPE_ALL:
+      switch (cache)
+	{
+	case FLUSH_CACHE_DATA:
+	  __asm__ __volatile__ (".word 0xf478 /* cpusha %%dc */\n\t"
+				".word 0xf458 /* cinva %%dc */");
+	  break;
+	case FLUSH_CACHE_INSN:
+	  __asm__ __volatile__ (".word 0xf4b8 /* cpusha %%ic */\n\t"
+				".word 0xf498 /* cinva %%ic */");
+	  break;
+	default:
+	case FLUSH_CACHE_BOTH:
+	  __asm__ __volatile__ (".word 0xf4f8 /* cpusha %%bc */\n\t"
+				".word 0xf4d8 /* cinva %%bc */");
+	  break;
+	}
+      break;
+
+    case FLUSH_SCOPE_LINE:
+      len >>= 4;
+      for (;;)
+	{
+	  virt_to_phys_060 (addr, paddr, valid);
+	  if (valid)
+	    break;
+	  if (len <= PAGE_SIZE / 16)
+	    return 0;
+	  len -= PAGE_SIZE / 16;
+	  addr += PAGE_SIZE;
+	}
+      while (len--)
+	{
+	  register unsigned long tmp __asm__ ("a0") = paddr;
+	  switch (cache)
+	    {
+	    case FLUSH_CACHE_DATA:
+	      __asm__ __volatile__ (".word 0xf468 /* cpushl %%dc,(%0) */\n\t"
+				    ".word 0xf448 /* cinv %%dc,(%0) */"
+				    : : "a" (tmp));
+	      break;
+	    case FLUSH_CACHE_INSN:
+	      __asm__ __volatile__ (".word 0xf4a8 /* cpushl %%ic,(%0) */\n\t"
+				    ".word 0xf488 /* cinv %%ic,(%0) */"
+				    : : "a" (tmp));
+	      break;
+	    default:
+	    case FLUSH_CACHE_BOTH:
+	      __asm__ __volatile__ (".word 0xf4e8 /* cpushl %%bc,(%0) */\n\t"
+				    ".word 0xf4c8 /* cinv %%bc,(%0) */"
+				    : : "a" (paddr));
+	      break;
+	    }
+	  addr += 16;
+	  if (len)
+	    {
+	      if ((addr & (PAGE_SIZE-1)) < 16)
+		{
+		  /* Recompute the physical address when crossing a
+		     page boundary.  */
+		  for (;;)
+		    {
+		      virt_to_phys_060 (addr, paddr, valid);
+		      if (valid)
+			break;
+		      if (len <= PAGE_SIZE / 16)
+			return 0;
+		      len -= PAGE_SIZE / 16;
+		      addr += PAGE_SIZE;
+		    }
+		}
+	      else
+		paddr += 16;
+	    }
+	}
+      break;
+
+    default:
+    case FLUSH_SCOPE_PAGE:
+      for (len >>= PAGE_SHIFT; len--; addr += PAGE_SIZE)
+	{
+	  register unsigned long tmp __asm__ ("a0");
+	  virt_to_phys_060 (addr, paddr, valid);
+	  if (!valid)
+	    continue;
+	  tmp = paddr;
+	  switch (cache)
+	    {
+	    case FLUSH_CACHE_DATA:
+	      __asm__ __volatile__ (".word 0xf470 /* cpushp %%dc,(%0) */\n\t"
+				    ".word 0xf450 /* cinv %%dc,(%0) */"
+				    : : "a" (tmp));
+	      break;
+	    case FLUSH_CACHE_INSN:
+	      __asm__ __volatile__ (".word 0xf4b0 /* cpushp %%ic,(%0) */\n\t"
+				    ".word 0xf490 /* cinv %%ic,(%0) */"
+				    : : "a" (tmp));
+	      break;
+	    default:
+	    case FLUSH_CACHE_BOTH:
+	      __asm__ __volatile__ (".word 0xf4f0 /* cpushp %%bc,(%0) */\n\t"
+				    ".word 0xf4d0 /* cinv %%bc,(%0) */"
+				    : : "a" (tmp));
+	      break;
+	    }
+	}
+      break;
+    }
+  return 0;
+}
+
+/* sys_cacheflush -- flush (part of) the processor cache.  */
+asmlinkage int
+sys_cacheflush (unsigned long addr, int scope, int cache, unsigned long len)
+{
+  struct vm_area_struct *vma;
+
+  if (scope < FLUSH_SCOPE_LINE || scope > FLUSH_SCOPE_ALL
+      || cache & ~FLUSH_CACHE_BOTH)
+    return -EINVAL;
+
+  if (scope == FLUSH_SCOPE_ALL)
+    {
+      /* Only the superuser may flush the whole cache. */
+      if (!suser ())
+	return -EPERM;
+    }
+  else
+    {
+      /* Verify that the specified address region actually belongs to
+	 this process.  */
+      vma = find_vma (current, addr);
+      if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
+	return -EINVAL;
+    }
+
+  switch (m68k_is040or060)
+    {
+    default: /* 030 */
+      /* Always flush the whole cache, everything else would not be
+	 worth the hassle.  */
+      __asm__ __volatile__
+	("movec %%cacr, %%d0\n\t"
+	 "or %0, %%d0\n\t"
+	 "movec %%d0, %%cacr"
+	 : /* no outputs */
+	 : "di" ((cache & FLUSH_CACHE_INSN ? 8 : 0)
+		 | (cache & FLUSH_CACHE_DATA ? 0x800 : 0))
+	 : "d0");
+      return 0;
+
+    case 4: /* 040 */
+      return cache_flush_040 (addr, scope, cache, len);
+
+    case 6: /* 060 */
+      return cache_flush_060 (addr, scope, cache, len);
+    }
 }
diff -u --recursive --new-file pre2.0.4/linux/arch/m68k/kernel/time.c linux/arch/m68k/kernel/time.c
--- pre2.0.4/linux/arch/m68k/kernel/time.c	Tue Apr 23 13:57:08 1996
+++ linux/arch/m68k/kernel/time.c	Thu May 16 09:05:10 1996
@@ -137,7 +137,7 @@
 
 	xtime = *tv;
 	time_state = TIME_BAD;
-	time_maxerror = 0x70000000;
-	time_esterror = 0x70000000;
+	time_maxerror = MAXPHASE;
+	time_esterror = MAXPHASE;
 	sti();
 }
diff -u --recursive --new-file pre2.0.4/linux/arch/m68k/mm/init.c linux/arch/m68k/mm/init.c
--- pre2.0.4/linux/arch/m68k/mm/init.c	Sat Apr 27 15:19:47 1996
+++ linux/arch/m68k/mm/init.c	Thu May 16 09:05:10 1996
@@ -12,7 +12,7 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/types.h>
-#ifdef CONFIG_BLK_DEV_INITRD
+#ifdef CONFIG_BLK_DEV_RAM
 #include <linux/blk.h>
 #endif
 
@@ -24,6 +24,7 @@
 #include <asm/machdep.h>
 
 extern void die_if_kernel(char *,struct pt_regs *,long);
+extern void init_kpointer_table(void);
 extern void show_net_buffers(void);
 extern unsigned long mm_phys_to_virt (unsigned long addr);
 extern char *rd_start;
@@ -304,6 +305,7 @@
 	}
 #endif
 
+	init_kpointer_table();
 #if 0
 	/*
 	 * Setup cache bits
@@ -416,6 +418,7 @@
 	printk ("before free_area_init\n");
 #endif
 
+#ifdef CONFIG_BLK_DEV_RAM
 #ifndef CONFIG_BLK_DEV_INITRD
 	/*
 	 * Since the initialization of the ramdisk's has been changed
@@ -440,6 +443,7 @@
 	  start_mem += ramdisk_length;
 	  rd_doload = 1;     /* tell rd_load to load this thing */
 	}
+#endif
 #endif
 
 	return free_area_init (start_mem, end_mem);
diff -u --recursive --new-file pre2.0.4/linux/arch/m68k/mm/memory.c linux/arch/m68k/mm/memory.c
--- pre2.0.4/linux/arch/m68k/mm/memory.c	Tue May  7 16:22:20 1996
+++ linux/arch/m68k/mm/memory.c	Thu May 16 09:05:10 1996
@@ -20,6 +20,15 @@
 
 extern pte_t *kernel_page_table (unsigned long *memavailp);
 
+/* Strings for `extern inline' functions in <asm/pgtable.h>.  If put
+   directly into these functions, they are output for every file that
+   includes pgtable.h */
+
+const char PgtabStr_bad_pmd[] = "Bad pmd in pte_alloc: %08lx\n";
+const char PgtabStr_bad_pgd[] = "Bad pgd in pmd_alloc: %08lx\n";
+const char PgtabStr_bad_pmdk[] = "Bad pmd in pte_alloc_kernel: %08lx\n";
+const char PgtabStr_bad_pgdk[] = "Bad pgd in pmd_alloc_kernel: %08lx\n";
+
 static struct ptable_desc {
 	struct ptable_desc *prev;
 	struct ptable_desc *next;
@@ -145,40 +154,100 @@
 	}
 }
 
-static unsigned char alloced = 0;
-extern pmd_t (*kernel_pmd_table)[PTRS_PER_PMD]; /* initialized in head.S */
+/* maximum pages used for kpointer tables */
+#define KPTR_PAGES      4
+/* # of reserved slots */
+#define RESERVED_KPTR	4
+extern pmd_tablepage kernel_pmd_table; /* reserved in head.S */
+
+static struct kpointer_pages {
+        pmd_tablepage *page[KPTR_PAGES];
+        u_char alloced[KPTR_PAGES];
+} kptr_pages;
+
+void init_kpointer_table(void) {
+	short i = KPTR_PAGES-1;
+
+	/* first page is reserved in head.S */
+	kptr_pages.page[i] = &kernel_pmd_table;
+	kptr_pages.alloced[i] = ~(0xff>>RESERVED_KPTR);
+	for (i--; i>=0; i--) {
+		kptr_pages.page[i] = NULL;
+		kptr_pages.alloced[i] = 0;
+	}
+}
 
 pmd_t *get_kpointer_table (void)
 {
 	/* For pointer tables for the kernel virtual address space,
-	 * use a page that is allocated in head.S that can hold up to
-	 * 8 pointer tables.  This allows mapping of 8 * 32M = 256M of
-	 * physical memory.  This should be sufficient for now.
+	 * use the page that is reserved in head.S that can hold up to
+	 * 8 pointer tables. 3 of these tables are always reserved
+	 * (kernel_pg_dir, swapper_pg_dir and kernel pointer table for
+	 * the first 16 MB of RAM). In addition, the 4th pointer table
+	 * in this page is reserved. On Amiga and Atari, it is used to
+	 * map in the hardware registers. It may be used for other
+	 * purposes on other 68k machines. This leaves 4 pointer tables
+	 * available for use by the kernel. 1 of them are usually used
+	 * for the vmalloc tables. This allows mapping of 3 * 32 = 96 MB
+	 * of physical memory. But these pointer tables are also used
+	 * for other purposes, like kernel_map(), so further pages can
+	 * now be allocated.
 	 */
-	pmd_t *ptable;
-	int i;
-
-	for (i = 0; i < PAGE_SIZE/(PTRS_PER_PMD*sizeof(pmd_t)); i++)
-		if ((alloced & (1 << i)) == 0) {
-			ptable = kernel_pmd_table[i];
-			memset (ptable, 0, PTRS_PER_PMD*sizeof(pmd_t));
-			alloced |= (1 << i);
-			return ptable;
+	pmd_tablepage *page;
+	pmd_table *table;
+	long nr, offset = -8;
+	short i;
+
+	for (i=KPTR_PAGES-1; i>=0; i--) {
+		asm volatile("bfffo %1{%2,#8},%0"
+			: "=d" (nr)
+			: "d" ((u_char)~kptr_pages.alloced[i]), "d" (offset));
+		if (nr)
+			break;
+	}
+	if (i < 0) {
+		printk("No space for kernel pointer table!\n");
+		return NULL;
+	}
+	if (!(page = kptr_pages.page[i])) {
+		if (!(page = (pmd_tablepage *)__get_free_page(GFP_KERNEL))) {
+			printk("No space for kernel pointer table!\n");
+			return NULL;
 		}
-	printk ("no space for kernel pointer table\n");
-	return NULL;
+		nocache_page((u_long)(kptr_pages.page[i] = page));
+	}
+	asm volatile("bfset %0@{%1,#1}"
+		: /* no output */
+		: "a" (&kptr_pages.alloced[i]), "d" (nr-offset));
+	table = &(*page)[nr-offset];
+	memset(table, 0, sizeof(pmd_table));
+	return ((pmd_t *)table);
 }
 
 void free_kpointer_table (pmd_t *pmdp)
 {
-	int index = (pmd_t (*)[PTRS_PER_PMD])pmdp - kernel_pmd_table;
+	pmd_table *table = (pmd_table *)pmdp;
+	pmd_tablepage *page = (pmd_tablepage *)((u_long)table & PAGE_MASK);
+	long nr;
+	short i;
 
-	if (index < 0 || index > 7 ||
-	    /* This works because kernel_pmd_table is page aligned. */
-	    ((unsigned long)pmdp & (sizeof(pmd_t) * PTRS_PER_PMD - 1)))
-		panic("attempt to free invalid kernel pointer table");
-	else
-		alloced &= ~(1 << index);
+	for (i=KPTR_PAGES-1; i>=0; i--) {
+		if (kptr_pages.page[i] == page)
+			break;
+	}
+	nr = ((u_long)table - (u_long)page) / sizeof(pmd_table);
+	if (!table || i < 0 || (i == KPTR_PAGES-1 && nr < RESERVED_KPTR)) {
+		printk("Attempt to free invalid kernel pointer table: %p\n", table);
+		return;
+	}
+	asm volatile("bfclr %0@{%1,#1}"
+		: /* no output */
+		: "a" (&kptr_pages.alloced[i]), "d" (nr));
+	if (!kptr_pages.alloced[i]) {
+		kptr_pages.page[i] = 0;
+		cache_page ((u_long)page);
+		free_page ((u_long)page);
+	}
 }
 
 /*
@@ -319,22 +388,41 @@
 	return paddr;
 }
 
+/* invalidate page in both caches */
 #define	clear040(paddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\
+					      "nop\n\t"\
 					      ".word 0xf4d0"\
 					      /* CINVP I/D (a0) */\
 					      : : "g" ((paddr))\
 					      : "a0")
 
+/* invalidate page in i-cache */
+#define	cleari040(paddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\
+					       /* CINVP I (a0) */\
+					       "nop\n\t"\
+					       ".word 0xf490"\
+					       : : "g" ((paddr))\
+					       : "a0")
+
+/* push page in both caches */
 #define	push040(paddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\
+					      "nop\n\t"\
 					     ".word 0xf4f0"\
 					     /* CPUSHP I/D (a0) */\
 					     : : "g" ((paddr))\
 					     : "a0")
 
+/* push and invalidate page in both caches */
 #define	pushcl040(paddr) do { push040((paddr));\
 			      if (m68k_is040or060 == 6) clear040((paddr));\
 			 } while(0)
 
+/* push page in both caches, invalidate in i-cache */
+#define	pushcli040(paddr) do { push040((paddr));\
+			       if (m68k_is040or060 == 6) cleari040((paddr));\
+			  } while(0)
+
+/* push page defined by virtual address in both caches */
 #define	pushv040(vaddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\
 					      /* ptestr (a0) */\
 					      ".word 0xf568\n\t"\
@@ -343,10 +431,12 @@
 					      "andw #0xf000,%/d0\n\t"\
 					      "movel %/d0,%/a0\n\t"\
 					      /* CPUSHP I/D (a0) */\
+					      "nop\n\t"\
 					      ".word 0xf4f0"\
 					      : : "g" ((vaddr))\
 					      : "a0", "d0")
 
+/* push page defined by virtual address in both caches */
 #define	pushv060(vaddr) __asm__ __volatile__ ("movel %0,%/a0\n\t"\
 					      /* plpar (a0) */\
 					      ".word 0xf5c8\n\t"\
@@ -374,6 +464,14 @@
  * the DPI bit in the CACR; would it cause problems with temporarily changing
  * this?). So we have to push first and then additionally to invalidate.
  */
+
+/*
+ * cache_clear() semantics: Clear any cache entries for the area in question,
+ * without writing back dirty entries first. This is useful if the data will
+ * be overwritten anyway, e.g. by DMA to memory. The range is defined by a
+ * _physical_ address.
+ */
+
 void cache_clear (unsigned long paddr, int len)
 {
     if (m68k_is040or060) {
@@ -419,6 +517,12 @@
 }
 
 
+/*
+ * cache_push() semantics: Write back any dirty cache data in the given area,
+ * and invalidate the range in the instruction cache. It needs not (but may)
+ * invalidate those entries also in the data cache. The range is defined by a
+ * _physical_ address.
+ */
 
 void cache_push (unsigned long paddr, int len)
 {
@@ -429,18 +533,18 @@
 	 * the '060!
 	 */
 	while (len > PAGE_SIZE) {
-	    push040(paddr);
+	    pushcli040(paddr);
 	    len -= PAGE_SIZE;
 	    paddr += PAGE_SIZE;
 	    }
 	if (len > 0) {
-	    push040(paddr);
+	    pushcli040(paddr);
 #if 0
 	    if (((paddr + len - 1) / PAGE_SIZE) != (paddr / PAGE_SIZE)) {
 #endif
 	    if (((paddr + len - 1) ^ paddr) & PAGE_MASK) {
 		/* a page boundary gets crossed at the end */
-		push040(paddr + len - 1);
+		pushcli040(paddr + len - 1);
 		}
 	    }
 	}
@@ -463,6 +567,15 @@
 		      : "d0");
 }
 
+
+/*
+ * cache_push_v() semantics: Write back any dirty cache data in the given
+ * area, and invalidate those entries at least in the instruction cache. This
+ * is intended to be used after data has been written that can be executed as
+ * code later. The range is defined by a _user_mode_ _virtual_ address  (or,
+ * more exactly, the space is defined by the %sfc/%dfc register.)
+ */
+
 void cache_push_v (unsigned long vaddr, int len)
 {
     if (m68k_is040or060 == 4) {
@@ -506,65 +619,12 @@
 		      : : "i" (FLUSH_I)
 		      : "d0");
 }
-#if 1
-void flush_cache_all(void)
-{
-    if (m68k_is040or060 >= 4)
-        __asm__ __volatile__ (".word 0xf478\n" ::);
-    else /* 68030 or 68020 */
-	asm volatile ("movec %/cacr,%/d0\n\t"
-		      "oriw %0,%/d0\n\t"
-		      "movec %/d0,%/cacr"
-		      : : "i" (FLUSH_I_AND_D)
-		      : "d0");
-}
-
-void flush_cache_mm(struct mm_struct *mm){
-
-    if (mm == current->mm)
-        flush_cache_all();
-}
-
-void flush_cache_range(struct mm_struct *mm, unsigned long start,
-		       unsigned long end){
-    if (mm == current->mm)
-        cache_push_v(start, end-start);
-}
-
-void flush_cache_page (struct vm_area_struct *vma, unsigned long vaddr)
-{
-    if (m68k_is040or060 >= 4)
-        pushv040(vaddr); /*
-			  * the 040 always invalidates the I-cache when
-			  * pushing its contents to ram.
-			  */
-
-    /* 68030/68020 have no writeback cache; still need to clear icache. */
-    else /* 68030 or 68020 */
-        asm volatile ("movec %/cacr,%/d0\n\t"
-		      "oriw %0,%/d0\n\t"
-		      "movec %/d0,%/cacr"
-		      : : "i" (FLUSH_I_AND_D)
-		      : "d0");
-}
-
-void flush_page_to_ram (unsigned long vaddr)
-{
-    if (m68k_is040or060 >= 4)
-        pushcl040(VTOP(vaddr));
-
-    /* 68030/68020 have no writeback cache; still need to clear icache. */
-    else /* 68030 or 68020 */
-	asm volatile ("movec %/cacr,%/d0\n\t"
-		      "oriw %0,%/d0\n\t"
-		      "movec %/d0,%/cacr"
-		      : : "i" (FLUSH_I_AND_D)
-		      : "d0");
-}
-#endif
 
 #undef clear040
+#undef cleari040
 #undef push040
+#undef pushcl040
+#undef pushcli040
 #undef pushv040
 #undef pushv060
 
diff -u --recursive --new-file pre2.0.4/linux/drivers/block/Config.in linux/drivers/block/Config.in
--- pre2.0.4/linux/drivers/block/Config.in	Tue May  7 16:22:22 1996
+++ linux/drivers/block/Config.in	Thu May 16 16:35:39 1996
@@ -16,36 +16,38 @@
   bool '   Support removable IDE interfaces (PCMCIA)' CONFIG_BLK_DEV_IDE_PCMCIA
   bool '   CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640
   if [ "$CONFIG_PCI" = "y" ]; then
-    bool '   RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
     bool '   Intel 430FX (Triton) chipset DMA support' CONFIG_BLK_DEV_TRITON
+    bool '   RZ1000 chipset bugfix/support' CONFIG_BLK_DEV_RZ1000
   fi
   bool '   Other IDE chipset support' CONFIG_IDE_CHIPSETS
   if [ "$CONFIG_IDE_CHIPSETS" = "y" ]; then
     comment 'Note: most of these also require special kernel boot parameters'
+    bool '      ALI M1439/M1445 support' CONFIG_BLK_DEV_ALI14XX
     bool '      DTC-2278        support' CONFIG_BLK_DEV_DTC2278
     bool '      Holtek HT6560B  support' CONFIG_BLK_DEV_HT6560B
+    bool '      PROMISE DC4030  support (ALPHA)' CONFIG_BLK_DEV_PROMISE
     bool '      QDI QD6580      support' CONFIG_BLK_DEV_QD6580
     bool '      UMC 8672        support' CONFIG_BLK_DEV_UMC8672
-    bool '      ALI M1439/M1445 support' CONFIG_BLK_DEV_ALI14XX
-    bool '      PROMISE DC4030  support (ALPHA)' CONFIG_BLK_DEV_PROMISE
   fi
 fi
 
+comment 'Additional Block Devices'
+
+tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
+bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
+if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
+  tristate '   Linear (append) mode' CONFIG_MD_LINEAR
+  tristate '   RAID-0 (striping) mode' CONFIG_MD_STRIPED
+fi
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
 if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
   bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
 fi
+tristate 'XT harddisk support' CONFIG_BLK_DEV_XD
 
-tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP
 
 if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then
   define_bool CONFIG_BLK_DEV_HD y
 fi
 
-tristate 'XT harddisk support' CONFIG_BLK_DEV_XD
-bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
-if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
-  tristate '   Linear (append) mode' CONFIG_MD_LINEAR
-  tristate '   RAID-0 (striping) mode' CONFIG_MD_STRIPED
-fi
 endmenu
diff -u --recursive --new-file pre2.0.4/linux/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- pre2.0.4/linux/drivers/block/amiflop.c	Tue May  7 16:22:22 1996
+++ linux/drivers/block/amiflop.c	Thu May 16 09:05:10 1996
@@ -1780,12 +1780,3 @@
 
   return 0;
 }
-
-#ifndef MODULE
-/*
- * This is just a dummy function to keep fs/super.c happy.
- */
-void floppy_eject(void)
-{
-}
-#endif
diff -u --recursive --new-file pre2.0.4/linux/drivers/block/ataflop.c linux/drivers/block/ataflop.c
--- pre2.0.4/linux/drivers/block/ataflop.c	Tue May  7 16:22:22 1996
+++ linux/drivers/block/ataflop.c	Thu May 16 09:05:10 1996
@@ -608,11 +608,11 @@
 	if (!CURRENT) return;
 	CURRENT->errors++;
 	if (CURRENT->errors >= MAX_ERRORS) {
-		printk( "fd%d: too many errors.\n", SelectedDrive );
+		printk(KERN_ERR "fd%d: too many errors.\n", SelectedDrive );
 		end_request( 0 );
 	}
 	else if (CURRENT->errors == RECALIBRATE_ERRORS) {
-		printk( "fd%d: recalibrating\n", SelectedDrive );
+		printk(KERN_WARNING "fd%d: recalibrating\n", SelectedDrive );
 		if (SelectedDrive != -1)
 			SUD.track = -1;
 	}
@@ -793,7 +793,7 @@
 	if (ATARIHW_PRESENT(FDCSPEED))
 		dma_wd.fdc_speed = SUDT->fdc_speed;
 	if (status & FDCSTAT_RECNF) {
-		printk( "fd%d: restore failed\n", SelectedDrive );
+		printk(KERN_ERR "fd%d: restore failed\n", SelectedDrive );
 		fd_error();
 	}
 	else {
@@ -841,7 +841,7 @@
 	if (ATARIHW_PRESENT(FDCSPEED))
 		dma_wd.fdc_speed = SUDT->fdc_speed;
 	if (status & FDCSTAT_RECNF) {
-		printk( "fd%d: seek error (to track %d)\n",
+		printk(KERN_ERR "fd%d: seek error (to track %d)\n",
 				SelectedDrive, ReqTrack );
 		/* we don't know exactly which track we are on now! */
 		SUD.track = -1;
@@ -1049,14 +1049,14 @@
 		dma_wd.dma_mode_status = 0x90;
 		MFPDELAY();
 		if (!(dma_wd.dma_mode_status & 0x01)) {
-			printk( "fd%d: DMA error\n", SelectedDrive );
+			printk(KERN_ERR "fd%d: DMA error\n", SelectedDrive );
 			goto err_end;
 		}
 	}
 	MFPDELAY();
 
 	if (ReqCmd == WRITE && (status & FDCSTAT_WPROT)) {
-		printk( "fd%d: is write protected\n", SelectedDrive );
+		printk(KERN_NOTICE "fd%d: is write protected\n", SelectedDrive );
 		goto err_end;
 	}	
 	if ((status & FDCSTAT_RECNF) &&
@@ -1071,7 +1071,7 @@
 			}
 			else {
 				if (SUD.flags & FTD_MSG)
-					printk( "fd%d: Auto-detected floppy type %s\n",
+					printk(KERN_INFO "fd%d: Auto-detected floppy type %s\n",
 					       SelectedDrive, SUDT->name );
 				Probing=0;
 			}
@@ -1094,17 +1094,17 @@
 			return;
 		}
 
-		printk( "fd%d: sector %d not found (side %d, track %d)\n",
+		printk(KERN_ERR "fd%d: sector %d not found (side %d, track %d)\n",
 		       SelectedDrive, FDC_READ (FDCREG_SECTOR), ReqSide, ReqTrack );
 		goto err_end;
 	}
 	if (status & FDCSTAT_CRC) {
-		printk( "fd%d: CRC error (side %d, track %d, sector %d)\n",
+		printk(KERN_ERR "fd%d: CRC error (side %d, track %d, sector %d)\n",
 		       SelectedDrive, ReqSide, ReqTrack, FDC_READ (FDCREG_SECTOR) );
 		goto err_end;
 	}
 	if (status & FDCSTAT_LOST) {
-		printk( "fd%d: lost data (side %d, track %d, sector %d)\n",
+		printk(KERN_ERR "fd%d: lost data (side %d, track %d, sector %d)\n",
 		       SelectedDrive, ReqSide, ReqTrack, FDC_READ (FDCREG_SECTOR) );
 		goto err_end;
 	}
@@ -1214,11 +1214,11 @@
 	STOP_TIMEOUT();
 
 	if (status & FDCSTAT_WPROT) {
-		printk( "fd%d: is write protected\n", SelectedDrive );
+		printk(KERN_NOTICE "fd%d: is write protected\n", SelectedDrive );
 		goto err_end;
 	}	
 	if (status & FDCSTAT_LOST) {
-		printk( "fd%d: lost data (side %d, track %d)\n",
+		printk(KERN_ERR "fd%d: lost data (side %d, track %d)\n",
 				SelectedDrive, ReqSide, ReqTrack );
 		goto err_end;
 	}
@@ -1244,7 +1244,7 @@
 	FDC_WRITE( FDCREG_CMD, FDCCMD_FORCI );
 	udelay( 25 );
 	
-	printk( "floppy timeout\n" );
+	printk(KERN_ERR "floppy timeout\n" );
 	fd_error();
   end:
 	atari_enable_irq( IRQ_MFP_FDC );
@@ -1345,7 +1345,7 @@
 	unsigned int drive = MINOR(dev) & 0x03;
 
 	if (MAJOR(dev) != MAJOR_NR) {
-		printk("floppy_changed: not a floppy\n");
+		printk(KERN_ERR "floppy_changed: not a floppy\n");
 		return 0;
 	}
 	
@@ -1445,7 +1445,7 @@
 	
 	if (!UD.connected) {
 		/* drive not connected */
-		printk( "Unknown Device: fd%d\n", drive );
+		printk(KERN_ERR "Unknown Device: fd%d\n", drive );
 		end_request(0);
 		goto repeat;
 	}
@@ -1461,12 +1461,12 @@
 	else {
 		/* user supplied disk type */
 		if (--type >= NUM_DISK_MINORS) {
-			printk( "fd%d: invalid disk format", drive );
+			printk(KERN_WARNING "fd%d: invalid disk format", drive );
 			end_request( 0 );
 			goto repeat;
 		}
 		if (minor2disktype[type].drive_types > DriveType)  {
-			printk( "fd%d: unsupported disk format", drive );
+			printk(KERN_WARNING "fd%d: unsupported disk format", drive );
 			end_request( 0 );
 			goto repeat;
 		}
@@ -1712,11 +1712,11 @@
 	if (ATARIHW_PRESENT(FDCSPEED))
 		dma_wd.fdc_speed = 0;
 
-	printk("Probing floppy drive(s):\n");
+	printk(KERN_INFO "Probing floppy drive(s):\n");
 	for( drive = 0; drive < FD_MAX_UNITS; drive++ ) {
 		fd_probe( drive );
 		if (UD.connected) {
-			printk("fd%d\n", drive);
+			printk(KERN_INFO "fd%d\n", drive);
 			++cnt;
 		}
 	}
@@ -1789,6 +1789,8 @@
   if (filp->f_mode & 2)
     filp->f_mode |= OPEN_WRITE_BIT;
 
+  MOD_INC_USE_COUNT;
+
   if (filp->f_flags & O_NDELAY)
     return 0;
 
@@ -1821,9 +1823,11 @@
     fd_ref[drive] = 0;
   else if (!fd_ref[drive]--)
     {
-      printk("floppy_release with fd_ref == 0");
+      printk(KERN_ERR "floppy_release with fd_ref == 0");
       fd_ref[drive] = 0;
     }
+
+  MOD_DEC_USE_COUNT;
 }
 
 static struct file_operations floppy_fops = {
@@ -1847,7 +1851,7 @@
 	int i;
 
 	if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
-		printk("Unable to get major %d for floppy\n",MAJOR_NR);
+		printk(KERN_ERR "Unable to get major %d for floppy\n",MAJOR_NR);
 		return -EBUSY;
 	}
 
@@ -1868,7 +1872,7 @@
 
 	DMABuffer = kmalloc(BUFFER_SIZE + 512, GFP_KERNEL | GFP_DMA);
 	if (!DMABuffer) {
-		printk("atari_floppy_init: cannot get dma buffer\n");
+		printk(KERN_ERR "atari_floppy_init: cannot get dma buffer\n");
 		unregister_blkdev(MAJOR_NR, "fd");
 		return -ENOMEM;
 	}
@@ -1893,7 +1897,7 @@
 	blksize_size[MAJOR_NR] = floppy_blocksizes;
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 
-	printk("Atari floppy driver: max. %cD, %strack buffering\n",
+	printk(KERN_INFO "Atari floppy driver: max. %cD, %strack buffering\n",
 	       DriveType == 0 ? 'D' : DriveType == 1 ? 'H' : 'E',
 	       UseTrackbuffer ? "" : "no ");
 	config_types();
@@ -1907,15 +1911,15 @@
 	int i;
 	
 	if (ints[0] < 1) {
-		printk( "ataflop_setup: no arguments!\n" );
+		printk(KERN_ERR "ataflop_setup: no arguments!\n" );
 		return;
 	}
 	else if (ints[0] > 2+FD_MAX_UNITS) {
-		printk( "ataflop_setup: too many arguments\n" );
+		printk(KERN_ERR "ataflop_setup: too many arguments\n" );
 	}
 
 	if (ints[1] < 0 || ints[1] > 2)
-		printk( "ataflop_setup: bad drive type\n" );
+		printk(KERN_ERR "ataflop_setup: bad drive type\n" );
 	else
 		DriveType = ints[1];
 
@@ -1924,7 +1928,7 @@
 
 	for( i = 3; i <= ints[0] && i-3 < FD_MAX_UNITS; ++i ) {
 		if (ints[i] != 2 && ints[i] != 3 && ints[i] != 6 && ints[i] != 12)
-			printk( "ataflop_setup: bad steprate\n" );
+			printk(KERN_ERR "ataflop_setup: bad steprate\n" );
 		else
 			UserSteprate[i-3] = ints[i];
 	}
@@ -1933,6 +1937,8 @@
 #ifdef MODULE
 int init_module (void)
 {
+	if (!MACH_IS_ATARI)
+		return -ENXIO;
 	return atari_floppy_init ();
 }
 
@@ -1944,13 +1950,6 @@
 	timer_active &= ~(1 << FLOPPY_TIMER);
 	timer_table[FLOPPY_TIMER].fn = 0;
 	kfree (DMABuffer);
-}
-#else
-/*
- * This is just a dummy function to keep fs/super.c happy.
- */
-void floppy_eject(void)
-{
 }
 #endif
 
diff -u --recursive --new-file pre2.0.4/linux/drivers/block/floppy.c linux/drivers/block/floppy.c
--- pre2.0.4/linux/drivers/block/floppy.c	Wed May 15 11:01:14 1996
+++ linux/drivers/block/floppy.c	Wed May 15 10:08:25 1996
@@ -482,7 +482,6 @@
 static void process_fd_request(void);
 static void recalibrate_floppy(void);
 static void floppy_shutdown(void);
-static void unexpected_floppy_interrupt(void);
 
 static int floppy_grab_irq_and_dma(void);
 static void floppy_release_irq_and_dma(void);
@@ -525,21 +524,9 @@
 static long current_count_sectors = 0;
 static unsigned char sector_t; /* sector in track */
 
-
 #ifndef fd_eject
-#ifdef __sparc__
-static int fd_eject(int drive)
-{
-	set_dor(0, ~0, 0x90);
-	udelay(500);
-	set_dor(0, ~0x80, 0);
-	udelay(500);
-	return 0;
-}
-#else
 #define fd_eject(x) -EINVAL
 #endif
-#endif
 
 
 #ifdef DEBUGT
@@ -930,7 +917,7 @@
 }
 
 static struct tq_struct floppy_tq =
-{ 0, 0, (void *) (void *) unexpected_floppy_interrupt, 0 };
+{ 0, 0, 0, 0 };
 
 static struct timer_list fd_timer ={ NULL, NULL, 0, 0, 0 };
 
@@ -1660,40 +1647,22 @@
 	floppy_ready();
 }
 
-/*
- * Unexpected interrupt - Print as much debugging info as we can...
- * All bets are off...
- */
-static void unexpected_floppy_interrupt(void)
+static void print_result(char *message, int inr)
 {
 	int i;
-	if (initialising)
-		return;
-	if (print_unex){
-		DPRINT("unexpected interrupt\n");
-		if (inr >= 0)
-			for (i=0; i<inr; i++)
-				printk("%d %x\n", i, reply_buffer[i]);
-	}
-	FDCS->reset = 0;        /* Allow SENSEI to be sent. */
-	while(1){
-		output_byte(FD_SENSEI);
-		inr=result();
-		if (inr != 2)
-			break;
-		if (print_unex){
-			printk("sensei\n");
-			for (i=0; i<inr; i++)
-				printk("%d %x\n", i, reply_buffer[i]);
-		}
-	}
-	FDCS->reset = 1;
+
+	DPRINT("%s ", message);
+	if (inr >= 0)
+		for (i=0; i<inr; i++)
+			printk("repl[%d]=%x ", i, reply_buffer[i]);
+	printk("\n");
 }
 
 /* interrupt handler */
 void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	void (*handler)(void) = DEVICE_INTR;
+	int do_print;
 
 	lasthandler = handler;
 	interruptjiffies = jiffies;
@@ -1709,20 +1678,36 @@
 		is_alive("bizarre fdc");
 		return;
 	}
+
+	FDCS->reset = 0;
+	/* We have to clear the reset flag here, because apparently on boxes
+	 * with level triggered interrupts (PS/2, Sparc, ...), it is needed to
+	 * emit SENSEI's to clear the interrupt line. And FDCS->reset blocks the
+	 * emission of the SENSEI's.
+	 * It is OK to emit floppy commands because we are in an interrupt
+	 * handler here, and thus we have to fear no interference of other
+	 * activity.
+	 */
+
+	do_print = !handler && print_unex && !initialising;
+
 	inr = result();
-	if (!handler){
-		unexpected_floppy_interrupt();
-		is_alive("unexpected");
-		return;
-	}
+	if(do_print)
+		print_result("unexpected interrupt", inr);
 	if (inr == 0){
 		do {
 			output_byte(FD_SENSEI);
 			inr = result();
+			if(do_print)
+				print_result("sensei", inr);
 		} while ((ST0 & 0x83) != UNIT(current_drive) && inr == 2);
 	}
-	floppy_tq.routine = (void *)(void *) handler;
-	queue_task_irq(&floppy_tq, &tq_timer);
+	if (handler) {
+		/* expected interrupt */
+		floppy_tq.routine = (void *)(void *) handler;
+		queue_task_irq(&floppy_tq, &tq_timer);
+	} else
+		FDCS->reset = 1;
 	is_alive("normal interrupt end");
 }
 
@@ -4098,12 +4083,13 @@
 	sti();
 	MOD_INC_USE_COUNT;
 	for (i=0; i< N_FDC; i++){
-		if (FDCS->address != -1){
+		if (fdc_state[i].address != -1){
 			fdc = i;
 			reset_fdc_info(1);
 			fd_outb(FDCS->dor, FD_DOR);
 		}
 	}
+	fdc = 0;
 	set_dor(0, ~0, 8);  /* avoid immediate interrupt */
 
 	if (fd_request_irq()) {
diff -u --recursive --new-file pre2.0.4/linux/drivers/block/ide.c linux/drivers/block/ide.c
--- pre2.0.4/linux/drivers/block/ide.c	Sun May 12 22:54:22 1996
+++ linux/drivers/block/ide.c	Wed May 15 10:33:05 1996
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide.c	Version 5.42  May 12, 1996
+ *  linux/drivers/block/ide.c	Version 5.43  May 14, 1996
  *
  *  Copyright (C) 1994-1996  Linus Torvalds & authors (see below)
  */
@@ -237,6 +237,7 @@
  *			disable io_32bit by default on drive reset
  * Version 5.42		simplify irq-masking after probe
  *			fix NULL pointer deref in save_match()
+ * Version 5.43		Ugh.. unexpected_intr is back: try to exterminate it
  *
  *  Some additional driver compile-time options are in ide.h
  *
@@ -2421,11 +2422,14 @@
 	} else
 		rc = 2;			/* drive refused ID */
 	if (!HWIF(drive)->irq) {
-		OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* mask device irq */
-		udelay(5);
 		irqs = probe_irq_off(irqs);	/* get our irq number */
 		if (irqs > 0) {
 			HWIF(drive)->irq = irqs; /* save it for later */
+			irqs = probe_irq_on();
+			OUT_BYTE(drive->ctl|2,IDE_CONTROL_REG); /* mask device irq */
+			udelay(5);
+			(void) GET_STAT();	/* clear drive IRQ */
+			(void) probe_irq_off(irqs);
 		} else {	/* Mmmm.. multiple IRQs.. don't know which was ours */
 			printk("%s: IRQ probe failed (%d)\n", drive->name, irqs);
 #ifdef CONFIG_BLK_DEV_CMD640
diff -u --recursive --new-file pre2.0.4/linux/drivers/block/linear.c linux/drivers/block/linear.c
--- pre2.0.4/linux/drivers/block/linear.c	Mon May 13 23:02:47 1996
+++ linux/drivers/block/linear.c	Wed May 15 09:09:00 1996
@@ -193,10 +193,7 @@
 
 void cleanup_module (void)
 {
-  if (MOD_IN_USE)
-    printk ("md linear : module still busy...\n");
-  else
-    unregister_md_personality (LINEAR);
+  unregister_md_personality (LINEAR);
 }
 
 #endif
diff -u --recursive --new-file pre2.0.4/linux/drivers/block/raid0.c linux/drivers/block/raid0.c
--- pre2.0.4/linux/drivers/block/raid0.c	Sun Apr 21 19:22:02 1996
+++ linux/drivers/block/raid0.c	Wed May 15 09:09:00 1996
@@ -291,10 +291,7 @@
 
 void cleanup_module (void)
 {
-  if (MOD_IN_USE)
-    printk ("md raid0 : module still busy...\n");
-  else
-    unregister_md_personality (RAID0);
+  unregister_md_personality (RAID0);
 }
 
 #endif
diff -u --recursive --new-file pre2.0.4/linux/drivers/cdrom/Config.in linux/drivers/cdrom/Config.in
--- pre2.0.4/linux/drivers/cdrom/Config.in	Mon Apr 29 18:05:17 1996
+++ linux/drivers/cdrom/Config.in	Thu May 16 16:35:39 1996
@@ -1,9 +1,8 @@
 #
 # CDROM driver configuration
 #
-tristate 'Sony CDU31A/CDU33A CDROM support' CONFIG_CDU31A
-tristate 'Standard Mitsumi [no XA/Multisession] CDROM support' CONFIG_MCD
-tristate 'Mitsumi [XA/MultiSession] CDROM support' CONFIG_MCDX
+tristate 'Aztech/Orchid/Okano/Wearnes/TXC/CyDROM  CDROM support' CONFIG_AZTCD
+tristate 'Goldstar R420 CDROM support' CONFIG_GSCD
 tristate 'Matsushita/Panasonic/Creative, Longshine, TEAC CDROM support' CONFIG_SBPCD
 if [ "$CONFIG_SBPCD" = "y" ]; then
   bool 'Matsushita/Panasonic, ... second CDROM controller support' CONFIG_SBPCD2
@@ -14,13 +13,14 @@
     fi
   fi
 fi
-tristate 'Aztech/Orchid/Okano/Wearnes/TXC/CyDROM  CDROM support' CONFIG_AZTCD
-tristate 'Sony CDU535 CDROM support' CONFIG_CDU535
-tristate 'Goldstar R420 CDROM support' CONFIG_GSCD
-tristate 'Philips/LMS CM206 CDROM support' CONFIG_CM206
+tristate 'Mitsumi (standard) [no XA/Multisession] CDROM support' CONFIG_MCD
+tristate 'Mitsumi [XA/MultiSession] CDROM support' CONFIG_MCDX
 tristate 'Optics Storage DOLPHIN 8000AT CDROM support' CONFIG_OPTCD
+tristate 'Philips/LMS CM206 CDROM support' CONFIG_CM206
 tristate 'Sanyo CDR-H94A CDROM support' CONFIG_SJCD
 bool 'Soft configurable cdrom interface card support' CONFIG_CDI_INIT
 if [ "$CONFIG_CDI_INIT" = "y" ]; then
   tristate 'ISP16/MAD16/Mozart soft configurable cdrom interface support' CONFIG_ISP16_CDI
 fi
+tristate 'Sony CDU31A/CDU33A CDROM support' CONFIG_CDU31A
+tristate 'Sony CDU535 CDROM support' CONFIG_CDU535
diff -u --recursive --new-file pre2.0.4/linux/drivers/cdrom/mcdx.c linux/drivers/cdrom/mcdx.c
--- pre2.0.4/linux/drivers/cdrom/mcdx.c	Mon May 13 23:02:47 1996
+++ linux/drivers/cdrom/mcdx.c	Fri May 17 15:24:15 1996
@@ -1,7 +1,7 @@
 /*
  * The Mitsumi CDROM interface
  * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 2.2
+ * VERSION: 2.3
  * 
  * 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
@@ -35,8 +35,13 @@
  * 2.2  1996/05/06 Marcin Dalecki <dalecki@namu03.gwdg.de>
  *      Mostly fixes to some silly bugs in the previous release :-).
  *      (Hi Michael Thimm! Thank's for lending me Your's double speed drive.)
+ * 2.3  1996/05/15 Marcin Dalecki <dalecki@namu03.gwdg.de>
+ *	Fixed stereo support. 
+ * NOTE:
+ *	There will be propably a 3.0 adhering to the new generic non ATAPI
+ *	cdrom interface in the unforseen future.
  */
-#define VERSION "2.2"
+#define VERSION "2.3"
 
 #include <linux/version.h>
 #include <linux/module.h>
@@ -794,7 +799,7 @@
 		memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl));
 		/* Adjust for the wiredness of workman. */
 		volctrl.channel2 = volctrl.channel1;
-		volctrl.channel1 = volctrl.channel3 = 0xff;
+		volctrl.channel1 = volctrl.channel3 = 0x00;
 		return talk(stuffp, MCDX_CMD_SET_ATTENATOR,
 			    &volctrl, sizeof(volctrl),
 			    &volctrl, sizeof(volctrl), 2 * HZ);
@@ -1022,7 +1027,8 @@
 	}
 	/*
 	 * Check if a disk is in.
-	 */ bang = jiffies + 10 * HZ;
+	 */ 
+	bang = jiffies + 10 * HZ;
 	while (jiffies < bang) {
 		st = issue_command(stuffp, MCDX_CMD_GET_STATUS, 5 * HZ);
 		if (st != -1 && (st & MCDX_RBIT_DISKSET))
@@ -1232,7 +1238,6 @@
 #else
 	printk(KERN_INFO "Mitsumi driver version " VERSION "\n");
 #endif
-	printk("%d\n", MCDX_NDRIVES);
 	for (drive = 0; drive < MCDX_NDRIVES; drive++) {
 		struct {
 			u_char code;
diff -u --recursive --new-file pre2.0.4/linux/drivers/char/Makefile linux/drivers/char/Makefile
--- pre2.0.4/linux/drivers/char/Makefile	Mon May 13 23:02:48 1996
+++ linux/drivers/char/Makefile	Thu May 16 16:35:39 1996
@@ -190,6 +190,14 @@
   endif
 endif  
 
+ifeq ($(CONFIG_BAYCOM),y)
+L_OBJS += baycom.o
+else
+  ifeq ($(CONFIG_BAYCOM),m)
+  M_OBJS += baycom.o
+  endif
+endif  
+
 ifdef CONFIG_TGA_CONSOLE
 L_OBJS += tga.o
 else
diff -u --recursive --new-file pre2.0.4/linux/drivers/char/README.baycom linux/drivers/char/README.baycom
--- pre2.0.4/linux/drivers/char/README.baycom	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/README.baycom	Thu May 16 16:35:39 1996
@@ -0,0 +1,164 @@
+		    LINUX DRIVER FOR BAYCOM MODEMS
+
+	     Thomas M. Sailer <hb9jnx@radio.amiv.ethz.ch>
+
+This document describes the Linux Kernel Driver for simple Baycom style
+amateur radio modems. The driver supports the following modems:
+
+ser12: This is a very simple 1200 baud AFSK modem. The modem consists only
+       of a modulator/demodulator chip, usually a TI TCM3105. The computer
+       is responsible for regenerating the receiver bit clock, as well as
+       for handling the HDLC protocol. The modem connects to a serial port,
+       hence the name. Since the serial port is not used as an async serial
+       port, the kernel driver for serial ports cannot be used, and this
+       driver only supports standard serial hardware (8250, 16450, 16550)
+
+par96: This is a modem for 9600 baud FSK compatible to the G3RUH standard.
+       The modem does all the filtering and regenerates the receiver clock.
+       Data is transferred from and to the PC via a shift register.
+       The shift register is filled with 16 bits and an interrupt is signalled.
+       The PC then empties the shift register in a burst. This modem connects
+       to the parallel port, hence the name. The modem leaves the 
+       implementation of the HDLC protocol and the scrambler polynomial to
+       the PC.
+
+par97: This is a redesign of the par96 modem by Henning Rech, DF9IC. The modem
+       is protocol compatible to par96, but uses only three low power ICs
+       and can therefore be fed from the parallel port and does not require
+       an additional power supply.
+
+All of the above modems only support half duplex communications. However,
+the driver supports the KISS (see below) fullduplex command. It then simply
+starts to send as soon as there's a packet to transmit and does not care
+about DCD, i.e. it starts to send even if there's someone else on the channel.
+This command is required by some implementations of the DAMA channel 
+access protocol.
+
+
+The Interface of the driver
+
+The driver interfaces to the AX25 stack via a KISS interface. The driver
+can be accessed as a character device with major 60. Major 60 is the first
+number of the local/experimental range. I did no steps to coordinate a
+major number for this driver, but I plan to do so in the near future.
+The driver supports multiple modems (currently four, as defined with
+NR_PORTS). It therefore responds to minor numbers 0 to 3. I recommend
+to access the driver via the special device files /dev/bc[0-3], which
+can be created with 'make bc'.
+
+
+Compiling and installing the driver
+
+First unpack the source files into a directory. Then enter the following: (you
+must be root to do it)
+
+  make dep
+  make
+
+This will create the files baycom.o and setbaycom. baycom.o is as well copied
+to /lib/modules/`uname -n`/misc. If you plan to use kerneld, do the following:
+
+  depmod -a
+
+Do not forget to create the device special files if you install the driver the
+first time. This can be done with:
+
+  make bc
+
+You are now ready to use the driver. You can now activate the driver manually
+by entering
+
+  insmod baycom
+
+or leave this task to kerneld (if installed). Add the following line to
+/etc/conf.modules
+
+  alias char-major-60 baycom
+
+
+
+Configuring the driver
+
+Everytime the driver is inserted into the kernel, it has to know which
+modems it should access at which ports. This can be done with the setbaycom
+utility. If you are only using one modem, you can also configure the
+driver from the insmod command line (or by means of an option line in
+/etc/conf.modules).
+
+Examples:
+  insmod baycom modem=1 iobase=0x3f8 irq=4 options=1
+  setbaycom -i /dev/bc0 -p ser12 0x3f8 4 1
+
+Both lines configure the first port to drive a ser12 modem at the first
+serial port (COM1 under DOS). options=1 instructs the driver to use
+the software DCD algorithm (see below).
+
+  insmod baycom modem=2 iobase=0x378 irq=7 options=1
+  setbaycom -i /dev/bc0 -p par96 0x378 7 1
+
+Both lines configure the first port to drive a par96 or par97 modem at the
+first parallel port (LPT1 under DOS). options=1 instructs the driver to use
+the software DCD algorithm (see below).
+  
+The channel access parameters must be set through KISS parameter frames. The
+AX25 stack may be used to generate such frames. KA9Q NET derivatives such
+as WAMPES or TNOS offer the 'param' command for this purpose.
+
+
+
+Hardware DCD versus Software DCD
+
+To avoid collisions on the air, the driver must know when the channel is
+busy. This is the task of the DCD circuitry/software. The driver may either
+utilise a software DCD algorithm (options=1) or use a DCD signal from
+the hardware (options=0).
+
+ser12: if software DCD is utilised, the radio's squelch should always be
+       open. It is highly recommended to use the software DCD algorithm,
+       as it is much faster than most hardware squelch circuitry. The
+       disadvantage is a slightly higher load on the system.
+
+par96: the software DCD algorithm for this type of modem is rather poor.
+       The modem simply does not provide enough information to implement
+       a reasonable DCD algorithm in software. Therefore, if your radio
+       feeds the DCD input of the PAR96 modem, the use of the hardware
+       DCD circuitry is recommended.
+
+par97: as far as I know it is in this respect equivalent to par96.
+
+
+
+Compatibility with the rest of the Linux kernel
+
+The tty interface gave me some headaches. I did not find a reasonable
+documentation of its interfaces, so I'm not particularly sure if I implemented
+it the way I should. Perhaps someone with a more profound knowledge about
+tty drivers could check the interface routines.
+The driver produces a rather high interrupt load. par96/par97 generates 600
+interrupts per second, ser12 1200 while transmitting and 2400 if hardware
+DCD is used, 3600 otherwise. If other device drivers disable interrupts
+too long, the performance of the driver drops (the packet loss rate increases),
+especially with the ser12 modem.
+There were also reports that under rather high load situations the driver
+drops frames. This might be either an interrupt problem, or an AX25 stack
+running in user mode might not get enough CPU time to process the packets
+before the drivers internal buffers overflow. There is no way to throttle
+the other radio stations from this layer, throttling must be done in the
+AX25 layer.
+
+The serial driver, the line printer (lp) driver and the baycom driver compete
+for the same hardware resources. Of course only one driver can access a given
+interface at a time. The serial driver grabs all interfaces it can find at
+startup time. Therefore the baycom driver subsequently won't be able to
+access a serial port. You might therefore find it necessary to release
+a port owned by the serial driver with 'setserial /dev/ttyS# uart none', where
+# is the number of the interface. The baycom driver does not reserve any
+port at startup, unless one is specified on the 'insmod' command line. Another
+method to solve the problem is to compile all three drivers as modules and
+leave it to kerneld to load the correct driver depending on the application.
+
+
+
+vy 73s de
+Tom Sailer, hb9jnx@radio.amiv.ethz.ch
+hb9jnx @ hb9w.ampr.org
diff -u --recursive --new-file pre2.0.4/linux/drivers/char/apm_bios.c linux/drivers/char/apm_bios.c
--- pre2.0.4/linux/drivers/char/apm_bios.c	Sun May  5 08:51:59 1996
+++ linux/drivers/char/apm_bios.c	Wed May 15 09:06:55 1996
@@ -25,6 +25,7 @@
  *    (Thanks to Ulrich Windl <Ulrich.Windl@rz.uni-regensburg.de>)
  * April 1996, Stephen Rothwell (Stephen.Rothwell@canb.auug.org.au)
  *    Version 1.0 and 1.1
+ * May 1996, Version 1.2
  *
  * History:
  *    0.6b: first version in official kernel, Linux 1.3.46
@@ -35,6 +36,10 @@
  *         Linux 1.3.85
  *    1.1: support user-space standby and suspend, power off after system
  *         halted, Linux 1.3.98
+ *    1.2: When resetting RTC after resume, take care so that the the time
+ *         is only incorrect by 30-60mS (vs. 1S previously) (Gabor J. Toth
+ *         <jtoth@princeton.edu>); improve interaction between
+ *         screen-blanking and gpm (Stephen Rothwell); Linux 1.99.4
  *
  * Reference:
  *
@@ -334,7 +339,7 @@
 
 static struct timer_list	apm_timer;
 
-static char			driver_version[] = "1.1";/* no spaces */
+static char			driver_version[] = "1.2";/* no spaces */
 
 #ifdef APM_DEBUG
 static char *	apm_event_name[] = {
@@ -625,8 +630,9 @@
 				/* Estimate time zone so that set_time can
                                    update the clock */
 	save_flags(flags);
+	clock_cmos_diff = -get_cmos_time();
 	cli();
-	clock_cmos_diff = CURRENT_TIME - get_cmos_time();
+	clock_cmos_diff += CURRENT_TIME;
 	got_clock_diff = 1;
 	restore_flags(flags);
 	
diff -u --recursive --new-file pre2.0.4/linux/drivers/char/baycom.c linux/drivers/char/baycom.c
--- pre2.0.4/linux/drivers/char/baycom.c	Thu Jan  1 02:00:00 1970
+++ linux/drivers/char/baycom.c	Thu May 16 16:35:39 1996
@@ -0,0 +1,2168 @@
+/*****************************************************************************/
+
+/*
+ *	baycom.c  -- baycom ser12 and par96 radio modem driver.
+ *
+ *	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.
+ *
+ *
+ *  Supported modems
+ *
+ *  ser12: This is a very simple 1200 baud AFSK modem. The modem consists only
+ *         of a modulator/demodulator chip, usually a TI TCM3105. The computer
+ *         is responsible for regenerating the receiver bit clock, as well as
+ *         for handling the HDLC protocol. The modem connects to a serial port,
+ *         hence the name. Since the serial port is not used as an async serial
+ *         port, the kernel driver for serial ports cannot be used, and this
+ *         driver only supports standard serial hardware (8250, 16450, 16550)
+ *  
+ *  par96: This is a modem for 9600 baud FSK compatible to the G3RUH standard.
+ *         The modem does all the filtering and regenerates the receiver clock.
+ *         Data is transferred from and to the PC via a shift register.
+ *         The shift register is filled with 16 bits and an interrupt is
+ *         signalled. The PC then empties the shift register in a burst. This
+ *         modem connects to the parallel port, hence the name. The modem
+ *         leaves the implementation of the HDLC protocol and the scrambler
+ *         polynomial to the PC.
+ *  
+ *  par97: This is a redesign of the par96 modem by Henning Rech, DF9IC. The
+ *         modem is protocol compatible to par96, but uses only three low
+ *         power ICs and can therefore be fed from the parallel port and
+ *         does not require an additional power supply.
+ *
+ *
+ *  Command line options (insmod command line)
+ * 
+ *  major    major number the driver should use; default 60 
+ *  modem    modem type of the first channel (minor 0); 1=ser12,
+ *           2=par96/par97, any other value invalid
+ *  iobase   base address of the port; common values are for ser12 0x3f8,
+ *           0x2f8, 0x3e8, 0x2e8 and for par96/par97 0x378, 0x278, 0x3bc
+ *  irq      interrupt line of the port; common values are for ser12 3,4
+ *           and for par96/par97 7
+ *  options  0=use hardware DCD, 1=use software DCD
+ * 
+ *
+ *  History:
+ *   0.1  03.05.96  Renamed from ser12 0.5 and added support for par96
+ *                  Various resource allocation cleanups
+ *   0.2  12.05.96  Changed major to allocated 51. Integrated into kernel
+ *                  source tree
+ */
+
+/*****************************************************************************/
+
+#include <linux/module.h>
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/major.h>
+#include <asm/segment.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#include <linux/baycom.h>
+
+/* --------------------------------------------------------------------- */
+
+#define BAYCOM_TYPE_NORMAL 0		/* not used */
+#define TTY_DRIVER_TYPE_BAYCOM 6
+
+/*
+ * ser12 options:
+ * BAYCOM_OPTIONS_SOFTDCD: if undefined, you must use the transmitters
+ * hardware carrier detect circuitry, the driver will report DCD as soon as
+ * there are transitions on the input line. Advantage: lower interrupt load
+ * on the system. Disadvantage: slower, since hardware carrier detect
+ * circuitry is usually slow.
+ */
+
+#define BUFLEN_RX 16384
+#define BUFLEN_TX 16384
+
+#define NR_PORTS 4
+
+#define KISS_VERBOSE
+#undef HDLC_LOOPBACK
+
+#define BAYCOM_MAGIC 0x3105bac0
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * user settable parameters (from the command line)
+ */
+#ifndef MODULE
+static
+#endif /* MODULE */
+int major = BAYCOM_MAJOR;
+
+/* --------------------------------------------------------------------- */
+
+static struct tty_struct *baycom_table[NR_PORTS];
+static struct termios *baycom_termios[NR_PORTS];
+static struct termios *baycom_termios_locked[NR_PORTS];
+
+static int baycom_refcount;
+
+static struct tty_driver baycom_driver;
+
+static struct {
+	int modem, iobase, irq, options;
+} baycom_ports[NR_PORTS] = { { BAYCOM_MODEM_INVALID, 0, 0, 0, }, };
+
+/* --------------------------------------------------------------------- */
+
+#define RBR(iobase) (iobase+0)
+#define THR(iobase) (iobase+0)
+#define IER(iobase) (iobase+1)
+#define IIR(iobase) (iobase+2)
+#define FCR(iobase) (iobase+2)
+#define LCR(iobase) (iobase+3)
+#define MCR(iobase) (iobase+4)
+#define LSR(iobase) (iobase+5)
+#define MSR(iobase) (iobase+6)
+#define SCR(iobase) (iobase+7)
+#define DLL(iobase) (iobase+0)
+#define DLM(iobase) (iobase+1)
+
+#define SER12_EXTENT 8
+
+#define LPT_DATA(iobase)    (iobase+0)
+#define LPT_STATUS(iobase)  (iobase+1)
+#define LPT_CONTROL(iobase) (iobase+2)
+#define LPT_IRQ_ENABLE      0x10
+#define PAR96_BURSTBITS 16
+#define PAR96_BURST     4
+#define PAR96_PTT       2
+#define PAR96_TXBIT     1
+#define PAR96_ACK       0x40
+#define PAR96_RXBIT     0x20
+#define PAR96_DCD       0x10
+#define PAR97_POWER     0xf8
+
+#define PAR96_EXTENT 3
+
+/* ---------------------------------------------------------------------- */
+
+struct access_params {
+	int tx_delay;
+	int tx_tail;
+	int slottime;
+	int ppersist;
+	int fulldup;
+};
+
+struct hdlc_state_rx {
+	int rx_state;	/* 0 = sync hunt, != 0 receiving */
+	unsigned char lastbit;
+	unsigned int bitstream;
+	unsigned int assembly;
+	
+	int len;
+	unsigned char *bp;
+	unsigned char buffer[BAYCOM_MAXFLEN+2];	   /* make room for CRC */
+};
+
+struct hdlc_state_tx {
+	/*
+	 * 0 = send flags
+	 * 1 = send txtail (flags)
+	 * 2 = send packet
+	 */
+	int tx_state;	
+	int numflags;
+	unsigned int bitstream;
+	unsigned int current_byte;
+	unsigned char ptt;
+
+	int len;
+	unsigned char *bp;
+	unsigned char buffer[BAYCOM_MAXFLEN+2];		/* make room for CRC */
+};
+
+struct modem_state_ser12 {
+	unsigned char last_sample;
+	unsigned char interm_sample;
+	unsigned int bit_pll;
+	unsigned int dcd_shreg;
+	int dcd_sum0, dcd_sum1, dcd_sum2;
+	unsigned int dcd_time;
+	unsigned char last_rxbit;
+	unsigned char tx_bit;
+};
+
+struct modem_state_par96 {
+	int dcd_count;
+	unsigned int dcd_shreg;
+	unsigned long descram;
+	unsigned long scram;
+	unsigned int tx_bits;
+};
+
+struct modem_state {
+	unsigned char dcd;
+	short arb_divider;
+	struct modem_state_ser12 ser12;
+	struct modem_state_par96 par96;
+};
+
+struct packet_buffer {
+	unsigned int rd;
+	unsigned int wr;
+	
+	unsigned int buflen;
+	unsigned char *buffer;
+};
+
+struct packet_hdr {
+	unsigned int next;
+	unsigned int len;
+	/* packet following */
+};
+
+#ifdef BAYCOM_DEBUG
+struct bit_buffer {
+	unsigned int rd;
+	unsigned int wr;
+	unsigned int shreg;
+	unsigned char buffer[64];
+};
+
+struct debug_vals {
+	unsigned long last_jiffies;
+	unsigned cur_intcnt;
+	unsigned last_intcnt;
+	int cur_pllcorr;
+	int last_pllcorr;
+};
+#endif /* BAYCOM_DEBUG */
+
+struct kiss_decode {
+	unsigned char dec_state; /* 0 = hunt FEND */
+	unsigned char escaped;
+	unsigned char pkt_buf[BAYCOM_MAXFLEN+1];
+	unsigned int wr;
+};
+
+/* ---------------------------------------------------------------------- */
+
+struct baycom_state {
+	int magic;
+
+	unsigned char modem_type;
+
+	unsigned int iobase;
+	unsigned int irq;
+	unsigned int options;
+
+	int opened;
+	struct tty_struct *tty;
+
+	struct packet_buffer rx_buf;
+	struct packet_buffer tx_buf;
+
+	struct access_params ch_params;
+
+	struct hdlc_state_rx hdlc_rx;
+	struct hdlc_state_tx hdlc_tx;
+
+	int calibrate;
+
+	struct modem_state modem;
+
+#ifdef BAYCOM_DEBUG
+	struct bit_buffer bitbuf_channel;
+	struct bit_buffer bitbuf_hdlc;
+	
+	struct debug_vals debug_vals;
+#endif /* BAYCOM_DEBUG */
+
+	struct kiss_decode kiss_decode;
+
+	struct baycom_statistics stat;
+};
+
+/* --------------------------------------------------------------------- */
+
+struct baycom_state baycom_state[NR_PORTS];
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * the CRC routines are stolen from WAMPES
+ * by Dieter Deyke
+ */
+
+static const unsigned short crc_ccitt_table[] = {
+	0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
+	0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
+	0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
+	0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
+	0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
+	0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
+	0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
+	0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
+	0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
+	0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
+	0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
+	0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
+	0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
+	0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
+	0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
+	0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
+	0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
+	0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
+	0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
+	0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
+	0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
+	0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
+	0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
+	0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
+	0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
+	0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
+	0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
+	0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
+	0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
+	0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
+	0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
+	0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
+};
+
+/*---------------------------------------------------------------------------*/
+
+static inline void append_crc_ccitt(unsigned char *buffer, int len)
+{
+ 	unsigned int crc = 0xffff;
+
+	for (;len>0;len--)
+		crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buffer++) & 0xff];
+	crc ^= 0xffff;
+	*buffer++ = crc;
+	*buffer++ = crc >> 8;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static inline int check_crc_ccitt(const unsigned char *buf,int cnt)
+{
+	unsigned int crc = 0xffff;
+
+	for (; cnt > 0; cnt--)
+		crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff];
+	return (crc & 0xffff) == 0xf0b8;
+}
+
+/*---------------------------------------------------------------------------*/
+
+#if 0
+static int calc_crc_ccitt(const unsigned char *buf,int cnt)
+{
+	unsigned int crc = 0xffff;
+
+	for (; cnt > 0; cnt--)
+		crc = (crc >> 8) ^ crc_ccitt_table[(crc ^ *buf++) & 0xff];
+	crc ^= 0xffff;
+	return (crc & 0xffff);
+}
+#endif
+
+/* ---------------------------------------------------------------------- */
+
+static int store_packet(struct packet_buffer *buf, unsigned char *data,
+	char from_user, unsigned int len)
+{
+	unsigned int free;
+	struct packet_hdr *hdr;
+	unsigned int needed = sizeof(struct packet_hdr)+len;
+	
+	free = buf->rd-buf->wr;
+	if(buf->rd <= buf->wr) {
+		free = buf->buflen - buf->wr;
+		if((free < needed) && (buf->rd >= needed)) {
+			hdr = (struct packet_hdr *)(buf->buffer+buf->wr);
+			hdr->next = 0;
+			hdr->len = 0;
+			buf->wr = 0;
+			free = buf->rd;
+		}
+	}
+	if(free < needed) return 0;		/* buffer overrun */
+	hdr = (struct packet_hdr *)(buf->buffer+buf->wr);
+	if (from_user) 
+		memcpy_fromfs(hdr+1,data,len);
+	else
+		memcpy(hdr+1,data,len);
+	hdr->len = len;
+	hdr->next = buf->wr+needed;
+	if (hdr->next + sizeof(struct packet_hdr) >= buf->buflen)
+		hdr->next = 0;
+	buf->wr = hdr->next;
+	return 1;
+}
+	
+/* ---------------------------------------------------------------------- */
+
+static void get_packet(struct packet_buffer *buf, unsigned char **data,
+	unsigned int *len)
+{
+	struct packet_hdr *hdr;
+	
+	*data = NULL;
+	*len = 0;
+	if (buf->rd == buf->wr)
+		return;
+	hdr = (struct packet_hdr *)(buf->buffer+buf->rd);
+	while (!(hdr->len)) {
+		buf->rd = hdr->next;
+		if (buf->rd == buf->wr)
+			return;
+		hdr = (struct packet_hdr *)(buf->buffer+buf->rd);
+	}
+	*data = (unsigned char *)(hdr+1);
+	*len = hdr->len;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void ack_packet(struct packet_buffer *buf)
+{
+	struct packet_hdr *hdr;
+	
+	if (buf->rd == buf->wr)
+		return;
+	hdr = (struct packet_hdr *)(buf->buffer+buf->rd);
+	buf->rd = hdr->next;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int store_kiss_packet(struct packet_buffer *buf, unsigned char *data,
+	unsigned int len)
+{
+	unsigned char *bp = data;
+	int ln = len;
+	/*
+	 * variables of buf
+	 */
+	unsigned int rd;
+	unsigned int wr;
+	unsigned int buflen;
+	unsigned char *buffer;
+
+	if (!len || !data || !buf)
+		return 0;
+	buflen = buf->buflen;
+	rd = buf->rd;
+	wr = buf->wr;
+	buffer = buf->buffer;
+	
+#define ADD_CHAR(c) {\
+		buffer[wr++] = c;\
+		if (wr >= buflen) wr = 0;\
+		if (wr == rd) return 0;\
+	}
+#define ADD_KISSCHAR(c) {\
+		if (((c) & 0xff) == KISS_FEND) {\
+			ADD_CHAR(KISS_FESC);\
+			ADD_CHAR(KISS_TFEND);\
+		} else if (((c) & 0xff) == KISS_FESC) {\
+			ADD_CHAR(KISS_FESC);\
+			ADD_CHAR(KISS_TFESC);\
+		} else {\
+			ADD_CHAR(c);\
+		}\
+	}
+
+	ADD_CHAR(KISS_FEND);
+	ADD_KISSCHAR(KISS_CMD_DATA);
+	for(; ln > 0; ln--,bp++) {
+		ADD_KISSCHAR(*bp);
+	}
+	ADD_CHAR(KISS_FEND);
+	buf->wr = wr;
+#undef ADD_CHAR
+#undef ADD_KISSCHAR
+	return 1;
+}
+
+/* ---------------------------------------------------------------------- */
+
+#ifdef BAYCOM_DEBUG
+static inline void add_bitbuffer(struct bit_buffer * buf, unsigned int bit)
+{
+	if (!buf) return;
+	buf->shreg <<= 1;
+	if (bit)
+		buf->shreg |= 1;
+	if (buf->shreg & 0x100) {
+		buf->buffer[buf->wr] = buf->shreg;
+		buf->wr = (buf->wr+1) % sizeof(buf->buffer);
+		buf->shreg = 1;
+	}
+}
+#endif /* BAYCOM_DEBUG */
+
+/* ---------------------------------------------------------------------- */
+
+static inline unsigned int tenms_to_flags(struct baycom_state *bc, 
+					  unsigned int tenms)
+{
+	switch (bc->modem_type) {
+	case BAYCOM_MODEM_SER12:
+		return tenms * 12 / 8;
+	case BAYCOM_MODEM_PAR96:
+		return tenms * 12;
+	default:
+		return 0;
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+/*
+ * The HDLC routines could be more efficient; they could take more than
+ * one bit per call
+ */
+
+static void hdlc_rx_bit(struct baycom_state *bc, unsigned int bit)
+{
+	if (!bc) return;
+
+	bc->hdlc_rx.bitstream <<= 1;
+	if (bit)
+		bc->hdlc_rx.bitstream |= 1;
+#ifdef BAYCOM_DEBUG
+	add_bitbuffer(&bc->bitbuf_hdlc, bc->hdlc_rx.bitstream & 1);
+#endif /* BAYCOM_DEBUG */
+	if(bc->hdlc_rx.rx_state) {
+		if ((bc->hdlc_rx.bitstream & 0x3f) != 0x3e) {
+			/* not a stuffed bit */
+			if (bc->hdlc_rx.bitstream & 1)
+				bc->hdlc_rx.assembly |= 0x100;
+			if (bc->hdlc_rx.assembly & 1) {
+				/* store byte */
+				if (bc->hdlc_rx.len >= sizeof(bc->hdlc_rx.buffer)) {
+					bc->hdlc_rx.rx_state = 0;
+				} else {
+					*bc->hdlc_rx.bp++ = bc->hdlc_rx.assembly>>1;
+					bc->hdlc_rx.len++;
+					bc->hdlc_rx.assembly = 0x80;
+				}
+			} else {
+				bc->hdlc_rx.assembly >>= 1;
+			}
+		}
+		if ((bc->hdlc_rx.bitstream & 0x7f) == 0x7e) {
+			if (bc->hdlc_rx.len >= 4) {
+				if (check_crc_ccitt(bc->hdlc_rx.buffer,bc->hdlc_rx.len)) {
+					bc->stat.rx_packets++;
+					if (!store_kiss_packet(&bc->rx_buf,bc->hdlc_rx.buffer,bc->hdlc_rx.len-2))
+						bc->stat.rx_bufferoverrun++;
+				}
+			}
+			bc->hdlc_rx.len = 0;
+			bc->hdlc_rx.bp = bc->hdlc_rx.buffer;
+			bc->hdlc_rx.assembly = 0x80;
+		}
+		if ((bc->hdlc_rx.bitstream & 0x7f) == 0x7f)
+			bc->hdlc_rx.rx_state = 0;
+	} else {
+		if ((bc->hdlc_rx.bitstream & 0x7f) == 0x7e) {
+			bc->hdlc_rx.len = 0;
+			bc->hdlc_rx.bp = bc->hdlc_rx.buffer;
+			bc->hdlc_rx.assembly = 0x80;
+			bc->hdlc_rx.rx_state = 1;
+		}
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+
+static unsigned char hdlc_tx_bit(struct baycom_state *bc)
+{
+	unsigned char bit;
+
+	if (!bc || !bc->hdlc_tx.ptt)
+		return 0;
+	for(;;) {
+		switch (bc->hdlc_tx.tx_state) {
+		default:
+			bc->hdlc_tx.ptt = 0;
+			bc->hdlc_tx.tx_state = 0;
+			return 0;
+		case 0:
+		case 1:
+			if (bc->hdlc_tx.current_byte > 1) {
+				/*
+				 * return bit 
+				 */
+				bit = bc->hdlc_tx.current_byte & 1;
+				bc->hdlc_tx.current_byte >>= 1;
+				return bit;
+			}
+			/*
+			 * get new bit 
+			 */
+			if (bc->hdlc_tx.numflags) {
+				bc->hdlc_tx.numflags--;
+				bc->hdlc_tx.current_byte = 0x17e;
+			} else {
+				if (bc->hdlc_tx.tx_state == 1) {
+					bc->hdlc_tx.ptt = 0;
+					return 0;
+				}
+				get_packet(&bc->tx_buf, &bc->hdlc_tx.bp,
+					   &bc->hdlc_tx.len);
+				if (!bc->hdlc_tx.bp || !bc->hdlc_tx.len) {
+					bc->hdlc_tx.tx_state = 1;
+					bc->hdlc_tx.current_byte = 0;
+					bc->hdlc_tx.numflags = tenms_to_flags
+						(bc, bc->ch_params.tx_tail);
+				} else if (bc->hdlc_tx.len >= BAYCOM_MAXFLEN) {
+					bc->hdlc_tx.tx_state = 0;
+					bc->hdlc_tx.current_byte = 0;
+					bc->hdlc_tx.numflags = 1;
+					ack_packet(&bc->tx_buf);
+				} else {
+					memcpy(bc->hdlc_tx.buffer,
+					       bc->hdlc_tx.bp, 
+					       bc->hdlc_tx.len);
+					ack_packet(&bc->tx_buf);
+					bc->hdlc_tx.bp = bc->hdlc_tx.buffer;
+					append_crc_ccitt(bc->hdlc_tx.buffer,
+							 bc->hdlc_tx.len);
+					/* the appended CRC */
+					bc->hdlc_tx.len += 2; 
+					bc->hdlc_tx.tx_state = 2;
+					bc->hdlc_tx.current_byte = 0;
+					bc->hdlc_tx.bitstream = 0;
+					bc->stat.tx_packets++;
+				}
+			}
+			break;
+		case 2:
+			if ((bc->hdlc_tx.bitstream & 0x1f) == 0x1f) {
+				/*
+				 * bit stuffing
+				 */
+				bc->hdlc_tx.bitstream <<= 1;
+				return 0;
+			}
+			if (bc->hdlc_tx.current_byte > 1) {
+				/*
+				 * return bit 
+				 */
+				bc->hdlc_tx.bitstream <<= 1;
+				bit = bc->hdlc_tx.current_byte & 1;
+				bc->hdlc_tx.bitstream |= bit;
+				bc->hdlc_tx.current_byte >>= 1;
+				return bit;
+			}
+			if (!bc->hdlc_tx.len) {
+				bc->hdlc_tx.tx_state = 0;
+				bc->hdlc_tx.current_byte = 0;
+				bc->hdlc_tx.numflags = 1;
+			} else {
+				bc->hdlc_tx.len--;
+				bc->hdlc_tx.current_byte = 0x100 | 
+					(*bc->hdlc_tx.bp++);
+			}
+			break;
+		}
+	}
+}
+
+/* ---------------------------------------------------------------------- */
+
+static unsigned short random_seed;
+
+static inline unsigned short random_num(void)
+{
+	random_seed = 28629 * random_seed + 157;
+	return random_seed;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static inline void tx_arbitrate(struct baycom_state *bc)
+{
+	unsigned char *bp;
+	unsigned int len;
+	
+	if (!bc || bc->hdlc_tx.ptt || bc->modem.dcd)
+		return;
+	get_packet(&bc->tx_buf,&bp,&len);
+	if (!bp || !len)
+		return;
+	
+	if (!bc->ch_params.fulldup) {
+		if ((random_num() % 256) > bc->ch_params.ppersist)
+			return;
+	}
+	bc->hdlc_tx.ptt = 1;
+	bc->hdlc_tx.tx_state = 0;
+	bc->hdlc_tx.numflags = tenms_to_flags(bc, bc->ch_params.tx_delay);
+	bc->stat.ptt_keyed++;
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef BAYCOM_DEBUG
+static void inline baycom_int_freq(struct baycom_state *bc)
+{
+	unsigned long cur_jiffies = jiffies;
+	/* 
+	 * measure the interrupt frequency
+	 */
+	bc->debug_vals.cur_intcnt++;
+	if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
+		bc->debug_vals.last_jiffies = cur_jiffies;
+		bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
+		bc->debug_vals.cur_intcnt = 0;
+		bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr;
+		bc->debug_vals.cur_pllcorr = 0;
+	}
+}
+#endif /* BAYCOM_DEBUG */
+
+/* --------------------------------------------------------------------- */
+
+static inline void rx_chars_to_flip(struct baycom_state *bc) 
+{
+	int flip_free;
+	unsigned int cnt;
+	unsigned int new_rd;
+	unsigned long flags;
+
+	if ((!bc) || (!bc->tty) || (bc->tty->flip.count >= TTY_FLIPBUF_SIZE) ||
+	    (bc->rx_buf.rd == bc->rx_buf.wr) || 
+	    (!bc->tty->flip.char_buf_ptr) ||
+	    (!bc->tty->flip.flag_buf_ptr))
+		return;
+	for(;;) {
+		flip_free = TTY_FLIPBUF_SIZE - bc->tty->flip.count;
+		if (bc->rx_buf.rd <= bc->rx_buf.wr)
+			cnt = bc->rx_buf.wr - bc->rx_buf.rd;
+		else
+			cnt = bc->rx_buf.buflen - bc->rx_buf.rd;
+		if ((flip_free <= 0) || (!cnt)) {
+			tty_schedule_flip(bc->tty);
+			return;
+		}
+		if (cnt > flip_free)
+			cnt = flip_free;
+		save_flags(flags); cli();
+		memcpy(bc->tty->flip.char_buf_ptr, bc->rx_buf.buffer+bc->rx_buf.rd, cnt);
+		memset(bc->tty->flip.flag_buf_ptr, TTY_NORMAL, cnt);
+		bc->tty->flip.count += cnt;
+		bc->tty->flip.char_buf_ptr += cnt;
+		bc->tty->flip.flag_buf_ptr += cnt;
+		restore_flags(flags);
+		new_rd = bc->rx_buf.rd+cnt;
+		if (new_rd >= bc->rx_buf.buflen)
+			new_rd -= bc->rx_buf.buflen;
+		bc->rx_buf.rd = new_rd;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+/*
+ * ===================== SER12 specific routines =========================
+ */
+
+static void inline ser12_set_divisor(struct baycom_state *bc, 
+				     unsigned char divisor)
+{
+	outb(0x81, LCR(bc->iobase));	/* DLAB = 1 */
+	outb(divisor, DLL(bc->iobase));
+	outb(0, DLM(bc->iobase));
+	outb(0x01, LCR(bc->iobase));	/* word length = 6 */
+}
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * must call the TX arbitrator every 10ms
+ */
+#define SER12_ARB_DIVIDER(bc) ((bc->options & BAYCOM_OPTIONS_SOFTDCD) ? \
+			       36 : 24)
+#define SER12_DCD_INTERVAL(bc) ((bc->options & BAYCOM_OPTIONS_SOFTDCD) ? \
+				240 : 12)
+
+static void baycom_ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct baycom_state *bc = (struct baycom_state *)dev_id;
+	unsigned char cur_s;
+	
+	if (!bc || bc->magic != BAYCOM_MAGIC)
+		return;
+	/*
+	 * make sure the next interrupt is generated;
+	 * 0 must be used to power the modem; the modem draws its
+	 * power from the TxD line
+	 */	
+	outb(0x00, THR(bc->iobase));
+	rx_chars_to_flip(bc);
+#ifdef BAYCOM_DEBUG
+	baycom_int_freq(bc);
+#endif /* BAYCOM_DEBUG */
+	/*
+	 * check if transmitter active
+	 */
+	if (bc->hdlc_tx.ptt || bc->calibrate > 0) {
+		ser12_set_divisor(bc, 12); /* one interrupt per channel bit */
+		/*
+		 * first output the last bit (!) then call HDLC transmitter,
+		 * since this may take quite long
+		 */
+		outb(0x0e | (bc->modem.ser12.tx_bit ? 1 : 0), MCR(bc->iobase));
+		if (bc->calibrate > 0) {
+			bc->modem.ser12.tx_bit = !bc->modem.ser12.tx_bit;
+			bc->calibrate--;
+			return;
+		}
+#ifdef HDLC_LOOPBACK
+		hdlc_rx_bit(bc, bc->modem.ser12.tx_bit == 
+			    bc->modem.ser12.last_rxbit);
+		bc->modem.ser12.last_rxbit = bc->modem.ser12.tx_bit;
+#endif /* HDLC_LOOPBACK */
+		if (!hdlc_tx_bit(bc))
+			bc->modem.ser12.tx_bit = !bc->modem.ser12.tx_bit;
+		return;
+	}
+	/*
+	 * do demodulator
+	 */
+	outb(0x0d, MCR(bc->iobase));			/* transmitter off */
+	cur_s = inb(MSR(bc->iobase)) & 0x10;	/* the CTS line */
+#ifdef BAYCOM_DEBUG
+	add_bitbuffer(&bc->bitbuf_channel, cur_s);
+#endif /* BAYCOM_DEBUG */
+	bc->modem.ser12.dcd_shreg <<= 1;
+	if(cur_s != bc->modem.ser12.last_sample) {
+		bc->modem.ser12.dcd_shreg |= 1;
+
+		if (bc->options & BAYCOM_OPTIONS_SOFTDCD) {
+			unsigned int dcdspos, dcdsneg;
+
+			dcdspos = dcdsneg = 0;
+			dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1);
+			if (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe))
+				dcdspos += 2;
+			dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1);
+			dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1);
+			dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1);
+
+			bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg;
+		} else
+			bc->modem.ser12.dcd_sum0--;
+	}
+	bc->modem.ser12.last_sample = cur_s;
+	if(!bc->modem.ser12.dcd_time) {
+		bc->modem.dcd = (bc->modem.ser12.dcd_sum0 + 
+				 bc->modem.ser12.dcd_sum1 +
+				 bc->modem.ser12.dcd_sum2) < 0;
+		bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
+		bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
+		/* offset to ensure DCD off on silent input */
+		bc->modem.ser12.dcd_sum0 = 2;
+		bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc);
+	}
+	bc->modem.ser12.dcd_time--;
+	if (bc->options & BAYCOM_OPTIONS_SOFTDCD) {
+		/*
+		 * PLL code for the improved software DCD algorithm
+		 */
+		if (bc->modem.ser12.interm_sample) {
+			/*
+			 * intermediate sample; set timing correction to normal
+			 */
+			ser12_set_divisor(bc, 4);
+		} else {
+			/*
+			 * do PLL correction and call HDLC receiver
+			 */
+			switch (bc->modem.ser12.dcd_shreg & 7) {
+			case 1: /* transition too late */
+				ser12_set_divisor(bc, 5);
+#ifdef BAYCOM_DEBUG
+				bc->debug_vals.cur_pllcorr++;
+#endif /* BAYCOM_DEBUG */
+				break;
+			case 4:	/* transition too early */
+				ser12_set_divisor(bc, 3);
+#ifdef BAYCOM_DEBUG
+				bc->debug_vals.cur_pllcorr--;
+#endif /* BAYCOM_DEBUG */
+				break;
+			default:
+				ser12_set_divisor(bc, 4);
+				break;
+			}
+			hdlc_rx_bit(bc, bc->modem.ser12.last_sample == 
+			    bc->modem.ser12.last_rxbit);
+			bc->modem.ser12.last_rxbit = 
+				bc->modem.ser12.last_sample;
+		}
+		if (++bc->modem.ser12.interm_sample >= 3)
+			bc->modem.ser12.interm_sample = 0;		
+	} else {
+		/*
+		 * PLL algorithm for the hardware squelch DCD algorithm
+		 */
+		if (bc->modem.ser12.interm_sample) {
+			/*
+			 * intermediate sample; set timing correction to normal
+			 */
+			ser12_set_divisor(bc, 6);
+		} else {
+			/*
+			 * do PLL correction and call HDLC receiver
+			 */
+			switch (bc->modem.ser12.dcd_shreg & 3) {
+			case 1: /* transition too late */
+				ser12_set_divisor(bc, 7);
+#ifdef BAYCOM_DEBUG
+				bc->debug_vals.cur_pllcorr++;
+#endif /* BAYCOM_DEBUG */
+				break;
+			case 2:	/* transition too early */
+				ser12_set_divisor(bc, 5);
+#ifdef BAYCOM_DEBUG
+				bc->debug_vals.cur_pllcorr--;
+#endif /* BAYCOM_DEBUG */
+				break;
+			default:
+				ser12_set_divisor(bc, 6);
+				break;
+			}
+			hdlc_rx_bit(bc, bc->modem.ser12.last_sample == 
+			    bc->modem.ser12.last_rxbit);
+			bc->modem.ser12.last_rxbit = 
+				bc->modem.ser12.last_sample;
+		}
+		bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample;
+	}
+	if (--bc->modem.arb_divider <= 0) {
+		tx_arbitrate(bc);
+		bc->modem.arb_divider = bc->ch_params.slottime * 
+			SER12_ARB_DIVIDER(bc);
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+enum uart { c_uart_unknown, c_uart_8250,
+	c_uart_16450, c_uart_16550, c_uart_16550A};
+static const char *uart_str[] =
+	{ "unknown", "8250", "16450", "16550", "16550A" };
+
+static enum uart ser12_check_uart(unsigned int iobase)
+{
+	unsigned char b1,b2,b3;
+	enum uart u;
+	enum uart uart_tab[] =
+		{ c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };
+
+	b1 = inb(MCR(iobase));
+	outb(b1 | 0x10, MCR(iobase));	/* loopback mode */
+	b2 = inb(MSR(iobase));
+	outb(0x1a, MCR(iobase));
+	b3 = inb(MSR(iobase)) & 0xf0;
+	outb(b1, MCR(iobase));			/* restore old values */
+	outb(b2, MSR(iobase));
+	if (b3 != 0x90) 
+		return c_uart_unknown;
+	inb(RBR(iobase));
+	inb(RBR(iobase));
+	outb(0x01, FCR(iobase));		/* enable FIFOs */
+	u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];
+	if (u == c_uart_16450) {
+		outb(0x5a, SCR(iobase));
+		b1 = inb(SCR(iobase));
+		outb(0xa5, SCR(iobase));
+		b2 = inb(SCR(iobase));
+		if ((b1 != 0x5a) || (b2 != 0xa5)) 
+			u = c_uart_8250;
+	}
+	return u;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int ser12_allocate_resources(unsigned int iobase, unsigned int irq,
+				    unsigned int options)
+{
+	enum uart u;
+
+	if (!iobase || iobase > 0xfff || irq < 2 || irq > 15)
+		return -ENXIO;
+	if (check_region(iobase, SER12_EXTENT))
+		return -EACCES;
+	if ((u = ser12_check_uart(iobase)) == c_uart_unknown)
+		return -EIO;
+	request_region(iobase, SER12_EXTENT, "baycom_ser12");
+	outb(0, FCR(iobase));		/* disable FIFOs */
+	outb(0x0d, MCR(iobase));
+	printk(KERN_INFO "baycom: ser12 at iobase 0x%x irq %u options 0x%x "
+	       "uart %s\n", iobase, irq, options, uart_str[u]);
+	return 0;
+}
+	
+/* --------------------------------------------------------------------- */
+
+static void ser12_deallocate_resources(struct baycom_state *bc) 
+{
+	if (!bc || bc->modem_type != BAYCOM_MODEM_SER12)
+		return;
+	/*
+	 * disable interrupts
+	 */
+	outb(0, IER(bc->iobase));
+	outb(1, MCR(bc->iobase));
+	/* 
+	 * this should prevent kernel: Trying to free IRQx
+	 * messages
+	 */
+	if (bc->opened > 0)
+		free_irq(bc->irq, bc);
+	release_region(bc->iobase, SER12_EXTENT);
+	bc->modem_type = BAYCOM_MODEM_INVALID;
+	printk(KERN_INFO "baycom: release ser12 at iobase 0x%x irq %u\n",
+	       bc->iobase, bc->irq);
+	bc->iobase = bc->irq = bc->options = 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int ser12_on_open(struct baycom_state *bc) 
+{
+	if (!bc || bc->modem_type != BAYCOM_MODEM_SER12)
+		return -ENXIO;
+	/*
+	 * set the SIO to 6 Bits/character and 19200 or 28800 baud, so that
+	 * we get exactly (hopefully) 2 or 3 interrupts per radio symbol,
+	 * depending on the usage of the software DCD routine
+	 */
+	ser12_set_divisor(bc, (bc->options & BAYCOM_OPTIONS_SOFTDCD) ? 4 : 6);
+	outb(0x0d, MCR(bc->iobase));
+	outb(0, IER(bc->iobase));
+	if (request_irq(bc->irq, baycom_ser12_interrupt, 0, 
+			"baycom_ser12", bc))
+		return -EBUSY;
+	/*
+	 * enable transmitter empty interrupt
+	 */
+	outb(2, IER(bc->iobase));  
+	/* 
+	 * the value here serves to power the modem
+	 */     
+	outb(0x00, THR(bc->iobase));
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void ser12_on_close(struct baycom_state *bc) 
+{
+	if (!bc || bc->modem_type != BAYCOM_MODEM_SER12)
+		return;
+	/*
+	 * disable interrupts
+	 */
+	outb(0, IER(bc->iobase));
+	outb(1, MCR(bc->iobase));
+	free_irq(bc->irq, bc);	
+}
+
+/* --------------------------------------------------------------------- */
+/*
+ * ===================== PAR96 specific routines =========================
+ */
+
+#define PAR96_DESCRAM_TAP1 0x20000
+#define PAR96_DESCRAM_TAP2 0x01000
+#define PAR96_DESCRAM_TAP3 0x00001
+
+#define PAR96_DESCRAM_TAPSH1 17
+#define PAR96_DESCRAM_TAPSH2 12
+#define PAR96_DESCRAM_TAPSH3 0
+
+#define PAR96_SCRAM_TAP1 0x20000 /* X^17 */
+#define PAR96_SCRAM_TAPN 0x00021 /* X^0+X^5 */
+
+/* --------------------------------------------------------------------- */
+
+static void baycom_par96_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	register struct baycom_state *bc = (struct baycom_state *)dev_id;
+	int i;
+	unsigned int data, mask, mask2;
+	
+	if (!bc || bc->magic != BAYCOM_MAGIC)
+		return;
+
+	rx_chars_to_flip(bc);
+#ifdef BAYCOM_DEBUG
+	baycom_int_freq(bc);
+#endif /* BAYCOM_DEBUG */
+	/*
+	 * check if transmitter active
+	 */
+	if (bc->hdlc_tx.ptt || bc->calibrate > 0) {
+		/*
+		 * first output the last 16 bits (!) then call HDLC
+		 * transmitter, since this may take quite long
+		 * do the differential encoder and the scrambler on the fly
+		 */
+		data = bc->modem.par96.tx_bits;
+		for(i = 0; i < PAR96_BURSTBITS; i++, data <<= 1) {
+			unsigned char val = PAR97_POWER;
+			bc->modem.par96.scram = ((bc->modem.par96.scram << 1) |
+						 (bc->modem.par96.scram & 1));
+			if (!(data & 0x8000))
+				bc->modem.par96.scram ^= 1;
+			if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 1))
+				bc->modem.par96.scram ^= 
+					(PAR96_SCRAM_TAPN << 1);
+			if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 2))
+				val |= PAR96_TXBIT;
+			outb(val, LPT_DATA(bc->iobase));
+			outb(val | PAR96_BURST, LPT_DATA(bc->iobase));
+		}
+		if (bc->calibrate > 0) {
+			bc->modem.par96.tx_bits = 0;
+			bc->calibrate--;
+			return;
+		}
+#ifdef HDLC_LOOPBACK
+		for(mask = 0x8000, i = 0; i < PAR96_BURSTBITS; i++, mask >>= 1)
+			hdlc_rx_bit(bc, bc->modem.par96.tx_bits & mask);
+#endif /* HDLC_LOOPBACK */
+		bc->modem.par96.tx_bits = 0;
+		for(i = 0; i < PAR96_BURSTBITS; i++) {
+			bc->modem.par96.tx_bits <<= 1;
+			if (hdlc_tx_bit(bc))
+				bc->modem.par96.tx_bits |= 1;
+		}
+		return;
+	}
+	/*
+	 * do receiver; differential decode and descramble on the fly
+	 */
+	for(data = i = 0; i < PAR96_BURSTBITS; i++) {
+		unsigned int descx;
+		bc->modem.par96.descram = (bc->modem.par96.descram << 1);
+		if (inb(LPT_STATUS(bc->iobase)) & PAR96_RXBIT)
+			bc->modem.par96.descram |= 1;
+		descx = bc->modem.par96.descram ^ 
+			(bc->modem.par96.descram >> 1);
+		/* now the diff decoded data is inverted in descram */
+		outb(PAR97_POWER | PAR96_PTT, LPT_DATA(bc->iobase));
+		descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^
+			  (descx >> PAR96_DESCRAM_TAPSH2));
+		data <<= 1;
+		data |= !(descx & 1);
+		outb(PAR97_POWER | PAR96_PTT | PAR96_BURST, 
+		     LPT_DATA(bc->iobase));
+	}
+	for(mask = 0x8000, i = 0; i < PAR96_BURSTBITS; i++, mask >>= 1)
+		hdlc_rx_bit(bc, data & mask);
+	/*
+	 * do DCD algorithm
+	 */
+	if (bc->options & BAYCOM_OPTIONS_SOFTDCD) {
+		bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg << 16)
+			| data;
+		/* search for flags and set the dcd counter appropriately */
+		for(mask = 0x7f8000, mask2 = 0x3f0000, i = 0; 
+		    i < PAR96_BURSTBITS; i++, mask >>= 1, mask2 >>= 1)
+			if ((bc->modem.par96.dcd_shreg & mask) == mask2)
+				bc->modem.par96.dcd_count = BAYCOM_MAXFLEN+4;
+		/* check for abort/noise sequences */
+		for(mask = 0x3f8000, mask2 = 0x3f8000, i = 0; 
+		    i < PAR96_BURSTBITS; i++, mask >>= 1, mask2 >>= 1)
+			if ((bc->modem.par96.dcd_shreg & mask) == mask2)
+				if (bc->modem.par96.dcd_count >= 0)
+					bc->modem.par96.dcd_count -= 
+						BAYCOM_MAXFLEN-10;
+		/* decrement and set the dcd variable */
+		if (bc->modem.par96.dcd_count >= 0)
+			bc->modem.par96.dcd_count -= 2;
+		bc->modem.dcd = bc->modem.par96.dcd_count > 0;
+	} else {
+		bc->modem.dcd = !!(inb(LPT_STATUS(bc->iobase)) & PAR96_DCD);
+	}
+	if (--bc->modem.arb_divider <= 0) {
+		tx_arbitrate(bc);
+		bc->modem.arb_divider = bc->ch_params.slottime * 6;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static int par96_check_lpt(unsigned int iobase)
+{
+	unsigned char b1,b2;
+	int i;
+
+	b1 = inb(LPT_DATA(iobase));
+	b2 = inb(LPT_CONTROL(iobase));
+	outb(0xaa, LPT_DATA(iobase));
+	i = inb(LPT_DATA(iobase)) == 0xaa;
+	outb(0x55, LPT_DATA(iobase));
+	i &= inb(LPT_DATA(iobase)) == 0x55;
+	outb(0x0a, LPT_CONTROL(iobase));
+	i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x0a;
+	outb(0x05, LPT_CONTROL(iobase));
+	i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x05;
+	outb(b1, LPT_DATA(iobase));
+	outb(b2, LPT_CONTROL(iobase));
+	return !i;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int par96_allocate_resources(unsigned int iobase, unsigned int irq,
+				    unsigned int options)
+{
+	if (!iobase || iobase > 0xfff || irq < 2 || irq > 15)
+		return -ENXIO;
+	if (check_region(iobase, PAR96_EXTENT))
+		return -EACCES;
+	if (par96_check_lpt(iobase))
+		return -EIO;
+	request_region(iobase, PAR96_EXTENT, "baycom_par96");
+	outb(0, LPT_CONTROL(iobase));                 /* disable interrupt */
+	outb(PAR96_PTT | PAR97_POWER, LPT_DATA(iobase)); /* switch off PTT */
+	printk(KERN_INFO "baycom: par96 at iobase 0x%x irq %u options 0x%x\n", 
+	       iobase, irq, options);
+	return 0;
+}
+	
+/* --------------------------------------------------------------------- */
+
+static void par96_deallocate_resources(struct baycom_state *bc) 
+{
+	if (!bc || bc->modem_type != BAYCOM_MODEM_PAR96)
+		return;
+	outb(0, LPT_CONTROL(bc->iobase));      /* disable interrupt */
+	outb(PAR96_PTT, LPT_DATA(bc->iobase)); /* switch off PTT */
+	/* 
+	 * this should prevent kernel: Trying to free IRQx
+	 * messages
+	 */
+	if (bc->opened > 0)
+		free_irq(bc->irq, bc);
+	release_region(bc->iobase, PAR96_EXTENT);
+	bc->modem_type = BAYCOM_MODEM_INVALID;
+	printk(KERN_INFO "baycom: release par96 at iobase 0x%x irq %u\n",
+	       bc->iobase, bc->irq);
+	bc->iobase = bc->irq = bc->options = 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int par96_on_open(struct baycom_state *bc) 
+{
+	if (!bc || bc->modem_type != BAYCOM_MODEM_PAR96)
+		return -ENXIO;
+	outb(0, LPT_CONTROL(bc->iobase));      /* disable interrupt */
+	 /* switch off PTT */
+	outb(PAR96_PTT | PAR97_POWER, LPT_DATA(bc->iobase));
+	if (request_irq(bc->irq, baycom_par96_interrupt, 0, 
+			"baycom_par96", bc))
+		return -EBUSY;
+	outb(LPT_IRQ_ENABLE, LPT_CONTROL(bc->iobase));  /* enable interrupt */
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void par96_on_close(struct baycom_state *bc) 
+{
+	if (!bc || bc->modem_type != BAYCOM_MODEM_PAR96)
+		return;
+	outb(0, LPT_CONTROL(bc->iobase));  /* disable interrupt */
+	/* switch off PTT */
+	outb(PAR96_PTT | PAR97_POWER, LPT_DATA(bc->iobase));
+	free_irq(bc->irq, bc);	
+}
+
+/* --------------------------------------------------------------------- */
+/*
+ * ===================== TTY interface routines ==========================
+ */
+
+static inline int baycom_paranoia_check(struct baycom_state *bc, 
+					const char *routine)
+{
+	if (!bc || bc->magic != BAYCOM_MAGIC) {
+		printk(KERN_ERR "baycom: bad magic number for baycom struct "
+		       "in routine %s\n", routine);
+		return 1;
+	}
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+/*
+ * Here the tty driver code starts
+ */
+
+static void baycom_put_fend(struct baycom_state *bc)
+{
+	if (bc->kiss_decode.wr <= 0 ||
+	    (bc->kiss_decode.pkt_buf[0] & 0xf0) != 0)
+		return;
+
+	switch (bc->kiss_decode.pkt_buf[0] & 0xf) {
+	case KISS_CMD_DATA:
+		if (bc->kiss_decode.wr <= 8) 
+			break;
+		if (!store_packet(&bc->tx_buf, bc->kiss_decode.pkt_buf+1, 0, 
+				  bc->kiss_decode.wr-1))
+			bc->stat.tx_bufferoverrun++;
+		break;
+
+	case KISS_CMD_TXDELAY:
+		if (bc->kiss_decode.wr < 2) 
+			break;
+		bc->ch_params.tx_delay = bc->kiss_decode.pkt_buf[1];
+#ifdef KISS_VERBOSE
+		printk(KERN_INFO "baycom: TX delay = %ums\n", 
+		       bc->ch_params.tx_delay * 10);
+#endif /* KISS_VERBOSE */
+		break;
+
+	case KISS_CMD_PPERSIST:
+		if (bc->kiss_decode.wr < 2) 
+			break;
+		bc->ch_params.ppersist = bc->kiss_decode.pkt_buf[1];
+#ifdef KISS_VERBOSE
+		printk("KERN_INFO baycom: p-persistence = %u\n", 
+		       bc->ch_params.ppersist);
+#endif /* KISS_VERBOSE */
+		break;
+
+	case KISS_CMD_SLOTTIME:
+		if (bc->kiss_decode.wr < 2) 
+			break;
+		bc->ch_params.slottime = bc->kiss_decode.pkt_buf[1];
+#ifdef KISS_VERBOSE
+		printk("baycom: slottime = %ums\n", 
+		       bc->ch_params.slottime * 10);
+#endif /* KISS_VERBOSE */
+		break;
+
+	case KISS_CMD_TXTAIL:
+		if (bc->kiss_decode.wr < 2) 
+			break;
+		bc->ch_params.tx_tail = bc->kiss_decode.pkt_buf[1];
+#ifdef KISS_VERBOSE
+		printk(KERN_INFO "baycom: TX tail = %ums\n",
+		       bc->ch_params.tx_tail * 10);
+#endif /* KISS_VERBOSE */
+		break;
+
+	case KISS_CMD_FULLDUP:
+		if (bc->kiss_decode.wr < 2) 
+			break;
+		bc->ch_params.fulldup = bc->kiss_decode.pkt_buf[1];
+#ifdef KISS_VERBOSE
+		printk(KERN_INFO "baycom: %s duplex\n", 
+		       bc->ch_params.fulldup ? "full" : "half");
+#endif /* KISS_VERBOSE */
+		break;
+
+	default:
+#ifdef KISS_VERBOSE
+		printk(KERN_INFO "baycom: unhandled KISS packet code %u\n",
+		       bc->kiss_decode.pkt_buf[0] & 0xf);
+#endif /* KISS_VERBOSE */
+		break;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static void baycom_put_char(struct tty_struct *tty, unsigned char ch)
+{
+	struct baycom_state *bc;
+		
+	if (!tty)
+		return;
+	if (baycom_paranoia_check(bc = tty->driver_data, "put_char"))
+		return;
+		
+	if (ch == KISS_FEND) {
+		baycom_put_fend(bc);
+		bc->kiss_decode.wr = 0;
+		bc->kiss_decode.escaped = 0;
+		bc->kiss_decode.dec_state = 1;
+		return;
+	}
+	if (!bc->kiss_decode.dec_state)
+		return;
+	if (bc->kiss_decode.wr >= sizeof(bc->kiss_decode.pkt_buf)) {
+		bc->kiss_decode.wr = 0;
+		bc->kiss_decode.dec_state = 0;
+		return;
+	}
+	if (bc->kiss_decode.escaped) {
+		if (ch == KISS_TFEND)
+			bc->kiss_decode.pkt_buf[bc->kiss_decode.wr++] = 
+				KISS_FEND;
+		else if (ch == KISS_TFESC)
+			bc->kiss_decode.pkt_buf[bc->kiss_decode.wr++] = 
+				KISS_FESC;
+		else {
+			bc->kiss_decode.wr = 0;
+			bc->kiss_decode.dec_state = 0;
+		}
+		bc->kiss_decode.escaped = 0;
+		return;
+	}
+	bc->kiss_decode.pkt_buf[bc->kiss_decode.wr++] = ch;
+}
+	
+/* --------------------------------------------------------------------- */
+
+static int baycom_write(struct tty_struct * tty, int from_user,
+	const unsigned char *buf, int count)
+{
+	int c;
+	const unsigned char *bp;
+	struct baycom_state *bc;
+		
+	if (!tty || !buf || count <= 0)
+		return count;
+	
+	if (baycom_paranoia_check(bc = tty->driver_data, "write"))
+		return count; 
+		
+	if (from_user) {
+		for(c = count, bp = buf; c > 0; c--,bp++)
+			baycom_put_char(tty, get_user(bp));
+	} else {
+		for(c = count, bp = buf; c > 0; c--,bp++)
+			baycom_put_char(tty, *bp);
+	}
+	return count;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int baycom_write_room(struct tty_struct *tty)
+{
+	int free;
+	struct baycom_state *bc;
+		
+	if (!tty)
+		return 0;
+	if (baycom_paranoia_check(bc = tty->driver_data, "write_room"))
+		return 0;
+		
+	free = bc->tx_buf.rd - bc->tx_buf.wr;
+	if (free <= 0) {
+		free = bc->tx_buf.buflen - bc->tx_buf.wr;
+		if (free < bc->tx_buf.rd)
+			free = bc->tx_buf.rd;	/* we may fold */
+	}
+
+	return free / 2; /* a rather pessimistic estimate */
+}
+
+/* --------------------------------------------------------------------- */
+
+static int baycom_chars_in_buffer(struct tty_struct *tty)
+{
+	int cnt;
+	struct baycom_state *bc;
+		
+	if (!tty)
+		return 0;
+	if (baycom_paranoia_check(bc = tty->driver_data, "chars_in_buffer"))
+		return 0;
+		
+	cnt = bc->rx_buf.wr - bc->rx_buf.rd;
+	if (cnt < 0)
+		cnt += bc->rx_buf.buflen;
+		
+	return cnt;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void baycom_flush_buffer(struct tty_struct *tty)
+{
+	struct baycom_state *bc;
+		
+	if (!tty)
+		return;
+	if (baycom_paranoia_check(bc = tty->driver_data, "flush_buffer"))
+		return;
+
+	wake_up_interruptible(&tty->write_wait);
+	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+		tty->ldisc.write_wakeup)
+			(tty->ldisc.write_wakeup)(tty);
+}
+
+/* --------------------------------------------------------------------- */
+
+static inline void baycom_dealloc_hw(struct baycom_state *bc) 
+{
+	if (!bc || bc->magic != BAYCOM_MAGIC || 
+	    bc->modem_type == BAYCOM_MODEM_INVALID)
+		return;
+	switch(bc->modem_type) {
+	case BAYCOM_MODEM_SER12:
+		ser12_deallocate_resources(bc);
+		break;
+	case BAYCOM_MODEM_PAR96:
+		par96_deallocate_resources(bc);
+		break;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+static int baycom_set_hardware(struct baycom_state *bc,
+			       unsigned int modem_type, unsigned int iobase, 
+			       unsigned int irq, unsigned int options)
+{
+	int i;
+
+	if (!bc)
+		return -EINVAL;
+
+	if (modem_type == BAYCOM_MODEM_SER12) {
+		i = ser12_allocate_resources(iobase, irq, options);
+		if (i < 0)
+			return i;
+	} else if (modem_type == BAYCOM_MODEM_PAR96) {
+		i = par96_allocate_resources(iobase, irq, options);
+		if (i < 0)
+			return i;
+	} else if (modem_type == BAYCOM_MODEM_INVALID) {
+		iobase = irq = options = 0;
+	} else {
+		return -ENXIO;
+	}
+	baycom_dealloc_hw(bc);
+	bc->modem_type = modem_type;
+	bc->iobase = iobase;
+	bc->irq = irq;
+	bc->options = options;
+	i = 0;
+	if (bc->opened > 0) {
+		switch(bc->modem_type) {
+		case BAYCOM_MODEM_SER12:
+			i = ser12_on_open(bc);
+			break;
+		case BAYCOM_MODEM_PAR96:
+			i = par96_on_open(bc);
+			break;
+		}
+	}
+	return i;
+}
+
+/* --------------------------------------------------------------------- */
+
+static int baycom_ioctl(struct tty_struct *tty, struct file * file,
+	unsigned int cmd, unsigned long arg)
+{
+	int i;
+	struct baycom_state *bc;
+	struct baycom_params par;
+		
+	if (!tty)
+		return -EINVAL;
+	if (baycom_paranoia_check(bc = tty->driver_data, "ioctl"))
+		return -EINVAL;
+		
+	switch (cmd) {
+	default:
+		return -ENOIOCTLCMD;
+
+	case TIOCMGET:
+		i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
+		if (i)
+			return i;
+		i = (bc->modem.dcd ? TIOCM_CAR : 0) |
+			(bc->hdlc_tx.ptt ? TIOCM_RTS : 0);
+		put_user(i, (int *) arg);
+		return 0;
+		
+	case BAYCOMCTL_GETDCD:
+		i = verify_area(VERIFY_WRITE, (void *) arg,
+				sizeof(unsigned char));
+		if (!i)
+			put_user(bc->modem.dcd, (unsigned char *) arg);
+		return i;
+		
+	case BAYCOMCTL_GETPTT:
+		i = verify_area(VERIFY_WRITE, (void *) arg, 
+				sizeof(unsigned char));
+		if (!i)
+			put_user(bc->hdlc_tx.ptt, (unsigned char *) arg);
+		return i;
+		
+	case BAYCOMCTL_PARAM_TXDELAY:
+		if (arg > 255)
+			return -EINVAL;
+		bc->ch_params.tx_delay = arg;
+		return 0;
+		
+	case BAYCOMCTL_PARAM_PPERSIST:
+		if (arg > 255)
+			return -EINVAL;
+		bc->ch_params.ppersist = arg;
+		return 0;
+		
+	case BAYCOMCTL_PARAM_SLOTTIME:
+		if (arg > 255)
+			return -EINVAL;
+		bc->ch_params.slottime = arg;
+		return 0;
+		
+	case BAYCOMCTL_PARAM_TXTAIL:
+		if (arg > 255)
+			return -EINVAL;
+		bc->ch_params.tx_tail = arg;
+		return 0;
+		
+	case BAYCOMCTL_PARAM_FULLDUP:
+		bc->ch_params.fulldup = arg ? 1 : 0;
+		return 0;
+		
+	case BAYCOMCTL_CALIBRATE:
+		bc->calibrate = arg * ((bc->modem_type == BAYCOM_MODEM_PAR96) ?
+				       600 : 1200);
+		return 0;
+
+	case BAYCOMCTL_GETPARAMS:
+		i = verify_area(VERIFY_WRITE, (void *) arg, 
+				sizeof(par));
+		if (i)
+			return i;
+		par.modem_type = bc->modem_type;
+		par.iobase = bc->iobase;
+		par.irq = bc->irq;
+		par.options = bc->options;
+		par.tx_delay = bc->ch_params.tx_delay;
+		par.tx_tail = bc->ch_params.tx_tail;
+		par.slottime = bc->ch_params.slottime;
+		par.ppersist = bc->ch_params.ppersist;
+		par.fulldup = bc->ch_params.fulldup;
+		memcpy_tofs((void *)arg, &par, sizeof(par));
+		return 0;
+
+	case BAYCOMCTL_SETPARAMS:
+		if (!suser())
+			return -EPERM;
+		i = verify_area(VERIFY_READ, (void *) arg, 
+				sizeof(par));
+		if (i)
+			return i;
+		memcpy_fromfs(&par, (void *)arg, sizeof(par));
+		printk(KERN_INFO "baycom: changing hardware type: modem %u "
+		       "iobase 0x%x irq %u options 0x%x\n", par.modem_type,
+		       par.iobase, par.irq, par.options);
+		i = baycom_set_hardware(bc, par.modem_type, par.iobase,
+					par.irq, par.options); 
+		if (i)
+			return i;
+		bc->ch_params.tx_delay = par.tx_delay;
+		bc->ch_params.tx_tail = par.tx_tail;
+		bc->ch_params.slottime = par.slottime;
+		bc->ch_params.ppersist = par.ppersist;
+		bc->ch_params.fulldup = par.fulldup;
+		return 0;
+
+	case BAYCOMCTL_GETSTAT:
+		i = verify_area(VERIFY_WRITE, (void *) arg, 
+				sizeof(struct baycom_statistics));
+		if (i)
+			return i;
+		memcpy_tofs((void *)arg, &bc->stat, 
+			    sizeof(struct baycom_statistics));
+		return 0;
+		
+
+#ifdef BAYCOM_DEBUG
+	case BAYCOMCTL_GETSAMPLES:
+		if (bc->bitbuf_channel.rd == bc->bitbuf_channel.wr) 
+			return -EAGAIN;
+		i = verify_area(VERIFY_WRITE, (void *) arg, 
+				sizeof(unsigned char));
+		if (!i) {
+			put_user(bc->bitbuf_channel.buffer
+				 [bc->bitbuf_channel.rd],
+				 (unsigned char *) arg);
+			bc->bitbuf_channel.rd = (bc->bitbuf_channel.rd+1) %
+				sizeof(bc->bitbuf_channel.buffer);
+		}
+		return i;
+		
+	case BAYCOMCTL_GETBITS:
+		if (bc->bitbuf_hdlc.rd == bc->bitbuf_hdlc.wr) 
+			return -EAGAIN;
+		i = verify_area(VERIFY_WRITE, (void *) arg, 
+				sizeof(unsigned char));
+		if (!i) {
+			put_user(bc->bitbuf_hdlc.buffer[bc->bitbuf_hdlc.rd],
+				 (unsigned char *) arg);
+			bc->bitbuf_hdlc.rd = (bc->bitbuf_hdlc.rd+1) %
+				sizeof(bc->bitbuf_hdlc.buffer);
+		}
+		return i;
+		
+	case BAYCOMCTL_DEBUG1:
+		i = verify_area(VERIFY_WRITE, (void *) arg,
+				sizeof(unsigned long));
+		if (!i)
+			put_user((bc->rx_buf.wr-bc->rx_buf.rd) % 
+				 bc->rx_buf.buflen, (unsigned long *)arg);
+		return i;
+		
+	case BAYCOMCTL_DEBUG2:
+		i = verify_area(VERIFY_WRITE, (void *) arg,
+				sizeof(unsigned long));
+		if (!i)
+			put_user(bc->debug_vals.last_intcnt, 
+				 (unsigned long *)arg);
+		return i;
+		
+	case BAYCOMCTL_DEBUG3:
+		i = verify_area(VERIFY_WRITE, (void *) arg, 
+				sizeof(unsigned long));
+		if (!i)
+			put_user((long)bc->debug_vals.last_pllcorr,
+				 (long *)arg);
+		return i;		
+#endif /* BAYCOM_DEBUG */
+	}
+}
+
+/* --------------------------------------------------------------------- */
+
+int baycom_open(struct tty_struct *tty, struct file * filp)
+{
+	int line;
+	struct baycom_state *bc;
+	int i;
+
+	if(!tty)
+		return -ENODEV;
+
+	line = MINOR(tty->device) - tty->driver.minor_start;
+	if (line < 0 || line >= NR_PORTS)
+		return -ENODEV;
+	bc = baycom_state+line;
+
+	if (bc->opened > 0) {
+		bc->opened++;
+		MOD_INC_USE_COUNT;
+		return 0;
+	}
+	/*
+	 * initialise some variables
+	 */
+	bc->calibrate = 0;
+
+	/*
+	 * allocate the buffer space
+	 */
+	if (bc->rx_buf.buffer)
+		kfree_s(bc->rx_buf.buffer, bc->rx_buf.buflen);
+	if (bc->tx_buf.buffer)
+		kfree_s(bc->tx_buf.buffer, bc->tx_buf.buflen);
+	bc->rx_buf.buflen = BUFLEN_RX;
+	bc->tx_buf.buflen = BUFLEN_TX;
+	bc->rx_buf.rd = bc->rx_buf.wr = 0;
+	bc->tx_buf.rd = bc->tx_buf.wr = 0;
+	bc->rx_buf.buffer = kmalloc(bc->rx_buf.buflen, GFP_KERNEL);
+	bc->tx_buf.buffer = kmalloc(bc->tx_buf.buflen, GFP_KERNEL);
+	if (!bc->rx_buf.buffer || !bc->tx_buf.buffer) {
+		if (bc->rx_buf.buffer)
+			kfree_s(bc->rx_buf.buffer, bc->rx_buf.buflen);
+		if (bc->tx_buf.buffer)
+			kfree_s(bc->tx_buf.buffer, bc->tx_buf.buflen);
+		bc->rx_buf.buffer = bc->tx_buf.buffer = NULL;
+		bc->rx_buf.buflen = bc->tx_buf.buflen = 0;
+		return -ENOMEM;
+	}
+	/*
+	 * check if the modem type has been set
+	 */
+	switch(bc->modem_type) {
+	case BAYCOM_MODEM_SER12:
+		i = ser12_on_open(bc);
+		break;
+	case BAYCOM_MODEM_PAR96:
+		i = par96_on_open(bc);
+		break;
+	case BAYCOM_MODEM_INVALID:
+		/*
+		 * may open even if no hardware specified, in order to
+		 * subsequently allow the BAYCOMCTL_SETPARAMS ioctl
+		 */
+		i = 0;
+		break;
+	default:
+		return -ENODEV;
+	}
+	if (i) 
+		return i;
+
+	bc->opened++;
+	MOD_INC_USE_COUNT;
+
+	tty->driver_data = bc;
+	bc->tty = tty;
+
+	return 0;   
+}
+
+
+/* --------------------------------------------------------------------- */
+	
+static void baycom_close(struct tty_struct *tty, struct file * filp)
+{
+	struct baycom_state *bc;
+		
+	if(!tty) return;
+	if (baycom_paranoia_check(bc = tty->driver_data, "close"))
+		return;
+
+	MOD_DEC_USE_COUNT;
+	bc->opened--;
+	if (bc->opened <= 0) {
+		switch(bc->modem_type) {
+		case BAYCOM_MODEM_SER12:
+			ser12_on_close(bc);
+			break;
+		case BAYCOM_MODEM_PAR96:
+			par96_on_close(bc);
+			break;
+		}
+		tty->driver_data = NULL;
+		bc->tty = NULL;
+		bc->opened = 0;
+		/*
+		 * free the buffers 
+		 */
+		bc->rx_buf.rd = bc->rx_buf.wr = 0;
+		bc->tx_buf.rd = bc->tx_buf.wr = 0;
+		if (bc->rx_buf.buffer)
+			kfree_s(bc->rx_buf.buffer, bc->rx_buf.buflen);
+		if (bc->tx_buf.buffer)
+			kfree_s(bc->tx_buf.buffer, bc->tx_buf.buflen);
+		bc->rx_buf.buffer = bc->tx_buf.buffer = NULL;
+		bc->rx_buf.buflen = bc->tx_buf.buflen = 0;
+	}
+}
+
+/* --------------------------------------------------------------------- */
+/*
+ * And now the modules code and kernel interface.
+ */
+
+static void init_channel(struct baycom_state *bc)
+{
+	struct access_params dflt_ch_params = { 20, 2, 10, 40, 0 };
+
+	if (!bc)
+		return;
+
+	bc->hdlc_rx.rx_state = 0;
+
+	bc->hdlc_tx.tx_state = bc->hdlc_tx.numflags = 0;
+	bc->hdlc_tx.bitstream = 0;
+	bc->hdlc_tx.current_byte = bc->hdlc_tx.ptt = 0;
+
+	memset(&bc->modem, 0, sizeof(bc->modem));
+
+#ifdef BAYCOM_DEBUG
+	bc->bitbuf_channel.rd = bc->bitbuf_channel.wr = 0;
+	bc->bitbuf_channel.shreg = 1;
+
+	bc->bitbuf_hdlc.rd = bc->bitbuf_hdlc.wr = 0;
+	bc->bitbuf_hdlc.shreg = 1;
+#endif /* BAYCOM_DEBUG */
+
+	bc->kiss_decode.dec_state = bc->kiss_decode.escaped = 
+	bc->kiss_decode.wr = 0;
+
+	bc->ch_params = dflt_ch_params;
+}
+
+static void init_datastructs(void)
+{
+	int i;
+
+	for(i = 0; i < NR_PORTS; i++) {
+		struct baycom_state *bc = baycom_state+i;
+
+		bc->magic = BAYCOM_MAGIC;
+		bc->modem_type = BAYCOM_MODEM_INVALID;
+		bc->iobase = bc->irq = bc->options = bc->opened = 0;
+		bc->tty = NULL;
+
+		bc->rx_buf.rd = bc->rx_buf.wr = 0;
+		bc->rx_buf.buflen = 0;
+		bc->rx_buf.buffer = NULL;
+
+		bc->tx_buf.rd = bc->tx_buf.wr = 0;
+		bc->tx_buf.buflen = 0;
+		bc->tx_buf.buffer = NULL;
+
+		memset(&bc->stat, 0, sizeof(bc->stat));
+
+		init_channel(bc);
+	}
+}
+
+int baycom_init(void) {
+	int i, j;
+
+	/*
+	 * initialize the data structures
+	 */
+	init_datastructs();
+	/*
+	 * register the driver as tty driver
+	 */
+	memset(&baycom_driver, 0, sizeof(struct tty_driver));
+	baycom_driver.magic = TTY_DRIVER_MAGIC;
+	baycom_driver.name = "baycom";
+	baycom_driver.major = major;
+	baycom_driver.minor_start = 0;
+	baycom_driver.num = NR_PORTS;
+	baycom_driver.type = TTY_DRIVER_TYPE_BAYCOM;
+	baycom_driver.subtype = BAYCOM_TYPE_NORMAL;
+	baycom_driver.init_termios.c_iflag = 0;
+	baycom_driver.init_termios.c_oflag = 0;
+	baycom_driver.init_termios.c_cflag = CS8 | B1200 | CREAD | CLOCAL;
+	baycom_driver.init_termios.c_lflag = 0;
+	baycom_driver.flags = TTY_DRIVER_REAL_RAW;
+	baycom_driver.refcount = &baycom_refcount;
+	baycom_driver.table = baycom_table;
+	baycom_driver.termios = baycom_termios;
+	baycom_driver.termios_locked = baycom_termios_locked;
+	/*
+	 * the functions
+	 */
+	baycom_driver.open = baycom_open;
+	baycom_driver.close = baycom_close;
+	baycom_driver.write = baycom_write;
+	baycom_driver.put_char = baycom_put_char;
+	baycom_driver.flush_chars = NULL;
+	baycom_driver.write_room = baycom_write_room;
+	baycom_driver.chars_in_buffer = baycom_chars_in_buffer;
+	baycom_driver.flush_buffer = baycom_flush_buffer;
+	baycom_driver.ioctl = baycom_ioctl;
+	/*
+	 * cannot throttle the transmitter on this layer
+	 */
+	baycom_driver.throttle = NULL;
+	baycom_driver.unthrottle = NULL;
+	/*
+	 * no special actions on termio changes
+	 */
+	baycom_driver.set_termios = NULL;
+	/*
+	 * no XON/XOFF and no hangup on the radio port
+	 */
+	baycom_driver.stop = NULL;
+	baycom_driver.start = NULL;
+	baycom_driver.hangup = NULL;
+	baycom_driver.set_ldisc = NULL;
+
+	if (tty_register_driver(&baycom_driver)) {
+		printk(KERN_WARNING "baycom: tty_register_driver failed\n");
+		return -EIO;
+	}
+
+	for (i = 0; i < NR_PORTS && 
+	     baycom_ports[i].modem != BAYCOM_MODEM_INVALID; i++) {
+		j = baycom_set_hardware(baycom_state+i, 
+					baycom_ports[i].modem,
+					baycom_ports[i].iobase, 
+					baycom_ports[i].irq, 
+					baycom_ports[i].options);
+		if (j < 0) {
+			const char *s;
+			switch (-j) {
+			case ENXIO:
+				s = "invalid iobase and/or irq";
+				break;
+			case EACCES:
+				s = "io region already used";
+				break;
+			case EIO:
+				s = "no uart/lpt port at iobase";
+				break;
+			case EBUSY:
+				s = "interface already in use";
+				break;
+			case EINVAL:
+				s = "internal error";
+				break;
+			default:
+				s = "unknown error";
+				break;
+			}
+			printk(KERN_WARNING "baycom: modem %u iobase 0x%x "
+			       "irq %u: (%i) %s\n", baycom_ports[i].modem, 
+			       baycom_ports[i].iobase, baycom_ports[i].irq, 
+			       j, s);
+		}
+	}
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+#ifdef MODULE
+
+int modem = BAYCOM_MODEM_INVALID;
+int iobase = 0x3f8;
+int irq = 4;
+int options = BAYCOM_OPTIONS_SOFTDCD;
+
+int init_module(void)
+{
+	int i;
+
+	printk(KERN_INFO "baycom: init_module called\n");
+
+	baycom_ports[0].modem = modem;
+	baycom_ports[0].iobase = iobase;
+	baycom_ports[0].irq = irq;
+	baycom_ports[0].options = options;
+	baycom_ports[1].modem = BAYCOM_MODEM_INVALID;
+
+	i = baycom_init();
+	if (i)
+		return i;
+
+	printk(KERN_INFO "baycom: version 0.2; "
+	       "(C) 1996 by Thomas Sailer HB9JNX, sailer@ife.ee.ethz.ch\n");
+
+	return 0;
+}
+
+/* --------------------------------------------------------------------- */
+
+void cleanup_module(void)
+{
+	int i;
+
+#if 0
+	if (MOD_IN_USE)
+		printk(KERN_INFO "baycom: device busy, remove delayed\n");
+#endif
+	printk(KERN_INFO "baycom: cleanup_module called\n");
+
+	if (tty_unregister_driver(&baycom_driver))
+		printk(KERN_WARNING "baycom: failed to unregister tty "
+		       "driver\n");
+	for(i = 0; i < NR_PORTS; i++) {
+		struct baycom_state *bc = baycom_state+i;
+
+		if (bc->magic != BAYCOM_MAGIC)
+			printk(KERN_ERR "baycom: invalid magic in "
+			       "cleanup_module\n");
+		else {
+			baycom_dealloc_hw(bc);
+			/*
+			 * free the buffers 
+			 */
+			bc->rx_buf.rd = bc->rx_buf.wr = 0;
+			bc->tx_buf.rd = bc->tx_buf.wr = 0;
+			if (bc->rx_buf.buffer)
+				kfree_s(bc->rx_buf.buffer, bc->rx_buf.buflen);
+			if (bc->tx_buf.buffer)
+				kfree_s(bc->tx_buf.buffer, bc->tx_buf.buflen);
+			bc->rx_buf.buffer = bc->tx_buf.buffer = NULL;
+			bc->rx_buf.buflen = bc->tx_buf.buflen = 0;
+		}
+	}
+}
+
+#else /* MODULE */
+/* --------------------------------------------------------------------- */
+/*
+ * format: baycom=modem,io,irq,options[,modem,io,irq,options]
+ * modem=1: ser12, modem=2: par96
+ * options=0: hardware DCD, options=1: software DCD
+ */
+
+void baycom_setup(char *str, int *ints)
+{
+	int i;
+
+	for (i = 0; i < NR_PORTS; i++) 
+		if (ints[0] >= 4*i+4) {
+			baycom_ports[i].modem = ints[4*i+1];
+			baycom_ports[i].iobase = ints[4*i+2];
+			baycom_ports[i].irq = ints[4*i+3];
+			baycom_ports[i].options = ints[4*i+4];
+		} else
+			baycom_ports[i].modem = BAYCOM_MODEM_INVALID;
+
+}
+
+#endif /* MODULE */
+/* --------------------------------------------------------------------- */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file pre2.0.4/linux/drivers/char/console.c linux/drivers/char/console.c
--- pre2.0.4/linux/drivers/char/console.c	Tue May  7 16:22:23 1996
+++ linux/drivers/char/console.c	Wed May 15 09:06:55 1996
@@ -2116,11 +2116,6 @@
 {
 	int currcons;
 
-#ifdef CONFIG_APM
-	if (apm_display_blank())
-		return;
-#endif
-
 	if (console_blanked)
 		return;
 
@@ -2146,6 +2141,10 @@
 	hide_cursor();
 	console_blanked = fg_console + 1;
 
+#ifdef CONFIG_APM
+	if (apm_display_blank())
+		return;
+#endif
 	if(!nopowersave)
 	    vesa_blank();
 }
@@ -2156,11 +2155,6 @@
 	int resetorg;
 	long offset;
 
-#ifdef CONFIG_APM
-	if (apm_display_unblank())
-		return;
-#endif
-
 	if (!console_blanked)
 		return;
 	if (!vc_cons_allocated(fg_console)) {
@@ -2193,6 +2187,10 @@
 		__set_origin(blank__origin);
 
 	vesa_unblank();
+#ifdef CONFIG_APM
+	if (apm_display_unblank())
+		return;
+#endif
 }
 
 /*
diff -u --recursive --new-file pre2.0.4/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c
--- pre2.0.4/linux/drivers/char/tty_io.c	Wed Apr 24 17:00:39 1996
+++ linux/drivers/char/tty_io.c	Thu May 16 16:35:39 1996
@@ -1874,6 +1874,9 @@
 #ifdef CONFIG_RISCOM8
 	riscom8_init();
 #endif
+#ifdef CONFIG_BAYCOM
+	baycom_init();
+#endif
 	pty_init();
 	vcs_init();
 	return 0;
diff -u --recursive --new-file pre2.0.4/linux/drivers/isdn/Config.in linux/drivers/isdn/Config.in
--- pre2.0.4/linux/drivers/isdn/Config.in	Sun Apr 21 19:22:06 1996
+++ linux/drivers/isdn/Config.in	Thu May 16 16:35:39 1996
@@ -8,6 +8,6 @@
     bool 'Support generic MP (RFC 1717)' CONFIG_ISDN_MPP
   fi
 fi
-dep_tristate 'Teles/NICCY1016PC/Creatix support' CONFIG_ISDN_DRV_TELES $CONFIG_ISDN
 dep_tristate 'ICN B1 and B2 support' CONFIG_ISDN_DRV_ICN $CONFIG_ISDN
 dep_tristate 'PCBIT-D support' CONFIG_ISDN_DRV_PCBIT $CONFIG_ISDN
+dep_tristate 'Teles/NICCY1016PC/Creatix support' CONFIG_ISDN_DRV_TELES $CONFIG_ISDN
diff -u --recursive --new-file pre2.0.4/linux/drivers/isdn/pcbit/module.c linux/drivers/isdn/pcbit/module.c
--- pre2.0.4/linux/drivers/isdn/pcbit/module.c	Wed Apr 24 17:00:39 1996
+++ linux/drivers/isdn/pcbit/module.c	Wed May 15 09:09:00 1996
@@ -93,11 +93,6 @@
 {
 	int board;
 
-	if (MOD_IN_USE) {
-		printk(KERN_WARNING "pcbit: device busy, remove cancelled\n");
-		return;
-	}
-
 	for (board = 0; board < num_boards; board++)
 		pcbit_terminate(board);
 	printk(KERN_INFO 
diff -u --recursive --new-file pre2.0.4/linux/drivers/net/3c509.c linux/drivers/net/3c509.c
--- pre2.0.4/linux/drivers/net/3c509.c	Sat Apr 27 15:19:53 1996
+++ linux/drivers/net/3c509.c	Wed May 15 09:09:00 1996
@@ -784,16 +784,11 @@
 void
 cleanup_module(void)
 {
-	if (MOD_IN_USE)
-		printk("3c509: device busy, remove delayed\n");
-	else
-	{
-		unregister_netdev(&dev_3c509);
-		kfree_s(dev_3c509.priv,sizeof(struct el3_private));
-		dev_3c509.priv=NULL;
-		/* If we don't do this, we can't re-insmod it later. */
-		release_region(dev_3c509.base_addr, EL3_IO_EXTENT);
-	}
+	unregister_netdev(&dev_3c509);
+	kfree_s(dev_3c509.priv,sizeof(struct el3_private));
+	dev_3c509.priv=NULL;
+	/* If we don't do this, we can't re-insmod it later. */
+	release_region(dev_3c509.base_addr, EL3_IO_EXTENT);
 }
 #endif /* MODULE */
 
diff -u --recursive --new-file pre2.0.4/linux/drivers/net/8390.c linux/drivers/net/8390.c
--- pre2.0.4/linux/drivers/net/8390.c	Tue May  7 16:22:26 1996
+++ linux/drivers/net/8390.c	Thu May 16 11:18:50 1996
@@ -29,6 +29,7 @@
 			  ei_block_input() for eth_io_copy_and_sum().
   Paul Gortmaker	: exchange static int ei_pingpong for a #define,
 			  also add better Tx error handling.
+  Paul Gortmaker	: rewrite Rx overrun handling as per NS specs.
 
 
   Sources:
@@ -377,6 +378,7 @@
     int e8390_base = dev->base_addr;
     unsigned char txsr = inb_p(e8390_base+EN0_TSR);
     unsigned char tx_was_aborted = txsr & (ENTSR_ABT+ENTSR_FU);
+    struct ei_device *ei_local = (struct ei_device *) dev->priv;
 
 #ifdef VERBOSE_ERROR_DUMP
     printk(KERN_DEBUG "%s: transmitter error (%#2x): ", dev->name, txsr);
@@ -398,6 +400,13 @@
     if (tx_was_aborted)
 		ei_tx_intr(dev);
 
+    /*
+     * Note: NCR reads zero on 16 collisions so we add them
+     * in by hand. Somebody might care...
+     */
+    if (txsr & ENTSR_ABT)
+	ei_local->stat.collisions += 16;
+	
 }
 
 /* We have finished a transmit: check for errors and then trigger the next
@@ -580,43 +589,76 @@
     return;
 }
 
-/* We have a receiver overrun: we have to kick the 8390 to get it started
-   again.*/
+/* 
+ * We have a receiver overrun: we have to kick the 8390 to get it started
+ * again. Problem is that you have to kick it exactly as NS prescribes in
+ * the updated datasheets, or "the NIC may act in an unpredictable manner."
+ * This includes causing "the NIC to defer indefinitely when it is stopped
+ * on a busy network."  Ugh.
+ */
 static void ei_rx_overrun(struct device *dev)
 {
     int e8390_base = dev->base_addr;
-    int reset_start_time = jiffies;
+    unsigned long wait_start_time;
+    unsigned char was_txing, must_resend = 0;
     struct ei_device *ei_local = (struct ei_device *) dev->priv;
     
-    /* We should already be stopped and in page0.  Remove after testing. */
+    /*
+     * Record whether a Tx was in progress and then issue the
+     * stop command.
+     */
+    was_txing = inb_p(e8390_base+E8390_CMD) & E8390_TRANS;
     outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
     
     if (ei_debug > 1)
-		printk("%s: Receiver overrun.\n", dev->name);
+	printk("%s: Receiver overrun.\n", dev->name);
     ei_local->stat.rx_over_errors++;
     
-    /* The old Biro driver does dummy = inb_p( RBCR[01] ); at this point.
-       It might mean something -- magic to speed up a reset?  A 8390 bug?*/
-    
-    /* Wait for the reset to complete.	This should happen almost instantly,
-	   but could take up to 1.5msec in certain rare instances.  There is no
-	   easy way of timing something in that range, so we use 'jiffies' as
-	   a sanity check. */
-    while ((inb_p(e8390_base+EN0_ISR) & ENISR_RESET) == 0)
-		if (jiffies - reset_start_time > 2*HZ/100) {
-			printk("%s: reset did not complete at ei_rx_overrun.\n",
-				   dev->name);
-			NS8390_init(dev, 1);
-			return;
-		}
-    
-    /* Remove packets right away. */
+    /* 
+     * Wait a full Tx time (1.2ms) + some guard time, NS says 1.6ms total.
+     * Early datasheets said to poll the reset bit, but now they say that
+     * it "is not a reliable indicator and subequently should be ignored."
+     * We wait at least 10ms.
+     */
+    wait_start_time = jiffies;
+    while (jiffies - wait_start_time <= 1*HZ/100)
+	barrier();
+
+    /*
+     * Reset RBCR[01] back to zero as per magic incantation.
+     */
+    outb_p(0x00, e8390_base+EN0_RCNTLO);
+    outb_p(0x00, e8390_base+EN0_RCNTHI);
+
+    /*
+     * See if any Tx was interrupted or not. According to NS, this
+     * step is vital, and skipping it will cause no end of havoc.
+     */
+    if (was_txing) { 
+	unsigned char tx_completed = inb_p(e8390_base+EN0_ISR) & (ENISR_TX+ENISR_TX_ERR);
+	if (!tx_completed) must_resend = 1;
+    }
+
+    /*
+     * Have to enter loopback mode and then restart the NIC before
+     * you are allowed to slurp packets up off the ring.
+     */
+    outb_p(E8390_TXOFF, e8390_base + EN0_TXCR);
+    outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
+
+    /*
+     * Clear the Rx ring of all the debris, and ack the interrupt.
+     */
     ei_receive(dev);
-    
     outb_p(ENISR_OVER, e8390_base+EN0_ISR);
-    /* Generic 8390 insns to start up again, same as in open_8390(). */
-    outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
-    outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
+
+    /*
+     * Leave loopback mode, and resend any packet that got stopped.
+     */
+    outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); 
+    if (must_resend)
+    	outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START + E8390_TRANS, e8390_base + E8390_CMD);
+	
 }
 
 static struct enet_statistics *get_stats(struct device *dev)
diff -u --recursive --new-file pre2.0.4/linux/drivers/net/CONFIG linux/drivers/net/CONFIG
--- pre2.0.4/linux/drivers/net/CONFIG	Sun Apr 21 12:39:01 1996
+++ linux/drivers/net/CONFIG	Thu May 16 20:12:56 1996
@@ -59,6 +59,8 @@
 #                       For manual 100Mb/s mode selection  (DC21140) = _100Mb
 #                       The DC21040 will default to TP if TP_NW is specified
 #                       The DC21041 will default to BNC if BNC_AUI is specified
+#     DE4X5_DO_MEMCPY   Forces the Intels to use memory copies into sk_buffs
+#	                rather than straight DMA.
 #
 #  TULIP		Tulip (dc21040/dc21041/ds21140) driver
 #	TULIP_PORT	specify default if_port
diff -u --recursive --new-file pre2.0.4/linux/drivers/net/Config.in linux/drivers/net/Config.in
--- pre2.0.4/linux/drivers/net/Config.in	Mon May 13 23:02:49 1996
+++ linux/drivers/net/Config.in	Thu May 16 20:12:57 1996
@@ -25,15 +25,16 @@
 bool 'Radio network interfaces' CONFIG_NET_RADIO
 if [ "$CONFIG_NET_RADIO" != "n" ]; then
   if [ "$CONFIG_AX25" = "y" ]; then
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      tristate 'BAYCOM ser12 and par96 kiss emulation driver for AX.25' CONFIG_BAYCOM
+    fi
     bool 'Gracilis PackeTwin support' CONFIG_PT
     bool 'Ottawa PI and PI/2 support' CONFIG_PI
   fi
   tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP
   tristate 'WaveLAN support' CONFIG_WAVELAN
   tristate 'WIC Radio IP bridge (EXPERIMENTAL)' CONFIG_WIC
-  if [ "$CONFIG_AX25" = "y" ]; then
-    tristate 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC
-  fi
+  tristate 'Z8530 SCC kiss emulation driver for AX.25' CONFIG_SCC
 fi
 #
 #	Ethernet
@@ -67,12 +68,12 @@
       tristate 'AT1700 support (EXPERIMENTAL)' CONFIG_AT1700
     fi
     tristate 'Cabletron E21xx support' CONFIG_E2100
-    tristate 'DEPCA support' CONFIG_DEPCA
-    tristate 'EtherWorks 3 support' CONFIG_EWRK3
+    tristate 'DEPCA, DE10x, DE200, DE201, DE202, DE422 support' CONFIG_DEPCA
+    tristate 'EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
     tristate 'EtherExpress 16 support' CONFIG_EEXPRESS
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
       tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO
-      tristate 'FMV-181/182 support' CONFIG_FMV18X
+      tristate 'FMV-181/182/183/184 support' CONFIG_FMV18X
     fi
     tristate 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
     tristate 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
@@ -96,7 +97,7 @@
       tristate 'Ansel Communications EISA 3200 support (EXPERIMENTAL)' CONFIG_AC3200
     fi
     tristate 'Apricot Xen-II on board ethernet' CONFIG_APRICOT
-    tristate 'DE425, DE434, DE435, DE500 support' CONFIG_DE4X5
+    tristate 'DE425, DE434, DE435, DE450, DE500 support' CONFIG_DE4X5
     tristate 'DECchip Tulip (dc21x4x) PCI support' CONFIG_DEC_ELCP
     tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
diff -u --recursive --new-file pre2.0.4/linux/drivers/net/de4x5.c linux/drivers/net/de4x5.c
--- pre2.0.4/linux/drivers/net/de4x5.c	Sat Apr 27 15:19:53 1996
+++ linux/drivers/net/de4x5.c	Thu May 16 20:12:56 1996
@@ -53,7 +53,7 @@
     achieved by letting the driver autoprobe as if it were compiled into the
     kernel, except that there is no autoprobing of the IRQ lines. This is of
     no great  consequence except do make sure  you're not sharing interrupts
-    with  anything that cannot  accommodate  interrupt sharing!  The existing
+    with  anything that cannot  accommodate  interrupt sharing! The existing
     register_netdevice() code will only allow one device to be registered at
     a time. 
 
@@ -108,7 +108,7 @@
     applies most particularly to the DC21140 based cards).
 
     I've changed the timing routines to  use the kernel timer and scheduling
-    functions  so that the  hangs  and other assorted  problems that occurred
+    functions  so that the  hangs  and other assorted problems that occurred
     while autosensing the  media  should be gone.  A  bonus  for the DC21040
     auto  media sense algorithm is  that it can now  use one that is more in
     line with the  rest (the DC21040  chip doesn't  have a hardware  timer).
@@ -820,7 +820,7 @@
 	** Set up the RX descriptor ring (Intels)
 	** Allocate contiguous receive buffers, long word aligned (Alphas) 
 	*/
-#ifndef __alpha__
+#if !defined(__alpha__) && !defined(DE4X5_DO_MEMCPY)
 	for (i=0; i<NUM_RX_DESC; i++) {
 	    lp->rx_ring[i].status = 0;
 	    lp->rx_ring[i].des1 = RX_BUFF_SZ;
@@ -2627,7 +2627,7 @@
     struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
     struct sk_buff *p;
 
-#ifndef __alpha__
+#if !defined(__alpha__) && !defined(DE4X5_DO_MEMCPY)
     struct sk_buff *ret;
     u_long i=0, tmp;
 
diff -u --recursive --new-file pre2.0.4/linux/drivers/net/fmv18x.c linux/drivers/net/fmv18x.c
--- pre2.0.4/linux/drivers/net/fmv18x.c	Fri Apr 12 15:51:55 1996
+++ linux/drivers/net/fmv18x.c	Thu May 16 16:35:40 1996
@@ -1,4 +1,4 @@
-/* fmv18x.c: A network device driver for  the Fujitsu FMV-181/182.
+/* fmv18x.c: A network device driver for the Fujitsu FMV-181/182/183/184.
 
 	Original: at1700.c (1993-94 by Donald Becker).
 		Copyright 1993 United States Government as represented by the
@@ -22,8 +22,8 @@
 	This software may be used and distributed according to the terms
 	of the GNU Public License, incorporated herein by reference.
 
-	This is a device driver for the Fujitsu FMV-181/182, which is a
-	straight-forward Fujitsu MB86965 implementation.
+	This is a device driver for the Fujitsu FMV-181/182/183/184, which
+	is a straight-forward Fujitsu MB86965 implementation.
 
   Sources:
     at1700.c
diff -u --recursive --new-file pre2.0.4/linux/drivers/net/sdla.c linux/drivers/net/sdla.c
--- pre2.0.4/linux/drivers/net/sdla.c	Tue May  7 16:22:30 1996
+++ linux/drivers/net/sdla.c	Wed May 15 10:38:35 1996
@@ -5,7 +5,7 @@
  *
  *		Global definitions for the Frame relay interface.
  *
- * Version:	@(#)sdla.c   0.20	13 Apr 1996
+ * Version:	@(#)sdla.c   0.25	14 May 1996
  *
  * Credits:	Sangoma Technologies, for the use of 2 cards for an extended
  *			period of time.
@@ -20,7 +20,9 @@
  *		0.15	Mike McLagan	Improved error handling, packet dropping
  *		0.20	Mike McLagan	New transmit/receive flags for config
  *					If in FR mode, don't accept packets from
- *					non-DLCI devices.
+ *					non DLCI devices.
+ *		0.25	Mike McLagan	Fixed problem with rejecting packets
+ *					from non DLCI devices.
  *
  *
  *		This program is free software; you can redistribute it and/or
@@ -56,7 +58,7 @@
 
 #include <linux/sdla.h>
 
-static const char* version = "SDLA driver v0.20, 13 Apr 1996, mike.mclagan@linux.org";
+static const char* version = "SDLA driver v0.25, 14 May 1996, mike.mclagan@linux.org";
 
 static const char* devname = "sdla";
 
@@ -327,7 +329,7 @@
    struct _dlci_stat *pstatus;
    short             *pdlci;
    int               i;
-   char              *state;
+   char              *state, line[30];
 
    switch (ret)
    {
@@ -364,8 +366,10 @@
                   if (pstatus->flags & SDLA_DLCI_ACTIVE)
                      state = "active";
                   else
-                     state = "unknown status";
- 
+                  {
+                     sprintf(line, "uknown status: %02X", pstatus->flags);
+                     state = line;
+                  }
             printk(KERN_INFO "%s: DLCI %i: %s.\n", dev->name, pstatus->dlci, state);
 /* same here */
          }
@@ -637,13 +641,14 @@
 static int sdla_transmit(struct sk_buff *skb, struct device *dev)
 {
    struct frad_local *flp;
-   int               ret, addr;
+   int               ret, addr, accept;
    short             size;
    unsigned long     flags;
    struct buf_entry  *pbuf;
 
    flp = dev->priv;
    ret = 0;
+   accept = 1;
 
    if (dev->tbusy) 
       return(1);
@@ -655,75 +660,77 @@
       printk(KERN_WARNING "%s: transmitter access conflict.\n", dev->name);
    else
    {
- 
       /*
        * stupid GateD insists on setting up the multicast router thru us
        * and we're ill equipped to handle a non Frame Relay packet at this
        * time!
        */
 
+      accept = 1;
       switch (dev->type)
       {
          case ARPHRD_FRAD:
             if (skb->dev->type != ARPHRD_DLCI)
             {
-               printk(KERN_WARNING "%s: FRAD module accepts packets from DLCI ONLY!\n", dev->name);
-               dev_kfree_skb(skb, FREE_WRITE);
-               return(0);
+               printk(KERN_WARNING "%s: Non DLCI device, type %i, tried to send on FRAD module.\n", dev->name, skb->dev->type);
+               accept = 0;
             }
             break;
 
          default:
             printk(KERN_WARNING "%s: unknown firmware type 0x%4.4X\n", dev->name, dev->type);
-            dev_kfree_skb(skb, FREE_WRITE);
-            return(0);
-      }
-
-      /* this is frame specific, but till there's a PPP module, it's the default */
-      switch (flp->type)
-      {
-         case SDLA_S502A:
-         case SDLA_S502E:
-            ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, skb->data, skb->len, NULL, NULL);
-            break;
-
-         case SDLA_S508:
-            size = sizeof(addr);
-            ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size);
-            if (ret == SDLA_RET_OK)
-            {
-               save_flags(flags); 
-               cli();
-               SDLA_WINDOW(dev, addr);
-               pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
-
-               sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
-
-               SDLA_WINDOW(dev, addr);
-               pbuf->opp_flag = 1;
-               restore_flags(flags);
-            }
+            accept = 0;
             break;
       }
- 
-      switch (ret)
+
+      if (accept)
       {
-         case SDLA_RET_OK:
-            flp->stats.tx_packets++;
-            ret = DLCI_RET_OK;
-            break;
- 
-         case SDLA_RET_CIR_OVERFLOW:
-         case SDLA_RET_BUF_OVERSIZE:
-         case SDLA_RET_NO_BUFS:
-            flp->stats.tx_dropped++;
-            ret = DLCI_RET_DROP;
-            break;
+         /* this is frame specific, but till there's a PPP module, it's the default */
+         switch (flp->type)
+         {
+            case SDLA_S502A:
+            case SDLA_S502E:
+               ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, skb->data, skb->len, NULL, NULL);
+               break;
+
+            case SDLA_S508:
+               size = sizeof(addr);
+               ret = sdla_cmd(dev, SDLA_INFORMATION_WRITE, *(short *)(skb->dev->dev_addr), 0, NULL, skb->len, &addr, &size);
+               if (ret == SDLA_RET_OK)
+               {
+                  save_flags(flags); 
+                  cli();
+                  SDLA_WINDOW(dev, addr);
+                  pbuf = (void *)(((int) dev->mem_start) + (addr & SDLA_ADDR_MASK));
+
+                  sdla_write(dev, pbuf->buf_addr, skb->data, skb->len);
+
+                  SDLA_WINDOW(dev, addr);
+                  pbuf->opp_flag = 1;
+                  restore_flags(flags);
+               }
+               break;
+         }
 
-         default:
-            flp->stats.tx_errors++;
-            ret = DLCI_RET_ERR;
-            break;
+         switch (ret)
+         {
+            case SDLA_RET_OK:
+               flp->stats.tx_packets++;
+               ret = DLCI_RET_OK;
+               break;
+
+            case SDLA_RET_CIR_OVERFLOW:
+            case SDLA_RET_BUF_OVERSIZE:
+            case SDLA_RET_NO_BUFS:
+               flp->stats.tx_dropped++;
+               ret = DLCI_RET_DROP;
+               break;
+
+            default:
+               flp->stats.tx_errors++;
+               ret = DLCI_RET_ERR;
+               break;
+         }
       }
       dev->tbusy = 0;
    }
diff -u --recursive --new-file pre2.0.4/linux/drivers/scsi/BusLogic.c linux/drivers/scsi/BusLogic.c
--- pre2.0.4/linux/drivers/scsi/BusLogic.c	Fri Apr 19 10:07:59 1996
+++ linux/drivers/scsi/BusLogic.c	Fri May 17 10:02:01 1996
@@ -24,8 +24,8 @@
 */
 
 
-#define BusLogic_DriverVersion		"1.3.2"
-#define BusLogic_DriverDate		"16 April 1996"
+#define BusLogic_DriverVersion		"2.0.3"
+#define BusLogic_DriverDate		"17 May 1996"
 
 
 #include <linux/module.h>
@@ -69,6 +69,15 @@
 
 
 /*
+  BusLogic_ProbeOptions is a bit mask of Probe Options to be applied
+  across all Host Adapters.
+*/
+
+static int
+  BusLogic_ProbeOptions =		0;
+
+
+/*
   BusLogic_GlobalOptions is a bit mask of Global Options to be applied
   across all Host Adapters.
 */
@@ -570,7 +579,7 @@
 
 static void BusLogic_InitializeAddressProbeList(void)
 {
-  int DestinationIndex = 0, SourceIndex = 0;
+  int ProbeAddressCount = 0, StandardAddressIndex = 0;
   /*
     If BusLogic_Setup has provided an I/O Address probe list, do not override
     the Kernel Command Line specifications.
@@ -601,31 +610,35 @@
 	    (BaseAddress0 & PCI_BASE_ADDRESS_SPACE) ==
 	      PCI_BASE_ADDRESS_SPACE_IO)
 	  {
-	    BusLogic_IO_AddressProbeList[DestinationIndex] =
+	    BusLogic_IO_AddressProbeList[ProbeAddressCount] =
 	      BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
-	    BusDeviceFunction[DestinationIndex] = (Bus << 8) | DeviceFunction;
-	    if (DestinationIndex > 0 &&
-		BusDeviceFunction[DestinationIndex] <
-		  BusDeviceFunction[DestinationIndex-1])
+	    BusDeviceFunction[ProbeAddressCount] = (Bus << 8) | DeviceFunction;
+	    if (ProbeAddressCount > 0 &&
+		BusDeviceFunction[ProbeAddressCount] <
+		  BusDeviceFunction[ProbeAddressCount-1])
 	      NonIncreasingScanningOrder = true;
-	    DestinationIndex++;
+	    ProbeAddressCount++;
 	  }
       /*
 	If there are multiple BusLogic PCI SCSI Host Adapters present and if
 	they are enumerated by the PCI BIOS in an order other than by strictly
 	increasing Bus Number and Device Number, then interrogate the setting
 	of the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option.
-	If it is ON, sort the PCI Host Adapter I/O Addresses by increasing Bus
-	Number and Device Number so that the Host Adapters are recognized in
-	the same order by the Linux kernel as by the Host Adapter's BIOS.
+	If it is ON, and if the first enumeratedBusLogic Host Adapter is a
+	BT-948/958/958D, then sort the PCI Host Adapter I/O Addresses by
+	increasing Bus Number and Device Number so that the Host Adapters are
+	recognized in the same order by the Linux kernel as by the Host
+	Adapter's BIOS.
       */
-      if (DestinationIndex > 1 && NonIncreasingScanningOrder)
+      if (ProbeAddressCount > 1 && NonIncreasingScanningOrder &&
+	  !(BusLogic_ProbeOptions & BusLogic_NoSortPCI))
 	{
+	  BusLogic_HostAdapter_T HostAdapterPrototype;
+	  BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
 	  BusLogic_FetchHostAdapterLocalRAMRequest_T
 	    FetchHostAdapterLocalRAMRequest;
 	  BusLogic_AutoSCSIByte45_T AutoSCSIByte45;
-	  BusLogic_HostAdapter_T HostAdapterPrototype;
-	  BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
+	  BusLogic_BoardID_T BoardID;
 	  HostAdapter->IO_Address = BusLogic_IO_AddressProbeList[0];
 	  FetchHostAdapterLocalRAMRequest.ByteOffset =
 	    BusLogic_AutoSCSI_BaseOffset + 45;
@@ -636,13 +649,18 @@
 			   &FetchHostAdapterLocalRAMRequest,
 			   sizeof(FetchHostAdapterLocalRAMRequest),
 			   &AutoSCSIByte45, sizeof(AutoSCSIByte45));
-	  if (AutoSCSIByte45.ForceBusDeviceScanningOrder)
+	  BoardID.FirmwareVersion1stDigit = '\0';
+	  BusLogic_Command(HostAdapter, BusLogic_InquireBoardID,
+			   NULL, 0, &BoardID, sizeof(BoardID));
+	  if (BoardID.FirmwareVersion1stDigit == '5' &&
+	      AutoSCSIByte45.ForceBusDeviceScanningOrder)
 	    {
 	      /*
-		Sort the I/O Addresses such that the corresponding PCI devices
-		are in ascending order by Bus Number and Device Number.
+		Sort the I/O Addresses such that the corresponding
+		PCI devices are in ascending order by Bus Number and
+		Device Number.
 	      */
-	      int LastInterchange = DestinationIndex-1, Bound, j;
+	      int LastInterchange = ProbeAddressCount-1, Bound, j;
 	      while (LastInterchange > 0)
 		{
 		  Bound = LastInterchange;
@@ -668,11 +686,12 @@
   /*
     Append the list of standard BusLogic ISA I/O Addresses.
   */
-  while (DestinationIndex < BusLogic_IO_MaxProbeAddresses &&
-	 BusLogic_IO_StandardAddresses[SourceIndex] > 0)
-    BusLogic_IO_AddressProbeList[DestinationIndex++] =
-      BusLogic_IO_StandardAddresses[SourceIndex++];
-  BusLogic_IO_AddressProbeList[DestinationIndex] = 0;
+  if (!(BusLogic_ProbeOptions & BusLogic_NoProbeISA))
+    while (ProbeAddressCount < BusLogic_IO_MaxProbeAddresses &&
+	   BusLogic_IO_StandardAddresses[StandardAddressIndex] > 0)
+      BusLogic_IO_AddressProbeList[ProbeAddressCount++] =
+	BusLogic_IO_StandardAddresses[StandardAddressIndex++];
+  BusLogic_IO_AddressProbeList[ProbeAddressCount] = 0;
 }
 
 
@@ -1871,6 +1890,7 @@
 {
   int BusLogicHostAdapterCount = 0, CommandLineEntryIndex = 0;
   int AddressProbeIndex = 0;
+  if (BusLogic_ProbeOptions & BusLogic_NoProbe) return 0;
   BusLogic_InitializeAddressProbeList();
   while (BusLogic_IO_AddressProbeList[AddressProbeIndex] > 0)
     {
@@ -2851,6 +2871,12 @@
 	  Result = SCSI_RESET_PENDING;
 	  goto Done;
 	}
+      else if (HostAdapter->BusDeviceResetPendingCCB[TargetID] != NULL)
+	{
+	  printk("scsi%d: Bus Device Reset already pending to Target %d\n",
+		 HostAdapter->HostNumber, TargetID);
+	  goto Done;
+	}
     }
   /*
     If this is a Synchronous Reset and a Bus Device Reset is already pending
@@ -2863,6 +2889,8 @@
       {
 	Command->reset_chain = CCB->Command;
 	CCB->Command = Command;
+	printk("scsi%d: Unable to Reset Command to Target %d - "
+	       "Reset Pending\n", HostAdapter->HostNumber, TargetID);
 	Result = SCSI_RESET_PENDING;
 	goto Done;
       }
@@ -3139,9 +3167,8 @@
   defaults to 0.  Note that Global Options are applied across all Host
   Adapters.
 
-  The string options are used to provide control over Tagged Queuing and Error
-  Recovery. If both Tagged Queuing and Error Recovery strings are provided, the
-  Tagged Queuing specification string must come first.
+  The string options are used to provide control over Tagged Queuing, Error
+  Recovery, and Host Adapter Probing.
 
   The Tagged Queuing specification begins with "TQ:" and allows for explicitly
   specifying whether Tagged Queuing is permitted on Target Devices that support
@@ -3207,6 +3234,20 @@
 			the sequence of "D", "H", "B", and "N" characters does
 			not cover all the possible Target Devices, unspecified
 			characters are assumed to be "D".
+
+  The Host Adapter Probing specification comprises the following strings:
+
+  NoProbe		No probing of any kind is to be performed, and hence
+			no BusLogic Host Adapters will be detected.
+
+  NoProbeISA		No probing of the standard ISA I/O Addresses will
+			be done, and hence only PCI Host Adapters will be
+			detected.
+
+  NoSortPCI		PCI Host Adapters will be enumerated in the order
+			provided by the PCI BIOS, ignoring any setting of
+			the AutoSCSI "Use Bus And Device # For PCI Scanning
+			Seq." option.
 */
 
 void BusLogic_Setup(char *Strings, int *Integers)
@@ -3277,97 +3318,120 @@
       return;
     }
   if (Strings == NULL) return;
-  if (strncmp(Strings, "TQ:", 3) == 0)
+  while (*Strings != '\0')
     {
-      Strings += 3;
-      if (strncmp(Strings, "Default", 7) == 0)
-	Strings += 7;
-      else if (strncmp(Strings, "Enable", 6) == 0)
-	{
-	  Strings += 6;
-	  CommandLineEntry->TaggedQueuingPermitted = 0xFFFF;
-	  CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF;
-	}
-      else if (strncmp(Strings, "Disable", 7) == 0)
+      if (strncmp(Strings, "TQ:", 3) == 0)
 	{
-	  Strings += 7;
-	  CommandLineEntry->TaggedQueuingPermitted = 0x0000;
-	  CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF;
+	  Strings += 3;
+	  if (strncmp(Strings, "Default", 7) == 0)
+	    Strings += 7;
+	  else if (strncmp(Strings, "Enable", 6) == 0)
+	    {
+	      Strings += 6;
+	      CommandLineEntry->TaggedQueuingPermitted = 0xFFFF;
+	      CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF;
+	    }
+	  else if (strncmp(Strings, "Disable", 7) == 0)
+	    {
+	      Strings += 7;
+	      CommandLineEntry->TaggedQueuingPermitted = 0x0000;
+	      CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF;
+	    }
+	  else
+	    for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+	      switch (*Strings++)
+		{
+		case 'Y':
+		  CommandLineEntry->TaggedQueuingPermitted |= 1 << TargetID;
+		  CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID;
+		  break;
+		case 'N':
+		  CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID;
+		  break;
+		case 'X':
+		  break;
+		default:
+		  Strings--;
+		  TargetID = BusLogic_MaxTargetDevices;
+		  break;
+		}
 	}
-      else
-	for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
-	  switch (*Strings++)
+      else if (strncmp(Strings, "ER:", 3) == 0)
+	{
+	  Strings += 3;
+	  if (strncmp(Strings, "Default", 7) == 0)
+	    Strings += 7;
+	  else if (strncmp(Strings, "HardReset", 9) == 0)
 	    {
-	    case 'Y':
-	      CommandLineEntry->TaggedQueuingPermitted |= 1 << TargetID;
-	      CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID;
-	      break;
-	    case 'N':
-	      CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID;
-	      break;
-	    case 'X':
-	      break;
-	    default:
-	      Strings--;
-	      TargetID = BusLogic_MaxTargetDevices;
-	      break;
+	      Strings += 9;
+	      memset(CommandLineEntry->ErrorRecoveryStrategy,
+		     BusLogic_ErrorRecovery_HardReset,
+		     sizeof(CommandLineEntry->ErrorRecoveryStrategy));
 	    }
-    }
-  if (*Strings == ',') Strings++;
-  if (strncmp(Strings, "ER:", 3) == 0)
-    {
-      Strings += 3;
-      if (strncmp(Strings, "Default", 7) == 0)
-	Strings += 7;
-      else if (strncmp(Strings, "HardReset", 9) == 0)
+	  else if (strncmp(Strings, "BusDeviceReset", 14) == 0)
+	    {
+	      Strings += 14;
+	      memset(CommandLineEntry->ErrorRecoveryStrategy,
+		     BusLogic_ErrorRecovery_BusDeviceReset,
+		     sizeof(CommandLineEntry->ErrorRecoveryStrategy));
+	    }
+	  else if (strncmp(Strings, "None", 4) == 0)
+	    {
+	      Strings += 4;
+	      memset(CommandLineEntry->ErrorRecoveryStrategy,
+		     BusLogic_ErrorRecovery_None,
+		     sizeof(CommandLineEntry->ErrorRecoveryStrategy));
+	    }
+	  else
+	    for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+	      switch (*Strings++)
+		{
+		case 'D':
+		  CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
+		    BusLogic_ErrorRecovery_Default;
+		  break;
+		case 'H':
+		  CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
+		    BusLogic_ErrorRecovery_HardReset;
+		  break;
+		case 'B':
+		  CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
+		    BusLogic_ErrorRecovery_BusDeviceReset;
+		  break;
+		case 'N':
+		  CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
+		    BusLogic_ErrorRecovery_None;
+		  break;
+		default:
+		  Strings--;
+		  TargetID = BusLogic_MaxTargetDevices;
+		  break;
+		}
+	}
+      else if (strcmp(Strings, "NoProbe") == 0 ||
+	       strcmp(Strings, "noprobe") == 0)
+	{
+	  Strings += 7;
+	  BusLogic_ProbeOptions |= BusLogic_NoProbe;
+	}
+      else if (strncmp(Strings, "NoProbeISA", 10) == 0)
+	{
+	  Strings += 10;
+	  BusLogic_ProbeOptions |= BusLogic_NoProbeISA;
+	}
+      else if (strncmp(Strings, "NoSortPCI", 9) == 0)
 	{
 	  Strings += 9;
-	  memset(CommandLineEntry->ErrorRecoveryStrategy,
-		 BusLogic_ErrorRecovery_HardReset,
-		 sizeof(CommandLineEntry->ErrorRecoveryStrategy));
-	}
-      else if (strncmp(Strings, "BusDeviceReset", 14) == 0)
-	{
-	  Strings += 14;
-	  memset(CommandLineEntry->ErrorRecoveryStrategy,
-		 BusLogic_ErrorRecovery_BusDeviceReset,
-		 sizeof(CommandLineEntry->ErrorRecoveryStrategy));
-	}
-      else if (strncmp(Strings, "None", 4) == 0)
-	{
-	  Strings += 4;
-	  memset(CommandLineEntry->ErrorRecoveryStrategy,
-		 BusLogic_ErrorRecovery_None,
-		 sizeof(CommandLineEntry->ErrorRecoveryStrategy));
+	  BusLogic_ProbeOptions |= BusLogic_NoSortPCI;
 	}
       else
-	for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
-	  switch (*Strings++)
-	    {
-	    case 'D':
-	      CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
-		BusLogic_ErrorRecovery_Default;
-	      break;
-	    case 'H':
-	      CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
-		BusLogic_ErrorRecovery_HardReset;
-	      break;
-	    case 'B':
-	      CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
-		BusLogic_ErrorRecovery_BusDeviceReset;
-	      break;
-	    case 'N':
-	      CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
-		BusLogic_ErrorRecovery_None;
-	      break;
-	    default:
-	      Strings--;
-	      TargetID = BusLogic_MaxTargetDevices;
-	      break;
-	    }
+	{
+	  printk("BusLogic: Unexpected Command Line String '%s' ignored\n",
+		 Strings);
+	  break;
+	}
+      if (*Strings == ',') Strings++;
     }
-  if (*Strings != '\0')
-    printk("BusLogic: Unexpected Command Line String '%s' ignored\n", Strings);
 }
 
 
diff -u --recursive --new-file pre2.0.4/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h
--- pre2.0.4/linux/drivers/scsi/BusLogic.h	Mon Apr 15 12:20:19 1996
+++ linux/drivers/scsi/BusLogic.h	Fri May 17 10:02:01 1996
@@ -147,6 +147,15 @@
 
 
 /*
+  Define the possible Probe Options.
+*/
+
+#define BusLogic_NoProbe			1
+#define BusLogic_NoProbeISA			2
+#define BusLogic_NoSortPCI			4
+
+
+/*
   Define the possible Global Options.
 */
 
diff -u --recursive --new-file pre2.0.4/linux/drivers/scsi/ChangeLog linux/drivers/scsi/ChangeLog
--- pre2.0.4/linux/drivers/scsi/ChangeLog	Tue May  7 16:22:32 1996
+++ linux/drivers/scsi/ChangeLog	Fri May 17 10:50:58 1996
@@ -1,3 +1,7 @@
+Fri May 17 00:00:00 1996  Leonard N. Zubkoff <lnz@dandelion.com>
+
+	* BusLogic Driver Version 2.0.3 Released.
+
 Tue Apr 16 21:00:00 1996  Leonard N. Zubkoff <lnz@dandelion.com>
 
 	* BusLogic Driver Version 1.3.2 Released.
diff -u --recursive --new-file pre2.0.4/linux/drivers/scsi/README.BusLogic linux/drivers/scsi/README.BusLogic
--- pre2.0.4/linux/drivers/scsi/README.BusLogic	Fri Apr 19 10:07:59 1996
+++ linux/drivers/scsi/README.BusLogic	Fri May 17 10:02:01 1996
@@ -1,9 +1,9 @@
 		  BusLogic MultiMaster SCSI Driver for Linux
 
-		       Version 1.2.2 for Linux 1.2.13
-		       Version 1.3.2 for Linux 1.3.88
+		       Version 1.2.3 for Linux 1.2.13
+		       Version 2.0.3 for Linux 2.0.0
 
-				 16 April 1996
+				  17 May 1996
 
 			       Leonard N. Zubkoff
 			       Dandelion Digital
@@ -114,7 +114,7 @@
   level parts of the SCSI subsystem request that a command be reset, action is
   taken to restore proper operation of the host adapter and SCSI bus.  On Linux
   1.2.13, by default a full host adapter hard reset and SCSI bus reset is
-  performed.  On Linux 1.3.x, by default a selection is made between a full
+  performed.  On Linux 2.0.x, by default a selection is made between a full
   host adapter hard reset and SCSI bus reset versus sending a bus device reset
   message to the individual target device based on the recommendation of the
   SCSI subsystem.  Error recovery strategies are selectable from the kernel
@@ -167,7 +167,7 @@
   All BusLogic MultiMaster SCSI Host Adapters share a common programming
   interface, except for the inevitable improvements and extensions as new
   models are released, so support for Wide SCSI data transfer has automatically
-  been available without explicit driver support.  When used with Linux 1.3.x,
+  been available without explicit driver support.  When used with Linux 2.0.x,
   this driver adds explicit support for up to 15 target devices and 64 logical
   units per target device, to fully exploit the capabilities of the newest
   BusLogic Wide SCSI Host Adapters.
@@ -299,12 +299,14 @@
     such as disk drives, but should not be disabled for tape drives or other
     devices where a single command may take over a second to execute.
 
-  "BusLogic=0,0,10"
+  "BusLogic=0,0,30"
 
     This command line selects default probing and automatic tagged queue depth
-    selection, but changes the bus settle time to 10 seconds.  It may be useful
+    selection, but changes the bus settle time to 30 seconds.  It may be useful
     with SCSI devices that take an unusually long time to become ready to
-    accept commands after a SCSI bus reset.
+    accept commands after a SCSI bus reset.  Some tape drives will not respond
+    properly immediately after a SCSI bus reset, especially if a tape is
+    present in the drive.
 
   "BusLogic=TQ:Disable"
 
@@ -323,19 +325,20 @@
 			     INSTALLATION
 
 This distribution was prepared for Linux kernel version 1.2.13
-(BusLogic-1.2.2.tar.gz) or Linux kernel version 1.3.88 (BusLogic-1.3.2.tar.gz).
+(BusLogic-1.2.3.tar.gz) or Linux kernel version 2.0.0 (BusLogic-2.0.3.tar.gz).
 Installation in later versions will probably be successful as well, though
 BusLogic.patch may not be required.  Installation in earlier versions is not
 recommended.
 
 To install the BusLogic SCSI driver, you may use the following commands,
 replacing "/usr/src" with wherever you keep your Linux kernel source tree
-(substitute '2' or '3' for 'x' in the tar command as appropriate):
+(substitute "1.2" or "2.0" for "x.y" in the tar command as appropriate):
 
   cd /usr/src
-  tar -xvzf BusLogic-1.x.2.tar.gz
+  tar -xvzf BusLogic-x.y.3.tar.gz
   mv README.* BusLogic.[ch] linux/drivers/scsi
-  patch -p < BusLogic.patch
+  patch -p < BusLogic.patch	    (on Linux 1.2.13 only)
+  patch -p < BusLogic.elf_patch	    (on Linux 1.2.13 ELF systems only)
   cd linux
   make config
   make depend
diff -u --recursive --new-file pre2.0.4/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c
--- pre2.0.4/linux/drivers/scsi/aha152x.c	Sat May 11 10:42:05 1996
+++ linux/drivers/scsi/aha152x.c	Thu May 16 16:38:16 1996
@@ -1830,6 +1830,13 @@
 #endif
 	      break;
 
+	    case RESTORE_POINTERS:
+#if defined(DEBUG_MSGI)
+		if(HOSTDATA(shpnt)->debug & debug_msgi)
+		  printk("inbound message (RESTORE DATA POINTERS), ");
+#endif
+	      break;
+
 	    case EXTENDED_MESSAGE:
 	      { 
         	  char buffer[16];
diff -u --recursive --new-file pre2.0.4/linux/drivers/scsi/atari_NCR5380.c linux/drivers/scsi/atari_NCR5380.c
--- pre2.0.4/linux/drivers/scsi/atari_NCR5380.c	Sat Apr 27 15:19:56 1996
+++ linux/drivers/scsi/atari_NCR5380.c	Thu May 16 09:05:11 1996
@@ -53,65 +53,25 @@
  *    Since most scatter-gather operations work on a page (4K) of
  *    4 buffers (1K), in more than 90% of all cases three interrupts and
  *    DMA setup actions are saved.
- * 
- */
-
-/*
- * +++roman: I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL,
- * PSEUDO_DMA and USLEEP, because these were messing up
- * readability and will never be needed for Atari SCSI.
- */
-
-
-/*
- * $Log: atari_NCR5380.c,v $
- * Revision 1.2  1996/04/04 13:30:22  root
- * interrupts more like the pc
- *
- * Revision 1.1  1996/03/20 17:51:35  root
- * Initial revision
- *
- * Revision 1.2  1994/11/26  03:38:32  hamish
- * v0.9pl4
  *
- * Revision 1.1  1994/11/08  03:25:43  hamish
- * Initial revision
- *
- * Revision 1.5  1994/01/19  09:14:57  drew
- * Fixed udelay() hack that was being used on DATAOUT phases
- * instead of a proper wait for the final handshake.
- *
- * Revision 1.4  1994/01/19  06:44:25  drew
- * *** empty log message ***
- *
- * Revision 1.3  1994/01/19  05:24:40  drew
- * Added support for TCR LAST_BYTE_SENT bit.
- *
- * Revision 1.2  1994/01/15  06:14:11  drew
- * REAL DMA support, bug fixes.
- *
- * Revision 1.1  1994/01/15  06:00:54  drew
- * Initial revision
+ * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
+ *    and USLEEP, because these were messing up readability and will never be
+ *    needed for Atari SCSI.
+ * 
+ * - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
+ *   stuff), and 'main' is executed in a bottom half if awoken by an
+ *   interrupt.
+ *
+ * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..."
+ *   constructs. In my eyes, this made the source rather unreadable, so I
+ *   finally replaced that by the *_PRINTK() macros.
  *
  */
 
 /*
  * Further development / testing that should be done : 
- * 1.  Cleanup the NCR5380_transfer_dma function and DMA operation complete
- *     code so that everything does the same thing that's done at the 
- *     end of a pseudo-DMA read operation.
- *
- * 2.  Fix REAL_DMA (interrupt driven, polled works fine) -
- *     basically, transfer size needs to be reduced by one 
- *     and the last byte read as is done with PSEUDO_DMA.
- * 
- * 3.  Test USLEEP code 
- *
- * 4.  Test SCSI-II tagged queueing (I have no devices which support 
- *	tagged queueing)
- *
- * 5.  Test linked command handling code after Eric is ready with 
- *      the high level code.
+ * 1.  Test linked command handling code after Eric is ready with 
+ *     the high level code.
  */
 
 #if (NDEBUG & NDEBUG_LISTS)
@@ -404,10 +364,8 @@
 	return( 0 );
     if (TagAlloc[cmd->target][cmd->lun].nr_allocated >=
 	TagAlloc[cmd->target][cmd->lun].queue_size ) {
-#if (NDEBUG & NDEBUG_TAGS)
-	printk( "scsi%d: target %d lun %d: no free tags\n",
-		H_NO(cmd), cmd->target, cmd->lun );
-#endif
+	TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
+		    H_NO(cmd), cmd->target, cmd->lun );
 	return( 1 );
     }
     return( 0 );
@@ -430,10 +388,8 @@
 	!setup_use_tagged_queuing || !cmd->device->tagged_supported) {
 	cmd->tag = TAG_NONE;
 	hostdata->busy[cmd->target] |= (1 << cmd->lun);
-#if (NDEBUG & NDEBUG_TAGS)
-	printk( "scsi%d: target %d lun %d now allocated by untagged command\n",
-		H_NO(cmd), cmd->target, cmd->lun );
-#endif
+	TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
+		    "command\n", H_NO(cmd), cmd->target, cmd->lun );
     }
     else {
 	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
@@ -441,12 +397,10 @@
 	cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS );
 	set_bit( cmd->tag, &ta->allocated );
 	ta->nr_allocated++;
-#if (NDEBUG & NDEBUG_TAGS)
-	printk( "scsi%d: using tag %d for target %d lun %d "
-		"(now %d tags in use)\n",
-		H_NO(cmd), cmd->tag, cmd->target, cmd->lun,
-		ta->nr_allocated );
-#endif
+	TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
+		    "(now %d tags in use)\n",
+		    H_NO(cmd), cmd->tag, cmd->target, cmd->lun,
+		    ta->nr_allocated );
     }
 }
 
@@ -461,28 +415,24 @@
 
     if (cmd->tag == TAG_NONE) {
 	hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
-#if (NDEBUG & NDEBUG_TAGS)
-	printk( "scsi%d: target %d lun %d untagged cmd finished\n",
-		H_NO(cmd), cmd->target, cmd->lun );
-#endif
+	TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
+		    H_NO(cmd), cmd->target, cmd->lun );
     }
     else if (cmd->tag >= MAX_TAGS) {
-	printk( "scsi%d: trying to free bad tag %d!\n",
+	printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
 		H_NO(cmd), cmd->tag );
     }
     else {
 	TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
 	clear_bit( cmd->tag, &ta->allocated );
 	ta->nr_allocated--;
-#if (NDEBUG & NDEBUG_TAGS)
-	printk( "scsi%d: freed tag %d for target %d lun %d\n",
-		H_NO(cmd), cmd->tag, cmd->target, cmd->lun );
-#endif
+	TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
+		    H_NO(cmd), cmd->tag, cmd->target, cmd->lun );
     }
 }
 
 
-#if 0
+#if 1
 static void free_all_tags( void )
 {
     int target, lun;
@@ -537,9 +487,9 @@
 	 cmd->SCp.buffers_residual &&
 	 VTOP( (cmd->SCp.buffer+1)->address ) == endadr + 1; ) {
 	
+	MER_PRINTK( "%08lx == %08lx -> merging\n",
+		    VTOP( (cmd->SCp.buffer+1)->address ), endadr );
 #if (NDEBUG & NDEBUG_MERGING)
-	printk( "%08lx == %08lx -> merging\n",
-		VTOP( (cmd->SCp.buffer+1)->address ), endadr );
 	++cnt;
 #endif
 	++cmd->SCp.buffer;
@@ -549,8 +499,8 @@
     }
 #if (NDEBUG & NDEBUG_MERGING)
     if (oldlen != cmd->SCp.this_residual)
-	printk( "merged %d buffers from %08lx, new length %08lx\n",
-		cnt, (long)(cmd->SCp.ptr), cmd->SCp.this_residual );
+	MER_PRINTK( "merged %d buffers from %08lx, new length %08lx\n",
+		    cnt, (long)(cmd->SCp.ptr), cmd->SCp.this_residual );
 #endif
 }
 
@@ -590,7 +540,7 @@
 #include <linux/config.h>
 #include <linux/delay.h>
 
-#ifdef NDEBUG
+#if NDEBUG
 static struct {
     unsigned char mask;
     const char * name;} 
@@ -671,63 +621,58 @@
 
     status = NCR5380_read(STATUS_REG);
     if (!(status & SR_REQ)) 
-	printk("scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+	printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
     else {
 	for (i = 0; (phases[i].value != PHASE_UNKNOWN) && 
 	    (phases[i].value != (status & PHASE_MASK)); ++i); 
-	printk("scsi%d: phase %s\n", HOSTNO, phases[i].name);
+	printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
     }
 }
-#endif
 
-/*
- * We need to have our coroutine active given these constraints : 
- * 1.  The mutex flag, main_running, can only be set when the main 
- *     routine can actually process data, otherwise SCSI commands
- *     will never get issued.
- *
- * 2.  NCR5380_main() shouldn't be called before it has exited, because
- *     other drivers have had kernel stack overflows in similar
- *     situations.
- *
- * 3.  We don't want to inline NCR5380_main() because of space concerns,
- *     even though it is only called in two places.
- *
- * So, the solution is to set the mutex in an inline wrapper for the 
- * main coroutine, and have the main coroutine exit with interrupts 
- * disabled after the final search through the queues so that no race 
- * conditions are possible.
- */
+#else /* !NDEBUG */
 
-static volatile int main_running = 0;
+/* dummys... */
+__inline__ void NCR5380_print(struct Scsi_Host *instance) { };
+__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
 
-/* 
- * Function : run_main(void)
+#endif
+
+/*
+ * ++roman: New scheme of calling NCR5380_main()
  * 
- * Purpose : insure that the coroutine is running and will process our 
- * 	request.  main_running is checked/set here (in an inline function)
- *	rather than in NCR5380_main itself to reduce the chances of stack
- *	overflow.
- *
+ * If we're not in an interrupt, we can call our main directly, it cannot be
+ * already running. Else, we queue it on a task queue, if not 'main_running'
+ * tells us that a lower level is already executing it. This way,
+ * 'main_running' needs not be protected in a special way.
+ *
+ * queue_main() is a utility function for putting our main onto the task
+ * queue, if main_running is false. It should be called only from a
+ * interrupt or bottom half.
  */
 
-static void NCR5380_main_a ( unsigned long flags );
+#include <linux/tqueue.h>
+#include <linux/interrupt.h>
 
-static __inline__ void run_main(void)
-{
-    unsigned long flags;
+static volatile int main_running = 0;
+static struct tq_struct NCR5380_tqueue = {
+    NULL,		/* next */
+    0,			/* sync */
+    (void (*)(void*))NCR5380_main,  /* routine, must have (void *) arg... */
+    NULL		/* data */
+};
 
-    save_flags(flags);
-    cli();
+static __inline__ void queue_main(void)
+{
     if (!main_running) {
-	main_running = 1;
-        NCR5380_main_a( flags );
-	/* 
-         * main_running is cleared in NCR5380_main once it can't do 
-	 * more work, and NCR5380_main exits with interrupts disabled.
-	 */
+	/* If in interrupt and NCR5380_main() not already running,
+	   queue it on the 'immediate' task queue, to be processed
+	   immediately after the current interrupt processing has
+	   finished. */
+	queue_task_irq(&NCR5380_tqueue, &tq_immediate);
+	mark_bh(IMMEDIATE_BH);
     }
-    restore_flags(flags);
+    /* else: nothing to do: the running NCR5380_main() will pick up
+       any newly queued command. */
 }
 
 
@@ -735,9 +680,7 @@
 {
     static int done = 0;
     if (!done) {
-#if (NDEBUG & NDEBUG_INIT)
-	printk("scsi : NCR5380_all_init()\n");
-#endif
+	INI_PRINTK("scsi : NCR5380_all_init()\n");
 	done = 1;
     }
 }
@@ -786,13 +729,8 @@
     char *start;
     int len;
 
-    printk("NCR5380: coroutine is%s running.\n",
-	main_running ? "" : "n't");
-    
-#ifdef NDEBUG
-    NCR5380_print (instance);
-    NCR5380_print_phase (instance);
-#endif
+    NCR_PRINT(NDEBUG_ANY);
+    NCR_PRINT_PHASE(NDEBUG_ANY);
 
     len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), HOSTNO, 0);
     pr_bfr[len] = 0;
@@ -993,7 +931,7 @@
     switch (cmd->cmnd[0]) {
     case WRITE_6:
     case WRITE_10:
-	printk("scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
+	printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
 	       H_NO(cmd));
 	cmd->result = (DID_ERROR << 16);
 	done(cmd);
@@ -1081,13 +1019,20 @@
     }
     restore_flags(flags);
 
-#if (NDEBUG & NDEBUG_QUEUES)
-    printk("scsi%d: command added to %s of queue\n", H_NO(cmd),
-	(cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
-#endif
+    QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
+	      (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
 
-/* Run the coroutine if it isn't already running. */
-    run_main();
+    /* If queue_command() is called from an interrupt (real one or bottom
+     * half), we let queue_main() do the job of taking care about main. If it
+     * is already running, this is a no-op, else main will be queued.
+     *
+     * If we're not in an interrupt, we can call NCR5380_main()
+     * unconditionally, because it cannot be already running.
+     */
+    if (intr_count > 0)
+	queue_main();
+    else
+	NCR5380_main();
     return 0;
 }
 
@@ -1103,14 +1048,13 @@
  *  reenable them.  This prevents reentrancy and kernel stack overflow.
  */ 	
     
-static inline void NCR5380_main () {}
-
-static void NCR5380_main_a ( unsigned long flags )
+static void NCR5380_main (void)
 {
     Scsi_Cmnd *tmp, *prev;
     struct Scsi_Host *instance = first_instance;
     struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
     int done;
+    unsigned long flags;
     
     /*
      * We run (with interrupts disabled) until we're sure that none of 
@@ -1128,14 +1072,20 @@
      * alter queues and touch the Falcon lock.
      */
 
+    /* Tell int handlers main() is now already executing.  Note that
+       no races are possible here. If an int comes in before
+       'main_running' is set here, and queues/executes main via the
+       task queue, it doesn't do any harm, just this instance of main
+       won't find any work left to do. */
+    main_running = 1;
+
+    save_flags(flags);
     do {
 	cli(); /* Freeze request queues */
 	done = 1;
 	
 	if (!hostdata->connected) {
-#if (NDEBUG & NDEBUG_MAIN)
-	    printk("scsi%d: not connected\n", HOSTNO);
-#endif
+	    MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO );
 	    /*
 	     * Search through the issue_queue for a command destined
 	     * for a target that's not busy.
@@ -1185,11 +1135,10 @@
 		     * On failure, we must add the command back to the
 		     *   issue queue so we can keep trying.	
 		     */
-#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES))
-		    printk("scsi%d: main(): command for target %d lun %d "
-			   "removed from issue_queue\n",
-			   HOSTNO, tmp->target, tmp->lun);
-#endif
+		    DPRINTK(NDEBUG_MAIN | NDEBUG_QUEUES,
+			    "scsi%d: main(): command for target %d lun %d "
+			    "removed from issue_queue\n",
+			    HOSTNO, tmp->target, tmp->lun);
 		    /* 
 		     * REQUEST SENSE commands are issued without tagged
 		     * queueing, even on SCSI-II devices because the 
@@ -1220,10 +1169,9 @@
 #endif
 			falcon_dont_release--;
 			restore_flags(flags);
-#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES))
-			printk("scsi%d: main(): select() failed, "
-			       "returned to issue_queue\n", HOSTNO);
-#endif
+			DPRINTK(NDEBUG_MAIN | NDEBUG_QUEUES,
+				"scsi%d: main(): select() failed, "
+				"returned to issue_queue\n", HOSTNO);
 			if (hostdata->connected)
 			    break;
 		    }
@@ -1237,21 +1185,19 @@
 #endif
 	    ) {
 	    restore_flags(flags);
-#if (NDEBUG & NDEBUG_MAIN)
-	    printk("scsi%d: main() : performing information transfer\n",
-		   HOSTNO);
-#endif
+	    MAIN_PRINTK("scsi%d: main: performing information transfer\n",
+			HOSTNO);
 	    NCR5380_information_transfer(instance);
-#if (NDEBUG & NDEBUG_MAIN)
-	    printk("scsi%d: main() : done set false\n", HOSTNO);
-#endif
+	    MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
 	    done = 0;
-	} else {
-	    cli(); /* ++guenther: be sure to protect main_running */
-	    break;
 	}
     } while (!done);
+
+    /* Better allow ints _after_ 'main_running' has been cleared, else
+       an interrupt could believe we'll pick up the work it left for
+       us, but we won't see it anymore here... */
     main_running = 0;
+    restore_flags(flags);
 }
 
 
@@ -1274,8 +1220,8 @@
     volatile int  *count;
 
     if (!hostdata->connected) {
-	printk("scsi%d: received end of DMA interrupt with no connected cmd\n",
-	       HOSTNO);
+	printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
+	       "no connected cmd\n", HOSTNO);
 	return;
     }
     
@@ -1288,18 +1234,14 @@
 		 (BASR_PHASE_MATCH|BASR_ACK))) {
 		saved_data = NCR5380_read(INPUT_DATA_REG);
 		overrun = 1;
-#if (NDEBUG & NDEBUG_DMA)
-		printk( "scsi%d: read overrun handled\n", HOSTNO );
-#endif
+		DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO);
 	    }
 	}
     }
 
-#if (NDEBUG & NDEBUG_DMA)
-    printk("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
-	   HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
-	   NCR5380_read(STATUS_REG));
-#endif
+    DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
+	       HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
+	       NCR5380_read(STATUS_REG));
 
     (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
     NCR5380_write(MODE_REG, MR_BASE);
@@ -1317,18 +1259,13 @@
 	if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
 	    cnt = toPIO = atari_read_overruns;
 	    if (overrun) {
-#if (NDEBUG & NDEBUG_DMA)
-		printk("Got an input overrun, using saved byte\n");
-#endif
+		DMA_PRINTK("Got an input overrun, using saved byte\n");
 		*(*data)++ = saved_data;
 		(*count)--;
 		cnt--;
 		toPIO--;
 	    }
-#if (NDEBUG & NDEBUG_DMA)
-	    printk( "Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data );
-#endif
-
+	    DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data);
 	    NCR5380_transfer_pio(instance, &p, &cnt, data);
 	    *count -= toPIO - cnt;
 	}
@@ -1354,39 +1291,27 @@
     int done = 1;
     unsigned char basr;
 
-#if (NDEBUG & NDEBUG_INTR)
-    printk("scsi%d: NCR5380 irq triggered\n", HOSTNO);
-#endif
+    INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
 
     /* Look for pending interrupts */
     basr = NCR5380_read(BUS_AND_STATUS_REG);
-#if (NDEBUG & NDEBUG_INTR)
-    printk( "scsi%d: BASR=%02x\n", HOSTNO, basr );
-#endif
+    INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
     /* dispatch to appropriate routine if found and done=0 */
     if (basr & BASR_IRQ) {
-#if (NDEBUG & NDEBUG_INTR)
-	NCR5380_print(instance);
-#endif
+	NCR_PRINT(NDEBUG_INTR);
 	if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
 	    done = 0;
 	    ENABLE_IRQ();
-#if (NDEBUG & NDEBUG_INTR)
-	    printk("scsi%d: SEL interrupt\n", HOSTNO);
-#endif
+	    INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
 	    NCR5380_reselect(instance);
 	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 	}
 	else if (basr & BASR_PARITY_ERROR) {
-#if (NDEBUG & NDEBUG_INTR)
-	    printk("scsi%d: PARITY interrupt\n", HOSTNO);
-#endif
+	    INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
 	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 	}
 	else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
-#if (NDEBUG & NDEBUG_INTR)
-	    printk("scsi%d: RESET interrupt\n", HOSTNO);
-#endif
+	    INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
 	    (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 	}
 	else {
@@ -1406,41 +1331,34 @@
 		((basr & BASR_END_DMA_TRANSFER) || 
 		 !(basr & BASR_PHASE_MATCH))) {
 		    
-#if (NDEBUG & NDEBUG_INTR)
-		printk("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
-#endif
+		INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
 		NCR5380_dma_complete( instance );
 		done = 0;
 		ENABLE_IRQ();
 	    } else
 #endif /* REAL_DMA */
 	    {
-#if 1 || (NDEBUG & NDEBUG_INTR)
 /* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
 		if (basr & BASR_PHASE_MATCH)
-		    printk("scsi%d: unknown interrupt, "
+		    printk(KERN_NOTICE "scsi%d: unknown interrupt, "
 			   "BASR 0x%x, MR 0x%x, SR 0x%x\n",
 			   HOSTNO, basr, NCR5380_read(MODE_REG),
 			   NCR5380_read(STATUS_REG));
-#endif
 		(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
 	    }
 	} /* if !(SELECTION || PARITY) */
     } /* BASR & IRQ */
     else {
-#if 1 || (NDEBUG & NDEBUG_INTR)
-	printk("scsi%d: interrupt without IRQ bit set in BASR, "
+	printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
 	       "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
 	       NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
-#endif
 	(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
     }
     
     if (!done) {
-#if (NDEBUG & NDEBUG_INTR)
-	printk("scsi%d: in int routine, calling main\n", HOSTNO );
-#endif
-	run_main();
+	INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
+	/* Put a call to NCR5380_main() on the queue... */
+	queue_main();
     }
 }
 
@@ -1511,11 +1429,9 @@
     unsigned long flags;
 
     hostdata->restart_select = 0;
-#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION) 
-    NCR5380_print(instance);
-    printk("scsi%d: starting arbitration, id = %d\n", HOSTNO,
-	instance->this_id);
-#endif
+    NCR_PRINT(NDEBUG_ARBITRATION);
+    ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
+	       instance->this_id);
 
     /* 
      * Set the phase bits to 0, otherwise the NCR5380 won't drive the 
@@ -1561,11 +1477,7 @@
 	 && !hostdata->connected);
 #endif
 
-#if (NDEBUG & NDEBUG_ARBITRATION) 
-    printk("scsi%d: arbitration complete\n", HOSTNO);
-/* Avoid GCC 2.4.5 asm needs to many reloads error */
-    __asm__("nop");
-#endif
+    ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
 
     if (hostdata->connected) {
 	NCR5380_write(MODE_REG, MR_BASE); 
@@ -1586,9 +1498,8 @@
 	(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
 	hostdata->connected) {
 	NCR5380_write(MODE_REG, MR_BASE); 
-#if (NDEBUG & NDEBUG_ARBITRATION)
-    printk("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n", HOSTNO);
-#endif
+	ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
+		   HOSTNO);
 	return -1;
     }
 
@@ -1602,9 +1513,8 @@
 	hostdata->connected) {
 	NCR5380_write(MODE_REG, MR_BASE);
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-#if (NDEBUG & NDEBUG_ARBITRATION)
-    printk("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n", HOSTNO);
-#endif
+	ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
+		   HOSTNO);
 	return -1;
     }
 
@@ -1626,10 +1536,7 @@
 	return -1;
     }
 
-#if (NDEBUG & NDEBUG_ARBITRATION)
-    printk("scsi%d: won arbitration\n", HOSTNO);
-#endif
-
+    ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
 
     /* 
      * Now that we have won arbitration, start Selection process, asserting 
@@ -1689,9 +1596,7 @@
 
     udelay(1);
 
-#if (NDEBUG & NDEBUG_SELECTION)
-    printk("scsi%d: selecting target %d\n", HOSTNO, cmd->target);
-#endif
+    SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->target);
 
     /* 
      * The SCSI specification calls for a 250 ms timeout for the actual 
@@ -1721,7 +1626,8 @@
 	    (SR_SEL | SR_IO)) {
 	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 	    NCR5380_reselect(instance);
-	    printk ("scsi%d: reselection after won arbitration?\n", HOSTNO);
+	    printk (KERN_ERR "scsi%d: reselection after won arbitration?\n",
+		    HOSTNO);
 	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 	    return -1;
     }
@@ -1742,12 +1648,10 @@
     if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
 	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 	if (hostdata->targets_present & (1 << cmd->target)) {
-	    printk("scsi%d: weirdness\n", HOSTNO);
+	    printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
 	    if (hostdata->restart_select)
-		printk("\trestart select\n");
-#ifdef NDEBUG
-	    NCR5380_print (instance);
-#endif
+		printk(KERN_NOTICE "\trestart select\n");
+	    NCR_PRINT(NDEBUG_ANY);
 	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 	    return -1;
 	}
@@ -1760,9 +1664,7 @@
 #endif
 	cmd->scsi_done(cmd);
 	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-#if (NDEBUG & NDEBUG_SELECTION)
-	printk("scsi%d: target did not respond within 250ms\n", HOSTNO);
-#endif
+	SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
 	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 	return 0;
     } 
@@ -1787,10 +1689,8 @@
     /* Wait for start of REQ/ACK handshake */
     while (!(NCR5380_read(STATUS_REG) & SR_REQ));
 
-#if (NDEBUG & NDEBUG_SELECTION)
-    printk("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
-	   HOSTNO, cmd->target);
-#endif
+    SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
+	       HOSTNO, cmd->target);
     tmp[0] = IDENTIFY(1, cmd->lun);
 
 #ifdef SUPPORT_TAGS
@@ -1809,9 +1709,7 @@
     data = tmp;
     phase = PHASE_MSGOUT;
     NCR5380_transfer_pio(instance, &phase, &len, &data);
-#if (NDEBUG & NDEBUG_SELECTION)
-    printk("scsi%d: nexus established.\n", HOSTNO);
-#endif
+    SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
     /* XXX need to handle errors here */
     hostdata->connected = cmd;
 #ifndef SUPPORT_TAGS
@@ -1872,16 +1770,12 @@
 	 */
 	while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
 
-#if (NDEBUG & NDEBUG_HANDSHAKE)
-	printk("scsi%d: REQ detected\n", HOSTNO);
-#endif
+	HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
 
 	/* Check for phase mismatch */	
 	if ((tmp & PHASE_MASK) != p) {
-#if (NDEBUG & NDEBUG_PIO)
-	    printk("scsi%d: phase mismatch\n", HOSTNO);
-	    NCR5380_print_phase(instance);
-#endif
+	    PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
+	    NCR_PRINT_PHASE(NDEBUG_PIO);
 	    break;
 	}
 
@@ -1904,32 +1798,24 @@
 	    if (!((p & SR_MSG) && c > 1)) {
 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
 		    ICR_ASSERT_DATA);
-#if (NDEBUG & NDEBUG_PIO)
-		NCR5380_print(instance);
-#endif
+		NCR_PRINT(NDEBUG_PIO);
 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
 			ICR_ASSERT_DATA | ICR_ASSERT_ACK);
 	    } else {
 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
 		    ICR_ASSERT_DATA | ICR_ASSERT_ATN);
-#if (NDEBUG & NDEBUG_PIO)
-		NCR5380_print(instance);
-#endif
+		NCR_PRINT(NDEBUG_PIO);
 		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
 		    ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
 	    }
 	} else {
-#if (NDEBUG & NDEBUG_PIO)
-	    NCR5380_print(instance);
-#endif
+	    NCR_PRINT(NDEBUG_PIO);
 	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
 	}
 
 	while (NCR5380_read(STATUS_REG) & SR_REQ);
 
-#if (NDEBUG & NDEBUG_HANDSHAKE)
-	printk("scsi%d: req false, handshake complete\n", HOSTNO);
-#endif
+	HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
 
 /*
  * We have several special cases to consider during REQ/ACK handshaking : 
@@ -1950,9 +1836,7 @@
 	} 
     } while (--c);
 
-#if (NDEBUG & NDEBUG_PIO) 
-    printk("scsi%d: residual %d\n", HOSTNO, c);
-#endif
+    PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
 
     *count = c;
     *data = d;
@@ -2064,11 +1948,9 @@
 	c -= atari_read_overruns;
     }
 
-#if (NDEBUG & NDEBUG_DMA)
-    printk("scsi%d: initializing DMA channel %d for %s, %d bytes %s %0x\n",
-	   HOSTNO, instance->dma_channel, (p & SR_IO) ? "reading" :
-	   "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d);
-#endif
+    DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
+	       HOSTNO, (p & SR_IO) ? "reading" : "writing",
+	       c, (p & SR_IO) ? "to" : "from", d);
 
     NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
 
@@ -2148,9 +2030,7 @@
 	    phase = (tmp & PHASE_MASK); 
 	    if (phase != old_phase) {
 		old_phase = phase;
-#if (NDEBUG & NDEBUG_INFORMATION)
-		NCR5380_print_phase(instance);
-#endif
+		NCR_PRINT_PHASE(NDEBUG_INFORMATION);
 	    }
 	    
 	    if (sink && (phase != PHASE_MSGOUT)) {
@@ -2191,11 +2071,9 @@
 		     * they are at consecutive physical addresses.
 		     */
 		    merge_consecutive_buffers( cmd );
-#if (NDEBUG & NDEBUG_INFORMATION)
-		    printk("scsi%d: %d bytes and %d buffers left\n",
-			   HOSTNO, cmd->SCp.this_residual,
-			   cmd->SCp.buffers_residual);
-#endif
+		    INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
+			       HOSTNO, cmd->SCp.this_residual,
+			       cmd->SCp.buffers_residual);
 		}
 
 		/*
@@ -2224,8 +2102,9 @@
 			 * If the watchdog timer fires, all future
 			 * accesses to this device will use the
 			 * polled-IO. */ 
-			printk("scsi%d: switching target %d lun %d to slow "
-			       "handshake\n", HOSTNO, cmd->target, cmd->lun);
+			printk(KERN_NOTICE "scsi%d: switching target %d "
+			       "lun %d to slow handshake\n", HOSTNO,
+			       cmd->target, cmd->lun);
 			cmd->device->borken = 1;
 			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
 			    ICR_ASSERT_ATN);
@@ -2276,10 +2155,9 @@
 		    /* Accept message by clearing ACK */
 		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 		    
-#if (NDEBUG & NDEBUG_LINKED) 
-		    printk("scsi%d: target %d lun %d linked command complete.\n",
-			HOSTNO, cmd->target, cmd->lun);
-#endif
+		    LNK_PRINTK("scsi%d: target %d lun %d linked command "
+			       "complete.\n", HOSTNO, cmd->target, cmd->lun);
+
 		    /* Enable reselect interrupts */
 		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
 		    /*
@@ -2289,8 +2167,8 @@
 		     */
 
 		    if (!cmd->next_link) {
-			 printk("scsi%d: target %d lun %d linked command "
-				"complete, no next_link\n",
+			 printk(KERN_NOTICE "scsi%d: target %d lun %d "
+				"linked command complete, no next_link\n",
 				HOSTNO, cmd->target, cmd->lun);
 			    sink = 1;
 			    do_abort (instance);
@@ -2302,11 +2180,9 @@
 		     * and don't free it! */
 		    cmd->next_link->tag = cmd->tag;
 		    cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
-#if (NDEBUG & NDEBUG_LINKED) 
-		    printk("scsi%d: target %d lun %d linked request done, "
-			   "calling scsi_done().\n",
-			   HOSTNO, cmd->target, cmd->lun);
-#endif
+		    LNK_PRINTK("scsi%d: target %d lun %d linked request "
+			       "done, calling scsi_done().\n",
+			       HOSTNO, cmd->target, cmd->lun);
 #ifdef NCR5380_STATS
 		    collect_stats(hostdata, cmd);
 #endif
@@ -2321,10 +2197,8 @@
 		    /* ++guenther: possible race with Falcon locking */
 		    falcon_dont_release++;
 		    hostdata->connected = NULL;
-#if (NDEBUG & NDEBUG_QUEUES)
-		    printk("scsi%d: command for target %d, lun %d completed\n",
-			   HOSTNO, cmd->target, cmd->lun);
-#endif
+		    QU_PRINTK("scsi%d: command for target %d, lun %d "
+			      "completed\n", HOSTNO, cmd->target, cmd->lun);
 #ifdef SUPPORT_TAGS
 		    cmd_free_tag( cmd );
 		    if (cmd->SCp.Status == QUEUE_FULL) {
@@ -2335,12 +2209,10 @@
 			 * commands now.
 			 */
 			TAG_ALLOC *ta = &TagAlloc[cmd->target][cmd->lun];
-#if (NDEBUG & NDEBUG_TAGS)
-			printk( "scsi%d: target %d lun %d returned "
-				"QUEUE_FULL after %d commands\n",
-				HOSTNO, cmd->target, cmd->lun,
-				ta->nr_allocated );
-#endif
+			TAG_PRINTK("scsi%d: target %d lun %d returned "
+				   "QUEUE_FULL after %d commands\n",
+				   HOSTNO, cmd->target, cmd->lun,
+				   ta->nr_allocated);
 			if (ta->queue_size > ta->nr_allocated)
 			    ta->nr_allocated = ta->queue_size;
 			cmd->SCp.Status = BUSY;
@@ -2375,9 +2247,8 @@
 #ifdef AUTOSENSE
 		    if ((cmd->cmnd[0] != REQUEST_SENSE) && 
 			(cmd->SCp.Status == CHECK_CONDITION)) {
-#if (NDEBUG & NDEBUG_AUTOSENSE) 
-			printk("scsi%d: performing request sense\n", HOSTNO);
-#endif
+			ASEN_PRINTK("scsi%d: performing request sense\n",
+				    HOSTNO);
 			cmd->cmnd[0] = REQUEST_SENSE;
 			cmd->cmnd[1] &= 0xe0;
 			cmd->cmnd[2] = 0;
@@ -2396,10 +2267,8 @@
 			NEXT(cmd) = hostdata->issue_queue;
 		        hostdata->issue_queue = (Scsi_Cmnd *) cmd;
 		        restore_flags(flags);
-#if (NDEBUG & NDEBUG_QUEUES)
-			printk("scsi%d: REQUEST SENSE added to head of "
-			       "issue queue\n", H_NO(cmd));
-#endif
+			QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
+				  "issue queue\n", H_NO(cmd));
 		   } else
 #endif /* def AUTOSENSE */
 		   {
@@ -2444,11 +2313,10 @@
 			cmd->device->tagged_supported = 0;
 			hostdata->busy[cmd->target] |= (1 << cmd->lun);
 			cmd->tag = TAG_NONE;
-#if (NDEBUG & NDEBUG_TAGS)
-			printk( "scsi%d: target %d lun %d rejected QUEUE_TAG "
-				"message; tagged queuing disabled\n",
-				HOSTNO, cmd->target, cmd->lun );
-#endif
+			TAG_PRINTK("scsi%d: target %d lun %d rejected "
+				   "QUEUE_TAG message; tagged queuing "
+				   "disabled\n",
+				   HOSTNO, cmd->target, cmd->lun);
 			break;
 		    }
 		    break;
@@ -2463,11 +2331,10 @@
 		    hostdata->connected = NULL;
 		    hostdata->disconnected_queue = cmd;
 		    restore_flags(flags);
-#if (NDEBUG & NDEBUG_QUEUES)
-		    printk("scsi%d: command for target %d lun %d was moved from connected to"
-		           "  the disconnected_queue\n", HOSTNO, 
-			    cmd->target, cmd->lun);
-#endif
+		    QU_PRINTK("scsi%d: command for target %d lun %d was "
+			      "moved from connected to the "
+			      "disconnected_queue\n", HOSTNO, 
+			      cmd->target, cmd->lun);
 		    /* 
 		     * Restore phase bits to 0 so an interrupted selection, 
 		     * arbitration can resume.
@@ -2514,20 +2381,14 @@
 		    /* Accept first byte by clearing ACK */
 		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
-#if (NDEBUG & NDEBUG_EXTENDED)
-		    printk("scsi%d: receiving extended message\n", HOSTNO);
-#endif
+		    EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
 
 		    len = 2;
 		    data = extended_msg + 1;
 		    phase = PHASE_MSGIN;
 		    NCR5380_transfer_pio(instance, &phase, &len, &data);
-
-#if (NDEBUG & NDEBUG_EXTENDED)
-		    printk("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
-			   (int) extended_msg[1],
-			   (int) extended_msg[2]);
-#endif
+		    EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
+			       (int)extended_msg[1], (int)extended_msg[2]);
 
 		    if (!len && extended_msg[1] <= 
 			(sizeof (extended_msg) - 1)) {
@@ -2538,11 +2399,8 @@
 			phase = PHASE_MSGIN;
 
 			NCR5380_transfer_pio(instance, &phase, &len, &data);
-
-#if (NDEBUG & NDEBUG_EXTENDED)
-		    printk("scsi%d: message received, residual %d\n",
-			   HOSTNO, len);
-#endif
+			EXT_PRINTK("scsi%d: message received, residual %d\n",
+				   HOSTNO, len);
 
 			switch (extended_msg[2]) {
 			case EXTENDED_SDTR:
@@ -2552,11 +2410,12 @@
 			    tmp = 0;
 			}
 		    } else if (len) {
-			printk("scsi%d: error receiving extended message\n",
-			       HOSTNO);
+			printk(KERN_NOTICE "scsi%d: error receiving "
+			       "extended message\n", HOSTNO);
 			tmp = 0;
 		    } else {
-			printk("scsi%d: extended message code %02x length %d is too long\n",
+			printk(KERN_NOTICE "scsi%d: extended message "
+			       "code %02x length %d is too long\n",
 			       HOSTNO, extended_msg[2], extended_msg[1]);
 			tmp = 0;
 		    }
@@ -2568,14 +2427,16 @@
 		 */
 		default:
 		    if (!tmp) {
-			printk("scsi%d: rejecting message ", HOSTNO);
+			printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
 			print_msg (extended_msg);
 			printk("\n");
 		    } else if (tmp != EXTENDED_MESSAGE)
-			printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n",
+			printk(KERN_DEBUG "scsi%d: rejecting unknown "
+			       "message %02x from target %d, lun %d\n",
 			       HOSTNO, tmp, cmd->target, cmd->lun);
 		    else
-			printk("scsi%d: rejecting unknown extended message "
+			printk(KERN_DEBUG "scsi%d: rejecting unknown "
+			       "extended message "
 			       "code %02x, length %d from target %d, lun %d\n",
 			       HOSTNO, extended_msg[1], extended_msg[0],
 			       cmd->target, cmd->lun);
@@ -2629,9 +2490,7 @@
 		break;
 	    default:
 		printk("scsi%d: unknown phase\n", HOSTNO);
-#ifdef NDEBUG
-		NCR5380_print(instance);
-#endif
+		NCR_PRINT(NDEBUG_ANY);
 	    } /* switch(phase) */
 	} /* if (tmp * SR_REQ) */ 
     } /* while (1) */
@@ -2673,9 +2532,7 @@
 
     target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
 
-#if (NDEBUG & NDEBUG_RESELECTION)
-    printk("scsi%d: reselect\n", HOSTNO);
-#endif
+    RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
 
     /* 
      * At this point, we have detected that our SCSI ID is on the bus,
@@ -2703,7 +2560,7 @@
     NCR5380_transfer_pio(instance, &phase, &len, &data);
 
     if (!msg[0] & 0x80) {
-	printk("scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+	printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
 	print_msg(msg);
 	do_abort(instance);
 	return;
@@ -2724,10 +2581,8 @@
 	if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
 	    msg[1] == SIMPLE_QUEUE_TAG)
 	    tag = msg[2];
-#if (NDEBUG & NDEBUG_TAGS)
-	printk("scsi%d: target mask %02x, lun %d sent tag %d at reselection\n",
-	       HOSTNO, target_mask, lun, tag );
-#endif
+	TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
+		   "reselection\n", HOSTNO, target_mask, lun, tag);
     }
 #endif
     
@@ -2758,7 +2613,7 @@
     }
     
     if (!tmp) {
-	printk( "scsi%d: warning: target bitmask %02x lun %d "
+	printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
 #ifdef SUPPORT_TAGS
 		"tag %d "
 #endif
@@ -2780,10 +2635,8 @@
     NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
 
     hostdata->connected = tmp;
-#if (NDEBUG & NDEBUG_RESELECTION)
-    printk("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
-	   HOSTNO, tmp->target, tmp->lun, tmp->tag);
-#endif
+    RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
+	       HOSTNO, tmp->target, tmp->lun, tmp->tag);
     falcon_dont_release--;
 }
 
@@ -2815,7 +2668,7 @@
     Scsi_Cmnd *tmp, **prev;
     unsigned long flags;
 
-    printk("scsi%d: aborting command\n", HOSTNO);
+    printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
     print_Scsi_Cmnd (cmd);
 
     NCR5380_print_status (instance);
@@ -2824,16 +2677,14 @@
     cli();
     
     if (!IS_A_TT() && !falcon_got_lock)
-	printk("scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
+	printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
 	       HOSTNO);
 
-#if (NDEBUG & NDEBUG_ABORT)
-    printk("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
-	   NCR5380_read(BUS_AND_STATUS_REG),
-	   NCR5380_read(STATUS_REG));
-#endif
+    ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
+		NCR5380_read(BUS_AND_STATUS_REG),
+		NCR5380_read(STATUS_REG));
 
-#if 0
+#if 1
 /* 
  * Case 1 : If the command is the currently executing command, 
  * we'll set the aborted flag and return control so that 
@@ -2841,16 +2692,16 @@
  */
 
     if (hostdata->connected == cmd) {
-#if (NDEBUG & NDEBUG_ABORT)
-	printk("scsi%d: aborting connected command\n", HOSTNO);
-#endif
+	int rv;
+
+	ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
 	hostdata->aborted = 1;
 /*
  * We should perform BSY checking, and make sure we haven't slipped
  * into BUS FREE.
  */
 
-	NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN);
+/*	NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
 /* 
  * Since we can't change phases until we've completed the current 
  * handshake, we have to source or sink a byte of data if the current
@@ -2858,11 +2709,30 @@
  */
 
 /* 
+ * MSch: use the do_abort function instead ... unless there is need to wait
+ * a longer period for the target to go into MSGOUT.
+ */
+	rv = do_abort(instance);
+
+	save_flags(flags);
+	cli();
+
+	cmd->result = DID_ABORT << 16; 
+#ifdef SUPPORT_TAGS
+	cmd_free_tag( cmd );
+#else
+	hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+#endif
+	restore_flags(flags);
+	cmd->done(cmd);
+	falcon_release_lock_if_possible( hostdata );
+
+/* 
  * Return control to the executing NCR drive so we can clear the
  * aborted flag and get back into our main loop.
  */ 
  
-	return 0;
+	return rv ? SCSI_ABORT_SUCCESS : SCSI_ABORT_ERROR;
     }
 #endif
 
@@ -2879,10 +2749,8 @@
 	    NEXT(tmp) = NULL;
 	    tmp->result = DID_ABORT << 16;
 	    restore_flags(flags);
-#if (NDEBUG & NDEBUG_ABORT)
-	    printk("scsi%d: abort removed command from issue queue.\n",
-		   HOSTNO);
-#endif
+	    ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
+			HOSTNO);
 	    /* Tagged queuing note: no tag to free here, hasn't been assigned
 	     * yet... */
 	    tmp->done(tmp);
@@ -2903,10 +2771,8 @@
 
     if (hostdata->connected) {
 	restore_flags(flags);
-#if (NDEBUG & NDEBUG_ABORT)
-    printk("scsi%d: abort failed, command connected.\n", HOSTNO);
-#endif
-        return SCSI_ABORT_NOT_RUNNING;
+	ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
+        return SCSI_ABORT_SNOOZE;
     }
 
 /*
@@ -2938,16 +2804,12 @@
 	 tmp = NEXT(tmp)) 
         if (cmd == tmp) {
             restore_flags(flags);
-#if (NDEBUG & NDEBUG_ABORT)
-    printk("scsi%d: aborting disconnected command.\n", HOSTNO);
-#endif
+	    ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
   
             if (NCR5380_select (instance, cmd, (int) cmd->tag)) 
 		return SCSI_ABORT_BUSY;
 
-#if (NDEBUG & NDEBUG_ABORT)
-    printk("scsi%d: nexus reestablished.\n", HOSTNO);
-#endif
+	    ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
 
 	    do_abort (instance);
 
@@ -2988,8 +2850,8 @@
  */
 
     restore_flags(flags);
-    printk("scsi%d: warning : SCSI command probably completed successfully\n"
-           "        before abortion\n", HOSTNO); 
+    printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
+           KERN_INFO "        before abortion\n", HOSTNO); 
 
 /* Maybe it is sufficient just to release the ST-DMA lock... (if
  * possible at all) At least, we should check if the lock could be
@@ -3012,15 +2874,13 @@
 
 static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags)
 {
-#if 0
     SETUP_HOSTDATA(cmd->host);
     int           i;
     unsigned long flags;
     Scsi_Cmnd *connected, *disconnected_queue;
-#endif
 
     if (!IS_A_TT() && !falcon_got_lock)
-	printk("scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
+	printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
 	       H_NO(cmd) );
 
     NCR5380_print_status (cmd->host);
@@ -3040,7 +2900,7 @@
      * through anymore ... */
     (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG );
 
-#if 0 /* XXX Now done by midlevel code XXX */
+#if 1 /* XXX Should now be done by midlevel code, bug isn't XXX */
 
     /* After the reset, there are no more connected or disconnected commands
      * and no busy units; to avoid problems with re-inserting the commands
@@ -3064,9 +2924,7 @@
     restore_flags(flags);
 
     if ((cmd = connected)) {
-#if (NDEBUG & NDEBUG_ABORT)
-    printk( "scsi%d: reset aborted a connected command\n", H_NO(cmd));
-#endif
+	ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
 	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
 	cmd->scsi_done( cmd );
     }
@@ -3077,10 +2935,8 @@
 	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
 	cmd->scsi_done( cmd );
     }
-#if (NDEBUG & NDEBUG_ABORT)
     if (i > 0)
-	printk( "scsi : reset aborted %d disconnected command(s)\n", i );
-#endif
+	ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
 
 /* The Falcon lock should be released after a reset...
  */
@@ -3089,7 +2945,7 @@
  */
 /*    falcon_release_lock_if_possible( hostdata );*/
 
-#endif /* 0 */
+#endif /* 1 */
 
     return SCSI_RESET_WAKEUP;
 }
diff -u --recursive --new-file pre2.0.4/linux/drivers/scsi/atari_scsi.c linux/drivers/scsi/atari_scsi.c
--- pre2.0.4/linux/drivers/scsi/atari_scsi.c	Sat Apr 27 15:19:57 1996
+++ linux/drivers/scsi/atari_scsi.c	Thu May 16 09:05:11 1996
@@ -68,7 +68,11 @@
 #include <linux/config.h>
 #include <linux/module.h>
 
-/* #define NDEBUG (NDEBUG_DMA) */
+#define NDEBUG (0)
+
+#define NDEBUG_ABORT	0x800000
+#define NDEBUG_TAGS	0x1000000
+#define NDEBUG_MERGING	0x2000000
 
 #define AUTOSENSE
 /* For the Atari version, use only polled IO or REAL_DMA */
@@ -101,7 +105,7 @@
 #include <asm/atari_stdma.h>
 #include <asm/io.h>
 
-#include<linux/stat.h>
+#include <linux/stat.h>
 
 struct proc_dir_entry proc_scsi_atari = {
     PROC_SCSI_ATARI, 5, "Atari",
@@ -186,7 +190,6 @@
 
 #ifdef REAL_DMA
 static int scsi_dma_is_ignored_buserr( unsigned char dma_stat );
-static void scsi_dma_buserr( int irq, struct pt_regs *fp, void *dummy);
 static void atari_scsi_fetch_restbytes( void );
 static long atari_scsi_dma_residual( struct Scsi_Host *instance );
 static int falcon_classify_cmd( Scsi_Cmnd *cmd );
@@ -268,6 +271,11 @@
 }
 
 
+#if 0
+/* Dead code... wasn't called anyway :-) and causes some trouble, because at
+ * end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has
+ * to clear the DMA int pending bit before it allows other level 6 interrupts.
+ */
 static void scsi_dma_buserr (int irq, struct pt_regs *fp, void *dummy)
 {
 	unsigned char	dma_stat = tt_scsi_dma.dma_ctrl;
@@ -292,45 +300,29 @@
 		printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" );
 	}
 }
+#endif
 
 #endif
 
 
 static void scsi_tt_intr (int irq, struct pt_regs *fp, void *dummy)
 {
-	unsigned long	flags;
 #ifdef REAL_DMA
 	int dma_stat;
-#endif
 
-	/* If we got this interrupt, we don't need the other one from the DMA any
-	 * more. So clear it. */
-	atari_clear_pending_irq( IRQ_TT_MFP_SCSIDMA );
-	/* After this has been done, we can make this int handler "slow", i.e.
-	 * mask the NCR int and lower the IPL, as a slow int would do (see
-	 * arch/m68k/atari/ataints.c) */
-	atari_disable_irq( IRQ_TT_MFP_SCSI );
-	save_flags(flags);
-	flags &= 0xf8ff;
-	flags |= fp->sr & 0x0700;
-	restore_flags(flags);
-	
-#ifdef REAL_DMA
 	dma_stat = tt_scsi_dma.dma_ctrl;
 
-#if (NDEBUG & NDEBUG_INTR)
-	printk("scsi%d: NCR5380 interrupt, DMA status = %02x\n",
-	       atari_scsi_host->host_no, dma_stat & 0xff);
-#endif
+	INT_PRINTK("scsi%d: NCR5380 interrupt, DMA status = %02x\n",
+		   atari_scsi_host->host_no, dma_stat & 0xff);
 
 	/* Look if it was the DMA that has interrupted: First possibility
 	 * is that a bus error occurred...
 	 */
 	if (dma_stat & 0x80) {
 		if (!scsi_dma_is_ignored_buserr( dma_stat )) {
-			printk( "SCSI DMA caused bus error near 0x%08lx\n",
-					SCSI_DMA_READ_P( dma_addr ));
-			panic( "SCSI DMA bus error -- bad DMA programming!" );
+			printk(KERN_ERR "SCSI DMA caused bus error near 0x%08lx\n",
+			       SCSI_DMA_READ_P(dma_addr));
+			printk(KERN_CRIT "SCSI DMA bus error -- bad DMA programming!");
 		}
 	}
 
@@ -346,10 +338,10 @@
 	if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
 		atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P( dma_addr ) -
 												atari_dma_startaddr);
-#if (NDEBUG & NDEBUG_DMA)
-		printk( "SCSI DMA: There are %ld residual bytes.\n",
-				atari_dma_residual );
-#endif
+
+		DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
+			   atari_dma_residual);
+
 		if ((signed int)atari_dma_residual < 0)
 			atari_dma_residual = 0;
 		if ((dma_stat & 1) == 0) {
@@ -376,10 +368,9 @@
 			   other command.  These shouldn't disconnect anyway.
 			   */
 			if (atari_dma_residual & 0x1ff) {
-#if (NDEBUG & NDEBUG_DMA)
-				printk("SCSI DMA: DMA bug corrected, difference %ld bytes\n",
-				       512 - (atari_dma_residual & 0x1ff));
-#endif
+				DMA_PRINTK("SCSI DMA: DMA bug corrected, "
+					   "difference %ld bytes\n",
+					   512 - (atari_dma_residual & 0x1ff));
 				atari_dma_residual = (atari_dma_residual + 511) & ~0x1ff;
 			}
 		}
@@ -398,8 +389,10 @@
 	
 	NCR5380_intr (0, 0, 0);
 
+#if 0
 	/* To be sure the int is not masked */
 	atari_enable_irq( IRQ_TT_MFP_SCSI );
+#endif
 }
 
 
@@ -419,7 +412,7 @@
 	 */
 	if (!(dma_stat & 0x01)) {
 		/* DMA error */
-		printk( "SCSI DMA error near 0x%08lx!\n", SCSI_DMA_GETADR() );
+		printk(KERN_CRIT "SCSI DMA error near 0x%08lx!\n", SCSI_DMA_GETADR());
 	}
 
 	/* If the DMA was active, but now bit 1 is not clear, it is some
@@ -437,14 +430,12 @@
 		 * lost somewhere in outer space.
 		 */
 		if (transferred & 15)
-			printk( "SCSI DMA error: %ld bytes lost in ST-DMA fifo :-((\n",
-			       transferred & 15 );
+			printk(KERN_ERR "SCSI DMA error: %ld bytes lost in "
+			       "ST-DMA fifo\n", transferred & 15);
 
 		atari_dma_residual = HOSTDATA_DMALEN - transferred;
-#if (NDEBUG & NDEBUG_DMA)
-		printk( "SCSI DMA: There are %ld residual bytes.\n",
-		       atari_dma_residual );
-#endif
+		DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
+			   atari_dma_residual);
 	}
 	else
 		atari_dma_residual = 0;
@@ -477,15 +468,11 @@
 		/* there are 'nr' bytes left for the last long address before the
 		   DMA pointer */
 		dst = (char *)( (unsigned long)dst & ~3 );
-#if (NDEBUG & NDEBUG_DMA)
-		printk( "SCSI DMA: there are %d rest bytes for phys addr 0x%08lx",
-		       nr, (long)dst );
-#endif
+		DMA_PRINTK("SCSI DMA: there are %d rest bytes for phys addr 0x%08lx",
+			   nr, (long)dst);
 		dst = (char *)PTOV(dst);  /* The content of the DMA pointer
 					   * is a physical address! */
-#if (NDEBUG & NDEBUG_DMA)
-		printk( " = virt addr 0x%08lx\n", (long)dst );
-#endif
+		DMA_PRINTK(" = virt addr 0x%08lx\n", (long)dst);
 		for( src = (char *)&tt_scsi_dma.dma_restdata; nr > 0; --nr )
 			*dst++ = *src++;
 	}
@@ -697,18 +684,10 @@
 		/* This int is actually "pseudo-slow", i.e. it acts like a slow
 		 * interrupt after having cleared the pending flag for the DMA
 		 * interrupt. */
-		add_isr(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_PRIO,
+		add_isr(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_SLOW,
 			NULL, "SCSI NCR5380");
 		tt_mfp.active_edge |= 0x80;		/* SCSI int on L->H */
 #ifdef REAL_DMA
-		/* On the TT, we got a second interrupt for DMA ready and DMA buserror.
-		 * Since on DMA ready we get a "normal" interrupt, too, the service
-		 * routine for the second int just checks for buserrs.
-		 */
-		add_isr(IRQ_TT_MFP_SCSIDMA, scsi_dma_buserr, IRQ_TYPE_SLOW,
-			NULL, "SCSI DMA");
-		tt_mfp.active_edge &= ~0x20;	/* DMA int on H->L */
-
 		tt_scsi_dma.dma_ctrl = 0;
 		atari_dma_residual = 0;
 #endif /* REAL_DMA */
@@ -744,7 +723,7 @@
 #endif
 	}
 
-	printk( "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCAT-GAT=%d "
+	printk(KERN_INFO "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCAT-GAT=%d "
 #ifdef SUPPORT_TAGS
 			"TAGGED-QUEUING=%s "
 #endif
@@ -766,12 +745,8 @@
 #ifdef MODULE
 int atari_scsi_release (struct Scsi_Host *sh)
 {
-	if (IS_A_TT()) {
+	if (IS_A_TT())
 		remove_isr (IRQ_TT_MFP_SCSI, scsi_tt_intr);
-#ifdef REAL_DMA
-		remove_isr (IRQ_TT_MFP_SCSIDMA, scsi_dma_buserr);
-#endif
-	}
 	if (atari_dma_buffer)
 		scsi_init_free (atari_dma_buffer, STRAM_BUFFER_SIZE);
 	return 1;
@@ -926,10 +901,8 @@
 {
 	unsigned long addr = VTOP( data );
 
-#if (NDEBUG & NDEBUG_DMA)
-	printk ("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, dir = %d\n",
-		instance->host_no, data, addr, count, dir);
-#endif
+	DMA_PRINTK("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, "
+		   "dir = %d\n", instance->host_no, data, addr, count, dir);
 
 	if (!IS_A_TT() && !STRAM_ADDR(addr)) {
 		/* If we have a non-DMAable address on a Falcon, use the dribble
@@ -958,7 +931,7 @@
 	dma_cache_maintenance( addr, count, dir );
 
 	if (count == 0)
-		printk("SCSI warning: DMA programmed for 0 bytes !\n");
+		printk(KERN_NOTICE "SCSI warning: DMA programmed for 0 bytes !\n");
 
 	if (IS_A_TT()) {
 		tt_scsi_dma.dma_ctrl = dir;
@@ -1111,11 +1084,8 @@
 	if (possible_len > limit)
 		possible_len = limit;
 
-#if (NDEBUG & NDEBUG_DMA)
-	if (possible_len != wanted_len)
-		printk( "Sorry, must cut DMA transfer size to %ld bytes instead of %ld\n",
-				possible_len, wanted_len );
-#endif
+	DMA_PRINTK("Sorry, must cut DMA transfer size to %ld bytes instead "
+		   "of %ld\n", possible_len, wanted_len);
 
 	return( possible_len );
 }
diff -u --recursive --new-file pre2.0.4/linux/drivers/scsi/atari_scsi.h linux/drivers/scsi/atari_scsi.h
--- pre2.0.4/linux/drivers/scsi/atari_scsi.h	Sat Apr 27 15:19:57 1996
+++ linux/drivers/scsi/atari_scsi.h	Thu May 16 09:05:11 1996
@@ -92,6 +92,103 @@
 #define	NCR5380_dma_xfer_len(i,cmd,phase) \
 	atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
 
+/* Debugging printk definitions:
+ * DPRINTK() is the generic one, takes an NDEBUG_* mask as argument;
+ * all others are hardcoded to one NDEBUG_* code:
+ *
+ *  ARB  -> arbitration
+ *  ASEN -> auto-sense
+ *  DMA  -> DMA
+ *  HSH  -> PIO handshake
+ *  INF  -> information transfer
+ *  INI  -> initialization
+ *  INT  -> interrupt
+ *  LNK  -> linked commands
+ *  MAIN -> NCR5380_main() control flow
+ *  NDAT -> no data-out phase
+ *  NWR  -> no write commands
+ *  PIO  -> PIO tansfers
+ *  PDMA -> pseudo DMA (unused on Atari)
+ *  QU   -> queues
+ *  RSL  -> reselections
+ *  SEL  -> selections
+ *  USL  -> usleep cpde (unused on Atari)
+ *  LBS  -> last byte sent (unused on Atari)
+ *  RSS  -> restarting of selections
+ *  EXT  -> extended messages
+ *  ABRT -> aborting and resetting
+ *  TAG  -> queue tag handling
+ *  MER  -> merging of consec. buffers
+ *
+ */
+
+#define DPRINTK(mask, format, args...)				\
+	do {							\
+		if (NDEBUG & (mask))				\
+			printk(KERN_DEBUG format , ## args);	\
+	} while(0)
+
+#define ARB_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_ARBITRATION, format , ##args)
+#define ASEN_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_AUTOSENSE, format , ##args)
+#define DMA_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_DMA, format , ##args)
+#define HSH_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_HANDSHAKE, format , ##args)
+#define INF_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_INFORMATION, format , ##args)
+#define INI_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_INIT, format , ##args)
+#define INT_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_INTR, format , ##args)
+#define LNK_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_LINKED, format , ##args)
+#define MAIN_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_MAIN, format , ##args)
+#define NDAT_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_NO_DATAOUT, format , ##args)
+#define NWR_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_NO_WRITE, format , ##args)
+#define PIO_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_PIO, format , ##args)
+#define PDMA_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_PSEUDO_DMA, format , ##args)
+#define QU_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_QUEUES, format , ##args)
+#define RSL_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_RESELECTION, format , ##args)
+#define SEL_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_SELECTION, format , ##args)
+#define USL_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_USLEEP, format , ##args)
+#define LBS_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_LAST_BYTE_SENT, format , ##args)
+#define RSS_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_RESTART_SELECT, format , ##args)
+#define EXT_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_EXTENDED, format , ##args)
+#define ABRT_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_ABORT, format , ##args)
+#define TAG_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_TAGS, format , ##args)
+#define MER_PRINTK(format, args...) \
+	DPRINTK(NDEBUG_MERGING, format , ##args)
+
+/* conditional macros for NCR5380_print_{,phase,status} */
+
+#define NCR_PRINT(mask)	\
+	((NDEBUG & (mask)) ? NCR5380_print(instance) : (void)0)
+
+#define NCR_PRINT_PHASE(mask) \
+	((NDEBUG & (mask)) ? NCR5380_print_phase(instance) : (void)0)
+
+#define NCR_PRINT_STATUS(mask) \
+	((NDEBUG & (mask)) ? NCR5380_print_status(instance) : (void)0)
+
+#define NDEBUG_ANY	0xffffffff
+
+
 #endif /* else def HOSTS_C */
 #endif /* ndef ASM */
 #endif /* ATARI_SCSI_H */
diff -u --recursive --new-file pre2.0.4/linux/drivers/sound/dmasound.c linux/drivers/sound/dmasound.c
--- pre2.0.4/linux/drivers/sound/dmasound.c	Sat Apr 27 15:19:57 1996
+++ linux/drivers/sound/dmasound.c	Thu May 16 09:05:11 1996
@@ -1534,7 +1534,7 @@
 	order++;
 	a_size <<= 1;
     }
-    free_pages (obj, order);
+    free_pages ((unsigned long) obj, order);
 }
 
 static int AtaIrqInit(void)
diff -u --recursive --new-file pre2.0.4/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
--- pre2.0.4/linux/drivers/sound/soundcard.c	Mon Apr 15 12:20:20 1996
+++ linux/drivers/sound/soundcard.c	Wed May 15 09:09:00 1996
@@ -440,11 +440,6 @@
 {
   int             i;
 
-  if (MOD_IN_USE)
-    {
-      return;
-    }
-
   if (chrdev_registered)
     module_unregister_chrdev (sound_major, "sound");
 
diff -u --recursive --new-file pre2.0.4/linux/fs/Config.in linux/fs/Config.in
--- pre2.0.4/linux/fs/Config.in	Mon May 13 23:02:49 1996
+++ linux/fs/Config.in	Wed May 15 09:47:27 1996
@@ -35,10 +35,11 @@
 tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS
 tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS
 tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
-tristate 'Amiga FFS filesystem support (EXPERIMENTAL)' CONFIG_AFFS_FS
-if [ "$CONFIG_AFFS_FS" = "y" -o "$CONFIG_AFFS_FS" = "m" ]; then
-  define_bool CONFIG_AMIGA_PARTITION y
-fi
+# AFFS disabled until they can get that BYTE/WORD/LONG crap sorted out
+#tristate 'Amiga FFS filesystem support (EXPERIMENTAL)' CONFIG_AFFS_FS
+#if [ "$CONFIG_AFFS_FS" = "y" -o "$CONFIG_AFFS_FS" = "m" ]; then
+#  define_bool CONFIG_AMIGA_PARTITION y
+#fi
 tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS
 if [ "$CONFIG_UFS_FS" != "n" ]; then
   bool "BSD disklabel (FreeBSD partition tables) support" CONFIG_BSD_DISKLABEL
diff -u --recursive --new-file pre2.0.4/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c
--- pre2.0.4/linux/fs/affs/amigaffs.c	Sat May 11 10:42:06 1996
+++ linux/fs/affs/amigaffs.c	Thu May 16 09:05:11 1996
@@ -1,7 +1,7 @@
 /*
  *  linux/fs/affs/amigaffs.c
  *
- *  (c) 1996  Hans-Joachim Widmaier - Modified for larger blocks.
+ *  (c) 1996  Hans-Joachim Widmaier - rewritten
  *
  *  (C) 1993  Ray Burr - Amiga FFS filesystem.
  *
@@ -78,7 +78,7 @@
 	retval  = -ENOENT;
 	lock_super(startino->i_sb);
 	while (1) {
-		pr_debug("AFFS: fix_hash_pred(): next key=%d, offset=%d\n", nextkey, startoffset);
+		pr_debug("AFFS: fix_hash_pred(): next key=%d, offset=%d\n",nextkey,startoffset);
 		if (nextkey == 0)
 			break;
 		if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino))))
@@ -128,7 +128,7 @@
 	while (1) {
 		if (nextkey == 0)
 			break;
-		pr_debug("AFFS: find_link_pred(): next key=%d\n", nextkey);
+		pr_debug("AFFS: find_link_pred(): next key=%d\n",nextkey);
 		if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino))))
 			break;
 		if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype)
diff -u --recursive --new-file pre2.0.4/linux/fs/affs/bitmap.c linux/fs/affs/bitmap.c
--- pre2.0.4/linux/fs/affs/bitmap.c	Tue May  7 16:22:35 1996
+++ linux/fs/affs/bitmap.c	Thu May 16 09:05:11 1996
@@ -185,7 +185,7 @@
 				z->z_ino      = 0;
 				z->z_zone_no  = zone;
 				pr_debug("  ++ found zone (%d) in bh %d at offset %d with %d free blocks\n",
-					 zone,(zone >> (sb->s_blocksize_bits - 8)),offs,free);
+					zone,(zone >> (sb->s_blocksize_bits - 8)),offs,free);
 				break;
 			}
 			clear_bit(zone,sb->u.affs_sb.s_zonemap);
diff -u --recursive --new-file pre2.0.4/linux/fs/affs/dir.c linux/fs/affs/dir.c
--- pre2.0.4/linux/fs/affs/dir.c	Sun May 12 22:54:24 1996
+++ linux/fs/affs/dir.c	Thu May 16 09:05:11 1996
@@ -1,8 +1,8 @@
 /*
  *  linux/fs/affs/dir.c
  *
- *  (c) 1996  Hans-Joachim Widmaier - Modifications for larger blocks
- *		and hard links.
+ *  (c) 1996  Hans-Joachim Widmaier - rewritten
+ *
  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
  *
  *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
diff -u --recursive --new-file pre2.0.4/linux/fs/affs/file.c linux/fs/affs/file.c
--- pre2.0.4/linux/fs/affs/file.c	Tue May  7 16:22:35 1996
+++ linux/fs/affs/file.c	Thu May 16 09:05:11 1996
@@ -1,7 +1,7 @@
 /*
  *  linux/fs/affs/file.c
  *
- *  (c) 1996  Hans-Joachim Widmaier - Rewritten
+ *  (c) 1996  Hans-Joachim Widmaier - rewritten
  *
  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
  *
@@ -78,7 +78,7 @@
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
 	NULL,			/* no special open is needed */
-	NULL,			/* release */
+	affs_release_file,	/* release */
 	file_fsync		/* brute force, but works */
 };
 
@@ -98,7 +98,7 @@
 	NULL,			/* readpage */
 	NULL,			/* writepage */
 	NULL,			/* bmap */
-	affs_truncate_ofs,	/* truncate */
+	affs_truncate,		/* truncate */
 	NULL,			/* permission */
 	NULL			/* smap */
 };
@@ -262,6 +262,145 @@
 	return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
 }
 
+struct buffer_head *
+affs_getblock_ofs(struct inode *inode, LONG block, LONG *blk_key)
+{
+	struct buffer_head	*bh;
+	struct buffer_head	*pbh;
+	struct buffer_head	*ebh;
+	LONG			 key;
+	LONG			 ext;
+	LONG			 cnt, j, pt;
+
+	pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);
+
+	if (block < 0)
+		return NULL;
+	key = inode->i_ino;
+	pt  = T_SHORT;
+
+	ext = block / (AFFS_I2HSIZE(inode) - 24);
+	if (ext) {
+		if (ext > inode->u.affs_i.i_max_ext)
+			ext = inode->u.affs_i.i_max_ext;
+		if (ext) {
+			key    = inode->u.affs_i.i_ext[ext - 1];
+			block -= ext * AFFS_I2HSIZE(inode);
+			pt     = T_LIST;
+		}
+	}
+
+	pbh = NULL;
+	for (;;) {
+		bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+		if (!bh)
+			return NULL;
+		if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cnt,&j) ||
+		    cnt != pt || j != ST_FILE) {
+		    	printk("AFFS: getblock(): inode %d is not a valid %s\n",key,
+			       pt == T_SHORT ? "file header" : "extension block");
+			affs_brelse(bh);
+			return NULL;
+		}
+		j = htonl(((struct file_front *)bh->b_data)->block_count);
+		while (j < AFFS_I2HSIZE(inode) && j <= block) {
+			if (!pbh && inode->u.affs_i.i_lastblock >= 0) {
+				pbh = affs_getblock_ofs(inode,inode->u.affs_i.i_lastblock,&key);
+				if (!pbh) {
+					printk("AFFS: getblock(): cannot get last block in file\n");
+					break;
+				}
+			}
+			key = affs_new_data(inode);
+			if (!key)
+				break;
+			lock_super(inode->i_sb);
+			if (AFFS_BLOCK(bh->b_data,inode,j)) {
+				unlock_super(inode->i_sb);
+				printk("AFFS: getblock(): block already allocated\n");
+				affs_free_block(inode->i_sb,key);
+				j++;
+				continue;
+			}
+			AFFS_BLOCK(bh->b_data,inode,j) = ntohl(key);
+			unlock_super(inode->i_sb);
+			ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+			if (!ebh) {
+				printk("AFFS: getblock(): cannot get block %d\n",key);
+				affs_free_block(inode->i_sb,key);
+				AFFS_BLOCK(bh->b_data,inode,j) = 0;
+				break;
+			}
+			inode->u.affs_i.i_lastblock++;
+			DATA_FRONT(ebh)->primary_type    = ntohl(T_DATA);
+			DATA_FRONT(ebh)->header_key      = ntohl(inode->i_ino);
+			DATA_FRONT(ebh)->sequence_number = ntohl(inode->u.affs_i.i_lastblock + 1);
+			DATA_FRONT(pbh)->data_size       = ntohl(AFFS_I2HSIZE(inode) - 24);
+			DATA_FRONT(pbh)->next_data       = ntohl(key);
+			affs_fix_checksum(AFFS_I2HSIZE(inode),pbh->b_data,5);
+			mark_buffer_dirty(pbh,0);
+			mark_buffer_dirty(ebh,0);
+			affs_brelse(pbh);
+			pbh = ebh;
+			j++;
+		}
+		if (pt == T_SHORT)
+			((struct file_front *)bh->b_data)->first_data =
+								AFFS_BLOCK(bh->b_data,inode,0);
+		((struct file_front *)bh->b_data)->block_count = ntohl(j);
+		affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+		mark_buffer_dirty(bh,1);
+
+		if (block < j) {
+			if (pbh)
+				affs_brelse(pbh);
+			break;
+		}
+		if (j < AFFS_I2HSIZE(inode)) {
+			affs_brelse(bh);
+			return NULL;
+		}
+
+		block -= AFFS_I2HSIZE(inode);
+		key    = htonl(FILE_END(bh->b_data,inode)->extension);
+		if (!key) {
+			key = affs_new_header(inode);
+			if (!key) {
+				affs_brelse(bh);
+				return NULL;
+			}
+			ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+			if (!ebh) {
+				affs_free_block(inode->i_sb,key);
+				return NULL;
+			}
+			((struct file_front *)ebh->b_data)->primary_type = ntohl(T_LIST);
+			((struct file_front *)ebh->b_data)->own_key      = ntohl(key);
+			FILE_END(ebh->b_data,inode)->secondary_type      = ntohl(ST_FILE);
+			FILE_END(ebh->b_data,inode)->parent              = ntohl(inode->i_ino);
+			affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
+			FILE_END(bh->b_data,inode)->extension = ntohl(key);
+			affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+			mark_buffer_dirty(bh,1);
+			affs_brelse(bh);
+			bh = ebh;
+		}
+		affs_brelse(bh);
+		pt = T_LIST;
+		if (ext < EXT_CACHE_SIZE - 1) {
+			inode->u.affs_i.i_ext[ext] = key;
+			inode->u.affs_i.i_max_ext  = ++ext;
+		}
+	}
+	key = htonl(AFFS_BLOCK(bh->b_data,inode,block));
+	affs_brelse(bh);
+	if (!key)
+		return NULL;
+	*blk_key = key;
+
+	return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
+}
+
 /* This could be made static, regardless of what the former comment said.
  * You cannot directly read affs directories.
  */
@@ -395,101 +534,91 @@
 static int
 affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int count)
 {
-	pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
-		(unsigned long)filp->f_pos,count);
-
-	return -ENOSPC;
-}
-
-void
-affs_truncate(struct inode *inode)
-{
+	off_t			 pos;
+	int			 written;
+	int			 c;
+	int			 blocksize;
 	struct buffer_head	*bh;
 	struct inode		*ino;
-	LONG	 first;
-	LONG	 block;
-	LONG	 key;
-	LONG	*keyp;
-	LONG	 ekey;
-	LONG	 ptype, stype;
-	int	 freethis;
-	int	 ext;
+	char			*p;
 
-	pr_debug("AFFS: file_truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
+	pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
+		(unsigned long)filp->f_pos,count);
 
+	if (!inode) {
+		printk("AFFS: file_write(): inode=NULL\n");
+		return -EINVAL;
+	}
 	ino = NULL;
 	if (inode->u.affs_i.i_original) {
 		ino = iget(inode->i_sb,inode->u.affs_i.i_original);
 		if (!ino) {
-			printk("AFFS: truncate(): cannot follow link from %lu to %u\n",
+			printk("AFFS: could not follow link from inode %lu to %d\n",
 			       inode->i_ino,inode->u.affs_i.i_original);
-			return;
+			return -EINVAL;
 		}
 		inode = ino;
 	}
-	first = (inode->i_size + AFFS_I2BSIZE(inode) - 1) / AFFS_I2BSIZE(inode);
-	ekey  = inode->i_ino;
-	ext   = 0;
+	if (!S_ISREG(inode->i_mode)) {
+		printk("AFFS: file_write(): mode=%07o\n",inode->i_mode);
+		iput(inode);
+		return -EINVAL;
+	}
+	if (filp->f_flags & O_APPEND)
+		pos = inode->i_size;
+	else
+		pos = filp->f_pos;
 
-	while (ekey) {
-		if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) {
-			printk("AFFS: truncate(): Can't read block %d\n",ekey);
-			break;
-		}
-		ptype = htonl(((struct file_front *)bh->b_data)->primary_type);
-		stype = htonl(FILE_END(bh->b_data,inode)->secondary_type);
-		if (ekey == inode->i_ino && ptype == T_SHORT && stype == ST_LINKFILE &&
-		    LINK_END(bh->b_data,inode)->original == 0) {
-			pr_debug("AFFS: truncate(): dumping link\n");
-			affs_brelse(bh);
-			break;
-		}
-		if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) {
-			printk("AFFS: truncate(): bad block (ptype=%d, stype=%d)\n",
-			        ptype,stype);
-			affs_brelse(bh);
+	bh        = NULL;
+	blocksize = AFFS_I2BSIZE(inode) - 24;
+	written   = 0;
+	while (written < count) {
+		bh = affs_getblock(inode,pos / blocksize);
+		if (!bh) {
+			if (!written)
+				written = -ENOSPC;
 			break;
 		}
-		/* Do not throw away file header */
-		freethis = first == 0 && ekey != inode->i_ino;
-		for ( block = first; block < AFFS_I2HSIZE(inode); block++) {
-			keyp = &AFFS_BLOCK(bh->b_data,inode,block);
-			key  = htonl(*keyp);
-			if (key) {
-				*keyp = 0;
-				affs_free_block(inode->i_sb,key);
-			} else {
-				block = AFFS_I2HSIZE(inode);
+		c = blocksize - (pos % blocksize);
+		if (c > count - written)
+			c = count - written;
+		if (c != blocksize && !buffer_uptodate(bh)) {
+			ll_rw_block(READ,1,&bh);
+			wait_on_buffer(bh);
+			if (!buffer_uptodate(bh)) {
+				affs_brelse(bh);
+				if (!written)
+					written = -EIO;
 				break;
 			}
 		}
-		keyp = &GET_END_PTR(struct file_end,bh->b_data,AFFS_I2BSIZE(inode))->extension;
-		key  = htonl(*keyp);
-		if (first <= AFFS_I2HSIZE(inode)) {
-			((struct file_front *)bh->b_data)->block_count = htonl(first);
-			first = 0;
-			*keyp = 0;
-		} else {
-			first -= AFFS_I2HSIZE(inode);
-		}
-		if (freethis) {		/* Don't bother fixing checksum */
-			affs_brelse(bh);
-			affs_free_block(inode->i_sb,ekey);
-		} else {
-			affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
-			mark_buffer_dirty(bh,1);
-			affs_brelse(bh);
-		}
-		ekey = key;
+		p = (pos % blocksize) + bh->b_data + 24;
+		memcpy_fromfs(p,buf,c);
+		update_vm_cache(inode,pos,p,c);
+
+		pos     += c;
+		buf     += c;
+		written += c;
+		DATA_FRONT(bh)->data_size = ntohl(htonl(DATA_FRONT(bh)->data_size) + c);
+		affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+		mark_buffer_uptodate(bh,1);
+		mark_buffer_dirty(bh,0);
+		affs_brelse(bh);
 	}
-	inode->u.affs_i.i_max_ext = 0;		/* invalidate cache */
+	if (pos > inode->i_size)
+		inode->i_size = pos;
+	filp->f_pos = pos;
+	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	inode->i_dirt  = 1;
 	iput(ino);
+	return written;
 }
 
 void
-affs_truncate_ofs(struct inode *inode)
+affs_truncate(struct inode *inode)
 {
 	struct buffer_head	*bh;
+	struct buffer_head	*ebh;
 	struct inode		*ino;
 	LONG	 first;
 	LONG	 block;
@@ -499,8 +628,10 @@
 	LONG	 ptype, stype;
 	int	 freethis;
 	int	 blocksize;
+	int	 rem;
+	int	 ext;
 
-	pr_debug("AFFS: file_truncate_ofs(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
+	pr_debug("AFFS: file_truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
 
 	ino = NULL;
 	if (inode->u.affs_i.i_original) {
@@ -512,9 +643,25 @@
 		}
 		inode = ino;
 	}
-	blocksize = AFFS_I2BSIZE(inode) - 24;
+	blocksize = AFFS_I2BSIZE(inode) - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0);
 	first = (inode->i_size + blocksize - 1) / blocksize;
+	if (inode->u.affs_i.i_lastblock < first - 1) {
+		bh = affs_getblock(inode,first - 1);
+		if (!bh) {
+			printk("AFFS: truncate(): Cannot extend file\n");
+			inode->i_size = blocksize * (inode->u.affs_i.i_lastblock + 1);
+		} else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
+			rem = inode->i_size % blocksize;
+			DATA_FRONT(bh)->data_size = ntohl(rem ? rem : blocksize);
+			affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
+			mark_buffer_dirty(bh,0);
+		}
+		affs_brelse(bh);
+		iput(ino);
+		return;
+	}
 	ekey  = inode->i_ino;
+	ext   = 0;
 
 	while (ekey) {
 		if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) {
@@ -538,9 +685,8 @@
 		/* Do not throw away file header */
 		freethis = first == 0 && ekey != inode->i_ino;
 		for ( block = first; block < AFFS_I2HSIZE(inode); block++) {
-			keyp  = &((struct file_front *)bh->b_data)->
-				 blocks[AFFS_I2HSIZE(inode) - 1 - block];
-			key   = htonl(*keyp);
+			keyp = &AFFS_BLOCK(bh->b_data,inode,block);
+			key  = htonl(*keyp);
 			if (key) {
 				*keyp = 0;
 				affs_free_block(inode->i_sb,key);
@@ -555,6 +701,21 @@
 			((struct file_front *)bh->b_data)->block_count = htonl(first);
 			first = 0;
 			*keyp = 0;
+			if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) && first > 0) {
+				block = htonl(AFFS_BLOCK(bh->b_data,inode,first - 1));
+				if ((ebh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
+					if(!(affs_checksum_block(AFFS_I2BSIZE(inode),ebh->b_data,
+					     &ptype,NULL))) {
+						rem = inode->i_size % blocksize;
+						rem = ntohl(rem ? blocksize : rem);
+						((struct data_front *)ebh->b_data)->data_size = rem;
+						((struct data_front *)ebh->b_data)->next_data = 0;
+						affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
+						mark_buffer_dirty(ebh,1);
+					}
+					affs_brelse(ebh);
+				}
+			}
 		} else {
 			first -= AFFS_I2HSIZE(inode);
 		}
@@ -568,19 +729,31 @@
 		}
 		ekey = key;
 	}
-	inode->u.affs_i.i_max_ext = 0;		/* invalidate cache */
+	inode->u.affs_i.i_lastblock = ((inode->i_size + blocksize - 1) / blocksize) - 1;
+	inode->u.affs_i.i_max_ext   = 0;
 	iput(ino);
 }
 
 static void
 affs_release_file(struct inode *inode, struct file *filp)
 {
+	struct affs_zone	*zone;
+
+	pr_debug("AFFS: release_file(ino=%lu)\n",inode->i_ino);
+
 	if (filp->f_mode & 2) {		/* Free preallocated blocks */
 		while (inode->u.affs_i.i_pa_cnt) {
 			affs_free_block(inode->i_sb,
 					inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]);
 			inode->u.affs_i.i_pa_next &= MAX_PREALLOC - 1;
 			inode->u.affs_i.i_pa_cnt--;
+		}
+		if (inode->u.affs_i.i_zone) {
+			lock_super(inode->i_sb);
+			zone = &inode->i_sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
+			if (zone->z_ino == inode->i_ino)
+				zone->z_ino = 0;
+			unlock_super(inode->i_sb);
 		}
 	}
 }
diff -u --recursive --new-file pre2.0.4/linux/fs/affs/inode.c linux/fs/affs/inode.c
--- pre2.0.4/linux/fs/affs/inode.c	Sun May 12 10:16:07 1996
+++ linux/fs/affs/inode.c	Fri May 17 12:34:40 1996
@@ -1,7 +1,7 @@
 /*
  *  linux/fs/affs/inode.c
  *
- *  (c) 1996  Hans-Joachim Widmaier - Modified for larger blocks.
+ *  (c) 1996  Hans-Joachim Widmaier - rewritten
  *
  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
  * 
@@ -23,15 +23,16 @@
 #include <linux/locks.h>
 #include <linux/errno.h>
 #include <linux/genhd.h>
-#include <linux/major.h>
 #include <linux/amigaffs.h>
+#include <linux/major.h>
 #include <asm/system.h>
 #include <asm/segment.h>
 
 extern int *blk_size[];
 extern struct timezone sys_tz;
 
-void affs_put_super(struct super_block *sb)
+void
+affs_put_super(struct super_block *sb)
 {
 	int	 i;
 
@@ -58,7 +59,8 @@
 	return;
 }
 
-static void affs_write_super(struct super_block *sb)
+static void
+affs_write_super(struct super_block *sb)
 {
 	int	 i, clean = 2;
 
@@ -92,7 +94,8 @@
 	NULL			/* remount */
 };
 
-int affs_parent_ino(struct inode *dir)
+int
+affs_parent_ino(struct inode *dir)
 {
 	int root_ino = (dir->i_sb->u.affs_sb.s_root_block);
 
@@ -107,9 +110,8 @@
 
 
 static int
-parse_options(char *options, uid_t *uid, gid_t *gid, int *mode,
-	      int *reserved, int *root,	int *blocksize, char **prefix,
-	      char *volume, unsigned long *mount_opts)
+parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, int *root,
+		int *blocksize, char **prefix, char *volume, unsigned long *mount_opts)
 {
 	char	*this_char, *value;
 	int	 f;
@@ -242,8 +244,7 @@
 			 || !strcmp (this_char, "usrquota"))
 			;
 		else {
-			printk("AFFS: Unrecognized mount option %s\n",
-			       this_char);
+			printk("AFFS: Unrecognized mount option %s\n", this_char);
 			return 0;
 		}
 	}
@@ -319,12 +320,12 @@
 		num_bm = 4096;
 	}
 	for (blocksize = chksum; blocksize <= num_bm; blocksize <<= 1, size >>= 1) {
-		if (root_block < 0)
+	        if (root_block < 0){
 		    if (MAJOR(dev) == FLOPPY_MAJOR)
 		        s->u.affs_sb.s_root_block = size/4;
 		    else
 			s->u.affs_sb.s_root_block = (reserved + size - 1) / 2;
-		else
+		}else
 			s->u.affs_sb.s_root_block = root_block;
 		pr_debug("Trying bs=%d bytes, root at %d, size=%d blocks (%d reserved)\n",
 			blocksize,s->u.affs_sb.s_root_block,size,reserved);
@@ -461,9 +462,9 @@
 			if (bb) {
 				if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) /*&&
 				    !(s->s_flags & MS_RDONLY)*/) {
-					printk("AFFS: Bitmap (%d,key=%lu) invalid - mounting %s read only.\n",
-					       mapidx, htonl(bm[i]),
-					       kdevname(dev));
+					printk("AFFS: Bitmap (%d,key=%lu) invalid - "
+					       "mounting %s read only.\n",mapidx,htonl(bm[i]),
+						kdevname(dev));
 					s->s_flags |= MS_RDONLY;
 				}
 				if (size <= s->s_blocksize * 8 - 32) {	/* last bitmap */
@@ -487,14 +488,14 @@
 				s->u.affs_sb.s_bitmap[mapidx].bm_size     = ptype;
 				s->u.affs_sb.s_bitmap[mapidx].bm_bh       = bb;
 				s->u.affs_sb.s_bitmap[mapidx].bm_free     =
-				  affs_count_free_bits(ptype/8,bb->b_data + 4);
+						affs_count_free_bits(ptype / 8,bb->b_data + 4);
 				offset += ptype;
 			} else {
 				printk("AFFS: Can't read bitmap.\n");
 				goto out;
 			}
 		}
-		key   = htonl(bm[stype]);   /* Next block of bitmap pointers */
+		key   = htonl(bm[stype]);		/* Next block of bitmap pointers	*/
 		ptype = 0;
 		stype = s->s_blocksize / 4 - 1;
 		affs_brelse(bh);
@@ -507,11 +508,10 @@
 			bh = NULL;
 	}
 	if (mapidx != num_bm) {
-		printk("AFFS: Got only %d bitmap blocks, expected %d\n",
-		       mapidx, num_bm);
+		printk("AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm);
 		goto out;
 	}
-	s->u.affs_sb.s_num_zones = ((num_bm - 1) << (s->s_blocksize_bits - 8))+
+	s->u.affs_sb.s_num_zones = ((num_bm - 1) << (s->s_blocksize_bits - 8)) +
 				   (s->u.affs_sb.s_bitmap[num_bm - 1].bm_size + 2047) / 2048;
 nobitmap:
 	s->u.affs_sb.s_bm_count  = mapidx;
@@ -547,9 +547,9 @@
 			s->u.affs_sb.s_bitmap[i].bm_bh = NULL;
 		}
 	}
+		
 
-
-	pr_debug("AFFS: s_flags=%lX\n", s->s_flags);
+	pr_debug("AFFS: s_flags=%lX\n",s->s_flags);
 	return s;
 
  out: /* Kick out for various error conditions */
@@ -572,8 +572,8 @@
 	ULONG		 free;
 	struct statfs	 tmp;
 
-	pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",
-		sb->u.affs_sb.s_partition_size, sb->u.affs_sb.s_reserved);
+	pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",sb->u.affs_sb.s_partition_size,
+	     sb->u.affs_sb.s_reserved);
 
 	free          = affs_count_free_blocks(sb);
 	tmp.f_type    = AFFS_SUPER_MAGIC;
@@ -606,7 +606,7 @@
 	}
 	if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) || ptype != T_SHORT) {
 		printk("AFFS: read_inode(): checksum or type (ptype=%d) error on inode %d\n",
-		       ptype, block);
+		       ptype,block);
 		affs_brelse(bh);
 		return;
 	}
@@ -615,18 +615,19 @@
 	file_end   = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode));
 	prot       = (htonl(file_end->protect) & ~0x10) ^ FIBF_OWNER;
 
-	inode->u.affs_i.i_protect  = prot;
-	inode->u.affs_i.i_parent   = htonl(file_end->parent);
-	inode->u.affs_i.i_original = 0;	
-	inode->u.affs_i.i_zone     = 0;
-	inode->u.affs_i.i_hlink    = 0;
-	inode->u.affs_i.i_pa_cnt   = 0;
-	inode->u.affs_i.i_pa_next  = 0;
-	inode->u.affs_i.i_pa_last  = 0;
-	inode->u.affs_i.i_ext[0]   = 0;
-	inode->u.affs_i.i_max_ext  = 0;
-	inode->i_nlink             = 1;
-	inode->i_mode              = 0;
+	inode->u.affs_i.i_protect   = prot;
+	inode->u.affs_i.i_parent    = htonl(file_end->parent);
+	inode->u.affs_i.i_original  = 0;	
+	inode->u.affs_i.i_zone      = 0;
+	inode->u.affs_i.i_hlink     = 0;
+	inode->u.affs_i.i_pa_cnt    = 0;
+	inode->u.affs_i.i_pa_next   = 0;
+	inode->u.affs_i.i_pa_last   = 0;
+	inode->u.affs_i.i_ext[0]    = 0;
+	inode->u.affs_i.i_max_ext   = 0;
+	inode->u.affs_i.i_lastblock = -1;
+	inode->i_nlink              = 1;
+	inode->i_mode               = 0;
 
 	if (inode->i_sb->u.affs_sb.s_flags & SF_SETMODE)
 		inode->i_mode = inode->i_sb->u.affs_sb.s_mode;
@@ -691,6 +692,11 @@
 		case ST_FILE:
 			inode->i_mode |= S_IFREG;
 			inode->i_size  = htonl(file_end->byte_size);
+			if (inode->i_sb->u.affs_sb.s_flags & SF_OFS)
+				block = AFFS_I2BSIZE(inode) - 24;
+			else
+				block = AFFS_I2BSIZE(inode);
+			inode->u.affs_i.i_lastblock = ((inode->i_size + block - 1) / block) - 1;
 			break;
 		case ST_SOFTLINK:
 			inode->i_mode |= S_IFLNK;
@@ -709,10 +715,11 @@
 	
 	inode->i_op = NULL;
 	if (S_ISREG(inode->i_mode)) {
-		if (inode->i_sb->u.affs_sb.s_flags & SF_OFS)
+		if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
 			inode->i_op = &affs_file_inode_operations_ofs;
-		else
+		} else {
 			inode->i_op = &affs_file_inode_operations;
+		}
 	} else if (S_ISDIR(inode->i_mode))
 		inode->i_op = &affs_dir_inode_operations;
 	else if (S_ISLNK(inode->i_mode))
@@ -768,8 +775,7 @@
 {
 	int error;
 
-	pr_debug("AFFS: notify_change(%lu,0x%x)\n",
-		inode->i_ino,attr->ia_valid);
+	pr_debug("AFFS: notify_change(%lu,0x%x)\n",inode->i_ino,attr->ia_valid);
 
 	error = inode_change_ok(inode,attr);
 	if (error)
@@ -795,8 +801,7 @@
 void
 affs_put_inode(struct inode *inode)
 {
-	pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",
-		inode->i_ino,inode->i_nlink);
+	pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink);
 	if (inode->i_nlink) {
 		return;
 	}
@@ -840,15 +845,16 @@
 	inode->i_blksize = 0;
 	inode->i_mtime   = inode->i_atime = inode->i_ctime = CURRENT_TIME;
 
-	inode->u.affs_i.i_original = 0;
-	inode->u.affs_i.i_parent   = dir->i_ino;
-	inode->u.affs_i.i_zone     = 0;
-	inode->u.affs_i.i_hlink    = 0;
-	inode->u.affs_i.i_pa_cnt   = 0;
-	inode->u.affs_i.i_pa_next  = 0;
-	inode->u.affs_i.i_pa_last  = 0;
-	inode->u.affs_i.i_ext[0]   = 0;
-	inode->u.affs_i.i_max_ext  = 0;
+	inode->u.affs_i.i_original  = 0;
+	inode->u.affs_i.i_parent    = dir->i_ino;
+	inode->u.affs_i.i_zone      = 0;
+	inode->u.affs_i.i_hlink     = 0;
+	inode->u.affs_i.i_pa_cnt    = 0;
+	inode->u.affs_i.i_pa_next   = 0;
+	inode->u.affs_i.i_pa_last   = 0;
+	inode->u.affs_i.i_ext[0]    = 0;
+	inode->u.affs_i.i_max_ext   = 0;
+	inode->u.affs_i.i_lastblock = -1;
 
 	insert_inode_hash(inode);
 
@@ -864,12 +870,12 @@
 	struct buffer_head	*link_bh;
 	ULONG			 hash;
 
-	pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%ld\n",
-		dir->i_ino,inode->i_ino, len,name,type);
+	pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%ld\n",dir->i_ino,inode->i_ino,
+		len,name,type);
 
-	dir_bh     = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
-	inode_bh   = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
-	link_bh    = NULL;
+	dir_bh      = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
+	inode_bh    = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
+	link_bh     = NULL;
 	if (!dir_bh || !inode_bh) {
 		affs_brelse(dir_bh);
 		affs_brelse(inode_bh);
@@ -896,12 +902,12 @@
 
 	lock_super(inode->i_sb);
 	DIR_END(inode_bh->b_data,inode)->hash_chain = 
-			 ((struct dir_front *)dir_bh->b_data)->hashtable[hash];
+				((struct dir_front *)dir_bh->b_data)->hashtable[hash];
 	((struct dir_front *)dir_bh->b_data)->hashtable[hash] = ntohl(inode->i_ino);
 	if (link_bh) {
 		LINK_END(inode_bh->b_data,inode)->original   = ntohl(link->i_ino);
 		LINK_END(inode_bh->b_data,inode)->link_chain = 
-				    FILE_END(link_bh->b_data,link)->link_chain;
+						FILE_END(link_bh->b_data,link)->link_chain;
 		FILE_END(link_bh->b_data,link)->link_chain   = ntohl(inode->i_ino);
 		affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5);
 		link->i_version = ++event;
diff -u --recursive --new-file pre2.0.4/linux/fs/affs/namei.c linux/fs/affs/namei.c
--- pre2.0.4/linux/fs/affs/namei.c	Sat May 11 10:42:06 1996
+++ linux/fs/affs/namei.c	Thu May 16 09:05:11 1996
@@ -1,7 +1,7 @@
 /*
  *  linux/fs/affs/namei.c
  *
- *  (c) 1996  Hans-Joachim Widmaier - Heavily hacked up.
+ *  (c) 1996  Hans-Joachim Widmaier - rewritten
  *
  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
  *
@@ -235,9 +235,13 @@
 		iput (dir);
 		return -ENOSPC;
 	}
-	inode->i_op   = &affs_file_inode_operations;
 	inode->i_mode = mode;
-	error         = affs_add_entry(dir,NULL,inode,name,len,ST_FILE);
+	if (dir->i_sb->u.affs_sb.s_flags & SF_OFS)
+		inode->i_op = &affs_file_inode_operations_ofs;
+	else
+		inode->i_op = &affs_file_inode_operations;
+
+	error = affs_add_entry(dir,NULL,inode,name,len,ST_FILE);
 	if (error) {
 		iput(dir);
 		inode->i_nlink = 0;
@@ -603,7 +607,7 @@
 		if (affs_parent_ino(old_inode) != old_dir->i_ino)
 			goto end_rename;
 	}
-	/* Unlink destination if existent */
+	/* Unlink destination if existant */
 	if (new_inode) {
 		if ((retval = affs_fix_hash_pred(new_dir,affs_hash_name(new_name,new_len,
 		                                 AFFS_I2FSTYPE(new_dir),AFFS_I2HSIZE(new_dir)) + 6,
diff -u --recursive --new-file pre2.0.4/linux/fs/affs/symlink.c linux/fs/affs/symlink.c
--- pre2.0.4/linux/fs/affs/symlink.c	Tue May  7 16:22:36 1996
+++ linux/fs/affs/symlink.c	Thu May 16 09:05:11 1996
@@ -1,7 +1,7 @@
 /*
  *  linux/fs/affs/symlink.c
  *
- *  1995  Hans-Joachim Widmaier - modified for AFFS.
+ *  1995  Hans-Joachim Widmaier - modified for affs.
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
  *
@@ -15,7 +15,6 @@
 #include <linux/stat.h>
 #include <linux/affs_fs.h>
 #include <linux/amigaffs.h>
-
 #include <asm/segment.h>
 
 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
diff -u --recursive --new-file pre2.0.4/linux/fs/locks.c linux/fs/locks.c
--- pre2.0.4/linux/fs/locks.c	Wed May 15 11:01:15 1996
+++ linux/fs/locks.c	Wed May 15 11:22:04 1996
@@ -76,9 +76,15 @@
  *  flock() and fcntl().
  *  Andy Walker (andy@lysaker.kvaerner.no), April 29, 1996.
  *
- *	BUG: MUST DISALLOW MANDATORY LOCK ON NFS/SMB/NCP FILE SYSTEM 
- *	TO MATCH SYS5.4 SEMANTICS.
+ *  Allow only one type of locking scheme (F_POSIX or F_FLOCK) to be in use
+ *  for a given file at a time. Changed the CONFIG_MANDATORY_OPTION scheme to
+ *  guarantee sensible behaviour in the case where file system modules might
+ *  be compiled with different options than the kernel itself.
+ *  Andy Walker (andy@lysaker.kvaerner.no), May 15, 1996.
  *
+ *  TODO: Do not honour mandatory locks on remote file systems. This matches
+ *        the SVR4 semantics and neatly sidesteps a pile of awkward issues that
+ *        would otherwise have to be addressed.
  */
 
 #include <linux/config.h>
@@ -107,9 +113,11 @@
 			   unsigned int wait);
 static int posix_lock_file(struct file *filp, struct file_lock *caller,
 			   unsigned int wait);
-static int locks_deadlock(struct task_struct *my_task,
-			  struct task_struct *blocked_task);
+static int posix_locks_deadlock(struct task_struct *my_task,
+				struct task_struct *blocked_task);
 static int locks_overlap(struct file_lock *fl1, struct file_lock *fl2);
+static void posix_remove_locks(struct file_lock **before, struct task_struct *task);
+static void flock_remove_locks(struct file_lock **before, struct file *filp);
 
 static struct file_lock *locks_alloc_lock(struct file_lock *fl);
 static void locks_insert_lock(struct file_lock **pos, struct file_lock *fl);
@@ -212,16 +220,19 @@
 	if (!filp->f_inode || !posix_make_lock(filp, &file_lock, &flock))
 		return (-EINVAL);
 
-	for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
-		if (posix_locks_conflict(&file_lock, fl)) {
-			flock.l_pid = fl->fl_owner->pid;
-			flock.l_start = fl->fl_start;
-			flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
-				fl->fl_end - fl->fl_start + 1;
-			flock.l_whence = 0;
-			flock.l_type = fl->fl_type;
-			memcpy_tofs(l, &flock, sizeof(flock));
-			return (0);
+	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & F_POSIX)) { 
+		while (fl != NULL) {
+			if (posix_locks_conflict(&file_lock, fl)) {
+				flock.l_pid = fl->fl_owner->pid;
+				flock.l_start = fl->fl_start;
+				flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
+					fl->fl_end - fl->fl_start + 1;
+				flock.l_whence = 0;
+				flock.l_type = fl->fl_type;
+				memcpy_tofs(l, &flock, sizeof(flock));
+				return (0);
+			}
+			fl = fl->fl_next;
 		}
 	}
 
@@ -313,17 +324,41 @@
 void locks_remove_locks(struct task_struct *task, struct file *filp)
 {
 	struct file_lock *fl;
-	struct file_lock **before;
 
 	/* For POSIX locks we free all locks on this file for the given task.
 	 * For FLOCK we only free locks on this *open* file if it is the last
 	 * close on that file.
 	 */
-	before = &filp->f_inode->i_flock;
+	if ((fl = filp->f_inode->i_flock) != NULL) {
+		if (fl->fl_flags & F_POSIX)
+			posix_remove_locks(&filp->f_inode->i_flock, task);
+		else
+			flock_remove_locks(&filp->f_inode->i_flock, filp);
+	}
+
+	return;
+}
+
+static void posix_remove_locks(struct file_lock **before, struct task_struct *task)
+{
+	struct file_lock *fl;
+
 	while ((fl = *before) != NULL) {
-		if (((fl->fl_flags & F_POSIX) && (fl->fl_owner == task)) ||
-		    ((fl->fl_flags & F_FLOCK) && (fl->fl_file == filp) &&
-		     (filp->f_count == 1)))
+		if (fl->fl_owner == task)
+			locks_delete_lock(before, 0);
+		else
+			before = &fl->fl_next;
+	}
+
+	return;
+}
+
+static void flock_remove_locks(struct file_lock **before, struct file *filp)
+{
+	struct file_lock *fl;
+
+	while ((fl = *before) != NULL) {
+		if ((fl->fl_file == filp) && (filp->f_count == 1))
 			locks_delete_lock(before, 0);
 		else
 			before = &fl->fl_next;
@@ -358,17 +393,22 @@
 	return (0);
 }
 
-#ifdef CONFIG_LOCK_MANDATORY	
 int locks_mandatory_locked(struct inode *inode)
 {
+#ifdef CONFIG_LOCK_MANDATORY	
 	struct file_lock *fl;
 
 	/* Search the lock list for this inode for any POSIX locks.
 	 */
-	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
-		if ((fl->fl_flags & F_POSIX) && (fl->fl_owner != current))
+	if ((fl = inode->i_flock) && (fl->fl_flags & F_FLOCK))
+		return (0);
+	
+	while (fl != NULL) {
+		if (fl->fl_owner != current)
 			return (-EAGAIN);
+		fl = fl->fl_next;
 	}
+#endif
 	return (0);
 }
 
@@ -376,47 +416,53 @@
 			 struct file *filp, unsigned int offset,
 			 unsigned int count)
 {
+#ifdef CONFIG_LOCK_MANDATORY	
 	struct file_lock *fl;
 
 repeat:
+	/* Check that there are locks, and that they're not F_FLOCK locks.
+	 */
+	if ((fl = inode->i_flock) && (fl->fl_flags & F_FLOCK))
+		return (0);
+	
 	/*
 	 * Search the lock list for this inode for locks that conflict with
 	 * the proposed read/write.
 	 */
-	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
-		if ((fl->fl_flags & F_FLOCK) ||
-		    ((fl->fl_flags & F_POSIX) && (fl->fl_owner == current)))
-			continue;
-		if (fl->fl_end < offset ||
-		    fl->fl_start >= offset + count)
-			continue;
+	while (fl != NULL) {
+		if (fl->fl_owner == current ||
+		    fl->fl_end < offset || fl->fl_start >= offset + count)
+			goto next_lock;
+
 		/*
-		 * Block for writes against a "read" lock, and both reads and
-		 * writes against a "write" lock.
+		 * Block for writes against a "read" lock,
+		 * and both reads and writes against a "write" lock.
 		 */
-		if (read_write == FLOCK_VERIFY_WRITE ||
-		    fl->fl_type == F_WRLCK) {
+		if ((read_write == FLOCK_VERIFY_WRITE) ||
+		    (fl->fl_type == F_WRLCK)) {
 			if (filp && (filp->f_flags & O_NONBLOCK))
 				return (-EAGAIN);
 			if (current->signal & ~current->blocked)
 				return (-ERESTARTSYS);
-			if (locks_deadlock(current, fl->fl_owner))
+			if (posix_locks_deadlock(current, fl->fl_owner))
 				return (-EDEADLOCK);
 			interruptible_sleep_on(&fl->fl_wait);
 			if (current->signal & ~current->blocked)
 				return (-ERESTARTSYS);
 			/*
-			 * If we've been sleeping someone might have changed
-			 * the permissions behind our back.
+			 * If we've been sleeping someone might have
+			 * changed the permissions behind our back.
 			 */
 			if ((inode->i_mode & (S_ISGID | S_IXGRP)) != S_ISGID)
 				break;
 			goto repeat;
 		}
+	next_lock:
+		fl = fl->fl_next;
 	}
+#endif
 	return (0);
 }
-#endif
 
 /* Verify a "struct flock" and copy it to a "struct file_lock" as a POSIX
  * style lock.
@@ -500,7 +546,7 @@
 	fl->fl_start = 0;
 	fl->fl_end = OFFSET_MAX;
 	fl->fl_file = filp;
-	fl->fl_owner = current;
+	fl->fl_owner = NULL;
 	fl->fl_wait = NULL;		/* just for cleanliness */
 	
 	return (1);
@@ -514,8 +560,7 @@
 	/* POSIX locks owned by the same process do not conflict with
 	 * each other.
 	 */
-	if ((sys_fl->fl_flags & F_POSIX) &&
-	    (caller_fl->fl_owner == sys_fl->fl_owner))
+	if (caller_fl->fl_owner == sys_fl->fl_owner)
 		return (0);
 
 	return (locks_conflict(caller_fl, sys_fl));
@@ -529,8 +574,7 @@
 	/* FLOCK locks referring to the same filp do not conflict with
 	 * each other.
 	 */
-	if ((sys_fl->fl_flags & F_FLOCK) &&
-	    (caller_fl->fl_file == sys_fl->fl_file))
+	if (caller_fl->fl_file == sys_fl->fl_file)
 		return (0);
 
 	return (locks_conflict(caller_fl, sys_fl));
@@ -577,8 +621,8 @@
  * with blocked_task equal to that queue's owner, until either blocked_task
  * isn't found, or blocked_task is found on a queue owned by my_task.
  */
-static int locks_deadlock(struct task_struct *my_task,
-			  struct task_struct *blocked_task)
+static int posix_locks_deadlock(struct task_struct *my_task,
+				struct task_struct *blocked_task)
 {
 	struct wait_queue *dlock_wait;
 	struct file_lock *fl;
@@ -604,9 +648,8 @@
 	return (0);
 }
 
-/* Try to create a FLOCK lock on filp. We rely on FLOCK locks being sorted
- * first in an inode's lock list, and always insert new locks at the head
- * of the list.
+/* Try to create a FLOCK lock on filp. We always insert new locks at
+ * the head of the list.
  */
 static int flock_lock_file(struct file *filp, struct file_lock *caller,
 			   unsigned int wait)
@@ -616,11 +659,12 @@
 	struct file_lock **before;
 	int change = 0;
 
-	/* This a compact little algorithm based on us always placing FLOCK
-	 * locks at the front of the list.
-	 */
 	before = &filp->f_inode->i_flock;
-	while ((fl = *before) && (fl->fl_flags & F_FLOCK)) {
+
+	if ((fl = *before) && (fl->fl_flags & F_POSIX))
+		return (-EBUSY);
+
+	while ((fl = *before) != NULL) {
 		if (caller->fl_file == fl->fl_file) {
 			if (caller->fl_type == fl->fl_type)
 				return (0);
@@ -638,12 +682,18 @@
 		return (0);
 	if ((new_fl = locks_alloc_lock(caller)) == NULL)
 		return (-ENOLCK);
- repeat:
-	for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
-		if (!flock_locks_conflict(new_fl, fl))
-			continue;
-		
-		if (wait) {
+repeat:
+	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & F_POSIX)) {
+		locks_free_lock(new_fl);
+		return (-EBUSY);
+	}
+
+	while (fl != NULL) {
+		if (flock_locks_conflict(new_fl, fl)) {
+			if (!wait) {
+				locks_free_lock(new_fl);
+				return (-EAGAIN);
+			}
 			if (current->signal & ~current->blocked) {
 				/* Note: new_fl is not in any queue at this
 				 * point, so we must use locks_free_lock()
@@ -653,14 +703,6 @@
 				locks_free_lock(new_fl);
 				return (-ERESTARTSYS);
 			}
-			/* Try to avoid deadlocks due to pathological programs that
-			 * mix calls to flock() and fcntl(). Return EAGAIN, because
-			 * EDEADLOCK isn't a documented return value for flock().
-			 */
-			if (locks_deadlock(new_fl->fl_owner, fl->fl_owner)) {
-				locks_free_lock(new_fl);
-				return (-EAGAIN);
-			}
 			locks_insert_block(fl, new_fl);
 			interruptible_sleep_on(&new_fl->fl_wait);
 			wake_up(&new_fl->fl_wait);
@@ -677,9 +719,7 @@
 			}
 			goto repeat;
 		}
-		
-		locks_free_lock(new_fl);
-		return (-EAGAIN);
+		fl = fl->fl_next;
 	}
 	locks_insert_lock(&filp->f_inode->i_flock, new_fl);
 	return (0);
@@ -707,22 +747,25 @@
 	struct file_lock **before;
 	int added = 0;
 
-	if (caller->fl_type != F_UNLCK) {
 repeat:
-		for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) {
-			if (!posix_locks_conflict(caller, fl))
-				continue;
-			if (wait) {
+	if ((fl = filp->f_inode->i_flock) && (fl->fl_flags & F_FLOCK))
+		return (-EBUSY);
+
+	if (caller->fl_type != F_UNLCK) {
+		while (fl != NULL) {
+			if (posix_locks_conflict(caller, fl)) {
+				if (!wait)
+					return (-EAGAIN);
 				if (current->signal & ~current->blocked)
 					return (-ERESTARTSYS);
-				if (locks_deadlock(caller->fl_owner, fl->fl_owner))
+				if (posix_locks_deadlock(caller->fl_owner, fl->fl_owner))
 					return (-EDEADLOCK);
 				interruptible_sleep_on(&fl->fl_wait);
 				if (current->signal & ~current->blocked)
 					return (-ERESTARTSYS);
 				goto repeat;
 			}
-			return (-EAGAIN);
+			fl = fl->fl_next;
   		}
   	}
 	/*
@@ -733,8 +776,7 @@
 
 	/* First skip FLOCK locks and locks owned by other processes.
 	 */
-	while ((fl = *before) && ((fl->fl_flags & F_FLOCK) ||
-				  (caller->fl_owner != fl->fl_owner))) {
+	while ((fl = *before) && (caller->fl_owner != fl->fl_owner)) {
 		before = &fl->fl_next;
 	}
 	
@@ -956,7 +998,8 @@
 	}
 	p += sprintf(p, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE");
 	p += sprintf(p, "%d %s:%ld %ld %ld ",
-		     fl->fl_owner->pid, kdevname(fl->fl_file->f_inode->i_dev),
+		     fl->fl_owner ? fl->fl_owner->pid : 0,
+		     kdevname(fl->fl_file->f_inode->i_dev),
 		     fl->fl_file->f_inode->i_ino, fl->fl_start,
 		     fl->fl_end);
 	p += sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n%d:%s",
diff -u --recursive --new-file pre2.0.4/linux/fs/ncpfs/sock.c linux/fs/ncpfs/sock.c
--- pre2.0.4/linux/fs/ncpfs/sock.c	Fri Apr 19 10:08:01 1996
+++ linux/fs/ncpfs/sock.c	Thu May 16 16:35:42 1996
@@ -41,7 +41,7 @@
         msg.msg_namelen   = 0;
         if (addr_len)
                 msg.msg_namelen = *addr_len;
-        msg.msg_accrights = NULL;
+        msg.msg_control = NULL;
         msg.msg_iov       = &iov;
         msg.msg_iovlen    = 1;
 
@@ -61,7 +61,7 @@
 
         msg.msg_name      = (void *)sa;
         msg.msg_namelen   = addr_len;
-        msg.msg_accrights = NULL;
+        msg.msg_control = NULL;
         msg.msg_iov       = &iov;
         msg.msg_iovlen    = 1;
 
diff -u --recursive --new-file pre2.0.4/linux/fs/nfs/nfsroot.c linux/fs/nfs/nfsroot.c
--- pre2.0.4/linux/fs/nfs/nfsroot.c	Tue May  7 16:22:36 1996
+++ linux/fs/nfs/nfsroot.c	Thu May 16 16:35:42 1996
@@ -580,7 +580,7 @@
 	msg.msg_name = NULL;
 	msg.msg_iov = &iov;
 	msg.msg_iovlen = 1;
-	msg.msg_accrights = NULL;
+	msg.msg_control = NULL;
 	result = sock->ops->sendmsg(sock, &msg, size, 0, 0);
 	set_fs(oldfs);
 	return (result != size);
@@ -604,7 +604,7 @@
 	msg.msg_name = NULL;
 	msg.msg_iov = &iov;
 	msg.msg_iovlen = 1;
-	msg.msg_accrights = NULL;
+	msg.msg_control = NULL;
 	msg.msg_namelen = 0;
 	result = sock->ops->recvmsg(sock, &msg, size, O_NONBLOCK, 0, &msg.msg_namelen);
 	set_fs(oldfs);
diff -u --recursive --new-file pre2.0.4/linux/fs/nfs/rpcsock.c linux/fs/nfs/rpcsock.c
--- pre2.0.4/linux/fs/nfs/rpcsock.c	Mon Apr  8 19:01:45 1996
+++ linux/fs/nfs/rpcsock.c	Thu May 16 16:35:42 1996
@@ -115,7 +115,7 @@
 	msg.msg_iovlen	= nr;
 	msg.msg_name	= sap;
 	msg.msg_namelen = salen;
-	msg.msg_accrights = NULL;
+	msg.msg_control = NULL;
 
 	oldfs = get_fs();
 	set_fs(get_ds());
@@ -142,7 +142,7 @@
 	msg.msg_iovlen	= nr;
 	msg.msg_name	= &sa;
 	msg.msg_namelen = sizeof(sa);
-	msg.msg_accrights = NULL;
+	msg.msg_control = NULL;
 
 	oldfs = get_fs();
 	set_fs(get_ds());
diff -u --recursive --new-file pre2.0.4/linux/fs/read_write.c linux/fs/read_write.c
--- pre2.0.4/linux/fs/read_write.c	Wed May 15 11:01:15 1996
+++ linux/fs/read_write.c	Thu May 16 16:35:42 1996
@@ -180,7 +180,7 @@
 		return -EOPNOTSUPP;
 	msg.msg_name = NULL;
 	msg.msg_namelen = 0;
-	msg.msg_accrights = NULL;
+	msg.msg_control = NULL;
 	msg.msg_iov = (struct iovec *) iov;
 	msg.msg_iovlen = count;
 
diff -u --recursive --new-file pre2.0.4/linux/fs/smbfs/sock.c linux/fs/smbfs/sock.c
--- pre2.0.4/linux/fs/smbfs/sock.c	Fri Apr 12 15:52:05 1996
+++ linux/fs/smbfs/sock.c	Thu May 16 16:35:42 1996
@@ -37,7 +37,7 @@
         msg.msg_namelen   = 0;
         if (addr_len)
                 msg.msg_namelen = *addr_len;
-        msg.msg_accrights = NULL;
+        msg.msg_control = NULL;
         msg.msg_iov       = &iov;
         msg.msg_iovlen    = 1;
 
@@ -53,7 +53,7 @@
 
         msg.msg_name      = NULL;
         msg.msg_namelen   = 0;
-        msg.msg_accrights = NULL;
+        msg.msg_control = NULL;
         msg.msg_iov       = &iov;
         msg.msg_iovlen    = 1;
 
diff -u --recursive --new-file pre2.0.4/linux/include/asm-alpha/irq.h linux/include/asm-alpha/irq.h
--- pre2.0.4/linux/include/asm-alpha/irq.h	Wed Feb 28 11:36:37 1996
+++ linux/include/asm-alpha/irq.h	Tue May 14 14:38:08 1996
@@ -10,7 +10,7 @@
 #include <linux/linkage.h>
 #include <linux/config.h>
 
-#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || defined(CONFIG_ALPHA_EB164)
+#if defined(CONFIG_ALPHA_CABRIOLET) || defined(CONFIG_ALPHA_EB66P) || defined(CONFIG_ALPHA_EB164) || defined(CONFIG_ALPHA_PC164)
 # define NR_IRQS	33
 #elif defined(CONFIG_ALPHA_EB66) || defined(CONFIG_ALPHA_EB64P)
 # define NR_IRQS	32
diff -u --recursive --new-file pre2.0.4/linux/include/asm-alpha/unistd.h linux/include/asm-alpha/unistd.h
--- pre2.0.4/linux/include/asm-alpha/unistd.h	Mon Mar  4 11:46:31 1996
+++ linux/include/asm-alpha/unistd.h	Wed May 15 10:49:37 1996
@@ -142,7 +142,7 @@
 #define __NR_mlockall		316
 #define __NR_munlockall		317
 #define __NR_sysinfo		318
-#define __NR_sysctl		319
+#define __NR__sysctl		319
 #define __NR_idle		320
 #define __NR_umount		321
 #define __NR_swapon		322
diff -u --recursive --new-file pre2.0.4/linux/include/asm-m68k/atari_SCCserial.h linux/include/asm-m68k/atari_SCCserial.h
--- pre2.0.4/linux/include/asm-m68k/atari_SCCserial.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/atari_SCCserial.h	Thu May 16 09:05:11 1996
@@ -0,0 +1,60 @@
+#ifndef _ATARI_SCCSERIAL_H
+#define _ATARI_SCCSERIAL_H
+
+/* Special configuration ioctls for the Atari SCC5380 Serial
+ * Communications Controller
+ */
+
+/* ioctl command codes */
+
+#define TIOCGATSCC	0x54c0	/* get SCC configuration */
+#define TIOCSATSCC	0x54c1	/* set SCC configuration */
+#define TIOCDATSCC	0x54c2	/* reset configuration to defaults */
+
+/* Clock sources */
+
+#define CLK_RTxC	0
+#define CLK_TRxC	1
+#define CLK_PCLK	2
+
+/* baud_bases for the common clocks in the Atari. These are the real
+ * frequencies divided by 16.
+ */
+   
+#define SCC_BAUD_BASE_TIMC	19200	/* 0.3072 MHz from TT-MFP, Timer C */
+#define SCC_BAUD_BASE_BCLK	153600	/* 2.4576 MHz */
+#define SCC_BAUD_BASE_PCLK4	229500	/* 3.6720 MHz */
+#define SCC_BAUD_BASE_PCLK	503374	/* 8.0539763 MHz */
+#define SCC_BAUD_BASE_NONE	0		/* for not connected or unused
+						 * clock sources */
+
+/* The SCC configuration structure */
+
+struct atari_SCCserial {
+	unsigned	RTxC_base;	/* base_baud of RTxC */
+	unsigned	TRxC_base;	/* base_baud of TRxC */
+	unsigned	PCLK_base;	/* base_baud of PCLK, for both channels! */
+	struct {
+		unsigned clksrc;	/* CLK_RTxC, CLK_TRxC or CLK_PCLK */
+		unsigned divisor;	/* divisor for base baud, valid values:
+					 * see below */
+	} baud_table[17];		/* For 50, 75, 110, 135, 150, 200, 300,
+					 * 600, 1200, 1800, 2400, 4800, 9600,
+					 * 19200, 38400, 57600 and 115200 bps. The
+					 * last two could be replaced by other
+					 * rates > 38400 if they're not possible.
+					 */
+};
+
+/* The following divisors are valid:
+ *
+ *   - CLK_RTxC: 1 or even (1, 2 and 4 are the direct modes, > 4 use
+ *               the BRG)
+ *
+ *   - CLK_TRxC: 1, 2 or 4 (no BRG, only direct modes possible)
+ *
+ *   - CLK_PCLK: >= 4 and even (no direct modes, only BRG)
+ *
+ */
+
+#endif /* _ATARI_SCCSERIAL_H */
diff -u --recursive --new-file pre2.0.4/linux/include/asm-m68k/bootinfo.h linux/include/asm-m68k/bootinfo.h
--- pre2.0.4/linux/include/asm-m68k/bootinfo.h	Sat Apr 27 15:19:59 1996
+++ linux/include/asm-m68k/bootinfo.h	Thu May 16 09:05:11 1996
@@ -17,8 +17,6 @@
 #ifndef BOOTINFO_H
 #define BOOTINFO_H
 
-#ifndef __ASSEMBLY__
-
 #include <asm/zorro.h>
 
 /*
@@ -27,6 +25,8 @@
 
 #define NUM_AUTO    16
 
+#ifndef __ASSEMBLY__
+
 #define AMIGAHW_DECLARE(name)	unsigned name : 1
 #define AMIGAHW_SET(name)	(boot_info.bi_amiga.hw_present.name = 1)
 #define AMIGAHW_PRESENT(name)	(boot_info.bi_amiga.hw_present.name)
@@ -35,6 +35,10 @@
   int model;				/* Amiga Model (3000?) */
   int num_autocon;			/* # of autoconfig devices found */
   struct ConfigDev autocon[NUM_AUTO];	/* up to 16 autoconfig devices */
+#ifdef HACKER_KERNEL
+  void (*exit_func)(void);		/* addr of function to exit kernel */
+  unsigned long chip_addr;		/* start of chip memory (bytes) */
+#endif
   unsigned long chip_size;		/* size of chip memory (bytes) */
   unsigned char vblank; 		/* VBLANK frequency */
   unsigned char psfreq; 		/* power supply frequency */
@@ -79,6 +83,25 @@
   } hw_present;
 };
 
+#else	/* __ASSEMBLY__ */
+ 
+BI_amiga_model		= BI_un
+BI_amiga_num_autcon	= BI_amiga_model+4
+BI_amiga_autocon	= BI_amiga_num_autcon+4
+#ifdef HACKER_KERNEL
+BI_amiga_exit_func	= BI_amiga_autocon+(CD_sizeof*NUM_AUTO)
+BI_amiga_chip_addr	= BI_amiga_exit_func+4
+BI_amiga_chip_size	= BI_amiga_chip_addr+4
+#else
+BI_amiga_chip_size	= BI_amiga_autocon+(CD_sizeof*NUM_AUTO)
+#endif
+BI_amiga_vblank		= BI_amiga_chip_size+4
+BI_amiga_psfreq		= BI_amiga_vblank+1
+BI_amiga_eclock		= BI_amiga_psfreq+1
+BI_amiga_chipset	= BI_amiga_eclock+4
+BI_amiga_hw_present	= BI_amiga_chipset+4
+
+#endif	/* __ASSEMBLY__ */
 
 /* Atari specific part of bootinfo */
 
@@ -90,6 +113,8 @@
 
 /* ++roman 08/08/95: rewritten from ORing constants to a C bitfield */
 
+#ifndef __ASSEMBLY__
+
 #define ATARIHW_DECLARE(name)	unsigned name : 1
 #define ATARIHW_SET(name)	(boot_info.bi_atari.hw_present.name = 1)
 #define ATARIHW_PRESENT(name)	(boot_info.bi_atari.hw_present.name)
@@ -143,39 +168,55 @@
 #define	ATARI_MCH_TT		2
 #define	ATARI_MCH_FALCON	3
 
-/*
- * CPU and FPU types
- */
-#define CPU_68020    (1)
-#define CPU_68030    (2)
-#define CPU_68040    (4)
-#define CPU_68060    (8)
-#define CPU_MASK     (31)
-#define FPU_68881    (32)
-#define FPU_68882    (64)
-#define FPU_68040    (128)	/* Internal FPU */
-#define FPU_68060    (256)	/* Internal FPU */
-
 struct mem_info {
   unsigned long addr;		/* physical address of memory chunk */
   unsigned long size;		/* length of memory chunk (in bytes) */
 };
 
-#define NUM_MEMINFO  4
+#else	/* __ASSEMBLY__ */
+
+MI_addr		= 0
+MI_size		= MI_addr+4
+MI_sizeof	= MI_size+4
 
 #endif /* __ASSEMBLY__ */
 
+#define NUM_MEMINFO  4
+
 #define MACH_AMIGA   1
 #define MACH_ATARI   2
 #define MACH_MAC     3
 
+/*
+ * CPU and FPU types
+ */
+
+#define CPUB_68020 0
+#define CPUB_68030 1
+#define CPUB_68040 2
+#define CPUB_68060 3
+#define FPUB_68881 5
+#define FPUB_68882 6
+#define FPUB_68040 7	/* Internal FPU */
+#define FPUB_68060 8	/* Internal FPU */
+
+#define CPU_68020    (1<<CPUB_68020)
+#define CPU_68030    (1<<CPUB_68030)
+#define CPU_68040    (1<<CPUB_68040)
+#define CPU_68060    (1<<CPUB_68060)
+#define CPU_MASK     (31)
+#define FPU_68881    (1<<FPUB_68881)
+#define FPU_68882    (1<<FPUB_68882)
+#define FPU_68040    (1<<FPUB_68040)	/* Internal FPU */
+#define FPU_68060    (1<<FPUB_68060)	/* Internal FPU */
+
+#define CL_SIZE      (256)
+
 #ifndef __ASSEMBLY__
 
 #define MACH_IS_AMIGA	(boot_info.machtype == MACH_AMIGA)
 #define MACH_IS_ATARI	(boot_info.machtype == MACH_ATARI)
 
-#define CL_SIZE      (256)
-
 struct bootinfo {
   unsigned long machtype;		/* machine type */
   unsigned long cputype;		/* system CPU & FPU */
@@ -195,6 +236,17 @@
 
 extern struct bootinfo
     boot_info;
+
+#else	/* __ASSEMBLY__ */
+
+BI_machtype	= 0
+BI_cputype	= BI_machtype+4
+BI_memory	= BI_cputype+4
+BI_num_memory	= BI_memory+(MI_sizeof*NUM_MEMINFO)
+BI_ramdisk_size	= BI_num_memory+4
+BI_ramdisk_addr	= BI_ramdisk_size+4
+BI_command_line	= BI_ramdisk_addr+4
+BI_un		= BI_command_line+CL_SIZE
 
 #endif /* __ASSEMBLY__ */
 
diff -u --recursive --new-file pre2.0.4/linux/include/asm-m68k/cachectl.h linux/include/asm-m68k/cachectl.h
--- pre2.0.4/linux/include/asm-m68k/cachectl.h	Thu Jan  1 02:00:00 1970
+++ linux/include/asm-m68k/cachectl.h	Thu May 16 09:05:11 1996
@@ -0,0 +1,14 @@
+#ifndef _M68K_CACHECTL_H
+#define _M68K_CACHECTL_H
+
+/* Definitions for the cacheflush system call.  */
+
+#define FLUSH_SCOPE_LINE    1	/* Flush a cache line */
+#define FLUSH_SCOPE_PAGE    2	/* Flush a page */
+#define FLUSH_SCOPE_ALL     3	/* Flush the whole cache -- superuser only */
+
+#define FLUSH_CACHE_DATA    1	/* Writeback and flush data cache */
+#define FLUSH_CACHE_INSN    2	/* Flush instruction cache */
+#define FLUSH_CACHE_BOTH    3	/* Flush both caches */
+
+#endif /* _M68K_CACHECTL_H */
diff -u --recursive --new-file pre2.0.4/linux/include/asm-m68k/checksum.h linux/include/asm-m68k/checksum.h
--- pre2.0.4/linux/include/asm-m68k/checksum.h	Tue May  7 16:22:37 1996
+++ linux/include/asm-m68k/checksum.h	Thu May 16 09:05:11 1996
@@ -62,6 +62,21 @@
 	return ~sum;
 }
 
+/*
+ *	Fold a partial checksum
+ */
+
+static inline unsigned int csum_fold(unsigned int sum)
+{
+	unsigned int tmp = sum;
+	__asm__("swap %1\n\t"
+		"addw %1, %0\n\t"
+		"clrw %1\n\t"
+		"addxw %1, %0"
+		: "=&d" (sum), "=&d" (tmp)
+		: "0" (sum), "1" (sum));
+	return ~sum;
+}
 
 
 /*
@@ -76,31 +91,12 @@
 	__asm__ ("addl  %1,%0\n\t"
 		 "addxl %4,%0\n\t"
 		 "addxl %5,%0\n\t"
-		 "movl  %0,%1\n\t"
-		 "swap  %1\n\t"
-		 "addxw %1,%0\n\t"
-		 "clrw  %1\n\t"
-		 "addxw %1,%0\n\t"
+		 "clrl %1\n\t"
+		 "addxl %1,%0"
 		 : "=&d" (sum), "=&d" (saddr)
 		 : "0" (daddr), "1" (saddr), "d" (len + proto),
 		   "d"(sum));
-	return ~sum;
-}
-
-/*
- *	Fold a partial checksum without adding pseudo headers
- */
-
-static inline unsigned int csum_fold(unsigned int sum)
-{
-	unsigned int tmp = sum;
-	__asm__("swap %1\n\t"
-		"addw %1, %0\n\t"
-		"clrw %1\n\t"
-		"addxw %1, %0"
-		: "=&d" (sum), "=&d" (tmp)
-		: "0" (sum), "1" (sum));
-	return ~sum;
+	return csum_fold(sum);
 }
 
 /*
@@ -111,17 +107,7 @@
 static inline unsigned short
 ip_compute_csum(unsigned char * buff, int len)
 {
-	unsigned int sum;
-	unsigned int scratch;
-
-	__asm__("movel %0,%1\n\t"
-		"swap  %1\n\t"
-		"addw  %1,%0\n\t"
-		"clrw  %1\n\t"
-		"addxw %1,%0\n\t"
-		: "=d" (sum), "=d" (scratch)
-		: "0" (csum_partial(buff, len, 0)));
-	return ~sum;
+	return csum_fold (csum_partial(buff, len, 0));
 }
 
 #endif /* _M68K_CHECKSUM_H */
diff -u --recursive --new-file pre2.0.4/linux/include/asm-m68k/delay.h linux/include/asm-m68k/delay.h
--- pre2.0.4/linux/include/asm-m68k/delay.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/delay.h	Thu May 16 09:05:11 1996
@@ -9,7 +9,8 @@
 
 extern __inline__ void __delay(int loops)
 {
-	__asm__("\n\tmovel %0,%/d0\n1:\tsubql #1,%/d0\n\tbpls 1b\n"
+	__asm__ __volatile__ ("\n\tmovel %0,%/d0\n1:\tsubql #1,%/d0\n\t"
+			      "bpls 1b\n"
 		: /* no outputs */
 		: "g" (loops)
 		: "d0");
@@ -26,7 +27,7 @@
 {
 	usecs *= 0x000010c6;		/* 2**32 / 1000000 */
 
-	asm ("mulul %1,%0:%2"
+	__asm__ __volatile__ ("mulul %1,%0:%2"
 	     : "=d" (usecs)
 	     : "d" (usecs),
 	       "d" (loops_per_sec));
@@ -35,12 +36,12 @@
 
 extern __inline__ unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c)
 {
-	__asm__("mulul %1,%/d0:%0\n\tdivul %2,%/d0:%0"
-		:"=d" (a)
-		:"d" (b),
-		"d" (c),
-		"0" (a)
-		:"d0");
+	__asm__ ("mulul %1,%/d0:%0\n\tdivul %2,%/d0:%0"
+		 :"=d" (a)
+		 :"d" (b),
+		 "d" (c),
+		 "0" (a)
+		 :"d0");
 	return a;
 }
 
diff -u --recursive --new-file pre2.0.4/linux/include/asm-m68k/machdep.h linux/include/asm-m68k/machdep.h
--- pre2.0.4/linux/include/asm-m68k/machdep.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/machdep.h	Thu May 16 09:05:11 1996
@@ -30,7 +30,6 @@
 			   int *min, int *sec);
 extern int (*mach_hwclk)(int, struct hwclk_time*);
 extern int (*mach_set_clock_mmss)(unsigned long);
-extern void (*mach_check_partition) (struct gendisk *hd, unsigned int dev);
 extern void (*mach_mksound)( unsigned int count, unsigned int ticks );
 extern void (*mach_reset)( void );
 extern int (*mach_floppy_init) (void);
@@ -42,5 +41,6 @@
 extern void (*mach_debug_init)(void);
 extern void (*mach_video_setup)(char *, int *);
 extern void (*mach_floppy_setup)(char *, int *);
+extern void (*mach_floppy_eject)(void);
 
 #endif /* _M68K_MACHDEP_H */
diff -u --recursive --new-file pre2.0.4/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h
--- pre2.0.4/linux/include/asm-m68k/pgtable.h	Tue May  7 16:22:37 1996
+++ linux/include/asm-m68k/pgtable.h	Thu May 16 09:05:11 1996
@@ -1,6 +1,8 @@
 #ifndef _M68K_PGTABLE_H
 #define _M68K_PGTABLE_H
 
+#ifndef __ASSEMBLY__
+
 /*
  * This file contains the functions and defines necessary to modify and use
  * the m68k page table tree.
@@ -74,6 +76,18 @@
 /* the no. of pointers that fit on a page: this will go away */
 #define PTRS_PER_PAGE	(PAGE_SIZE/sizeof(void*))
 
+typedef pgd_t pgd_table[PTRS_PER_PGD];
+typedef pmd_t pmd_table[PTRS_PER_PMD];
+typedef pte_t pte_table[PTRS_PER_PTE];
+
+#define PGD_TABLES_PER_PAGE (PAGE_SIZE/sizeof(pgd_table))
+#define PMD_TABLES_PER_PAGE (PAGE_SIZE/sizeof(pmd_table))
+#define PTE_TABLES_PER_PAGE (PAGE_SIZE/sizeof(pte_table))
+
+typedef pgd_table pgd_tablepage[PGD_TABLES_PER_PAGE];
+typedef pmd_table pmd_tablepage[PMD_TABLES_PER_PAGE];
+typedef pte_table pte_tablepage[PTE_TABLES_PER_PAGE];
+
 /* Just any arbitrary offset to the start of the vmalloc VM area: the
  * current 8MB value just means that there will be a 8MB "hole" after the
  * physical memory until the kernel virtual memory starts.  That means that
@@ -85,6 +99,8 @@
 #define VMALLOC_START ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
 
+#endif /* __ASSEMBLY__ */
+
 /*
  * Definitions for MMU descriptors
  */
@@ -109,6 +125,8 @@
 #define _PAGE_TABLE	(_PAGE_SHORT)
 #define _PAGE_CHG_MASK  (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_NOCACHE)
 
+#ifndef __ASSEMBLY__
+
 #define PAGE_NONE	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | _PAGE_CACHE040)
 #define PAGE_SHARED	__pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_CACHE040)
 #define PAGE_COPY	__pgprot(_PAGE_PRESENT | _PAGE_RONLY | _PAGE_ACCESSED | _PAGE_CACHE040)
@@ -230,9 +248,9 @@
 #define pmd_present(pmd) pmd_present2(&(pmd))
 extern inline void pmd_clear(pmd_t * pmdp)
 {
-	int i;
+	short i;
 
-	for (i = 0; i < 16; i++)
+	for (i = 15; i >= 0; i--)
 		pmdp->pmd[i] = 0;
 }
 
@@ -358,6 +376,11 @@
 }
 
 
+extern const char PgtabStr_bad_pmd[];
+extern const char PgtabStr_bad_pgd[];
+extern const char PgtabStr_bad_pmdk[];
+extern const char PgtabStr_bad_pgdk[];
+
 extern inline void pte_free(pte_t * pte)
 {
 	cache_page((unsigned long)pte);
@@ -381,7 +404,7 @@
 		free_page((unsigned long)page);
 	}
 	if (pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
+		printk(PgtabStr_bad_pmd, pmd_val(*pmd));
 		pmd_set(pmd, BAD_PAGETABLE);
 		return NULL;
 	}
@@ -414,7 +437,7 @@
 		free_pointer_table(page);
 	}
 	if (pgd_bad(*pgd)) {
-		printk("Bad pgd in pmd_alloc: %08lx\n", pgd_val(*pgd));
+		printk(PgtabStr_bad_pgd, pgd_val(*pgd));
 		pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
 		return NULL;
 	}
@@ -444,7 +467,7 @@
 		free_page((unsigned long) page);
 	}
 	if (pmd_bad(*pmd)) {
-		printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
+		printk(PgtabStr_bad_pmdk, pmd_val(*pmd));
 		pmd_set(pmd, BAD_PAGETABLE);
 		return NULL;
 	}
@@ -472,7 +495,7 @@
 		free_kpointer_table(page);
 	}
 	if (pgd_bad(*pgd)) {
-		printk("Bad pgd in pmd_alloc_kernel: %08lx\n", pgd_val(*pgd));
+		printk(PgtabStr_bad_pgdk, pgd_val(*pgd));
 		pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
 		return NULL;
 	}
@@ -492,7 +515,7 @@
 #define flush_icache() \
 do { \
 	if (m68k_is040or060) \
-		asm (".word 0xf498"); /* CINVA I */ \
+		asm ("nop; .word 0xf498 /* cinva %%ic */"); \
 	else \
 		asm ("movec %/cacr,%/d0;" \
 		     "oriw %0,%/d0;" \
@@ -521,19 +544,99 @@
  */
 extern void cache_push_v (unsigned long vaddr, int len);
 
-/*
- * Could someone take a look at these?
- */
-extern void flush_cache_all(void);
-#define flush_cache_mm(mm)		   flush_cache_all()
-#define flush_cache_range(mm, start, end)  flush_cache_all()
-#define flush_cache_page(vma, addr)	   flush_cache_all()
-extern void flush_page_to_ram(unsigned long addr);
-
 /* cache code */
 #define FLUSH_I_AND_D	(0x00000808)
 #define FLUSH_I 	(0x00000008)
 
+/* This is needed whenever the virtual mapping of the current
+   process changes.  */
+#define __flush_cache_all()						\
+    do {								\
+	if (m68k_is040or060)					        \
+               __asm__ __volatile__ ("nop; .word 0xf478\n" ::);         \
+        else                                                            \
+	       __asm__ __volatile__ ("movec %%cacr,%%d0\n\t"		\
+				     "orw %0,%%d0\n\t"			\
+				     "movec %%d0,%%cacr"		\
+				     : : "di" (FLUSH_I_AND_D) : "d0");	\
+    } while (0)
+
+#define __flush_cache_030()						\
+    do {								\
+	if (m68k_is040or060 == 0)					\
+	       __asm__ __volatile__ ("movec %%cacr,%%d0\n\t"		\
+				     "orw %0,%%d0\n\t"			\
+				     "movec %%d0,%%cacr"		\
+				     : : "di" (FLUSH_I_AND_D) : "d0");	\
+    } while (0)
+
+#define flush_cache_all() __flush_cache_all()
+
+extern inline void flush_cache_mm(struct mm_struct *mm)
+{
+	if (mm == current->mm) __flush_cache_all();
+}
+
+extern inline void flush_cache_range(struct mm_struct *mm,
+				     unsigned long start,
+				     unsigned long end)
+{
+	if (mm == current->mm){
+	    if (m68k_is040or060)
+	        cache_push_v(start, end-start);
+	    else
+	        __flush_cache_030();
+	}
+}
+
+extern inline void flush_cache_page(struct vm_area_struct *vma,
+				    unsigned long vmaddr)
+{
+	if (vma->vm_mm == current->mm){
+	    if (m68k_is040or060)
+	        cache_push_v(vmaddr, PAGE_SIZE);
+	    else
+	        __flush_cache_030();
+	}
+}
+
+/* Push the page at kernel virtual address and clear the icache */
+extern inline void flush_page_to_ram (unsigned long address)
+{
+    if (m68k_is040or060) {
+	register unsigned long tmp __asm ("a0") = VTOP(address);
+	__asm__ __volatile__ ("nop\n\t"
+			      ".word 0xf470 /* cpushp %%dc,(%0) */\n\t"
+			      ".word 0xf490 /* cinvp %%ic,(%0) */"
+			      : : "a" (tmp));
+    }
+    else
+	__asm volatile ("movec %%cacr,%%d0\n\t"
+			"orw %0,%%d0\n\t"
+			"movec %%d0,%%cacr"
+			: : "di" (FLUSH_I) : "d0");
+}
+
+/* Push n pages at kernel virtual address and clear the icache */
+extern inline void flush_pages_to_ram (unsigned long address, int n)
+{
+    if (m68k_is040or060) {
+	while (n--) {
+	    register unsigned long tmp __asm ("a0") = VTOP(address);
+	    __asm__ __volatile__ ("nop\n\t"
+				  ".word 0xf470 /* cpushp %%dc,(%0) */\n\t"
+				  ".word 0xf490 /* cinvp %%ic,(%0) */"
+				  : : "a" (tmp));
+	    address += PAGE_SIZE;
+	}
+    }
+    else
+	__asm volatile ("movec %%cacr,%%d0\n\t"
+			"orw %0,%%d0\n\t"
+			"movec %%d0,%%cacr"
+			: : "di" (FLUSH_I) : "d0");
+}
+
 /*
  * Check if the addr/len goes up to the end of a physical
  * memory chunk.  Used for DMA functions.
@@ -580,5 +683,7 @@
 #define SWP_OFFSET(entry) ((entry) >> PAGE_SHIFT)
 #define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << PAGE_SHIFT))
 #endif
+
+#endif /* __ASSEMBLY__ */
 
 #endif /* _M68K_PGTABLE_H */
diff -u --recursive --new-file pre2.0.4/linux/include/asm-m68k/segment.h linux/include/asm-m68k/segment.h
--- pre2.0.4/linux/include/asm-m68k/segment.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/segment.h	Thu May 16 09:05:11 1996
@@ -155,7 +155,7 @@
 			 : "0" (from), "1" (to)
 			 : "d0", "memory");
 	if (tmp & 1)
-		__asm__ ("moveb %0@,%/d0\n\t"
+		__asm__ __volatile__ ("moveb %0@,%/d0\n\t"
 			 "movesb %/d0,%1@\n\t"
 			 : /* no outputs */
 			 : "a" (from), "a" (to)
@@ -251,7 +251,7 @@
 			 : "0" (from), "1" (to)
 			 : "d0", "memory");
 	if (tmp & 1)
-		__asm__ ("movesb %0@,%/d0\n\t"
+		__asm__ __volatile__ ("movesb %0@,%/d0\n\t"
 			 "moveb %/d0,%1@\n\t"
 			 : /* no outputs */
 			 : "a" (from), "a" (to)
diff -u --recursive --new-file pre2.0.4/linux/include/asm-m68k/unistd.h linux/include/asm-m68k/unistd.h
--- pre2.0.4/linux/include/asm-m68k/unistd.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/unistd.h	Thu May 16 09:05:11 1996
@@ -128,7 +128,7 @@
 #define __NR_clone		120
 #define __NR_setdomainname	121
 #define __NR_uname		122
-#define __NR_modify_ldt		123
+#define __NR_cacheflush		123
 #define __NR_adjtimex		124
 #define __NR_mprotect		125
 #define __NR_sigprocmask	126
diff -u --recursive --new-file pre2.0.4/linux/include/asm-m68k/zorro.h linux/include/asm-m68k/zorro.h
--- pre2.0.4/linux/include/asm-m68k/zorro.h	Tue Apr 23 13:57:12 1996
+++ linux/include/asm-m68k/zorro.h	Thu May 16 09:05:11 1996
@@ -11,6 +11,8 @@
 #ifndef _ASM_M68K_ZORRO_H_
 #define _ASM_M68K_ZORRO_H_
 
+#ifndef __ASSEMBLY__
+
 #include <linux/config.h>
 #include <asm/amigatypes.h>
 
@@ -302,6 +304,44 @@
     u_long		cd_Unused[4];	/* for whatever the driver wants */
 };
 
+#else	/* __ASSEMBLY__ */
+
+LN_Succ		= 0
+LN_Pred		= LN_Succ+4
+LN_Type		= LN_Pred+4
+LN_Pri		= LN_Type+1
+LN_Name		= LN_Pri+1
+LN_sizeof	= LN_Name+4
+
+ER_Type		= 0
+ER_Product	= ER_Type+1
+ER_Flags	= ER_Product+1
+ER_Reserved03	= ER_Flags+1
+ER_Manufacturer	= ER_Reserved03+1
+ER_SerialNumber	= ER_Manufacturer+2
+ER_InitDiagVec	= ER_SerialNumber+4
+ER_Reserved0c	= ER_InitDiagVec+2
+ER_Reserved0d	= ER_Reserved0c+1
+ER_Reserved0e	= ER_Reserved0d+1
+ER_Reserved0f	= ER_Reserved0e+1
+ER_sizeof	= ER_Reserved0f+1
+
+CD_Node		= 0
+CD_Flags	= CD_Node+LN_sizeof
+CD_Pad		= CD_Flags+1
+CD_Rom		= CD_Pad+1
+CD_BoardAddr	= CD_Rom+ER_sizeof
+CD_BoardSize	= CD_BoardAddr+4
+CD_SlotAddr	= CD_BoardSize+4
+CD_SlotSize	= CD_SlotAddr+2
+CD_Driver	= CD_SlotSize+2
+CD_NextCD	= CD_Driver+4
+CD_Unused	= CD_NextCD+4
+CD_sizeof	= CD_Unused+(4*4)
+
+#endif	/* __ASSEMBLY__ */
+
+#ifndef __ASSEMBLY__
 
 /*
  * Zorro Functions
@@ -341,5 +381,6 @@
 extern int zorro_get_list(char *buffer);
 #endif CONFIG_ZORRO
 
+#endif	/* __ASSEMBLY__ */
 
 #endif /* _ASM_M68K_ZORRO_H_ */
diff -u --recursive --new-file pre2.0.4/linux/include/linux/affs_fs.h linux/include/linux/affs_fs.h
--- pre2.0.4/linux/include/linux/affs_fs.h	Tue May  7 16:22:38 1996
+++ linux/include/linux/affs_fs.h	Thu May 16 09:05:12 1996
@@ -26,24 +26,24 @@
 /* amigaffs.c */
 
 extern int		   affs_get_key_entry(int bsize, void *data, int entry_pos);
-extern int		   affs_find_next_hash_entry(int bsize, void *dir_data, ULONG *hash_pos);
+extern int		   affs_find_next_hash_entry(int bsize, void *dir_data, __u32 *hash_pos);
 extern int		   affs_get_file_name(int bsize, void *fh_data, char **name);
-extern ULONG		   affs_checksum_block(int bsize, void *data, LONG *ptype, LONG *stype);
+extern __u32		   affs_checksum_block(int bsize, void *data, __s32 *ptype, __s32 *stype);
 extern void		   affs_fix_checksum(int bsize, void *data, int cspos);
 extern void		   secs_to_datestamp(int secs, struct DateStamp *ds);
-extern int		   prot_to_mode(ULONG prot);
-extern ULONG		   mode_to_prot(int mode);
+extern int		   prot_to_mode(__u32 prot);
+extern __u32		   mode_to_prot(int mode);
 extern int		   affs_fix_hash_pred(struct inode *startino, int startoffset,
-		 			      LONG key, LONG newkey);
-extern int		   affs_fix_link_pred(struct inode *startino, LONG key, LONG newkey);
+		 			      __s32 key, __s32 newkey);
+extern int		   affs_fix_link_pred(struct inode *startino, __s32 key, __s32 newkey);
 
 /* bitmap. c */
 
 extern int		   affs_count_free_blocks(struct super_block *s);
-extern int		   affs_count_free_bits(int blocksize, const UBYTE *data);
-extern void		   affs_free_block(struct super_block *sb, LONG block);
-extern LONG		   affs_new_header(struct inode *inode);
-extern LONG		   affs_new_data(struct inode *inode);
+extern int		   affs_count_free_bits(int blocksize, const __u8 *data);
+extern void		   affs_free_block(struct super_block *sb, __s32 block);
+extern __s32		   affs_new_header(struct inode *inode);
+extern __s32		   affs_new_data(struct inode *inode);
 extern void		   affs_make_zones(struct super_block *sb);
 
 /* namei.c */
@@ -78,7 +78,7 @@
 extern void		   affs_put_inode(struct inode *);
 extern struct inode	  *affs_new_inode(const struct inode *dir);
 extern int		   affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode,
-					  const char *name, int len, LONG type);
+					  const char *name, int len, __s32 type);
 
 /* file.c */
 
@@ -101,4 +101,5 @@
 extern struct inode_operations	 affs_blkdev_inode_operations;
 
 extern int init_affs_fs(void);
+
 #endif
diff -u --recursive --new-file pre2.0.4/linux/include/linux/affs_hardblocks.h linux/include/linux/affs_hardblocks.h
--- pre2.0.4/linux/include/linux/affs_hardblocks.h	Tue May  7 16:22:38 1996
+++ linux/include/linux/affs_hardblocks.h	Wed May 15 09:44:59 1996
@@ -8,59 +8,59 @@
 #endif
 
 struct RigidDiskBlock {
-	ULONG	rdb_ID;
-	ULONG	rdb_SummedLongs;
-	LONG	rdb_ChkSum;
-	ULONG	rdb_HostID;
-	ULONG	rdb_BlockBytes;
-	ULONG	rdb_Flags;
-	ULONG	rdb_BadBlockList;
-	ULONG	rdb_PartitionList;
-	ULONG	rdb_FileSysHeaderList;
-	ULONG	rdb_DriveInit;
-	ULONG	rdb_Reserved1[6];
-	ULONG	rdb_Cylinders;
-	ULONG	rdb_Sectors;
-	ULONG	rdb_Heads;
-	ULONG	rdb_Interleave;
-	ULONG	rdb_Park;
-	ULONG	rdb_Reserved2[3];
-	ULONG	rdb_WritePreComp;
-	ULONG	rdb_ReducedWrite;
-	ULONG	rdb_StepRate;
-	ULONG	rdb_Reserved3[5];
-	ULONG	rdb_RDBBlocksLo;
-	ULONG	rdb_RDBBlocksHi;
-	ULONG	rdb_LoCylinder;
-	ULONG	rdb_HiCylinder;
-	ULONG	rdb_CylBlocks;
-	ULONG	rdb_AutoParkSeconds;
-	ULONG	rdb_HighRDSKBlock;
-	ULONG	rdb_Reserved4;
+	__u32	rdb_ID;
+	__u32	rdb_SummedLongs;
+	__s32	rdb_ChkSum;
+	__u32	rdb_HostID;
+	__u32	rdb_BlockBytes;
+	__u32	rdb_Flags;
+	__u32	rdb_BadBlockList;
+	__u32	rdb_PartitionList;
+	__u32	rdb_FileSysHeaderList;
+	__u32	rdb_DriveInit;
+	__u32	rdb_Reserved1[6];
+	__u32	rdb_Cylinders;
+	__u32	rdb_Sectors;
+	__u32	rdb_Heads;
+	__u32	rdb_Interleave;
+	__u32	rdb_Park;
+	__u32	rdb_Reserved2[3];
+	__u32	rdb_WritePreComp;
+	__u32	rdb_ReducedWrite;
+	__u32	rdb_StepRate;
+	__u32	rdb_Reserved3[5];
+	__u32	rdb_RDBBlocksLo;
+	__u32	rdb_RDBBlocksHi;
+	__u32	rdb_LoCylinder;
+	__u32	rdb_HiCylinder;
+	__u32	rdb_CylBlocks;
+	__u32	rdb_AutoParkSeconds;
+	__u32	rdb_HighRDSKBlock;
+	__u32	rdb_Reserved4;
 	char	rdb_DiskVendor[8];
 	char	rdb_DiskProduct[16];
 	char	rdb_DiskRevision[4];
 	char	rdb_ControllerVendor[8];
 	char	rdb_ControllerProduct[16];
 	char	rdb_ControllerRevision[4];
-	ULONG	rdb_Reserved5[10];
+	__u32	rdb_Reserved5[10];
 };
 
 #define	IDNAME_RIGIDDISK	0x5244534B	/* "RDSK" */
 
 struct PartitionBlock {
-	ULONG	pb_ID;
-	ULONG	pb_SummedLongs;
-	LONG	pb_ChkSum;
-	ULONG	pb_HostID;
-	ULONG	pb_Next;
-	ULONG	pb_Flags;
-	ULONG	pb_Reserved1[2];
-	ULONG	pb_DevFlags;
-	UBYTE	pb_DriveName[32];
-	ULONG	pb_Reserved2[15];
-	ULONG	pb_Environment[17];
-	ULONG	pb_EReserved[15];
+	__u32	pb_ID;
+	__u32	pb_SummedLongs;
+	__s32	pb_ChkSum;
+	__u32	pb_HostID;
+	__u32	pb_Next;
+	__u32	pb_Flags;
+	__u32	pb_Reserved1[2];
+	__u32	pb_DevFlags;
+	__u8	pb_DriveName[32];
+	__u32	pb_Reserved2[15];
+	__u32	pb_Environment[17];
+	__u32	pb_EReserved[15];
 };
 
 #define	IDNAME_PARTITION	0x50415254	/* "PART" */
diff -u --recursive --new-file pre2.0.4/linux/include/linux/amigaffs.h linux/include/linux/amigaffs.h
--- pre2.0.4/linux/include/linux/amigaffs.h	Sat May 11 10:42:07 1996
+++ linux/include/linux/amigaffs.h	Thu May 16 09:05:12 1996
@@ -15,6 +15,7 @@
 #define DIR_END(p,i)	GET_END_PTR(struct dir_end,p,AFFS_I2BSIZE(i))
 #define LINK_END(p,i)	GET_END_PTR(struct hlink_end,p,AFFS_I2BSIZE(i))
 #define ROOT_END_S(p,s)	GET_END_PTR(struct root_end,p,(s)->s_blocksize)
+#define DATA_FRONT(bh)	((struct data_front *)(bh)->b_data)
 
 /* Only for easier debugging if need be */
 #define affs_bread	bread
@@ -44,19 +45,11 @@
 #define MUFS_DCOFS	0x6d754604   /* 'muF\4' */
 #define MUFS_DCFFS	0x6d754605   /* 'muF\5' */
 
-typedef __u32	ULONG;
-typedef __u16	UWORD;
-typedef __u8	UBYTE;
-
-typedef __s32	LONG;
-typedef __s16	WORD;
-typedef __s8	BYTE;
-
 struct DateStamp
 {
-  ULONG ds_Days;
-  ULONG ds_Minute;
-  ULONG ds_Tick;
+  __u32 ds_Days;
+  __u32 ds_Minute;
+  __u32 ds_Tick;
 };
 
 #define T_SHORT		2
@@ -72,120 +65,120 @@
 
 struct root_front
 {
-  LONG primary_type;
-  ULONG spare1[2];
-  ULONG hash_size;
-  ULONG spare2;
-  ULONG checksum;
-  ULONG hashtable[0];
+  __s32 primary_type;
+  __u32 spare1[2];
+  __u32 hash_size;
+  __u32 spare2;
+  __u32 checksum;
+  __u32 hashtable[0];
 };
 
 struct root_end
 {
-  LONG bm_flag;
-  ULONG bm_keys[25];
-  ULONG bm_extend;
+  __s32 bm_flag;
+  __u32 bm_keys[25];
+  __u32 bm_extend;
   struct DateStamp dir_altered;
-  UBYTE disk_name[40];
+  __u8 disk_name[40];
   struct DateStamp disk_altered;
   struct DateStamp disk_made;
-  ULONG spare1[3];
-  LONG secondary_type;
+  __u32 spare1[3];
+  __s32 secondary_type;
 };
 
 struct dir_front
 {
-  LONG primary_type;
-  ULONG own_key;
-  ULONG spare1[3];
-  ULONG checksum;
-  ULONG hashtable[0];
+  __s32 primary_type;
+  __u32 own_key;
+  __u32 spare1[3];
+  __u32 checksum;
+  __u32 hashtable[0];
 };
 
 struct dir_end
 {
-  ULONG spare1;
-  UWORD owner_uid;
-  UWORD owner_gid;
-  ULONG protect;
-  ULONG spare2;
-  UBYTE comment[92];
+  __u32 spare1;
+  __u16 owner_uid;
+  __u16 owner_gid;
+  __u32 protect;
+  __u32 spare2;
+  __u8 comment[92];
   struct DateStamp created;
-  UBYTE dir_name[32];
-  ULONG spare3[2];
-  ULONG link_chain;
-  ULONG spare4[5];
-  ULONG hash_chain;
-  ULONG parent;
-  ULONG spare5;
-  LONG secondary_type;
+  __u8 dir_name[32];
+  __u32 spare3[2];
+  __u32 link_chain;
+  __u32 spare4[5];
+  __u32 hash_chain;
+  __u32 parent;
+  __u32 spare5;
+  __s32 secondary_type;
 };
 
 struct file_front
 {
-  LONG primary_type;
-  ULONG own_key;
-  ULONG block_count;
-  ULONG unknown1;
-  ULONG first_data;
-  ULONG checksum;
-  ULONG blocks[0];
+  __s32 primary_type;
+  __u32 own_key;
+  __u32 block_count;
+  __u32 unknown1;
+  __u32 first_data;
+  __u32 checksum;
+  __u32 blocks[0];
 };
 
 struct file_end
 {
-  ULONG spare1;
-  UWORD owner_uid;
-  UWORD owner_gid;
-  ULONG protect;
-  ULONG byte_size;
-  UBYTE comment[92];
+  __u32 spare1;
+  __u16 owner_uid;
+  __u16 owner_gid;
+  __u32 protect;
+  __u32 byte_size;
+  __u8 comment[92];
   struct DateStamp created;
-  UBYTE file_name[32];
-  ULONG spare2;
-  ULONG original;	/* not really in file_end */
-  ULONG link_chain;
-  ULONG spare3[5];
-  ULONG hash_chain;
-  ULONG parent;
-  ULONG extension;
-  LONG secondary_type;
+  __u8 file_name[32];
+  __u32 spare2;
+  __u32 original;	/* not really in file_end */
+  __u32 link_chain;
+  __u32 spare3[5];
+  __u32 hash_chain;
+  __u32 parent;
+  __u32 extension;
+  __s32 secondary_type;
 };
 
 struct hlink_front
 {
-  LONG primary_type;
-  ULONG own_key;
-  ULONG spare1[3];
-  ULONG checksum;
+  __s32 primary_type;
+  __u32 own_key;
+  __u32 spare1[3];
+  __u32 checksum;
 };
 
 struct hlink_end
 {
-  ULONG spare1;
-  UWORD owner_uid;
-  UWORD owner_gid;
-  ULONG protect;
-  UBYTE comment[92];
+  __u32 spare1;
+  __u16 owner_uid;
+  __u16 owner_gid;
+  __u32 protect;
+  __u8 comment[92];
   struct DateStamp created;
-  UBYTE link_name[32];
-  ULONG spare2;
-  ULONG original;
-  ULONG link_chain;
-  ULONG spare3[5];
-  ULONG hash_chain;
-  ULONG parent;
-  ULONG spare4;
-  LONG secondary_type;
+  __u8 link_name[32];
+  __u32 spare2;
+  __u32 original;
+  __u32 link_chain;
+  __u32 spare3[5];
+  __u32 hash_chain;
+  __u32 parent;
+  __u32 spare4;
+  __s32 secondary_type;
 };
 
 struct slink_front
 {
-  LONG primary_type;
-  ULONG own_key;
-  ULONG spare1[3];
-  ULONG checksum;
-  UBYTE	symname[288];	/* depends on block size */
+  __s32 primary_type;
+  __u32 own_key;
+  __u32 spare1[3];
+  __u32 checksum;
+  __u8	symname[288];	/* depends on block size */
 };
 
 /* Permission bits */
diff -u --recursive --new-file pre2.0.4/linux/include/linux/baycom.h linux/include/linux/baycom.h
--- pre2.0.4/linux/include/linux/baycom.h	Thu Jan  1 02:00:00 1970
+++ linux/include/linux/baycom.h	Thu May 16 16:35:42 1996
@@ -0,0 +1,123 @@
+/*
+ * The Linux BAYCOM driver for the Baycom serial 1200 baud modem
+ * and the parallel 9600 baud modem
+ * (C) 1996 by Thomas Sailer, HB9JNX
+ */
+
+#ifndef _BAYCOM_H
+#define _BAYCOM_H
+
+#include <linux/ioctl.h>
+
+/* -------------------------------------------------------------------- */
+
+struct baycom_statistics {
+	unsigned long rx_packets, tx_packets;
+	unsigned long ptt_keyed;
+	unsigned long rx_bufferoverrun, tx_bufferoverrun;
+};
+
+struct baycom_params {
+	int modem_type;
+	int iobase;
+	int irq;
+	int options;
+	int tx_delay;  /* the transmitter keyup delay in 10ms units */
+	int tx_tail;   /* the transmitter keyoff delay in 10ms units */
+	int slottime;  /* the slottime in 10ms; usually 10 = 100ms */
+	int ppersist;  /* the p-persistence 0..255 */
+	int fulldup;   /* the driver does not support full duplex, setting */
+	               /* this just makes the driver send even if DCD is on */
+};	
+
+/* -------------------------------------------------------------------- */
+
+#define BAYCOM_MAJOR 		51
+
+/* maximum packet length, excluding CRC */
+#define BAYCOM_MAXFLEN 		400	
+
+/* the ioctl type of this driver */
+#define BAYCOM_IOCTL_TYPE       'B'
+
+#define KISS_FEND   ((unsigned char)0300)
+#define KISS_FESC   ((unsigned char)0333)
+#define KISS_TFEND  ((unsigned char)0334)
+#define KISS_TFESC  ((unsigned char)0335)
+
+#define KISS_CMD_DATA       0
+#define KISS_CMD_TXDELAY    1
+#define KISS_CMD_PPERSIST   2
+#define KISS_CMD_SLOTTIME   3
+#define KISS_CMD_TXTAIL     4
+#define KISS_CMD_FULLDUP    5
+
+/*
+ * modem types
+ */
+
+#define BAYCOM_MODEM_INVALID 0
+#define BAYCOM_MODEM_SER12   1
+#define BAYCOM_MODEM_PAR96   2
+
+/*
+ * modem options; bit mask
+ */
+#define BAYCOM_OPTIONS_SOFTDCD  1
+
+
+/*
+ * ioctl constants
+ */
+#define BAYCOMCTL_GETDCD           _IOR(BAYCOM_IOCTL_TYPE, 0, unsigned char)
+#define BAYCOMCTL_GETPTT           _IOR(BAYCOM_IOCTL_TYPE, 1, unsigned char)
+#define BAYCOMCTL_PARAM_TXDELAY    _IO(BAYCOM_IOCTL_TYPE, 2)
+#define BAYCOMCTL_PARAM_PPERSIST   _IO(BAYCOM_IOCTL_TYPE, 3)
+#define BAYCOMCTL_PARAM_SLOTTIME   _IO(BAYCOM_IOCTL_TYPE, 4)
+#define BAYCOMCTL_PARAM_TXTAIL     _IO(BAYCOM_IOCTL_TYPE, 5)
+#define BAYCOMCTL_PARAM_FULLDUP    _IO(BAYCOM_IOCTL_TYPE, 6)
+
+#define BAYCOMCTL_GETSTAT          _IOR(BAYCOM_IOCTL_TYPE, 7, \
+					struct baycom_statistics)
+
+#define BAYCOMCTL_GETPARAMS        _IOR(BAYCOM_IOCTL_TYPE, 8, \
+					struct baycom_params)
+#define BAYCOMCTL_SETPARAMS        _IOR(BAYCOM_IOCTL_TYPE, 9, \
+					struct baycom_params)
+
+#define BAYCOMCTL_CALIBRATE        _IO(BAYCOM_IOCTL_TYPE, 10)
+
+#ifdef BAYCOM_DEBUG
+/*
+ * these are mainly for debugging purposes
+ */
+#define BAYCOMCTL_GETSAMPLES       _IOR(BAYCOM_IOCTL_TYPE, 16, unsigned char)
+#define BAYCOMCTL_GETBITS          _IOR(BAYCOM_IOCTL_TYPE, 17, unsigned char)
+
+#define BAYCOMCTL_DEBUG1           _IOR(BAYCOM_IOCTL_TYPE, 18, unsigned long)
+#define BAYCOMCTL_DEBUG2           _IOR(BAYCOM_IOCTL_TYPE, 19, unsigned long)
+#define BAYCOMCTL_DEBUG3           _IOR(BAYCOM_IOCTL_TYPE, 20, unsigned long)
+#endif /* BAYCOM_DEBUG */
+
+/* -------------------------------------------------------------------- */
+
+#endif /* _BAYCOM_H */
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 8
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -8
+ * c-argdecl-indent: 8
+ * c-label-offset: -8
+ * c-continued-statement-offset: 8
+ * c-continued-brace-offset: 0
+ * End:
+ */
diff -u --recursive --new-file pre2.0.4/linux/include/linux/cm206.h linux/include/linux/cm206.h
--- pre2.0.4/linux/include/linux/cm206.h	Mon May 13 23:02:49 1996
+++ linux/include/linux/cm206.h	Wed May 15 10:06:26 1996
@@ -5,6 +5,8 @@
 #ifndef LINUX_CM206_H
 #define LINUX_CM206_H
 
+#include <linux/ioctl.h>
+
 /* First, the cm260 stuff */
 /* The ports and irq used. Although CM206_BASE and CM206_IRQ are defined
    below, the values are not used unless autoprobing is turned off and 
@@ -128,13 +130,13 @@
 
 /* finally some ioctls for the driver */
 
-#define CM206CTL_GET_STAT 0x2000
-#define CM206CTL_GET_LAST_STAT 0x2001
+#define CM206CTL_GET_STAT _IO( 0x20, 0 )
+#define CM206CTL_GET_LAST_STAT _IO( 0x20, 1 )
 
 /* for kernel 1.2.n */
 #if !defined(CDROM_GET_UPC)
-#define CDROM_GET_UPC 0x5311
-#define CDROMRESET 0x5312
+#define CDROM_GET_UPC _IO( 'S', 0x11 )
+#define CDROMRESET _IO( 'S', 0x12 )
 #endif
 
 #ifdef STATISTICS
diff -u --recursive --new-file pre2.0.4/linux/include/linux/fs.h linux/include/linux/fs.h
--- pre2.0.4/linux/include/linux/fs.h	Wed May 15 11:01:15 1996
+++ linux/include/linux/fs.h	Fri May 17 15:05:01 1996
@@ -272,7 +272,7 @@
 	uid_t		i_uid;
 	gid_t		i_gid;
 	kdev_t		i_rdev;
-	off_t		i_size;
+	unsigned long	i_size;
 	time_t		i_atime;
 	time_t		i_mtime;
 	time_t		i_ctime;
@@ -359,12 +359,10 @@
 #define FLOCK_VERIFY_READ  1
 #define FLOCK_VERIFY_WRITE 2
 
-#ifdef CONFIG_LOCK_MANDATORY	 
 extern int locks_mandatory_locked(struct inode *inode);
 extern int locks_mandatory_area(int read_write, struct inode *inode,
 				struct file *filp, unsigned int offset,
 				unsigned int count);
-#endif
 
 extern inline int locks_verify_locked(struct inode *inode)
 {
diff -u --recursive --new-file pre2.0.4/linux/include/linux/iso_fs.h linux/include/linux/iso_fs.h
--- pre2.0.4/linux/include/linux/iso_fs.h	Sat Apr 13 18:22:07 1996
+++ linux/include/linux/iso_fs.h	Wed May 15 09:09:00 1996
@@ -124,21 +124,6 @@
 #define ISOFS_BUFFER_BITS(INODE) ((INODE)->i_sb->s_blocksize_bits)
 #define ISOFS_ZONE_BITS(INODE)   ((INODE)->i_sb->u.isofs_sb.s_log_zone_size)
 
-#if 0
-#ifdef ISOFS_FIXED_BLOCKSIZE
-/* We use these until the buffer cache supports 2048 */
-#define ISOFS_BUFFER_BITS 10
-#define ISOFS_BUFFER_SIZE 1024
-
-#define ISOFS_BLOCK_NUMBER(X) (X<<1)
-#else
-#define ISOFS_BUFFER_BITS 11
-#define ISOFS_BUFFER_SIZE 2048
-
-#define ISOFS_BLOCK_NUMBER(X) (X)
-#endif
-#endif
-
 #define ISOFS_SUPER_MAGIC 0x9660
 #define ISOFS_FILE_UNKNOWN 0
 #define ISOFS_FILE_TEXT 1
diff -u --recursive --new-file pre2.0.4/linux/include/linux/mcdx.h linux/include/linux/mcdx.h
--- pre2.0.4/linux/include/linux/mcdx.h	Mon May 13 23:02:49 1996
+++ linux/include/linux/mcdx.h	Fri May 17 15:24:15 1996
@@ -1,7 +1,7 @@
 /*
  * Definitions for the Mitsumi CDROM interface
  * Copyright (C) 1995 Heiko Schlittermann <heiko@lotte.sax.de>
- * VERSION: 2.2
+ * VERSION: 2.3
  * 
  * 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
@@ -40,11 +40,13 @@
  *      o       MCDX_NDRIVES  :  number of used entries of the following table
  *      o       MCDX_DRIVEMAP :  table of {i/o base, irq} per controller
  *
- *      NOTE: I didn't get a drive at irq 9(2) working.  Not even alone.
+ *      NOTE: Don't even think about connecting the drive to IRQ 9(2).
+ *	In the AT architecture this interrupt is used to cascade the two
+ *	interrupt controllers and isn't therefore usable for enything else!
  */
  /* #define I_WAS_IN_MCDX_H */
 #define MCDX_NDRIVES 1
-#define MCDX_DRIVEMAP {	{0x300, 11},	\
+#define MCDX_DRIVEMAP {	{0x230, 11},	\
 			{0x304, 05},  	\
 			{0x000, 00},  	\
 			{0x000, 00},  	\
diff -u --recursive --new-file pre2.0.4/linux/include/linux/module.h linux/include/linux/module.h
--- pre2.0.4/linux/include/linux/module.h	Sun Mar 17 16:15:05 1996
+++ linux/include/linux/module.h	Tue May 14 14:55:51 1996
@@ -28,6 +28,7 @@
 
 /* magic marker for modules inserted from kerneld, to be auto-reaped */
 #define MOD_AUTOCLEAN 0x40000000 /* big enough, but no sign problems... */
+#define MOD_VISITED   0x20000000 /* Thanks Jacques! */
 
 /* maximum length of symbol name */
 #define SYM_MAX_NAME 60
@@ -88,9 +89,9 @@
 #ifdef MODULE
 
 extern long mod_use_count_;
-#define MOD_INC_USE_COUNT      mod_use_count_++
-#define MOD_DEC_USE_COUNT      mod_use_count_--
-#define MOD_IN_USE	       ((mod_use_count_ & ~MOD_AUTOCLEAN) != 0)
+#define MOD_INC_USE_COUNT      (mod_use_count_++, mod_use_count_ |= MOD_VISITED)
+#define MOD_DEC_USE_COUNT      (mod_use_count_--, mod_use_count_ |= MOD_VISITED)
+#define MOD_IN_USE	       ((mod_use_count_ & ~(MOD_AUTOCLEAN | MOD_VISITED)) != 0)
 
 #ifndef __NO_VERSION__
 #include <linux/version.h>
diff -u --recursive --new-file pre2.0.4/linux/include/linux/socket.h linux/include/linux/socket.h
--- pre2.0.4/linux/include/linux/socket.h	Fri Apr 12 15:52:08 1996
+++ linux/include/linux/socket.h	Thu May 16 16:35:42 1996
@@ -16,22 +16,22 @@
 	int		l_linger;	/* How long to linger for	*/
 };
 
+/*
+ *	As we do 4.4BSD message passing we use a 4.4BSD message passing
+ *	system, not 4.3. Thus msg_accrights(len) are now missing. They
+ *	belong in an obscure libc emulation or the bin.
+ */
+ 
 struct msghdr 
 {
 	void	*	msg_name;	/* Socket name			*/
 	int		msg_namelen;	/* Length of name		*/
 	struct iovec *	msg_iov;	/* Data blocks			*/
 	int 		msg_iovlen;	/* Number of blocks		*/
-	void 	*	msg_accrights;	/* Per protocol magic (eg BSD file descriptor passing) */
-	int		msg_accrightslen;	/* Length of rights list */
+	void 	*	msg_control;	/* Per protocol magic (eg BSD file descriptor passing) */
+	int		msg_controllen;	/* Length of rights list */
+	int		msg_flags;	/* 4.4 BSD item we dont use      */
 };
-
-/*
- *	4.4BSD changed to these new names for no apparent reason.
- */
- 
-#define msg_control	msg_accrights	
-#define msg_controllen	msg_accrightslen
 
 /* Control Messages */
 
diff -u --recursive --new-file pre2.0.4/linux/include/linux/tty.h linux/include/linux/tty.h
--- pre2.0.4/linux/include/linux/tty.h	Wed Apr 24 17:00:43 1996
+++ linux/include/linux/tty.h	Fri May 17 15:05:01 1996
@@ -292,6 +292,7 @@
 extern int stl_init(void);
 extern int stli_init(void);
 extern int riscom8_init(void);
+extern int baycom_init(void);
 
 extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device,
 			      const char *routine);
diff -u --recursive --new-file pre2.0.4/linux/include/net/ip_masq.h linux/include/net/ip_masq.h
--- pre2.0.4/linux/include/net/ip_masq.h	Tue Apr 23 13:57:14 1996
+++ linux/include/net/ip_masq.h	Fri May 17 15:10:53 1996
@@ -84,7 +84,7 @@
 /*
  *	functions called from ip layer
  */
-extern void ip_fw_masquerade(struct sk_buff **, struct device *);
+extern int ip_fw_masquerade(struct sk_buff **, struct device *);
 extern int ip_fw_demasquerade(struct sk_buff **, struct device *);
 
 /*
@@ -149,6 +149,7 @@
  *	service routine(s).
  */
 extern struct ip_masq * ip_masq_out_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
+extern struct ip_masq * ip_masq_in_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port);
 
 /*
  *	/proc/net entry
diff -u --recursive --new-file pre2.0.4/linux/include/net/netlink.h linux/include/net/netlink.h
--- pre2.0.4/linux/include/net/netlink.h	Tue May  7 16:22:39 1996
+++ linux/include/net/netlink.h	Fri May 17 15:10:43 1996
@@ -2,8 +2,8 @@
 #define __NET_NETLINK_H
 
 #define NET_MAJOR 36		/* Major 18 is reserved for networking 						*/
-#define MAX_LINKS 9		/* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved 	*/
-				/* 4-7 are psi0-psi3 */
+#define MAX_LINKS 10		/* 18,0 for route updates, 18,1 for SKIP, 18,2 debug tap 18,3 PPP reserved 	*/
+				/* 4-7 are psi0-psi3  8 is arpd 9 is ppp */
 #define MAX_QBYTES 32768	/* Maximum bytes in the queue 							*/
 
 #include <linux/config.h>
@@ -20,6 +20,7 @@
 #define NETLINK_FIREWALL	3	/* Firewalling hook				*/
 #define NETLINK_PSI		4	/* PSI devices - 4 to 7 */
 #define NETLINK_ARPD		8
+#define NETLINK_NET_PPP		9	/* Non tty PPP devices */
 
 #ifdef CONFIG_RTNETLINK
 extern void ip_netlink_msg(unsigned long, __u32, __u32, __u32, short, short, char *);
diff -u --recursive --new-file pre2.0.4/linux/include/net/sock.h linux/include/net/sock.h
--- pre2.0.4/linux/include/net/sock.h	Tue May  7 16:22:39 1996
+++ linux/include/net/sock.h	Fri May 17 15:07:07 1996
@@ -195,8 +195,8 @@
 	struct sock		*next;
 	struct sock		*prev; /* Doubly linked chain.. */
 	struct sock		*pair;
-	struct sk_buff		* volatile send_head;
-	struct sk_buff		* volatile send_tail;
+	struct sk_buff		* send_head;
+	struct sk_buff		* send_tail;
 	struct sk_buff_head	back_log;
 	struct sk_buff		*partial;
 	struct timer_list	partial_timer;
@@ -211,33 +211,34 @@
 	unsigned short		max_unacked;
 	unsigned short		window;
 	__u32                   lastwin_seq;    /* sequence number when we last updated the window we offer */
-	volatile unsigned long  ato;            /* ack timeout */
-	volatile unsigned long  lrcvtime;       /* jiffies at last rcv */
+	__u32			high_seq;	/* sequence number when we did current fast retransmit */
+	unsigned long		ato;            /* ack timeout */
+	unsigned long		lrcvtime;       /* jiffies at last rcv */
 	unsigned short		bytes_rcv;
 /*
  *	mss is min(mtu, max_window) 
  */
 	unsigned short		mtu;       /* mss negotiated in the syn's */
-	volatile unsigned short	mss;       /* current eff. mss - can change */
-	volatile unsigned short	user_mss;  /* mss requested by user in ioctl */
-	volatile unsigned short	max_window;
+	unsigned short		mss;       /* current eff. mss - can change */
+	unsigned short		user_mss;  /* mss requested by user in ioctl */
+	unsigned short		max_window;
 	unsigned long 		window_clamp;
+	unsigned int		ssthresh;
 	unsigned short		num;
-	volatile unsigned short	cong_window;
-	volatile unsigned short	cong_count;
-	volatile unsigned short	ssthresh;
-	volatile unsigned short	packets_out;
-	volatile unsigned short	shutdown;
-	volatile unsigned long	rtt;
-	volatile unsigned long	mdev;
-	volatile unsigned long	rto;
+	unsigned short		cong_window;
+	unsigned short		cong_count;
+	unsigned short		packets_out;
+	unsigned short		shutdown;
+	unsigned long		rtt;
+	unsigned long		mdev;
+	unsigned long		rto;
 
 /*
  *	currently backoff isn't used, but I'm maintaining it in case
  *	we want to go back to a backoff formula that needs it
  */
  
-	volatile unsigned short	backoff;
+	unsigned short		backoff;
 	int			err, err_soft;	/* Soft holds errors that don't
 						   cause failure but are the cause
 						   of a persistent failure not just
@@ -412,7 +413,7 @@
 
 static inline void lock_sock(struct sock *sk)
 {
-#if 1
+#if 0
 /* debugging code: the test isn't even 100% correct, but it can catch bugs */
 /* Note that a double lock is ok in theory - it's just _usually_ a bug */
 	if (sk->users) {
@@ -428,7 +429,7 @@
 static inline void release_sock(struct sock *sk)
 {
 	barrier();
-#if 1
+#if 0
 /* debugging code: remove me when ok */
 	if (sk->users == 0) {
 		__label__ here;
@@ -437,7 +438,7 @@
 here:
 	}
 #endif
-	if (!--sk->users)
+	if ((sk->users = sk->users-1) == 0)
 		__release_sock(sk);
 }
 
diff -u --recursive --new-file pre2.0.4/linux/include/net/tcp.h linux/include/net/tcp.h
--- pre2.0.4/linux/include/net/tcp.h	Sun May 12 10:16:07 1996
+++ linux/include/net/tcp.h	Fri May 17 15:10:17 1996
@@ -155,7 +155,7 @@
 extern void tcp_send_synack(struct sock *, struct sock *, struct sk_buff *);
 extern void tcp_send_skb(struct sock *, struct sk_buff *);
 extern void tcp_send_ack(struct sock *sk);
-extern void tcp_send_delayed_ack(struct sock *sk, int timeout);
+extern void tcp_send_delayed_ack(struct sock *sk, int max_timeout, unsigned long timeout);
 extern void tcp_send_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
 	  struct proto *prot, struct options *opt, struct device *dev, int tos, int ttl);
 
diff -u --recursive --new-file pre2.0.4/linux/init/main.c linux/init/main.c
--- pre2.0.4/linux/init/main.c	Sat May 11 10:42:07 1996
+++ linux/init/main.c	Thu May 16 16:35:55 1996
@@ -156,6 +156,9 @@
 #ifdef CONFIG_RISCOM8
 extern void riscom8_setup(char *str, int *ints);
 #endif
+#ifdef CONFIG_BAYCOM
+extern void baycom_setup(char *str, int *ints);
+#endif
 
 
 #if defined(CONFIG_SYSVIPC) || defined(CONFIG_KERNELD)
@@ -391,6 +394,9 @@
 #endif
 #ifdef CONFIG_RISCOM8
 	{ "riscom8=", riscom8_setup },
+#endif
+#ifdef CONFIG_BAYCOM
+	{ "baycom=", baycom_setup },
 #endif
 	{ 0, 0 }
 };
diff -u --recursive --new-file pre2.0.4/linux/kernel/module.c linux/kernel/module.c
--- pre2.0.4/linux/kernel/module.c	Tue May  7 16:22:40 1996
+++ linux/kernel/module.c	Tue May 14 14:55:51 1996
@@ -55,8 +55,6 @@
 static int get_mod_name( char *user_name, char *buf);
 static int free_modules( void);
 
-static int module_init_flag = 0; /* Hmm... */
-
 extern struct symbol_table symbol_table; /* in kernel/ksyms.c */
 
 /*
@@ -147,7 +145,7 @@
 	/* A little bit of protection... we "know" where the user stack is... */
 
 	if (symtab && ((unsigned long)symtab > 0xb0000000)) {
-		printk("warning: you are using an old insmod, no symbols will be inserted!\n");
+		printk(KERN_WARNING "warning: you are using an old insmod, no symbols will be inserted!\n");
 		symtab = NULL;
 	}
 #endif
@@ -211,7 +209,7 @@
 			newtab->n_refs * sizeof(struct module_ref);
 
 		if ((newtab->n_symbols < 0) || (newtab->n_refs < 0) || (legal_start > size)) {
-			printk("Rejecting illegal symbol table (n_symbols=%d,n_refs=%d)\n",
+			printk(KERN_WARNING "Rejecting illegal symbol table (n_symbols=%d,n_refs=%d)\n",
 			       newtab->n_symbols, newtab->n_refs);
 			kfree_s(newtab, size);
 			return -EINVAL;
@@ -220,7 +218,7 @@
 		/* relocate name pointers, index referred from start of table */
 		for (sym = &(newtab->symbol[0]), i = 0; i < newtab->n_symbols; ++sym, ++i) {
 			if ((unsigned long)sym->name < legal_start || size <= (unsigned long)sym->name) {
-				printk("Rejecting illegal symbol table\n");
+				printk(KERN_WARNING "Rejecting illegal symbol table\n");
 				kfree_s(newtab, size);
 				return -EINVAL;
 			}
@@ -246,7 +244,7 @@
 				link = link->next;
 
 			if (link == (struct module *)0) {
-				printk("Non-module reference! Rejected!\n");
+				printk(KERN_WARNING "Non-module reference! Rejected!\n");
 				return -EINVAL;
 			}
 
@@ -256,12 +254,12 @@
 		}
 	}
 
-	module_init_flag = 1; /* Hmm... */
+	GET_USE_COUNT(mp) += 1;
 	if ((*rt.init)() != 0) {
-		module_init_flag = 0; /* Hmm... */
+		GET_USE_COUNT(mp) = 0;
 		return -EBUSY;
 	}
-	module_init_flag = 0; /* Hmm... */
+	GET_USE_COUNT(mp) -= 1;
 	mp->state = MOD_RUNNING;
 
 	return 0;
@@ -282,9 +280,10 @@
 			return error;
 		if ((mp = find_module(name)) == NULL)
 			return -ENOENT;
-		if ((mp->ref != NULL) || ((GET_USE_COUNT(mp) & ~MOD_AUTOCLEAN) != 0))
+		if ((mp->ref != NULL) ||
+		    ((GET_USE_COUNT(mp) & ~(MOD_AUTOCLEAN | MOD_VISITED)) != 0))
 			return -EBUSY;
-		GET_USE_COUNT(mp) &= ~MOD_AUTOCLEAN;
+		GET_USE_COUNT(mp) &= ~(MOD_AUTOCLEAN | MOD_VISITED);
 		if (mp->state == MOD_RUNNING)
 			(*mp->cleanup)();
 		mp->state = MOD_DELETED;
@@ -293,11 +292,17 @@
 	/* for automatic reaping */
 	else {
 		for (mp = module_list; mp != &kernel_module; mp = mp->next) {
-			if ((mp->ref == NULL) && (GET_USE_COUNT(mp) == MOD_AUTOCLEAN) &&
-			    (mp->state == MOD_RUNNING)) {
-				GET_USE_COUNT(mp) &= ~MOD_AUTOCLEAN;
-				(*mp->cleanup)();
-				mp->state = MOD_DELETED;
+			if ((mp->ref == NULL) && (mp->state == MOD_RUNNING) &&
+			    ((GET_USE_COUNT(mp) & ~(MOD_AUTOCLEAN | MOD_VISITED)) == 0)) {
+			    	if ((GET_USE_COUNT(mp) & MOD_VISITED)) {
+					/* Don't reap until one "cycle" after last _use_ */
+			   		GET_USE_COUNT(mp) &= ~MOD_VISITED;
+				}
+				else {
+					GET_USE_COUNT(mp) &= ~(MOD_AUTOCLEAN | MOD_VISITED);
+					(*mp->cleanup)();
+					mp->state = MOD_DELETED;
+				}
 			}
 		}
 		free_modules();
@@ -534,7 +539,7 @@
 		}
 		if (mp->state == MOD_RUNNING) {
 			sprintf(size,"\t%ld%s",
-				GET_USE_COUNT(mp) & ~MOD_AUTOCLEAN,
+				GET_USE_COUNT(mp) & ~(MOD_AUTOCLEAN | MOD_VISITED),
 				((GET_USE_COUNT(mp) & MOD_AUTOCLEAN)?
 					" (autoclean)":""));
 			q = size;
@@ -639,11 +644,17 @@
 			intab->n_symbols +=1;
 	}
 
-#if 1
-	if (module_init_flag == 0) { /* Hmm... */
-#else
-	if (module_list == &kernel_module) {
-#endif
+	for (mp = module_list; intab && mp != &kernel_module; mp = mp->next) {
+		/*
+		 * New table stored within memory belonging to a module?
+		 * (Always true for a module)
+		 */
+		if (((unsigned long)(mp->addr) < (unsigned long)intab) &&
+		    ((unsigned long)intab < ((unsigned long)(mp->addr) + mp->size * PAGE_SIZE)))
+			break;
+	}
+
+	if (mp == &kernel_module) {
 		/* Aha! Called from an "internal" module */
 		if (!intab)
 			return 0; /* or -ESILLY_PROGRAMMER :-) */
@@ -651,7 +662,7 @@
 		/* create a pseudo module! */
 		if (!(mp = (struct module*) kmalloc(MODSIZ, GFP_KERNEL))) {
 			/* panic time! */
-			printk("Out of memory for new symbol table!\n");
+			printk(KERN_ERR "Out of memory for new symbol table!\n");
 			return -ENOMEM;
 		}
 		/* else  OK */
@@ -674,7 +685,6 @@
 	 * call to  init_module  i.e. when loading the module!!
 	 * Or else...
 	 */
-	mp = module_list; /* true when doing init_module! */
 
 	/* Any table there before? */
 	if ((oldtab = mp->symtab) == (struct symbol_table*)0) {
@@ -684,12 +694,6 @@
 	}
 
 	/* else  ****** we have to replace the module symbol table ******/
-#if 0
-	if (oldtab->n_symbols > 0) {
-		/* Oh dear, I have to drop the old ones... */
-		printk("Warning, dropping old symbols\n");
-	}
-#endif
 
 	if (oldtab->n_refs == 0) { /* no problems! */
 		mp->symtab = intab;
@@ -714,7 +718,7 @@
 			oldtab->n_refs * REFSIZ,
 		GFP_KERNEL))) {
 		/* panic time! */
-		printk("Out of memory for new symbol table!\n");
+		printk(KERN_ERR "Out of memory for new symbol table!\n");
 		return -ENOMEM;
 	}
 
diff -u --recursive --new-file pre2.0.4/linux/mm/filemap.c linux/mm/filemap.c
--- pre2.0.4/linux/mm/filemap.c	Tue May  7 16:22:40 1996
+++ linux/mm/filemap.c	Thu May 16 11:31:43 1996
@@ -117,11 +117,17 @@
 	struct page * page;
 	unsigned long limit = MAP_NR(high_memory);
 	struct buffer_head *tmp, *bh;
+	int count_max, count_min;
+
+	count_max = (limit<<1) >> (priority>>1);
+	count_min = (limit<<1) >> (priority);
 
-	priority = (limit<<2) >> priority;
 	page = mem_map + clock;
 	do {
-		priority--;
+		count_max--;
+		if (page->inode || page->buffers)
+			count_min--;
+
 		if (PageLocked(page))
 			goto next;
 		if (dma && !PageDMA(page))
@@ -179,7 +185,7 @@
 			clock = 0;
 			page = mem_map;
 		}
-	} while (priority > 0);
+	} while (count_max > 0 && count_min > 0);
 	return 0;
 }
 
diff -u --recursive --new-file pre2.0.4/linux/mm/memory.c linux/mm/memory.c
--- pre2.0.4/linux/mm/memory.c	Sat Apr 27 15:20:09 1996
+++ linux/mm/memory.c	Thu May 16 15:15:36 1996
@@ -76,7 +76,7 @@
  */
 void oom(struct task_struct * task)
 {
-	printk("\nOut of memory for %s.\n", current->comm);
+	printk("\nOut of memory for %s.\n", task->comm);
 	task->sig->action[SIGKILL-1].sa_handler = NULL;
 	task->blocked &= ~(1<<(SIGKILL-1));
 	send_sig(SIGKILL,task,1);
diff -u --recursive --new-file pre2.0.4/linux/net/Makefile linux/net/Makefile
--- pre2.0.4/linux/net/Makefile	Fri Apr 12 15:52:10 1996
+++ linux/net/Makefile	Thu May 16 16:35:55 1996
@@ -8,7 +8,7 @@
 # Note 2! The CFLAGS definition is now in the main makefile...
 
 MOD_SUB_DIRS := ipv4
-ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipx unix appletalk netrom 
+ALL_SUB_DIRS := 802 ax25 bridge core ethernet ipv4 ipx unix appletalk netrom #decnet
 SUB_DIRS     := core ethernet unix
 MOD_LIST_NAME := NET_MISC_MODULES
 
diff -u --recursive --new-file pre2.0.4/linux/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- pre2.0.4/linux/net/ax25/af_ax25.c	Mon May 13 23:02:51 1996
+++ linux/net/ax25/af_ax25.c	Thu May 16 16:35:55 1996
@@ -1950,7 +1950,7 @@
 		return sock_error(sk);
 	}
 
-	if (flags|| msg->msg_accrights)
+	if (flags|| msg->msg_control)
 		return -EINVAL;
 
 	if (sk->zapped)
diff -u --recursive --new-file pre2.0.4/linux/net/core/dev.c linux/net/core/dev.c
--- pre2.0.4/linux/net/core/dev.c	Mon May 13 23:02:51 1996
+++ linux/net/core/dev.c	Thu May 16 16:35:55 1996
@@ -45,6 +45,8 @@
  *		Alan Cox	:	Cleaned up the backlog initialise.
  *		Craig Metz	:	SIOCGIFCONF fix if space for under
  *					1 device.
+ *	    Thomas Bogendoerfer :	Return ENODEV for dev_open, if there
+ *					is no device open function.
  *
  */
 
@@ -236,7 +238,7 @@
  
 int dev_open(struct device *dev)
 {
-	int ret = 0;
+	int ret = -ENODEV;
 
 	/*
 	 *	Call device private open method
diff -u --recursive --new-file pre2.0.4/linux/net/core/iovec.c linux/net/core/iovec.c
--- pre2.0.4/linux/net/core/iovec.c	Sat Apr 27 15:20:10 1996
+++ linux/net/core/iovec.c	Thu May 16 16:35:55 1996
@@ -41,9 +41,9 @@
 			return err;
 		m->msg_name = address;
 	}
-	if(m->msg_accrights!=NULL)
+	if(m->msg_control!=NULL)
 	{
-		err=verify_area(mode, m->msg_accrights, m->msg_accrightslen);
+		err=verify_area(mode, m->msg_control, m->msg_controllen);
 		if(err)
 			return err;
 	}
diff -u --recursive --new-file pre2.0.4/linux/net/core/net_alias.c linux/net/core/net_alias.c
--- pre2.0.4/linux/net/core/net_alias.c	Mon May 13 23:02:51 1996
+++ linux/net/core/net_alias.c	Thu May 16 16:35:55 1996
@@ -509,7 +509,7 @@
   {
     if (!(alias = prevdev->next->my_alias))
     {
-      printk(KERN_ERR "ERROR: net_alias_dev_delete(): incorrect non-alias device after maindev\n");
+      printk(KERN_ERR "net_alias_dev_delete(): incorrect non-alias device after maindev\n");
       continue;			/* or should give up? */
     }
     if (alias->slot == slot) break;
@@ -537,7 +537,7 @@
       printk(KERN_WARNING "net_alias_dev_delete(%s): bad hashing recovered\n", alias->name);
     else
     {
-      printk(KERN_ERR "ERROR: net_alias_dev_delete(%s): unhashed alias!\n",alias->name);
+      printk(KERN_ERR "net_alias_dev_delete(%s): unhashed alias!\n",alias->name);
       return NULL;		/* ENODEV */
     }
   
@@ -760,7 +760,7 @@
   
   if (!sa)
   {
-    printk(KERN_ERR "ERROR: net_alias_rehash(): NULL sockaddr passed\n");
+    printk(KERN_ERR "net_alias_rehash(): NULL sockaddr passed\n");
     return -1;
   }
 
@@ -770,7 +770,7 @@
 
   if ( (main_dev = alias->main_dev) == NULL )
   {
-    printk(KERN_ERR "ERROR: net_alias_rehash for %s: NULL maindev\n", alias->name);
+    printk(KERN_ERR "net_alias_rehash for %s: NULL maindev\n", alias->name);
     return -1;
   }
 
@@ -780,7 +780,7 @@
 
   if (!(alias_info=main_dev->alias_info))
   {
-    printk(KERN_ERR "ERROR: net_alias_rehash for %s: NULL alias_info\n", alias->name);
+    printk(KERN_ERR "net_alias_rehash for %s: NULL alias_info\n", alias->name);
     return -1;
   }
   
@@ -791,7 +791,7 @@
   o_nat = alias->nat;
   if (!o_nat)
   {
-    printk(KERN_ERR "ERROR: net_alias_rehash(%s): unbound alias.\n", alias->name);
+    printk(KERN_ERR "net_alias_rehash(%s): unbound alias.\n", alias->name);
     return -1;
   }
 
@@ -806,7 +806,7 @@
     n_nat = nat_getbytype(sa->sa_family);
     if (!n_nat)
     {
-      printk(KERN_ERR "ERROR: net_alias_rehash(%s): unreg family==%d.\n", alias->name, sa->sa_family);
+      printk(KERN_ERR "net_alias_rehash(%s): unreg family==%d.\n", alias->name, sa->sa_family);
       return -1;
     }
   }
@@ -835,7 +835,7 @@
       printk(KERN_WARNING "net_alias_rehash(%s): bad hashing recovered\n", alias->name);
     else
     {
-      printk(KERN_ERR "ERROR: net_alias_rehash(%s): unhashed alias!\n", alias->name);
+      printk(KERN_ERR "net_alias_rehash(%s): unhashed alias!\n", alias->name);
       return -1;
     }
   
diff -u --recursive --new-file pre2.0.4/linux/net/decnet/README linux/net/decnet/README
--- pre2.0.4/linux/net/decnet/README	Thu Jan  1 02:00:00 1970
+++ linux/net/decnet/README	Thu May 16 16:35:55 1996
@@ -0,0 +1,6 @@
+Yes.. its being worked on.
+
+If you want to get involved email me <Alan.Cox@linux.org> and I'll put you
+in touch with the people doing the work.
+
+Alan
diff -u --recursive --new-file pre2.0.4/linux/net/ipv4/Config.in linux/net/ipv4/Config.in
--- pre2.0.4/linux/net/ipv4/Config.in	Mon May 13 23:02:51 1996
+++ linux/net/ipv4/Config.in	Thu May 16 16:35:55 1996
@@ -12,10 +12,14 @@
   tristate 'IP: tunneling' CONFIG_NET_IPIP
   if [ "$CONFIG_IP_FIREWALL" = "y" ]; then
     bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE
-    bool 'IP: masquerading (ALPHA)' CONFIG_IP_MASQUERADE
+    if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool 'IP: masquerading (ALPHA)' CONFIG_IP_MASQUERADE
+    fi
   fi
   if [ "$CONFIG_IP_MULTICAST" = "y" ]; then
-    bool 'IP: multicast routing (EXPERIMENTAL)' CONFIG_IP_MROUTE
+      if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+        bool 'IP: multicast routing (EXPERIMENTAL)' CONFIG_IP_MROUTE
+      fi		
   fi
 fi
 if [ "$CONFIG_NET_ALIAS" = "y" ]; then
diff -u --recursive --new-file pre2.0.4/linux/net/ipv4/icmp.c linux/net/ipv4/icmp.c
--- pre2.0.4/linux/net/ipv4/icmp.c	Sat Apr 27 15:20:10 1996
+++ linux/net/ipv4/icmp.c	Thu May 16 16:35:55 1996
@@ -24,6 +24,8 @@
  *		Martin Mares	:	Echo requests may be configured to be ignored (RFC 1812).
  *		Martin Mares	:	Limitation of ICMP error message transmit rate (RFC 1812).
  *		Martin Mares	:	TOS and Precedence set correctly (RFC 1812).
+ *		Martin Mares	:	Now copying as much data from the original packet
+ *					as we can without exceeding 576 bytes (RFC 1812).
  *
  *
  *
@@ -98,7 +100,7 @@
  *   MUST initialize TTL when originating an ICMP message (OK)
  *  4.3.2.3 (Original Message Header)
  *   SHOULD copy as much data from the offending packet as possible without
- *     the length of the ICMP datagram exceeding 576 bytes (NOT YET)
+ *     the length of the ICMP datagram exceeding 576 bytes (OK)
  *   MUST leave original IP header of the offending packet, but we're not
  *     required to undo modifications made (OK)
  *  4.3.2.4 (Original Message Source Address)
@@ -171,8 +173,8 @@
  *     compile-time option)
  *   SHOULD have option for each interface for AMRe's, MUST default to NO (NOT YET)
  *   MUST NOT reply to AMRq before knows the correct AM (OK)
- *   MUST NOT respond to AMRq with source address 0.0.0.0 and the AM's for
- *     logical i-faces for the physical i-face are not the same (NOT YET)
+ *   MUST NOT respond to AMRq with source address 0.0.0.0 on physical interfaces
+ *     having multiple logical i-faces with different masks (NOT YET)
  *   SHOULD examine all AMRe's it receives and check them (NOT YET)
  *   SHOULD log invalid AMRe's (AM+sender) (NOT YET)
  *   MUST NOT use contents of AMRe to determine correct AM (OK)
@@ -188,7 +190,7 @@
  *   SHOULD choose a best-match response code (OK)
  *   SHOULD NOT generate Host Isolated codes (OK)
  *   SHOULD use Communication Administratively Prohibited when administratively
- *     filtering packets (NOT YET)
+ *     filtering packets (NOT YET -- bug-to-bug compatibility)
  *   MAY include config option for not generating the above and silently discard
  *     the packets instead (OK)
  *   MAY include config option for not generating Precedence Violation and
@@ -496,7 +498,7 @@
 /*
  *	Send an ICMP message in response to a situation
  *
- *	RFC 1122: 3.2.2	MUST send at least the IP header and 8 bytes of header. MAY send more (we don't).
+ *	RFC 1122: 3.2.2	MUST send at least the IP header and 8 bytes of header. MAY send more (we do).
  *			MUST NOT change this header information.
  *			MUST NOT reply to a multicast/broadcast IP address.
  *			MUST NOT reply to a multicast/broadcast MAC address.
@@ -507,7 +509,7 @@
 {
 	struct iphdr *iph;
 	struct icmphdr *icmph;
-	int atype;
+	int atype, room;
 	struct icmp_bxm icmp_param;
 	__u32 saddr;
 	
@@ -572,25 +574,33 @@
 #endif	
 
 	/*
-	 *	Tell our driver what to send
+	 *	Construct source address and options.
 	 */
 	 
 	saddr=iph->daddr;
 	if(saddr!=dev->pa_addr && ip_chk_addr(saddr)!=IS_MYADDR)
 		saddr=dev->pa_addr;
-	
+	if(ip_options_echo(&icmp_param.replyopts, NULL, saddr, iph->saddr, skb_in))
+		return;
+
+	/*
+	 *	Prepare data for ICMP header.
+	 */
+
 	icmp_param.icmph.type=type;
 	icmp_param.icmph.code=code;
 	icmp_param.icmph.un.gateway = info;
 	icmp_param.data_ptr=iph;
-	icmp_param.data_len=(iph->ihl<<2)+8;	/* RFC says return header + 8 bytes */
+	room = 576 - sizeof(struct iphdr) - icmp_param.replyopts.optlen;
+	icmp_param.data_len=(iph->ihl<<2)+skb_in->len;	/* RFC says return as much as we can without exceeding 576 bytes */
+	if (icmp_param.data_len > room)
+		icmp_param.data_len = room;
 	
 	/*
-	 *	Set it to build.
+	 *	Build and send the packet.
 	 */
 
-	if (ip_options_echo(&icmp_param.replyopts, NULL, saddr, iph->saddr, skb_in) == 0)
-	  icmp_build_xmit(&icmp_param, saddr, iph->saddr, ((iph->tos & 0x38) | 6));
+	icmp_build_xmit(&icmp_param, saddr, iph->saddr, ((iph->tos & 0x38) | 6));
 }
 
 
diff -u --recursive --new-file pre2.0.4/linux/net/ipv4/ip_forward.c linux/net/ipv4/ip_forward.c
--- pre2.0.4/linux/net/ipv4/ip_forward.c	Mon May 13 23:02:52 1996
+++ linux/net/ipv4/ip_forward.c	Wed May 15 10:30:15 1996
@@ -250,7 +250,15 @@
 		 * (Don't masquerade de-masqueraded fragments)
 		 */
 		if (!(is_frag&IPFWD_MASQUERADED) && fw_res==FW_MASQUERADE)
-			ip_fw_masquerade(&skb, dev2);
+			if (ip_fw_masquerade(&skb, dev2) < 0)
+			{
+				/*
+				 * Masquerading failed; silently discard this packet.
+				 */
+				if (rt)
+					ip_rt_put(rt);
+				return -1;
+			}
 #endif
 		IS_SKB(skb);
 
diff -u --recursive --new-file pre2.0.4/linux/net/ipv4/ip_masq.c linux/net/ipv4/ip_masq.c
--- pre2.0.4/linux/net/ipv4/ip_masq.c	Tue May  7 16:22:41 1996
+++ linux/net/ipv4/ip_masq.c	Thu May 16 16:35:56 1996
@@ -12,7 +12,7 @@
  *	Juan Jose Ciarlante	:	Added hashed lookup by proto,maddr,mport and proto,saddr,sport
  *	Juan Jose Ciarlante	:	Fixed deadlock if free ports get exhausted
  *	Juan Jose Ciarlante	:	Added NO_ADDR status flag.
- *
+ *	Nigel Metheringham	:	ICMP handling.
  *	
  */
 
@@ -27,8 +27,10 @@
 #include <linux/in.h>
 #include <linux/ip.h>
 #include <net/protocol.h>
+#include <net/icmp.h>
 #include <net/tcp.h>
 #include <net/udp.h>
+#include <net/checksum.h>
 #include <net/ip_masq.h>
 
 #define IP_MASQ_TAB_SIZE 256    /* must be power of 2 */
@@ -192,8 +194,6 @@
 struct ip_masq *
 ip_masq_in_get(struct iphdr *iph)
 {
-        unsigned hash;
-        struct ip_masq *ms;
  	__u16 *portptr;
         int protocol;
         __u32 s_addr, d_addr;
@@ -206,6 +206,29 @@
         d_addr = iph->daddr;
         d_port = portptr[1];
 
+        return ip_masq_in_get_2(protocol, s_addr, s_port, d_addr, d_port);
+}
+
+/*
+ *	Returns ip_masq associated with supplied parameters, either
+ *	broken out of the ip/tcp headers or directly supplied for those
+ *	pathological protocols with address/port in the data stream
+ *	(ftp, irc).  addresses and ports are in network order.
+ *	called for pkts coming from INside-to-outside the firewall.
+ *
+ * 	NB. Cannot check destination address, just for the incoming port.
+ * 	reason: archie.doc.ac.uk has 6 interfaces, you send to
+ * 	phoenix and get a reply from any other interface(==dst)!
+ *
+ * 	[Only for UDP] - AC
+ */
+
+struct ip_masq *
+ip_masq_in_get_2(int protocol, __u32 s_addr, __u16 s_port, __u32 d_addr, __u16 d_port)
+{
+        unsigned hash;
+        struct ip_masq *ms;
+
         hash = ip_masq_hash_key(protocol, d_addr, d_port);
         for(ms = ip_masq_m_tab[hash]; ms ; ms = ms->m_link) {
  		if ( protocol==ms->protocol &&
@@ -293,7 +316,7 @@
 #ifdef DEBUG_CONFIG_IP_MASQUERADE
 	printk("Masqueraded %s %lX:%X expired\n",
 			masq_proto_name(ms->protocol),
-			ntohl(ms->src),ntohs(ms->sport));
+			ntohl(ms->saddr),ntohs(ms->sport));
 #endif
 	
 	save_flags(flags);
@@ -424,7 +447,7 @@
 		uh->check=0xFFFF;
 }
 	
-void ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
+int ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev)
 {
 	struct sk_buff  *skb=*skb_ptr;
 	struct iphdr	*iph = skb->h.iph;
@@ -438,7 +461,7 @@
 	 */
 
 	if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
-		return;
+		return -1;
 
 	/*
 	 *	Now hunt the list to see if we have an old entry
@@ -467,7 +490,7 @@
                                  iph->daddr, portptr[1],
                                  0);
                 if (ms == NULL)
-			return;
+			return -1;
  	}
 
  	/*
@@ -535,8 +558,92 @@
  #ifdef DEBUG_CONFIG_IP_MASQUERADE
  	printk("O-routed from %lX:%X over %s\n",ntohl(ms->maddr),ntohs(ms->mport),dev->name);
  #endif
+
+	return 0;
  }
 
+/*
+ *	Handle ICMP messages.
+ *	Find any that might be relevant, check against existing connections,
+ *	forward to masqueraded host if relevant.
+ *	Currently handles error types - unreachable, quench, ttl exceeded
+ */
+
+int ip_fw_demasq_icmp(struct sk_buff **skb_p, struct device *dev)
+{
+        struct sk_buff 	*skb   = *skb_p;
+ 	struct iphdr	*iph   = skb->h.iph;
+	struct icmphdr  *icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
+	struct iphdr    *ciph;	/* The ip header contained within the ICMP */
+	__u16	*portptr;	/* port numbers from TCP/UDP contained header */
+	struct ip_masq	*ms;
+
+#ifdef DEBUG_CONFIG_IP_MASQUERADE
+ 	printk("Incoming ICMP (%d) %lX -> %lX\n",
+	        icmph->type,
+ 		ntohl(iph->saddr), ntohl(iph->daddr));
+#endif
+
+	if ((icmph->type != ICMP_DEST_UNREACH) &&
+	    (icmph->type != ICMP_SOURCE_QUENCH) &&
+	    (icmph->type != ICMP_TIME_EXCEEDED))
+		return 0;
+
+	/* Now find the contained IP header */
+	ciph = (struct iphdr *) (icmph + 1);
+
+	/* We are only interested ICMPs generated from TCP or UDP packets */
+	if ((ciph->protocol != IPPROTO_UDP) && (ciph->protocol != IPPROTO_TCP))
+		return 0;
+
+	/* 
+	 * Find the ports involved - remember this packet was 
+	 * *outgoing* so the ports are reversed (and addresses)
+	 */
+	portptr = (__u16 *)&(((char *)ciph)[ciph->ihl*4]);
+	if (ntohs(portptr[0]) < PORT_MASQ_BEGIN ||
+ 	    ntohs(portptr[0]) > PORT_MASQ_END)
+ 		return 0;
+
+#ifdef DEBUG_CONFIG_IP_MASQUERADE
+ 	printk("Handling ICMP for %lX:%X -> %lX:%X\n",
+	       ntohl(ciph->saddr), ntohs(portptr[0]),
+	       ntohl(ciph->daddr), ntohs(portptr[1]));
+#endif
+
+	/* This is pretty much what ip_masq_in_get() does, except params are wrong way round */
+	ms = ip_masq_in_get_2(ciph->protocol, ciph->daddr, portptr[1], ciph->saddr, portptr[0]);
+
+	if (ms == NULL)
+		return 0;
+
+	/* Now we do real damage to this packet...! */
+	/* First change the dest IP address, and recalc checksum */
+	iph->daddr = ms->saddr;
+	ip_send_check(iph);
+	
+	/* Now change the *source* address in the contained IP */
+	ciph->saddr = ms->saddr;
+	ip_send_check(ciph);
+	
+	/* the TCP/UDP source port - cannot redo check */
+	portptr[0] = ms->sport;
+
+	/* And finally the ICMP checksum */
+	icmph->checksum = 0;
+	icmph->checksum = ip_compute_csum((unsigned char *) icmph, 
+				      skb->len - sizeof(struct iphdr));
+
+#ifdef DEBUG_CONFIG_IP_MASQUERADE
+ 	printk("Rewrote ICMP to %lX:%X -> %lX:%X\n",
+	       ntohl(ciph->saddr), ntohs(portptr[0]),
+	       ntohl(ciph->daddr), ntohs(portptr[1]));
+#endif
+
+	return 1;
+}
+
+
  /*
   *	Check if it's an masqueraded port, look it up,
   *	and send it on its way...
@@ -554,7 +661,8 @@
  	struct ip_masq	*ms;
 	unsigned short  frag;
 
- 	if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP)
+ 	if (iph->protocol!=IPPROTO_UDP && iph->protocol!=IPPROTO_TCP 
+	    && iph->protocol!=IPPROTO_ICMP)
  		return 0;
 
 	/*
@@ -567,6 +675,9 @@
 	{
 		return 0;
 	}
+
+	if (iph->protocol == IPPROTO_ICMP)
+		return ip_fw_demasq_icmp(skb_p, dev);
 
  	portptr = (__u16 *)&(((char *)iph)[iph->ihl*4]);
  	if (ntohs(portptr[1]) < PORT_MASQ_BEGIN ||
diff -u --recursive --new-file pre2.0.4/linux/net/ipv4/route.c linux/net/ipv4/route.c
--- pre2.0.4/linux/net/ipv4/route.c	Tue May  7 16:22:42 1996
+++ linux/net/ipv4/route.c	Thu May 16 16:35:56 1996
@@ -1712,8 +1712,13 @@
 
 void ip_rt_update(int event, struct device *dev)
 {
+/*
+ *	This causes too much grief to do now.
+ */
+#ifdef COMING_IN_2_1
 	if (event == NETDEV_UP)
 		rt_add(RTF_HOST|RTF_UP, dev->pa_addr, ~0, 0, dev, 0, 0, 0, 0);
 	else if (event == NETDEV_DOWN)
 		rt_del(dev->pa_addr, ~0, dev, 0, RTF_HOST|RTF_UP, 0);
+#endif		
 }
diff -u --recursive --new-file pre2.0.4/linux/net/ipv4/tcp.c linux/net/ipv4/tcp.c
--- pre2.0.4/linux/net/ipv4/tcp.c	Mon May 13 23:02:53 1996
+++ linux/net/ipv4/tcp.c	Fri May 17 09:42:00 1996
@@ -200,7 +200,8 @@
  *					against machines running Solaris,
  *					and seems to result in general
  *					improvement.
- *
+ *	Stefan Magdalinski	:	adjusted tcp_readable() to fix FIONREAD
+ *					
  * To Fix:
  *		Fast path the code. Two things here - fix the window calculation
  *		so it doesn't iterate over the queue, also spot packets with no funny
@@ -519,11 +520,13 @@
 	{
 		/*
 		 * FIXME:
-		 * For now we will just trigger a linear backoff.
-		 * The slow start code should cause a real backoff here.
+		 * Follow BSD for now and just reduce cong_window to 1 again.
+		 * It is possible that we just want to reduce the
+		 * window by 1/2, or that we want to reduce ssthresh by 1/2
+		 * here as well.
 		 */
-		if (sk->cong_window > 4)
-			sk->cong_window--;
+		sk->cong_window = 1;
+		sk->high_seq = sk->sent_seq;
 		return;
 	}
 
@@ -644,7 +647,7 @@
 		 */
 		if (skb->h.th->urg)
 			amount--;	/* don't count urg data */
-		if (amount && skb->h.th->psh) break;
+/*		if (amount && skb->h.th->psh) break;*/
 		skb = skb->next;
 	}
 	while(skb != (struct sk_buff *)&sk->receive_queue);
diff -u --recursive --new-file pre2.0.4/linux/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- pre2.0.4/linux/net/ipv4/tcp_input.c	Mon May 13 23:02:53 1996
+++ linux/net/ipv4/tcp_input.c	Fri May 17 09:42:00 1996
@@ -21,6 +21,10 @@
  *
  * FIXES
  *		Pedro Roque	:	Double ACK bug
+ *		Eric Schenk	:	Fixes to slow start algorithm.
+ *		Eric Schenk	:	Yet another double ACK bug.
+ *		Eric Schenk	:	Delayed ACK bug fixes.
+ *		Eric Schenk	:	Floyd style fast retrans war avoidance.
  */
 
 #include <linux/config.h>
@@ -57,7 +61,15 @@
 		if (m <= 0)
 			m = 1;
 
-		if (m > (sk->rtt >> 3)) 
+		/* Yikes. This used to test if m was larger than rtt/8.
+		 * Maybe on a long delay high speed link this would be
+	         * good initial guess, but over a slow link where the
+	         * delay is dominated by transmission time this will
+	         * be very bad, since ato will almost always be something
+		 * more like rtt/2. Better to discard data points that
+		 * are larger than the rtt estimate.
+	         */
+		if (m > sk->rtt)
 		{
 			sk->ato = sk->rtt >> 3;
 			/*
@@ -66,6 +78,11 @@
 		}
 		else 
 		{
+			/*
+		 	 * Very fast acting estimator.
+		 	 * May fluctuate too much. Probably we should be
+			 * doing something like the rtt estimator here.
+			 */
 			sk->ato = (sk->ato >> 1) + m;
 			/*
 			 * printk(KERN_DEBUG "ato: m %lu\n", sk->ato);
@@ -104,14 +121,14 @@
 	} else {
 		/* no previous measure. */
 		sk->rtt = m<<3;		/* take the measured time to be rtt */
-		sk->mdev = m<<2;	/* make sure rto = 3*rtt */
+		sk->mdev = m<<1;	/* make sure rto = 3*rtt */
 	}
 
 	/*
 	 *	Now update timeout.  Note that this removes any backoff.
 	 */
 			 
-	sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1;
+	sk->rto = (sk->rtt >> 3) + sk->mdev;
 	if (sk->rto > 120*HZ)
 		sk->rto = 120*HZ;
 	if (sk->rto < HZ/5)	/* Was 1*HZ - keep .2 as minimum cos of the BSD delayed acks */
@@ -180,11 +197,9 @@
 	}
 
 	/*
-	 *	4.3reno machines look for these kind of acks so they can do fast
-	 *	recovery. Three identical 'old' acks lets it know that one frame has
-	 *	been lost and should be resent. Because this is before the whole window
-	 *	of data has timed out it can take one lost frame per window without
-	 *	stalling. [See Jacobson RFC1323, Stevens TCP/IP illus vol2]
+	 * 	This packet is old news. Usually this is just a resend
+	 * 	from the far end, but sometimes it means the far end lost
+	 *	an ACK we send, so we better send an ACK.
 	 */
 	tcp_send_ack(sk);
 }
@@ -398,13 +413,19 @@
 	newsk->send_head = NULL;
 	newsk->send_tail = NULL;
 	skb_queue_head_init(&newsk->back_log);
-	newsk->rtt = 0;		/*TCP_CONNECT_TIME<<3*/
+	newsk->rtt = 0;
 	newsk->rto = TCP_TIMEOUT_INIT;
-	newsk->mdev = TCP_TIMEOUT_INIT<<1;
+	newsk->mdev = TCP_TIMEOUT_INIT;
 	newsk->max_window = 0;
+	/*
+	 * See draft-stevens-tcpca-spec-01 for discussion of the
+	 * initialization of these values.
+	 */
 	newsk->cong_window = 1;
 	newsk->cong_count = 0;
-	newsk->ssthresh = 0;
+	newsk->ssthresh = 0x7fffffff;
+
+	newsk->high_seq = 0;
 	newsk->backoff = 0;
 	newsk->blog = 0;
 	newsk->intr = 0;
@@ -684,7 +705,7 @@
 		 * interpreting "new data is acked" as including data that has
 		 * been retransmitted but is just now being acked.
 		 */
-		if (sk->cong_window < sk->ssthresh)  
+		if (sk->cong_window <= sk->ssthresh)
 			/* 
 			 *	In "safe" area, increase
 			 */
@@ -720,6 +741,8 @@
 	 * (2) it has the same window as the last ACK,
 	 * (3) we have outstanding data that has not been ACKed
 	 * (4) The packet was not carrying any data.
+	 * (5) [From Floyds paper on fast retransmit wars]
+	 *     The packet acked data after high_seq;
 	 * I've tried to order these in occurrence of most likely to fail
 	 * to least likely to fail.
 	 * [These are the rules BSD stacks use to determine if an ACK is a
@@ -729,7 +752,8 @@
 	if (sk->rcv_ack_seq == ack
 		&& sk->window_seq == window_seq
 		&& !(flag&1)
-		&& before(ack, sk->sent_seq))
+		&& before(ack, sk->sent_seq)
+		&& after(ack, sk->high_seq))
 	{
 		/* See draft-stevens-tcpca-spec-01 for explanation
 		 * of what we are doing here.
@@ -738,12 +762,16 @@
 		if (sk->rcv_ack_cnt == MAX_DUP_ACKS+1) {
 			sk->ssthresh = max(sk->cong_window >> 1, 2);
 			sk->cong_window = sk->ssthresh+MAX_DUP_ACKS+1;
-			tcp_do_retransmit(sk,0);
-			/* reduce the count. We don't want to be
-			* seen to be in "retransmit" mode if we
-			* are doing a fast retransmit.
-			*/
+			/* FIXME:
+			 * reduce the count. We don't want to be
+			 * seen to be in "retransmit" mode if we
+			 * are doing a fast retransmit.
+			 * This is also a signal to tcp_do_retransmit
+			 * not to set sk->high_seq.
+			 * This is a horrible ugly hack.
+			 */
 			sk->retransmits--;
+			tcp_do_retransmit(sk,0);
 		} else if (sk->rcv_ack_cnt > MAX_DUP_ACKS+1) {
 			sk->cong_window++;
 			/*
@@ -795,7 +823,18 @@
 			 *	Recompute rto from rtt.  this eliminates any backoff.
 			 */
 
-			sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1;
+			/*
+			 * Appendix C of Van Jacobson's final version of
+			 * the SIGCOMM 88 paper states that although
+			 * the original paper suggested that
+			 *  RTO = R*2V
+			 * was the correct calculation experience showed
+			 * better results using
+			 *  RTO = R*4V
+			 * In particular this gives better performance over
+			 * slow links, and should not effect fast links.
+			 */
+			sk->rto = (sk->rtt >> 3) + sk->mdev;
 			if (sk->rto > 120*HZ)
 				sk->rto = 120*HZ;
 			if (sk->rto < HZ/5)	/* Was 1*HZ, then 1 - turns out we must allow about
@@ -827,7 +866,7 @@
 			break;
 
 		if (sk->retransmits) 
-		{	
+		{
 			/*
 			 *	We were retransmitting.  don't count this in RTT est 
 			 */
@@ -1322,7 +1361,7 @@
 			int delay = HZ/2;
 			if (th->psh)
 				delay = HZ/50;
-			tcp_send_delayed_ack(sk, delay);
+			tcp_send_delayed_ack(sk, delay, sk->ato);
 		}
 
 		/*
@@ -1357,7 +1396,15 @@
 		    if(sk->debug)
 			    printk("Ack past end of seq packet.\n");
 		    tcp_send_ack(sk);
-		    tcp_send_delayed_ack(sk,HZ/2);
+		    /*
+		     * We need to be very careful here. We must
+		     * not violate Jacobsons packet conservation condition.
+		     * This means we should only send an ACK when a packet
+		     * leaves the network. We can say a packet left the
+		     * network when we see a packet leave the network, or
+		     * when an rto measure expires.
+		     */
+		    tcp_send_delayed_ack(sk,sk->rto,sk->rto);
 	    }
 	}
 }
@@ -1397,7 +1444,8 @@
 		kfree_skb(skb, FREE_READ);
 		return(0);
 	}
-	
+
+
 	/*
 	 *	We no longer have anyone receiving data on this connection.
 	 */
@@ -1455,6 +1503,11 @@
 
 #endif
 
+	/*
+  	 * We should only call this if there is data in the frame.
+ 	 */
+	tcp_delack_estimator(sk);
+
 	tcp_queue(skb, sk, th);
 
 	return(0);
@@ -1900,8 +1953,6 @@
 		return tcp_reset(sk,skb);	
 	}
 
-	tcp_delack_estimator(sk);
-	
 	/*
 	 *	Process the ACK
 	 */
diff -u --recursive --new-file pre2.0.4/linux/net/ipv4/tcp_output.c linux/net/ipv4/tcp_output.c
--- pre2.0.4/linux/net/ipv4/tcp_output.c	Mon May 13 23:02:53 1996
+++ linux/net/ipv4/tcp_output.c	Fri May 17 09:42:46 1996
@@ -188,7 +188,7 @@
 		tcp_send_check(th, sk->saddr, sk->daddr, size, skb);
 
 		sk->sent_seq = sk->write_seq;
-		
+
 		/*
 		 *	This is mad. The tcp retransmit queue is put together
 		 *	by the ip layer. This causes half the problems with
@@ -527,6 +527,7 @@
 			}
 		}
 		
+
 		/*
 		 *	Count retransmissions
 		 */
@@ -535,6 +536,13 @@
 		sk->retransmits++;
 		sk->prot->retransmits++;
 		tcp_statistics.TcpRetransSegs++;
+
+		/*
+		 * Record the high sequence number to help avoid doing
+		 * to much fast retransmission.
+		 */
+		if (sk->retransmits)
+			sk->high_seq = sk->sent_seq;
 		
 
 		/*
@@ -821,20 +829,27 @@
  *      - delay time <= 0.5 HZ
  *      - must send at least every 2 full sized packets
  *      - we don't have a window update to send
+ *
+ * 	additional thoughts:
+ *	- we should not delay sending an ACK if we have ato > 0.5 HZ.
+ *	  My thinking about this is that in this case we will just be
+ *	  systematically skewing the RTT calculation. (The rule about
+ *	  sending every two full sized packets will never need to be
+ *	  invoked, the delayed ack will be sent before the ATO timeout
+ *	  every time. Of course, the relies on our having a good estimate
+ *	  for packet interarrival times.
  */
-void tcp_send_delayed_ack(struct sock * sk, int max_timeout)
+void tcp_send_delayed_ack(struct sock * sk, int max_timeout, unsigned long timeout)
 {
-	unsigned long timeout, now;
+	unsigned long now;
 
 	/* Calculate new timeout */
 	now = jiffies;
-	timeout = sk->ato;
-	if (timeout > max_timeout)
-		timeout = max_timeout;
-	timeout += now;
-	if (sk->bytes_rcv > sk->max_unacked) {
+	if (timeout > max_timeout || sk->bytes_rcv >= sk->max_unacked) {
 		timeout = now;
 		mark_bh(TIMER_BH);
+	} else {
+		timeout += now;
 	}
 
 	/* Use new timeout only if there wasn't a older one earlier  */
@@ -894,7 +909,7 @@
 		 *	resend packets. 
 		 */
 
-		tcp_send_delayed_ack(sk, HZ/2);
+		tcp_send_delayed_ack(sk, HZ/2, HZ/2);
 		return;
 	}
 
diff -u --recursive --new-file pre2.0.4/linux/net/socket.c linux/net/socket.c
--- pre2.0.4/linux/net/socket.c	Mon May 13 23:02:54 1996
+++ linux/net/socket.c	Thu May 16 16:35:56 1996
@@ -351,7 +351,7 @@
 	msg.msg_name=NULL;
 	msg.msg_iov=&iov;
 	msg.msg_iovlen=1;
-	msg.msg_accrights=NULL;
+	msg.msg_control=NULL;
 	iov.iov_base=ubuf;
 	iov.iov_len=size;
 
@@ -386,7 +386,7 @@
 	msg.msg_name=NULL;
 	msg.msg_iov=&iov;
 	msg.msg_iovlen=1;
-	msg.msg_accrights=NULL;
+	msg.msg_control=NULL;
 	iov.iov_base=(void *)ubuf;
 	iov.iov_len=size;
 	
@@ -919,7 +919,7 @@
 	msg.msg_name=NULL;
 	msg.msg_iov=&iov;
 	msg.msg_iovlen=1;
-	msg.msg_accrights=NULL;
+	msg.msg_control=NULL;
 	return(sock->ops->sendmsg(sock, &msg, len, (file->f_flags & O_NONBLOCK), flags));
 }
 
@@ -959,7 +959,7 @@
 	msg.msg_namelen=addr_len;
 	msg.msg_iov=&iov;
 	msg.msg_iovlen=1;
-	msg.msg_accrights=NULL;
+	msg.msg_control=NULL;
 	return(sock->ops->sendmsg(sock, &msg, len, (file->f_flags & O_NONBLOCK),
 		flags));
 }
@@ -994,7 +994,7 @@
 	msg.msg_name=NULL;
 	msg.msg_iov=&iov;
 	msg.msg_iovlen=1;
-	msg.msg_accrights=NULL;
+	msg.msg_control=NULL;
 	iov.iov_base=ubuf;
 	iov.iov_len=size;
 
@@ -1030,7 +1030,7 @@
 	if(err)
 	  	return err;
   
-  	msg.msg_accrights=NULL;
+  	msg.msg_control=NULL;
   	msg.msg_iovlen=1;
   	msg.msg_iov=&iov;
   	iov.iov_len=size;
diff -u --recursive --new-file pre2.0.4/linux/net/unix/af_unix.c linux/net/unix/af_unix.c
--- pre2.0.4/linux/net/unix/af_unix.c	Wed May 15 11:01:16 1996
+++ linux/net/unix/af_unix.c	Thu May 16 16:35:56 1996
@@ -361,6 +361,9 @@
 	 *	Linux we behave like files and pipes do and wait for the last dereference.
 	 */
 	 
+	sock->data = NULL;
+	sk->socket = NULL;
+	
 	return 0;
 }
 
@@ -916,14 +919,14 @@
 	/*
 	 *	A control message has been attached.
 	 */
-	if(msg->msg_accrights) 
+	if(msg->msg_control) 
 	{
-		struct cmsghdr *cm=unix_copyrights(msg->msg_accrights, 
-						msg->msg_accrightslen);
-		if(cm==NULL || msg->msg_accrightslen<sizeof(struct cmsghdr) ||
+		struct cmsghdr *cm=unix_copyrights(msg->msg_control, 
+						msg->msg_controllen);
+		if(cm==NULL || msg->msg_controllen<sizeof(struct cmsghdr) ||
 		   cm->cmsg_type!=SCM_RIGHTS ||
 		   cm->cmsg_level!=SOL_SOCKET ||
-		   msg->msg_accrightslen!=cm->cmsg_len)
+		   msg->msg_controllen!=cm->cmsg_len)
 		{
 			kfree(cm);
 		   	return -EINVAL;
@@ -1072,22 +1075,22 @@
 	if(sk->err)
 		return sock_error(sk);
 
-	if(msg->msg_accrights) 
+	if(msg->msg_control) 
 	{
-		cm=unix_copyrights(msg->msg_accrights, 
-			msg->msg_accrightslen);
-		if(msg->msg_accrightslen<sizeof(struct cmsghdr)
+		cm=unix_copyrights(msg->msg_control, 
+			msg->msg_controllen);
+		if(msg->msg_controllen<sizeof(struct cmsghdr)
 #if 0 
 /*		investigate this further -- Stevens example doesn't seem to care */
 		||
 		   cm->cmsg_type!=SCM_RIGHTS ||
 		   cm->cmsg_level!=SOL_SOCKET ||
-		   msg->msg_accrightslen!=cm->cmsg_len
+		   msg->msg_controllen!=cm->cmsg_len
 #endif
 		)
 		{
 			kfree(cm);
-/*			printk("recvmsg: Bad msg_accrights\n");*/
+/*			printk("recvmsg: Bad msg_control\n");*/
 		   	return -EINVAL;
 		}
 	}
@@ -1160,7 +1163,7 @@
 out:
 	up(&sk->protinfo.af_unix.readsem);
 	if(cm)
-		unix_returnrights(msg->msg_accrights,msg->msg_accrightslen,cm);
+		unix_returnrights(msg->msg_control,msg->msg_controllen,cm);
 	return copied;
 }
 
